linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver
@ 2014-05-28  8:57 Satish Patel
  2014-05-28  8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel
                   ` (4 more replies)
  0 siblings, 5 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-28  8:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-omap, devicetree, gregkh,
	rob, tony
  Cc: grant.likely, robh+dt, Satish Patel

Changes since v2:
* RFC comments are fixed for all 

* ti-usim:
** synchronous card support is added
** Timeout added for ATR 
** BWT configuration
** softreset of IP at initialization added
** PM suspend/resume support added

* sc_phy : sync card support is added
* ARM: dts: AM43xx: fck clock entry is added to usim

v1 cover letter link#
https://lkml.org/lkml/2014/1/6/250

v2 cover letter link#
https://lkml.org/lkml/2014/1/19/168

Satish Patel (5):
  sc_phy:SmartCard(SC) PHY interface to SC controller
  misc: tda8026: Add NXP TDA8026 PHY driver
  char: ti-usim: Add driver for USIM module on AM43xx
  ARM: dts: AM43xx: DT entries added for ti-usim
  ARM: dts: AM43xx-epos-evm: DT entries  for ti-usim and phy

 Documentation/devicetree/bindings/misc/tda8026.txt |   19 +
 .../devicetree/bindings/ti-usim/ti-usim.txt        |   32 +
 Documentation/sc_phy.txt                           |  171 ++
 arch/arm/boot/dts/am4372.dtsi                      |   12 +
 arch/arm/boot/dts/am43x-epos-evm.dts               |   31 +
 drivers/char/Kconfig                               |    7 +
 drivers/char/Makefile                              |    1 +
 drivers/char/ti-usim-hw.h                          |  864 ++++++++
 drivers/char/ti-usim.c                             | 2213 ++++++++++++++++++++
 drivers/misc/Kconfig                               |    7 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/tda8026.c                             | 1258 +++++++++++
 include/linux/sc_phy.h                             |  136 ++
 include/linux/ti-usim.h                            |  111 +
 14 files changed, 4863 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt
 create mode 100644 Documentation/devicetree/bindings/ti-usim/ti-usim.txt
 create mode 100644 Documentation/sc_phy.txt
 create mode 100644 drivers/char/ti-usim-hw.h
 create mode 100644 drivers/char/ti-usim.c
 create mode 100644 drivers/misc/tda8026.c
 create mode 100644 include/linux/sc_phy.h
 create mode 100644 include/linux/ti-usim.h

-- 
1.7.9.5


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

* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-28  8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel
@ 2014-05-28  8:57 ` Satish Patel
  2014-05-28 18:44   ` Greg KH
  2014-05-28 18:53   ` Greg KH
  2014-05-28  8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-28  8:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-omap, devicetree, gregkh,
	rob, tony
  Cc: grant.likely, robh+dt, Satish Patel

SmartCard controller uses this interface to communicate with
SmartCard via PHY

Some SmartCard PHY has multiple slots for cards.
This inerface also enables controller to communicate
with one or more SmartCard connected over phy.

interface structure includes following APIs
- set/get config
- activate/deactivate smart card
- warm reset
- register_notify (for card insert/remove/overheat)
- unregister_notify

Signed-off-by: Satish Patel <satish.patel@ti.com>
---
 Documentation/sc_phy.txt |  171 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sc_phy.h   |  136 ++++++++++++++++++++++++++++++++++++
 2 files changed, 307 insertions(+)
 create mode 100644 Documentation/sc_phy.txt
 create mode 100644 include/linux/sc_phy.h

diff --git a/Documentation/sc_phy.txt b/Documentation/sc_phy.txt
new file mode 100644
index 0000000..d610e26
--- /dev/null
+++ b/Documentation/sc_phy.txt
@@ -0,0 +1,171 @@
+		SmartCard PHY Interface
+	Satish Patel <satish.patel@ti.com>
+
+This document explains the SmartCard interface between SmartCard
+controller and SmartCard phy. Document also describes how-to-use.
+
+1. Why SmartCard PHY Interface?
+
+The use of smartcard is increasing in embedded industry. As smartcard
+not only prevent duplication but also, brings key based authentication
+flow into picture.
+
+SmartCard standards like EMV(EuroPay-Mastercard-Visa) are becoming
+mandatory for payment terminals.
+
+Till date, most of the SmartCard readers are based on USB serial
+interface. Which drives its logic within firmware lies on device.
+Few are based on FPGA solutions. But now SoCs are coming up with
+inbuilt smartcard controller. e.g. TI-AM43x
+
+Role of SmartCard controller and SmartCard phy:
+
+Smartcard Phy:
+Forms electrical interface between controller and SmartCard. Phy
+enables access to more than one smartcard and in addition it provides
+fast deactivation logic when card gets removed from the slot. It can
+also generate the signals like card insert/remove/overheat etc.
+
+Smartcard Controller:
+In built mechanism to meet EMV L1 specification (e.g. T=0, T=1
+protocol timings, ATR timeout etc..) for SmartCard transaction. In
+addition to this, it has FIFO to store tx/rx bytes, internal state
+machine for ATR, Tx/Rx, Synchronous/Asynchronous mode, timing
+counters etc..
+
+Controller can also have direct interface through which SmartCard
+can be connected without phy.
+
+Below is the brief of SmartCard block diagram from user to h/w
+layer.
+
+
+        -----------
+        |PC/SC App|
+        -----------
+        -----------     -----------
+        |PC/SC F/W|     | Visa APP|
+        -----------     -----------
+        -----------     ------------    ------------
+        |IFD Hand.|     | EMV L1/L2|    | Test App |
+        -----------     ------------    ------------
+User Space
+--------------------------------------------------------------------
+
+        -----------------------------------------
+        |   SmartCard Controller Driver        |
+        -----------------------------------------
+                 |                     |
+                 |                     |
+        -------------                  |
+        | Phy Driver |                 |
+        -------------                  |
+                 |                     |
+Kernel Space     |                     |
+--------------------------------------------------------------------
+                 |                     |
+           ---------              ----------------
+           | PHY   |              |Controller IP |
+           ---------              ----------------
+                |                       |
+--------------------------------------------------------------------
+                |                       |
+           _______________________________________
+           |                |                |
+         VISA card       Master Card      Custom Card
+
+
+At present in Linux there is no public interface exist which acts as
+bridge between controller and phy. Mostly vendors uses proprietary
+solution in such cases.
+
+2. Introduction to SmartCard PHY interface
+
+SmartCard PHY interface that exposes phy's capabilities to the smart
+card controller. SmartCard controller uses this interface to
+communicate with SmartCard via phy.
+
+Such capabilities are:
+1) Some SmartCard phy (e.g. TDA8026-NxP) has multiple slots for smart
+cards. This interface enables controller to communicate with specific
+SmartCard inserted to the specific phy's slot.
+
+2) Warm reset to SmartCard inserted to phy slot.
+
+3) Bit banging of SmartCard pins to support vedor specific memory
+cards. Mostly when it comes to sychorous SmartCard
+
+4) Notification of card insert/remove/overheat etc.
+
+
+3. How to use
+
+SmartCard PHY:
+The SmartCard PHY driver, who wants to be interfaced with SmartCard
+controller require to follow below step
+
+- include "sc_phy.h"
+
+- use "sc_phy" structure as driver(client) data. PHY driver can use
+'void *pdata' of "sc_phy" to hold its private data(if any)
+
+- implement following capabilities (whichever is applicable)
+	set_config
+	get_config
+	activate_card
+	deactivate_card
+	warm_reset
+	register_notify
+	unregister_notify
+e.g.
+phyxx_init()
+{
+
+	struct sc_phy *sc_phy;
+	struct phyxx *pdata;
+
+	...
+	...
+	sc_phy->pdata = pdata;
+	sc_phy->set_config	= phyxx_set_config;
+	sc_phy->get_config	= phyxx_get_config;
+	sc_phy->activate_card	= phyxx_activate_card;
+}
+
+Device Tree Binding:
+Refer following reference to bind SmartCard PHY with SmartCard
+controller.
+
+	/* SmartCard PHY node */
+	&i2c0 {
+		clock-frequency = <10000000>;
+		phyxx: phyxx@yy {
+			compatible = "xyz,abc";
+			reg = <0xyy>;
+		 };
+	};
+
+	/* SmartCard Controller node*/
+	&usim0 {
+		....
+		phy = <&phyxx>;
+		phy-slots = <1>;
+	};
+
+SmartCard Controller:
+- Access PHY interface using DT.
+Refer below example code
+
+	phy_i2c = of_find_i2c_device_by_node(phy_node);
+	if (phy_i2c == NULL) {
+		ret = -EINVAL;
+	}
+
+	/* get phy interface */
+	sc_phy = (struct sc_phy *)i2c_get_clientdata(phy_i2c);
+
+	/* register notifier */
+	sc_phy->register_notify(sc_phy, &notifier_cb, (void *)data);
+
+
+- Controller can use then after all defined SmartCard PHY interface
diff --git a/include/linux/sc_phy.h b/include/linux/sc_phy.h
new file mode 100644
index 0000000..9aed530
--- /dev/null
+++ b/include/linux/sc_phy.h
@@ -0,0 +1,136 @@
+/*
+ * sc_phy.h - Header file for Smart Card PHY operations.
+ * This is a smart card phy's interface to smart card controller.
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SC_PHY_H__
+#define __SC_PHY_H__
+
+#include <linux/notifier.h>
+
+/* defines used in notify action
+ * action will be composed of two part
+ * | 0x0000 | <slot> - 2 bytes| <action>- 2 bytes |
+ */
+#define SC_PHY_NOTIFICATION_ACTION_MASK (0x000000ffU)
+#define SC_PHY_NOTIFICATION_ACTION_SHIFT (0)
+
+#define SC_PHY_NOTIFICATION_SLOT_MASK (0x0000ff00U)
+#define SC_PHY_NOTIFICATION_SLOT_SHIFT (8)
+/*
+ * smart card supply voltage levels
+ */
+enum sc_supply_voltage {
+	SC_PHY_5V = 0,
+	SC_PHY_3V,
+	SC_PHY_1_8V
+};
+
+/*
+ * smarcard type - async or sync
+ */
+enum sc_phy_card_mode {
+	SC_PHY_ASYNC = 0,
+	SC_PHY_SYNC,
+	SC_PHY_SYNC_TYPE1,
+	SC_PHY_SYNC_TYPE2,
+};
+
+/*
+ * phy operational modes
+ */
+enum sc_phy_mode {
+	SC_PHY_ACTIVE = 0x11,
+	SC_PHY_CLOCKSTOP,
+	SC_PHY_STANDBY,
+	SC_PHY_SHUTDOWN,
+	SC_PHY_REMOVED,
+};
+
+/*
+ * smartcard actions. more actions will be as they gets introduced in upcoming
+ * smart card phys.
+ */
+enum sc_phy_card_action {
+	SC_PHY_CARD_INSERTED	= 0x1,
+	SC_PHY_CARD_REMOVED	= 0x2,
+	SC_PHY_CARD_OVERHEAT	= 0x4,
+	SC_PHY_CARD_ATR_TIMEOUT	= 0x8,
+	SC_PHY_CARD_SYNC_ACT_COMPLETE = 0x10,
+};
+
+/*
+ * configuration parameters of smart card phy
+ */
+enum sc_phy_config {
+	SC_PHY_VERSION = 0,
+	SC_PHY_CARD_SUPPLY_VOLTAGE,
+	SC_PHY_CARD_PRESENCE,
+	SC_PHY_ATR_MUTE_TIME,
+	SC_PHY_ATR_EARLY_TIME,
+	SC_PHY_CARD_MODE,	/* sync or async mode */
+	SC_PHY_IO,	/* disable or enable i/o line connected to phy */
+	SC_PHY_CLKDIV,	/* clock division for the clock supplied to phy */
+	SC_PHY_MODE,
+	SC_PHY_PIN_CLK,
+	SC_PHY_PIN_RST,
+	SC_PHY_PIN_C4,
+	SC_PHY_PIN_C8
+};
+/**
+ * struct sc_phy - The basic smart card phy structure
+ *
+ * @dev: phy device
+ * @pdata: pointer to phy's private data structure
+ * @set_config: called to set phy's configuration
+ * @get_config: called to get phy's configuration
+ * @activate_card: perform smart card activation
+ * @deactivate_card: perform smart card de-activation
+ * @warm_reset: execute smart card warm reset sequence
+ * @register_card_activity_cb: register call back to phy device.
+ * This call back will be called on card insert or remove event
+ *
+ * smart card controller uses this interface to communicate with
+ * smart card via phy.Some smart card phy has multiple slots for
+ * cards. This inerface also enables controller to communicate with
+ * one or more smart card connected over phy.
+ */
+struct sc_phy {
+	/* phy's device pointer */
+	struct device *dev;
+
+	/* phy's private data */
+	void *pdata;
+
+	/* notify data, passed by interface user as a part of
+	 * register_notify API. Data should be passed back when
+	 * notification raised to the interface user
+	 */
+	void *notify_data;
+
+	int	(*set_config)(struct sc_phy *phy, u8 slot,
+			enum sc_phy_config attr, int value);
+	int	(*get_config)(struct sc_phy *phy, u8 slot, enum
+			sc_phy_config attr);
+	int	(*activate_card)(struct sc_phy *phy, u8 slot);
+	int	(*deactivate_card)(struct sc_phy *phy, u8 slot);
+	int	(*get_syncatr)(struct sc_phy *phy, u8 slot, u8 len, char *atr);
+	int	(*warm_reset)(struct sc_phy *phy, u8 slot);
+	int	(*register_notify)(struct sc_phy *phy,
+			 struct	notifier_block *nb, void *notify_data);
+	int	(*unregister_notify)(struct sc_phy *phy,
+			struct	notifier_block *nb);
+};
+
+#endif /* __SC_PHY_H__ */
-- 
1.7.9.5


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

* [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver
  2014-05-28  8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel
  2014-05-28  8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel
@ 2014-05-28  8:57 ` Satish Patel
  2014-05-28 18:44   ` Greg KH
  2014-05-28  8:57 ` [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx Satish Patel
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 22+ messages in thread
From: Satish Patel @ 2014-05-28  8:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-omap, devicetree, gregkh,
	rob, tony
  Cc: grant.likely, robh+dt, Satish Patel

TDA8026 is a SmartCard PHY from NXP.

The PHY interfaces with the main processor over the
I2C interface and acts as a slave device.

The driver also exposes the phy interface
(defined@include/linux/sc_phy.h) for SmartCard controller.
Controller uses this interface to communicate with smart card
inserted to the phy's slot.

Note: gpio irq is not validated as I do not have device with that.
I have validated interrupt with dedicated interrupt line on my device.

Signed-off-by: Satish Patel <satish.patel@ti.com>
---
 Documentation/devicetree/bindings/misc/tda8026.txt |   19 +
 drivers/misc/Kconfig                               |    7 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/tda8026.c                             | 1258 ++++++++++++++++++++
 4 files changed, 1285 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt
 create mode 100644 drivers/misc/tda8026.c

diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt
new file mode 100644
index 0000000..f115c9c
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/tda8026.txt
@@ -0,0 +1,19 @@
+TDA8026 smart card slot interface
+
+This is an i2c based smart card interface device forming the electrical
+interface between a microcontroller and smart cards. This device supports
+asynchronous cards (micro controller-based IC cards) as well as synchronous
+cards (mainly memory cards)
+
+Required properties:
+- compatible: "nxp,tda8026"
+- shutdown-gpio = GPIO pin mapping for SDWNN pin
+- reg = i2c interface address
+
+
+Example:
+tda8026: tda8026@48 {
+		 compatible = "nxp,tda8026";
+		 reg = <0x48>;
+		 shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */
+	 };
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 8baff0e..80b21d7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,13 @@ config SRAM
 	  the genalloc API. It is supposed to be used for small on-chip SRAM
 	  areas found on many SoCs.
 
+config NXP_TDA8026_PHY
+        tristate "NXP PHY Driver for Smart Card PHY"
+        depends on I2C=y
+        help
+          If you say yes here you get support for the TDA8026 Smart card PHY
+	  with I2C interface.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7eb4b69..f262c0b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM)		+= sram.o
 obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
+obj-$(CONFIG_NXP_TDA8026_PHY)	+= tda8026.o
diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c
new file mode 100644
index 0000000..38df33e
--- /dev/null
+++ b/drivers/misc/tda8026.c
@@ -0,0 +1,1258 @@
+/*
+ * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY
+ *
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/notifier.h>
+#include <linux/sc_phy.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/delay.h>
+
+#define TDA8026_MAX_SLOTS		(5)
+#define TDA8026_NUM_SAM_SLOTS		(4)
+#define TDA8026_USERCARD_SLOT		(1)
+
+#define TDA8026_CSB_ADDR		(0x24)
+#define TDA8026_REG0_ADDR		(0x20)
+#define TDA8026_REG1_ADDR		(0x21)
+#define TDA8026_SLEWRATE_ADDR		(0x20)
+#define TDA8026_PRODVER_ADDR		(0x20)
+#define TDA8026_INTSTAT_ADDR		(0x21)
+
+#define TDA8026_PHY_PRODUCT_VERSION	(0xC2)
+
+/* CSB register values */
+#define TDA8026_CSB_PV_INTSTAT_VAL	(0x0)
+#define TDA8026_CSB_SLEWRATE_VAL	(0x6)
+
+/* Slot REG0 read mode bit fields */
+#define TDA8026_REG0_ACTIVE_MASK	(0x80)
+#define TDA8026_REG0_EARLY_MASK		(0x40)
+#define TDA8026_REG0_MUTE_MASK		(0x20)
+#define TDA8026_REG0_PROT_MASK		(0x10)
+#define TDA8026_REG0_SUPL_MASK		(0x08)
+#define TDA8026_REG0_CLKSW_MASK		(0x04)
+#define TDA8026_REG0_PREL_MASK		(0x02)
+#define TDA8026_REG0_PRES_MASK		(0x01)
+
+/* Slot REG0 write mode bit fields */
+#define TDA8026_REG0_VCC1V8_MASK	(0x80)
+#define TDA8026_REG0_IOEN_MASK		(0x40)
+
+#define TDA8026_REG0_REG10_MASK		(0x30)
+#define TDA8026_REG0_REG10_SHIFT	(4)
+#define TDA8026_REG0_REG10_CFG_VAL	(0x0)
+#define TDA8026_REG0_REG10_D_VAL	(0x1)
+#define TDA8026_REG0_REG10_CMSB_VAL	(0x2)
+#define TDA8026_REG0_REG10_CLSB_VAL	(0x3)
+
+#define TDA8026_REG0_PDWN_MASK		(0x08)
+#define TDA8026_REG0_5V3VN_MASK		(0x04)
+#define TDA8026_REG0_WARM_RESET_MASK	(0x02)
+#define TDA8026_REG0_START_MASK		(0x01)
+
+/* Slot REG1 CFG bit fields REG[1:0] = 00b */
+#define TDA8026_REG1CFG_CFGP2_MASK	(0x80)
+#define TDA8026_REG1CFG_RSTIN_MASK	(0x40)
+#define TDA8026_REG1CFG_C8_MASK		(0x20)
+#define TDA8026_REG1CFG_C4_MASK		(0x10)
+#define TDA8026_REG1CFG_CLKPD_MASK	(0x0C)
+#define TDA8026_REG1CFG_CLKPD_SHIFT	(2)
+#define TDA8026_REG1CFG_CLKDIV_MASK	(0x03)
+#define TDA8026_REG1CFG_CLKDIV_SHIFT	(0)
+
+/* Slew rate register bit fields */
+#define TDA8026_SR_CLKSR_SLOT0_MASK	0x0C
+#define TDA8026_SR_CLKSR_SLOT0_SHIFT	0x2
+#define TDA8026_SR_IOSR_SLOT0_MASK	0x3
+#define TDA8026_SR_IOSR_SLOT0_SHIFT	0x0
+
+#define TDA8026_SR_CLKSR_SLOT2TO5_MASK	0xC0
+#define TDA8026_SR_CLKSR_SLOT2TO5_SHIFT	0x6
+#define TDA8026_SR_IOSR_SLOT2TO5_MASK	0x30
+#define TDA8026_SR_IOSR_SLOT2TO5_SHIFT	0x4
+
+#define TDA8026_MIN_EARLY_CYCLE    (200)
+
+struct tda8026 {
+	/* device pointer */
+	struct device *dev;
+
+	/* For device IO interfaces: I2C or SPI */
+	void *control_data;
+	/* Store a shadow of Slot Register 0 as it cannot be read */
+	u8 reg0[TDA8026_MAX_SLOTS];
+	int irq;
+	int notify;
+	int shutdown_gpio;
+	int enable;
+};
+
+static BLOCKING_NOTIFIER_HEAD(tda8026_notifier_list);
+
+static int tda8026_i2c_read(struct tda8026 *tda8026, u8 reg,
+		int bytes, u8 *dest)
+{
+	struct i2c_client *i2c = tda8026->control_data;
+	struct i2c_msg xfer;
+	int ret;
+
+	/* We need to read from the slave address itself, as there
+	 * is no separate register to be accessed in TDA8026
+	 */
+
+	xfer.addr = reg;
+	xfer.flags = I2C_M_RD;
+	xfer.len = bytes;
+	xfer.buf = dest;
+
+	ret = i2c_transfer(i2c->adapter, &xfer, 1);
+	if (ret < 0)
+		dev_err(tda8026->dev, "Read [0x%x] Error %d\n", reg, ret);
+
+	return ret;
+}
+
+static int tda8026_i2c_write(struct tda8026 *tda8026, u8 reg,
+		int bytes, u8 *src)
+{
+	struct i2c_client *i2c = tda8026->control_data;
+	struct i2c_msg xfer;
+	int ret;
+
+	/* We have to write to the slave address itself, as
+	 * there is no separate register to be accessed in TDA8026
+	 */
+	xfer.addr = reg;
+	xfer.flags = 0;
+	xfer.len = bytes;
+	xfer.buf = src;
+
+	ret = i2c_transfer(i2c->adapter, &xfer, 1);
+	if (ret < 0)
+		dev_err(tda8026->dev, "Write [0x%x] Error %d\n", reg, ret);
+
+	return ret;
+}
+
+/* put the phy in shutdown mode, which in turn deactivate
+ * all the cards in the slot and card pins are forced to 0V
+ */
+static inline void tda8026_disable(struct tda8026 *tda8026)
+{
+	dev_dbg(tda8026->dev, "tda8026_disable!!!!");
+	tda8026->enable = 0;
+	if (gpio_is_valid(tda8026->shutdown_gpio))
+		gpio_set_value(tda8026->shutdown_gpio, 0);
+}
+
+/* exit from shutdown mode */
+static inline void tda8026_enable(struct tda8026 *tda8026)
+{
+	dev_dbg(tda8026->dev, "tda8026_enable!!!!");
+	tda8026->enable = 1;
+	if (gpio_is_valid(tda8026->shutdown_gpio))
+		gpio_set_value(tda8026->shutdown_gpio, 1);
+	/* Added dealy to stabilized phy state after pulling shutdown line */
+	mdelay(100);
+}
+
+/*
+ * Select the card slot to communicate with the card
+ * Note that card slots are numbered from 0 in software.
+ * However TDA8026 PHY numbers the slot starting 1.
+ */
+static inline int tda8026_select_slot(struct tda8026 *tda8026, u8 slot)
+{
+	int ret = 0;
+
+	/* In SW slot starts from 0, in TDA8026 it starts from 1 */
+	slot = slot + 1;
+	ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &slot);
+
+	return ret;
+}
+
+static int tda8026_clear_interrupts(struct tda8026 *tda8026)
+{
+	u8 val;
+	u8 status;
+	int ret = 0;
+
+	/* Select the Interrupt register bank */
+	val = TDA8026_CSB_PV_INTSTAT_VAL;
+	tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val);
+
+	/* Read the interrupt status which will tell us the slot */
+	ret = tda8026_i2c_read(tda8026, TDA8026_INTSTAT_ADDR, 1, &status);
+	if (ret < 0)
+		return ret;
+
+	for (val = 1; val > TDA8026_MAX_SLOTS; val++) {
+		/* Program the slot number to the CSB register */
+		ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val);
+		if (ret < 0)
+			return ret;
+
+		ret = tda8026_i2c_read(tda8026, TDA8026_REG0_ADDR, 1, &status);
+		if (ret < 0)
+			return ret;
+	}
+	return ret;
+}
+/*
+ * TDA8026 PHY IRQ handler
+ */
+static irqreturn_t tda8026_irq(int irq, void *irq_data)
+{
+	struct sc_phy *phy_tda8026 = (struct sc_phy *)irq_data;
+	struct tda8026 *tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+	u8 slot;
+	u8 val;
+	u8 status;
+	int ret = 0;
+	int action = 0;
+
+	dev_dbg(tda8026->dev, "tda8026_irq!!");
+
+	if (tda8026->enable == 0) {
+		dev_dbg(tda8026->dev, "phy is disable not serving interrputs!!");
+		/* when, phy is in shutdown mode, it can detect the card insert
+		 * event. But if phy is not enable (i.e.) there is no consumer
+		 * of phy then just enable phy, clear the interrupt and disable
+		 * again
+		 */
+		tda8026_enable(tda8026);
+		tda8026_clear_interrupts(tda8026);
+		tda8026_disable(tda8026);
+		return IRQ_HANDLED;
+	}
+
+	/* Select the Interrupt register bank */
+	val = TDA8026_CSB_PV_INTSTAT_VAL;
+	tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val);
+
+	/* Read the interrupt status which will tell us the slot */
+	ret = tda8026_i2c_read(tda8026, TDA8026_INTSTAT_ADDR, 1, &status);
+	if (ret < 0)
+		return IRQ_HANDLED;
+
+
+	/* find out for which slot interrupt has occur */
+	slot = 0;
+	while (val == 0 && slot < TDA8026_MAX_SLOTS) {
+		val = status & (1 << slot);
+		slot++;
+	}
+
+	if (slot > TDA8026_MAX_SLOTS) {
+		dev_err(tda8026->dev, "invalid slot interrput");
+		return IRQ_HANDLED;
+	}
+
+	/* Program the slot number to the CSB register */
+	ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &slot);
+	if (ret < 0)
+		return IRQ_HANDLED;
+
+	/* Now read the slot reg0 to find out the cause of interrupt
+	 * Note that IRQ is raised only when one of the SUPL, PROT,
+	 * MUTE and EARLY bits are set to logic 1.
+	 */
+	ret = tda8026_i2c_read(tda8026, TDA8026_REG0_ADDR, 1, &status);
+	if (ret < 0)
+		return IRQ_HANDLED;
+
+	if (slot < 3) {
+		/* slot 1 and slot 2 can be used for user card, it can raise
+		 * interrupt for card insert and remove.Other slot are for SAM
+		 * modules. They are either always present or alwyas absent
+		 */
+		if (status & TDA8026_REG0_PREL_MASK) {
+			if (status & TDA8026_REG0_PRES_MASK) {
+				dev_dbg(tda8026->dev, "card is inserted");
+				action |= SC_PHY_CARD_INSERTED;
+			} else {
+				dev_dbg(tda8026->dev, "card is removed");
+				action |= SC_PHY_CARD_REMOVED;
+			}
+		}
+	}
+
+	if (status & (TDA8026_REG0_EARLY_MASK | TDA8026_REG0_MUTE_MASK)) {
+		dev_dbg(tda8026->dev, "CARD EARLY INTERRUPT\n");
+		action |= SC_PHY_CARD_ATR_TIMEOUT;
+	}
+
+	if (status & TDA8026_REG0_PROT_MASK) {
+		dev_dbg(tda8026->dev, "CARD OVERHEAT/OVERLOAD INTERRUPT\n");
+		action |= SC_PHY_CARD_OVERHEAT;
+	}
+
+	if (action != 0x0 && tda8026->notify) {
+		/* add slot information. Pass slot-1 as for controller slot
+		 * starts from 0,1,2.. */
+		action |= ((slot-1) << SC_PHY_NOTIFICATION_SLOT_SHIFT);
+
+		/* notify action */
+		blocking_notifier_call_chain(&tda8026_notifier_list, action,
+					     phy_tda8026->notify_data);
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * PDWN bit is set/cleared to apply CLKPD[1:0] bit clock settings to
+ * the clock pin for the selected card slot.
+ */
+static int tda8026_pwdn(struct tda8026 *tda8026, u8 slot, int state)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+
+	if (state)
+		reg0 |= TDA8026_REG0_PDWN_MASK;
+	else
+		reg0 &= ~(TDA8026_REG0_PDWN_MASK);
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Set the card supply voltage.
+ * TDA PHY supports supply voltage of 1.8V, 3V and 5V.
+ */
+static int tda8026_set_voltage(struct tda8026 *tda8026, u8 slot, int voltage)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+
+	reg0 &= ~(TDA8026_REG0_VCC1V8_MASK | TDA8026_REG0_5V3VN_MASK);
+
+	switch (voltage) {
+	case SC_PHY_1_8V:
+		reg0 |= TDA8026_REG0_VCC1V8_MASK;
+	break;
+
+	case SC_PHY_5V:
+		reg0 |= TDA8026_REG0_5V3VN_MASK;
+	break;
+
+	case SC_PHY_3V:
+	default:
+	break;
+	}
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Enable the I/O line by setting I/OEN bit of slot's main address register.
+ * The I/O line should be enabled prior to card activation.
+ */
+static int tda8026_io_enable(struct tda8026 *tda8026, u8 slot)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 |= TDA8026_REG0_IOEN_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Disable the I/O line by clearing I/OEN bit of slot's main address register.
+ * The I/O line can be disabled post card activation.
+ */
+static int tda8026_io_disable(struct tda8026 *tda8026, u8 slot)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 &= ~(TDA8026_REG0_IOEN_MASK);
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Sets the mute counter in C[15:8] and C[7:0] register
+ * Write Reg[1:0] = 11 to select C[7:0] register
+ * Write Reg[1:0] = 10 to select C[15:8] register
+ */
+static int tda8026_set_atr_mute_time(struct tda8026 *tda8026, u8 slot,
+		int mute_counter)
+{
+	u8 reg0;
+	u8 mute_counter_high = (mute_counter & 0xFF00) >> 8;
+	u8 mute_counter_low = mute_counter & 0xFF;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 |=  TDA8026_REG0_REG10_CLSB_VAL << TDA8026_REG0_REG10_SHIFT;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	/* Write the mute counter value in C[7:0] LSB register */
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1,
+			&mute_counter_low);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 |=  TDA8026_REG0_REG10_CMSB_VAL << TDA8026_REG0_REG10_SHIFT;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	/* Write the mute counter value in C[15:8] MSB register */
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1,
+			&mute_counter_high);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+/*
+ * Sets the ATR early time counter.
+ * Write Reg[1:0] = 01 to select D register
+ */
+static int tda8026_set_atr_early_time(struct tda8026 *tda8026, u8 slot,
+		int early_counter)
+{
+	u8 reg0;
+	int ret = 0;
+	u8 counter = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 |= TDA8026_REG0_REG10_D_VAL << TDA8026_REG0_REG10_SHIFT;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	/* Write the early atr counter value in D register */
+	counter = (early_counter - TDA8026_MIN_EARLY_CYCLE) & 0xFF;
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, &counter);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+static int tda8026_set_rstpin(struct tda8026 *tda8026, u8 slot, int state)
+{
+	u8 reg0 = 0;
+	u8 reg1 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	/* Write Reg[1:0] = 00 to select CONFIG register */
+	reg0 = tda8026->reg0[slot];
+	reg0 &= ~TDA8026_REG0_REG10_MASK;
+	reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) &
+		TDA8026_REG0_REG10_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	/* Read the Reg1 value */
+	ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1,
+			&reg1);
+	if (ret < 0)
+		return ret;
+
+	if (state)
+		reg1 |= TDA8026_REG1CFG_RSTIN_MASK;
+	else
+		reg1 &= ~TDA8026_REG1CFG_RSTIN_MASK;
+
+	/* Write the Reset value to the register  */
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, &reg1);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+/*
+ * Activate the card by setting START bit of slot's main register.
+ * Voltage selction and enabling of I/O lines should be done prior
+ * to activating the card.
+ */
+static int tda8026_activate_card(struct sc_phy *phy_tda8026, u8 slot)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+
+	/* if PHY is used then RSTIN should be 1 for async cards,
+	 * currently this is applicable only for TDA8026
+	 */
+	tda8026_set_rstpin(tda8026, slot, 1);
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 |= TDA8026_REG0_START_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Deactivate the card by clearing the START bit of slot's main register
+ * We implement normal de-activation here.
+ * On clearing the START bit with normal deactivation, automatic
+ * deactivation is initiated and performaed by TDA8026.
+ */
+static int tda8026_deactivate_card(struct sc_phy *phy_tda8026, u8 slot)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 &= ~(TDA8026_REG0_START_MASK);
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Warm reset is initiated by setting the WARM bit of slot's main register
+ */
+static int tda8026_warm_reset(struct sc_phy *phy_tda8026, u8 slot)
+{
+	u8 reg0 = 0;
+	int ret = 0;
+
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+
+	/* See section 6.5 in TDA app note */
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 |= TDA8026_REG0_WARM_RESET_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	return 0;
+}
+
+/*
+ * Read and return the TDA8026 PHY product version
+ */
+static int tda8026_get_provider_version(struct tda8026 *tda8026)
+{
+	u8 val;
+	u8 version = 0;
+	int ret = 0;
+
+	/* Select Product version bank i.e Write CSB = 00 */
+	val = TDA8026_CSB_PV_INTSTAT_VAL;
+	ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val);
+	if (ret < 0)
+		return ret;
+
+	ret = tda8026_i2c_read(tda8026, TDA8026_PRODVER_ADDR, 1, &version);
+	if (ret < 0)
+		return ret;
+	else
+		dev_info(tda8026->dev, "Product Version = %x\n", version);
+
+	return version;
+}
+
+
+/*
+ * Set/reset the C4/C8 Pin
+ * Write Reg[1:0] = 00 to select CONFIG register
+ */
+static int tda8026_set_c4c8(struct tda8026 *tda8026,
+				u8 slot,
+				int state,
+				int pin)
+{
+	u8 reg0 = 0;
+	u8 reg1 = 0;
+	int ret = 0;
+	int mask = 0;
+
+	if (slot != 0) {
+		/* C4/C8 pin value valid only for slot 1 */
+		return -EINVAL;
+	} else {
+		ret = tda8026_select_slot(tda8026, slot);
+		if (ret < 0)
+			return ret;
+
+		reg0 = tda8026->reg0[slot];
+		reg0 &= ~TDA8026_REG0_REG10_MASK;
+		reg0 |= (TDA8026_REG0_REG10_CFG_VAL <<
+				TDA8026_REG0_REG10_SHIFT) &
+			TDA8026_REG0_REG10_MASK;
+
+		ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+		if (ret < 0)
+			return ret;
+		else if (ret == 1)
+			tda8026->reg0[slot] = reg0;
+
+		ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1,
+				&reg1);
+		if (ret < 0)
+			return ret;
+		if (pin == SC_PHY_PIN_C8)
+			mask = TDA8026_REG1CFG_C8_MASK;
+		else if (pin == SC_PHY_PIN_C4)
+			mask = TDA8026_REG1CFG_C4_MASK;
+		else
+			return -EINVAL;
+
+		if (state)
+			reg1 |= mask;
+		else
+			reg1 &= ~mask;
+
+		ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1,
+				&reg1);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+/*
+ * Get the state of C4/C8 pin (high/low)
+ * Write Reg[1:0] = 00 to select CONFIG register
+ */
+static int tda8026_get_c4c8(struct tda8026 *tda8026, u8 slot, int pin)
+{
+	u8 reg0 = 0;
+	u8 reg1 = 0;
+	int ret = 0;
+	int mask = 0;
+
+	if (slot != 0) {
+		/* C4/C8 pin value valid only for slot 1 */
+		return -EINVAL;
+	} else {
+		ret = tda8026_select_slot(tda8026, slot);
+		if (ret < 0)
+			return ret;
+
+		reg0 = tda8026->reg0[slot];
+		reg0 &= ~TDA8026_REG0_REG10_MASK;
+		reg0 |= (TDA8026_REG0_REG10_CFG_VAL <<
+				TDA8026_REG0_REG10_SHIFT) &
+			TDA8026_REG0_REG10_MASK;
+
+		ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+		if (ret < 0)
+			return ret;
+		else if (ret == 1)
+			tda8026->reg0[slot] = reg0;
+
+		ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1,
+				&reg1);
+		if (ret < 0)
+			return ret;
+
+		if (pin == SC_PHY_PIN_C8)
+			mask = TDA8026_REG1CFG_C8_MASK;
+		else if (pin == SC_PHY_PIN_C4)
+			mask = TDA8026_REG1CFG_C4_MASK;
+		else
+			return -EINVAL;
+
+		return (reg1 &= mask) ? 1 : 0;
+	}
+	return 0;
+}
+
+/*
+ * Set card clock
+ * Applicable only for synchronous mode
+ */
+static int tda8026_set_cardclk(struct tda8026 *tda8026, u8 slot,
+		int config)
+{
+	u8 reg0 = 0;
+	u8 reg1 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 &= ~TDA8026_REG0_REG10_MASK;
+	reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) &
+		TDA8026_REG0_REG10_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, &reg1);
+	if (ret < 0)
+		return ret;
+
+	reg1 &= ~(TDA8026_REG1CFG_CLKPD_MASK);
+	reg1 |= (config << TDA8026_REG1CFG_CLKPD_SHIFT) &
+		TDA8026_REG1CFG_CLKPD_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, &reg1);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+/*
+ * Set the CLKDIV[1:0] bits.
+ * CLKDIV[1:0] bits define the card clock frequency
+ * Write Reg[1:0] = 00 to select CONFIG register
+ */
+static int tda8026_set_clkdiv(struct tda8026 *tda8026, u8 slot, int div)
+{
+	u8 reg0 = 0;
+	u8 reg1 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 &= ~TDA8026_REG0_REG10_MASK;
+	reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) &
+		TDA8026_REG0_REG10_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, &reg1);
+	if (ret < 0)
+		return ret;
+
+	reg1 &= ~(TDA8026_REG1CFG_CLKDIV_MASK);
+	reg1 |= (div << TDA8026_REG1CFG_CLKDIV_SHIFT) &
+		TDA8026_REG1CFG_CLKDIV_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, &reg1);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+/*
+ * Get the CLKDIV[1:0] bits.
+ * CLKDIV[1:0] bits define the card clock frequency
+ * Write Reg[1:0] = 00 to select CONFIG register
+ */
+static int tda8026_get_clkdiv(struct tda8026 *tda8026, u8 slot)
+{
+	u8 reg0 = 0;
+	u8 reg1 = 0;
+	int ret = 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	reg0 = tda8026->reg0[slot];
+	reg0 &= ~TDA8026_REG0_REG10_MASK;
+	reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) &
+		TDA8026_REG0_REG10_MASK;
+
+	ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, &reg0);
+	if (ret < 0)
+		return ret;
+	else if (ret == 1)
+		tda8026->reg0[slot] = reg0;
+
+	ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, &reg1);
+	if (ret < 0)
+		return ret;
+
+	ret = reg1 & TDA8026_REG1CFG_CLKDIV_MASK;
+
+	return ret;
+}
+
+/*
+ * Check if card is present in the slot.
+ */
+static int tda8026_card_present(struct tda8026 *tda8026, u8 slot)
+{
+	int present = 0;
+	int ret = 0;
+	u8 status = 0;
+
+	if (tda8026->enable == 0)
+		return 0;
+
+	ret = tda8026_select_slot(tda8026, slot);
+	if (ret < 0)
+		return ret;
+
+	ret = tda8026_i2c_read(tda8026, TDA8026_REG0_ADDR, 1, &status);
+	if (ret < 0)
+		return ret;
+
+	if (status & TDA8026_REG0_PRES_MASK)
+		present = 1;
+
+	return present;
+}
+
+/**
+ * tda8026_register_notify - register a notifier callback whenever a card
+ * event happens
+ * @nb: pointer to the notifier block for the callback events.
+ */
+static int tda8026_register_notify(struct sc_phy *phy_tda8026,
+		struct	notifier_block *nb, void *data)
+{
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	phy_tda8026->notify_data = data;
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+	blocking_notifier_chain_register(&tda8026_notifier_list, nb);
+	tda8026->notify = 1;
+	return 0;
+}
+
+/**
+ * tda8026_unregister_notify - unregister a notifier callback
+ * event happens
+ * @nb: pointer to the notifier block for the callback events.
+ */
+static int tda8026_unregister_notify(struct sc_phy *phy_tda8026,
+		struct	notifier_block *nb)
+{
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+	blocking_notifier_chain_unregister(&tda8026_notifier_list, nb);
+	tda8026->notify = 0;
+	return 0;
+}
+
+static int tda8026_set_config(struct sc_phy *phy_tda8026, u8 slot, enum
+		sc_phy_config attr, int value)
+{
+	int ret = 0;
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+	switch (attr) {
+	case SC_PHY_CARD_SUPPLY_VOLTAGE:
+		ret = tda8026_set_voltage(tda8026, slot, value);
+		break;
+
+	case SC_PHY_ATR_MUTE_TIME:
+		ret = tda8026_set_atr_mute_time(tda8026, slot, value);
+		break;
+
+	case SC_PHY_ATR_EARLY_TIME:
+		ret = tda8026_set_atr_early_time(tda8026, slot, value);
+		break;
+
+	case SC_PHY_CARD_MODE:
+		if (value == SC_PHY_SYNC) {
+			/* set clkdiv to zero, rst pin to low and pwdn bit to
+			 * logic 0
+			 */
+			tda8026_set_clkdiv(tda8026, slot, 0);
+			tda8026_set_rstpin(tda8026, slot, 0);
+			tda8026_pwdn(tda8026, slot, 0);
+		} else {
+			/* Nothing to do, default mode is async */
+		}
+		break;
+
+	case SC_PHY_IO:
+		if (value)
+			ret = tda8026_io_enable(tda8026, slot);
+		else
+			ret = tda8026_io_disable(tda8026, slot);
+		break;
+
+	case SC_PHY_PIN_RST:
+		ret = tda8026_set_rstpin(tda8026, slot, value);
+		break;
+
+	case SC_PHY_CLKDIV:
+		ret = tda8026_set_clkdiv(tda8026, slot, value);
+		break;
+
+	case SC_PHY_MODE:
+		if (value == SC_PHY_ACTIVE)
+			tda8026_enable(tda8026);
+		else if (value == SC_PHY_SHUTDOWN)
+			tda8026_disable(tda8026);
+		else
+			ret = -EINVAL;
+		break;
+
+	case SC_PHY_PIN_C4:
+		ret = tda8026_set_c4c8(tda8026, slot, value, SC_PHY_PIN_C4);
+		break;
+
+	case SC_PHY_PIN_C8:
+		ret = tda8026_set_c4c8(tda8026, slot, value, SC_PHY_PIN_C8);
+		break;
+
+	case SC_PHY_PIN_CLK:
+		ret = tda8026_set_cardclk(tda8026, slot, value);
+		break;
+
+	default:
+		ret = -EINVAL;
+		dev_err(phy_tda8026->dev, "operation not supported:%d", attr);
+		break;
+	}
+	return ret;
+}
+
+static int tda8026_get_config(struct sc_phy *phy_tda8026, u8 slot, enum
+		sc_phy_config attr)
+{
+	int ret = -1;
+	struct tda8026 *tda8026;
+
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+	switch (attr) {
+	case SC_PHY_CARD_PRESENCE:
+		ret = tda8026_card_present(tda8026, slot);
+	break;
+
+	case SC_PHY_VERSION:
+		ret = tda8026_get_provider_version(tda8026);
+	break;
+
+	case SC_PHY_CLKDIV:
+		ret = tda8026_get_clkdiv(tda8026, slot);
+	break;
+
+	case SC_PHY_PIN_C4:
+		ret = tda8026_get_c4c8(tda8026, slot, SC_PHY_PIN_C4);
+	break;
+
+	case SC_PHY_PIN_C8:
+		ret = tda8026_get_c4c8(tda8026, slot, SC_PHY_PIN_C8);
+	break;
+
+	default:
+		ret = -EINVAL;
+		dev_err(phy_tda8026->dev, "operation not supported:%d", attr);
+	break;
+	}
+	return ret;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tda8026_id_table[];
+#endif
+
+static int tda8026_parse_dt(struct device *dev, struct tda8026 *pdata)
+{
+	struct device_node *np = dev->of_node;
+	int ret = 0;
+
+	pdata->shutdown_gpio = of_get_named_gpio(np, "shutdown-gpio", 0);
+	if (!gpio_is_valid(pdata->shutdown_gpio)) {
+		dev_err(dev, "Failed to get shutdown gpio\n");
+		return -EINVAL;
+	}
+
+	ret = devm_gpio_request_one(dev, pdata->shutdown_gpio,
+			GPIOF_DIR_OUT, "shutdown_gpio");
+	if (ret) {
+		dev_err(dev, "Failed to request shutdown_gpio\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int tda8026_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sc_phy *phy_tda8026;
+	struct tda8026 *pdata;
+
+	struct device *dev = &i2c->dev;
+	struct device_node *np = dev->of_node;
+
+	if (np == NULL)
+		return -EINVAL;
+
+	pdata = devm_kzalloc(dev, sizeof(struct tda8026), GFP_KERNEL);
+	if (pdata == NULL)
+		return -ENOMEM;
+
+	phy_tda8026 = devm_kzalloc(dev, sizeof(struct sc_phy), GFP_KERNEL);
+	if (phy_tda8026 == NULL)
+		return -ENOMEM;
+
+	ret = tda8026_parse_dt(dev, pdata);
+	if (ret != 0)
+		return ret;
+
+	i2c_set_clientdata(i2c, phy_tda8026);
+	phy_tda8026->dev = &i2c->dev;
+
+	phy_tda8026->pdata = (void *)pdata;
+	pdata->control_data = i2c;
+	pdata->irq = i2c->irq;
+	pdata->dev = phy_tda8026->dev;
+	pdata->notify = 0;
+
+	if (pdata->irq == 0)
+		return -EINVAL;
+
+	ret = devm_request_threaded_irq(dev, pdata->irq, NULL, tda8026_irq,
+			IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+			"tda8026", phy_tda8026);
+	if (ret < 0) {
+		dev_err(phy_tda8026->dev, "can't get irq %d err %d\n",
+			pdata->irq, ret);
+		return ret;
+	}
+
+	/* enable phy */
+	tda8026_enable(pdata);
+
+	tda8026_clear_interrupts(pdata);
+	phy_tda8026->set_config	= tda8026_set_config;
+	phy_tda8026->get_config	= tda8026_get_config;
+	phy_tda8026->activate_card	= tda8026_activate_card;
+	phy_tda8026->deactivate_card	= tda8026_deactivate_card;
+	phy_tda8026->warm_reset	= tda8026_warm_reset;
+	phy_tda8026->register_notify	= tda8026_register_notify;
+	phy_tda8026->unregister_notify	= tda8026_unregister_notify;
+
+	/* disable phy */
+	tda8026_disable(pdata);
+
+	return 0;
+}
+
+static int tda8026_i2c_remove(struct i2c_client *i2c)
+{
+	struct sc_phy *phy_tda8026;
+	struct tda8026 *tda8026;
+	int action = 0;
+
+	phy_tda8026 = i2c_get_clientdata(i2c);
+	if (phy_tda8026 == NULL)
+		return -EINVAL;
+
+	tda8026	= (struct tda8026 *)phy_tda8026->pdata;
+
+	/* notify action */
+	action = SC_PHY_REMOVED;
+	blocking_notifier_call_chain(&tda8026_notifier_list, action,
+				     phy_tda8026->notify_data);
+	tda8026->notify = 0;
+
+	/* enable shutdown mode */
+	tda8026_disable(tda8026);
+
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tda8026_id_table[] = {
+	{ .compatible = "nxp,tda8026" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tda8026_id_table);
+#endif
+
+static const struct i2c_device_id tda8026_i2c_id[] = {
+	{"tda8026", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tda8026_i2c_id);
+
+static struct i2c_driver tda8026_i2c_driver = {
+	.driver = {
+		.name = "tda8026",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(tda8026_id_table),
+	},
+	.probe = tda8026_i2c_probe,
+	.remove = tda8026_i2c_remove,
+	.id_table = tda8026_i2c_id,
+};
+static int __init tda8026_i2c_init(void)
+{
+	int ret;
+	ret = i2c_add_driver(&tda8026_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register TDA8026 I2C driver: %d\n", ret);
+	return ret;
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tda8026_i2c_init);
+
+static void __exit tda8026_i2c_exit(void)
+{
+	i2c_del_driver(&tda8026_i2c_driver);
+}
+module_exit(tda8026_i2c_exit);
+
+MODULE_AUTHOR("Maulik Mankad <maulik@ti.com>");
+MODULE_DESCRIPTION("TDA8026 Smart Card NXP PHY driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx
  2014-05-28  8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel
  2014-05-28  8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel
  2014-05-28  8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel
@ 2014-05-28  8:57 ` Satish Patel
  2014-05-28 17:56   ` Rob Herring
  2014-05-28  8:57 ` [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim Satish Patel
  2014-05-28  8:57 ` [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy Satish Patel
  4 siblings, 1 reply; 22+ messages in thread
From: Satish Patel @ 2014-05-28  8:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-omap, devicetree, gregkh,
	rob, tony
  Cc: grant.likely, robh+dt, Satish Patel

TI-USIM driver is a platform driver that provides a character
driver interface to user applications.

It allows user applications to call IOCTL's to
perform smart card operations.

Driver currently supports
- Cold & Warm Reset
- T=0 & T=1 protocol
- clock stop mode
- smart card clock configuration
- Tx/Rx application data units (APDU) to smart card
- Interface to PHY using DT & phy interface

Validation is done with ACOS3 smart cards

Signed-off-by: Satish Patel <satish.patel@ti.com>
---
 .../devicetree/bindings/ti-usim/ti-usim.txt        |   32 +
 drivers/char/Kconfig                               |    7 +
 drivers/char/Makefile                              |    1 +
 drivers/char/ti-usim-hw.h                          |  864 ++++++++
 drivers/char/ti-usim.c                             | 2213 ++++++++++++++++++++
 include/linux/ti-usim.h                            |  111 +
 6 files changed, 3228 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/ti-usim/ti-usim.txt
 create mode 100644 drivers/char/ti-usim-hw.h
 create mode 100644 drivers/char/ti-usim.c
 create mode 100644 include/linux/ti-usim.h

diff --git a/Documentation/devicetree/bindings/ti-usim/ti-usim.txt b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt
new file mode 100644
index 0000000..4e599e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt
@@ -0,0 +1,32 @@
+ti-usim: USIM - Smart Card Controller
+
+Required Properties:
+- compatible: Should be "ti,usim"
+- reg: Specifies base physical address and size of the USIM registers
+- interrupts:  Interrupt number for the USIM controller
+- ti,hwmods: Name of the hwmod associated to the USIM controller
+
+- clocks        : list of clock specifiers, corresponding to entries in  the
+                  clock-names property
+- clock-names   : should contain "opt_fck" and "opt_fck32" entries, matching
+                  entries in the clocks property
+
+Optional properties:
+- pinctrl-0: Should specify pin control group used for this controller.
+- pinctrl-names: Should contain only one value - "default", for more details
+                 please refer to pinctrl-bindings.txt
+- phy : Should specify <smart card phy> reference connected to controller
+- phy-slots : No of slots to which controller will communicate
+
+Example:
+
+usim0: usim@48034000 {
+	       compatible = "ti,usim";
+	       reg = <0x48034000 0x1000>;
+	       interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+	       ti,hwmods = "usim0";
+	       clocks = <&usim0_opt_fck>, <&usim0_opt_fck32>,
+		      <&dpll_per_m2_div4_ck>;
+	       clock-names = "opt_fck", "opt_fck32", "fck";
+	       status = "disabled";
+       };
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 6e9f74a..c7c5fae 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -600,5 +600,12 @@ config TILE_SROM
 	  device appear much like a simple EEPROM, and knows
 	  how to partition a single ROM for multiple purposes.
 
+config TI_USIM
+	tristate "Character device access to TI's USIM module on AM43X"
+	depends on SOC_AM43XX
+	help
+	This device creates a character device interface that enables
+	user applications to exchange data with TI's USIM module.
+
 endmenu
 
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index a324f93..f7ee777 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_JS_RTC)		+= js-rtc.o
 js-rtc-y = rtc.o
 
 obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
+obj-$(CONFIG_TI_USIM)          += ti-usim.o
diff --git a/drivers/char/ti-usim-hw.h b/drivers/char/ti-usim-hw.h
new file mode 100644
index 0000000..1d3dd6e
--- /dev/null
+++ b/drivers/char/ti-usim-hw.h
@@ -0,0 +1,864 @@
+/*
+ * ti-usim-hw.h - Header file for USIM smart card interface
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __TI_USIM_HW_H__
+#define __TI_USIM_HW_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/sc_phy.h>
+#include <linux/ti-usim.h>
+
+
+#define USIM_MAX_SLOTS	0x2
+
+/* WWT Work Wait Time */
+#define USIM_EMV_WI      (10)
+#define USIM_EMV_WWT     ((960 * USIM_EMV_WI) + (480))
+/* CGT Character Guard Time */
+#define USIM_EMV_CGT     (12)
+
+#define USIM_ATR_TIMEOUT_EMV	(20160)
+#define USIM_EMV_ATR_EARLY_TO	(370)
+#define USIM_EMV_ATR_MUTE_TO	(42000)
+
+#define USIM_MAX_RX_FIFO_SIZE    (260)
+#define USIM_MAX_TX_FIFO_SIZE    (260)
+#define USIM_MAX_PARITY_RETRIES  (7)
+
+#define USIM_IRQ_NATR           (0x00000001)
+#define USIM_IRQ_WT		(0x00000002)
+#define USIM_IRQ_RXFULL		(0x00000004)
+#define USIM_IRQ_TX		(0x00000008)
+#define USIM_IRQ_RX		(0x00000010)
+#define USIM_IRQ_CD		(0x00000020)
+#define USIM_IRQ_EOB		(0x00000040)
+#define USIM_IRQ_TOC		(0x00000080)
+#define USIM_IRQ_TOB		(0x00000100)
+#define USIM_IRQ_RESENT		(0x00000200)
+#define USIM_IRQ_TS_ERR		(0x00000400)
+#define USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT	(0x00000800)
+#define USIM_IRQ_STOP		(0x00001000)
+#define USIM_IRQ_PAR_ERR_LEVEL_REACHED	(0x00002000)
+#define USIM_IRQ_FRAME_ERR	(0x00004000)
+#define USIM_IRQ_RXDMA_RDY	(0x00008000)
+#define USIM_IRQ_ATR_START	(0x00010000)
+#define USIM_IRQ_ACT_DONE	(0x00020000)
+#define USIM_IRQ_DEACT_DONE	(0x00040000)
+#define USIM_IRQ_TX_BLOCK_DONE	(0x00080000)
+#define USIM_IRQ_TX_BLOCK_REQ	(0x00100000)
+
+#define USIM_CONFSCLKMODE_LEGACY	0x0
+#define USIM_CONFSCLKMODE_HF		0x1
+
+/*
+ * Different operating modes supported in USIM.
+ * Programming USIM to a different mode from current mode would
+ * endup in state machine state change within the IPs FSM
+ */
+enum usim_mode {
+	USIM_MODE_LEGACY = 0x0,
+	USIM_MODE_FREEZE = 0x1,
+	USIM_MODE_TXRX   = 0x2,
+	USIM_MODE_ATR    = 0x3,
+	USIM_MODE_ACT    = 0x4,
+	USIM_MODE_DEACT  = 0x5,
+	USIM_MODE_IDLE   = 0x6,
+};
+
+/*
+ * structure to store slot specific information
+ */
+struct usim_slotcontext {
+	char atr[USIM_MAX_ATRLENGTH];
+	char rxbuf[USIM_MAX_APDU_LENGTH];
+	bool emv;
+	enum usim_mode state;
+	int event;
+	int protocol;
+	enum usim_card_voltage supply;
+	int rx_explen;
+	int rx_counter;
+	int atr_length;
+	enum usim_smartcard_clock clock;
+	enum usim_card_mode card_mode;
+};
+
+struct usim {
+	struct device *dev;
+
+	/* to protect interrput handling */
+	spinlock_t	lock;
+	int irq;
+	void __iomem            *base;
+	int slot;
+	int max_slots;
+	int phy_present;
+	int txdone;
+	int rxdone;
+	int atrdone;
+	int user_pid;
+	int enable;
+	struct sc_phy *phy;
+	struct usim_slotcontext *slot_ctx;
+
+	struct clk      *opt_fclk;
+	struct clk      *opt_fclk32;
+	struct clk      *usim_dbclk;
+	struct clk      *clkdiv32k_ick;
+	struct clk      *usim0_fck;
+	struct clk      *dpll_core_m4_ck;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry	*debugfs_root;
+#endif
+};
+
+/*
+ * Register Definitions: Taken from auto generated file
+ */
+#define USIM_REVISION                    (0x0U)
+#define USIM_IDENT                       (0x4U)
+#define USIM_SYSCONFIG                   (0x10U)
+#define USIM_SYSSTATUS                   (0x14U)
+#define USIM_IRQSTATUS                   (0x18U)
+#define USIM_IRQENABLE                   (0x1cU)
+#define USIM_WAKEUPEN                    (0x20U)
+#define USIM_CMD                         (0x24U)
+#define USIM_STAT                        (0x28U)
+#define USIM_CONF1                       (0x2cU)
+#define USIM_CONF2                       (0x30U)
+#define USIM_CONF3                       (0x34U)
+#define USIM_DRX                         (0x38U)
+#define USIM_DTX                         (0x3cU)
+#define USIM_FIFOS                       (0x40U)
+#define USIM_CGT                         (0x44U)
+#define USIM_CWT                         (0x48U)
+#define USIM_BWT                         (0x4cU)
+#define USIM_DEBUG                       (0x50U)
+#define USIM_CONF_SAM1_DIV               (0x54U)
+#define USIM_CONF4                       (0x58U)
+#define USIM_ATR_CLK_PRD_NBS             (0x5cU)
+#define USIM_CONF_ETU_DIV                (0x60U)
+#define USIM_CONF5                       (0x64U)
+#define USIM_TC_GUARD_TIME_ADD           (0x68U)
+#define USIM_RXFIFO_LEVEL                (0x6cU)
+#define USIM_RXFIFO_BYTECNT              (0x70U)
+#define USIM_WWT                         (0x74U)
+#define USIM_CONF6                       (0x78U)
+#define USIM_IO_DIRECT                   (0x7cU)
+#define USIM_TX_BLOCK                    (0x84U)
+
+/*
+ * Field Definition Macros
+ */
+#define USIM_REVISION_REV_SHIFT                       (0U)
+#define USIM_REVISION_REV_MASK                        (0x000000ffU)
+
+#define USIM_REVISION_RESERVED_24_SHIFT               (8U)
+#define USIM_REVISION_RESERVED_24_MASK                (0xffffff00U)
+
+#define USIM_IDENT_VC_SHIFT                           (0U)
+#define USIM_IDENT_VC_MASK                            (0x0000ffffU)
+
+#define USIM_IDENT_RESERVED_16_31_SHIFT               (16U)
+#define USIM_IDENT_RESERVED_16_31_MASK                (0xffff0000U)
+
+#define USIM_SYSCONFIG_AUTOIDLE_SHIFT                 (0U)
+#define USIM_SYSCONFIG_AUTOIDLE_MASK                  (0x00000001U)
+#define USIM_SYSCONFIG_AUTOIDLE_AUTOIDLE_VALUE_1       (1U)
+#define USIM_SYSCONFIG_AUTOIDLE_AUTOIDLE_VALUE_0       (0U)
+
+#define USIM_SYSCONFIG_SOFTRESET_SHIFT                (1U)
+#define USIM_SYSCONFIG_SOFTRESET_MASK                 (0x00000002U)
+#define USIM_SYSCONFIG_SOFTRESET_SOFTRESET_VALUE_1     (1U)
+#define USIM_SYSCONFIG_SOFTRESET_SOFTRESET_VALUE_0     (0U)
+
+#define USIM_SYSCONFIG_ENAWAKEUP_SHIFT                (2U)
+#define USIM_SYSCONFIG_ENAWAKEUP_MASK                 (0x00000004U)
+#define USIM_SYSCONFIG_ENAWAKEUP_ENAWAKEUP_VALUE_1     (1U)
+#define USIM_SYSCONFIG_ENAWAKEUP_ENAWAKEUP_VALUE_0     (0U)
+
+#define USIM_SYSCONFIG_IDLEMODE_SHIFT                 (3U)
+#define USIM_SYSCONFIG_IDLEMODE_MASK                  (0x00000018U)
+#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_3       (3U)
+#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_2       (2U)
+#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_1       (1U)
+#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_0       (0U)
+
+#define USIM_SYSCONFIG_EMUFREE_SHIFT                  (5U)
+#define USIM_SYSCONFIG_EMUFREE_MASK                   (0x00000020U)
+#define USIM_SYSCONFIG_EMUFREE_EMUFREE_VALUE_0         (0U)
+#define USIM_SYSCONFIG_EMUFREE_EMUFREE_VALUE_1         (1U)
+
+#define USIM_SYSCONFIG_RESERVED_6_7_SHIFT             (6U)
+#define USIM_SYSCONFIG_RESERVED_6_7_MASK              (0x000000c0U)
+
+#define USIM_SYSCONFIG_CLOCKACTIVITY_SHIFT            (8U)
+#define USIM_SYSCONFIG_CLOCKACTIVITY_MASK             (0x00000300U)
+
+#define USIM_SYSCONFIG_RESERVED_22_SHIFT              (10U)
+#define USIM_SYSCONFIG_RESERVED_22_MASK               (0xfffffc00U)
+
+#define USIM_SYSSTATUS_RESETDONE_SHIFT                (0U)
+#define USIM_SYSSTATUS_RESETDONE_MASK                 (0x00000001U)
+#define USIM_SYSSTATUS_RESETDONE_RESETDONE_VALUE_1     (1U)
+#define USIM_SYSSTATUS_RESETDONE_RESETDONE_VALUE_0     (0U)
+
+#define USIM_SYSSTATUS_RESERVED_31_SHIFT              (1U)
+#define USIM_SYSSTATUS_RESERVED_31_MASK               (0xfffffffeU)
+
+#define USIM_IRQSTATUS_USIM_NATR_SHIFT                (0U)
+#define USIM_IRQSTATUS_USIM_NATR_MASK                 (0x00000001U)
+
+#define USIM_IRQSTATUS_USIM_WT_SHIFT                  (1U)
+#define USIM_IRQSTATUS_USIM_WT_MASK                   (0x00000002U)
+
+#define USIM_IRQSTATUS_USIM_RXFULL_SHIFT              (2U)
+#define USIM_IRQSTATUS_USIM_RXFULL_MASK               (0x00000004U)
+
+#define USIM_IRQSTATUS_USIM_TX_SHIFT                  (3U)
+#define USIM_IRQSTATUS_USIM_TX_MASK                   (0x00000008U)
+
+#define USIM_IRQSTATUS_USIM_RX_SHIFT                  (4U)
+#define USIM_IRQSTATUS_USIM_RX_MASK                   (0x00000010U)
+
+#define USIM_IRQSTATUS_USIM_CD_SHIFT                  (5U)
+#define USIM_IRQSTATUS_USIM_CD_MASK                   (0x00000020U)
+
+#define USIM_IRQSTATUS_USIM_EOB_SHIFT                 (6U)
+#define USIM_IRQSTATUS_USIM_EOB_MASK                  (0x00000040U)
+
+#define USIM_IRQSTATUS_USIM_TOC_SHIFT                 (7U)
+#define USIM_IRQSTATUS_USIM_TOC_MASK                  (0x00000080U)
+
+#define USIM_IRQSTATUS_USIM_TOB_SHIFT                 (8U)
+#define USIM_IRQSTATUS_USIM_TOB_MASK                  (0x00000100U)
+
+#define USIM_IRQSTATUS_USIM_RESENT_SHIFT              (9U)
+#define USIM_IRQSTATUS_USIM_RESENT_MASK               (0x00000200U)
+
+#define USIM_IRQSTATUS_TS_ERROR_SHIFT                 (10U)
+#define USIM_IRQSTATUS_TS_ERROR_MASK                  (0x00000400U)
+
+#define USIM_IRQSTATUS_IT_EMV_ATR_LENGTH_TIME_OUT_SHIFT  (11U)
+#define USIM_IRQSTATUS_IT_EMV_ATR_LENGTH_TIME_OUT_MASK   (0x00000800U)
+
+#define USIM_IRQSTATUS_RESERVED_SHIFT                    (21U)
+#define USIM_IRQSTATUS_RESERVED_MASK                     (0xffe00000U)
+
+#define USIM_IRQSTATUS_USIM_STOP_CLK_SHIFT               (12U)
+#define USIM_IRQSTATUS_USIM_STOP_CLK_MASK                (0x00001000U)
+
+#define USIM_IRQSTATUS_PAR_ERR_LEVEL_REACHED_SHIFT       (13U)
+#define USIM_IRQSTATUS_PAR_ERR_LEVEL_REACHED_MASK        (0x00002000U)
+
+#define USIM_IRQSTATUS_FRAME_ERR_SHIFT            (14U)
+#define USIM_IRQSTATUS_FRAME_ERR_MASK             (0x00004000U)
+
+#define USIM_IRQSTATUS_RXDMA_RDY_SHIFT            (15U)
+#define USIM_IRQSTATUS_RXDMA_RDY_MASK             (0x00008000U)
+
+#define USIM_IRQSTATUS_ATR_START_SHIFT            (16U)
+#define USIM_IRQSTATUS_ATR_START_MASK             (0x00010000U)
+
+#define USIM_IRQSTATUS_ACT_DONE_SHIFT             (17U)
+#define USIM_IRQSTATUS_ACT_DONE_MASK              (0x00020000U)
+
+#define USIM_IRQSTATUS_DEACT_DONE_SHIFT           (18U)
+#define USIM_IRQSTATUS_DEACT_DONE_MASK            (0x00040000U)
+
+#define USIM_IRQSTATUS_TX_BLOCK_DONE_SHIFT        (19U)
+#define USIM_IRQSTATUS_TX_BLOCK_DONE_MASK         (0x00080000U)
+
+#define USIM_IRQSTATUS_TX_BLOCK_REQ_SHIFT         (20U)
+#define USIM_IRQSTATUS_TX_BLOCK_REQ_MASK          (0x00100000U)
+
+#define USIM_IRQENABLE_RESERVED_SHIFT             (21U)
+#define USIM_IRQENABLE_RESERVED_MASK              (0xffe00000U)
+
+#define USIM_IRQENABLE_EMV_ATR_LENGTH_TIME_OUT_EN_SHIFT    (11U)
+#define USIM_IRQENABLE_EMV_ATR_LENGTH_TIME_OUT_EN_MASK     (0x00000800U)
+
+#define USIM_IRQENABLE_TS_ERR_EN_SHIFT         (10U)
+#define USIM_IRQENABLE_TS_ERR_EN_MASK          (0x00000400U)
+
+#define USIM_IRQENABLE_RESENT_EN_SHIFT         (9U)
+#define USIM_IRQENABLE_RESENT_EN_MASK          (0x00000200U)
+
+#define USIM_IRQENABLE_TOB_EN_SHIFT            (8U)
+#define USIM_IRQENABLE_TOB_EN_MASK             (0x00000100U)
+
+#define USIM_IRQENABLE_TOC_EN_SHIFT            (7U)
+#define USIM_IRQENABLE_TOC_EN_MASK             (0x00000080U)
+
+#define USIM_IRQENABLE_EOB_EN_SHIFT            (6U)
+#define USIM_IRQENABLE_EOB_EN_MASK             (0x00000040U)
+
+#define USIM_IRQENABLE_CD_EN_SHIFT             (5U)
+#define USIM_IRQENABLE_CD_EN_MASK              (0x00000020U)
+
+#define USIM_IRQENABLE_RX_EN_SHIFT             (4U)
+#define USIM_IRQENABLE_RX_EN_MASK              (0x00000010U)
+
+#define USIM_IRQENABLE_TX_EN_SHIFT             (3U)
+#define USIM_IRQENABLE_TX_EN_MASK              (0x00000008U)
+
+#define USIM_IRQENABLE_RXFULL_EN_SHIFT         (2U)
+#define USIM_IRQENABLE_RXFULL_EN_MASK          (0x00000004U)
+
+#define USIM_IRQENABLE_WT_EN_SHIFT             (1U)
+#define USIM_IRQENABLE_WT_EN_MASK              (0x00000002U)
+
+#define USIM_IRQENABLE_NATR_EN_SHIFT           (0U)
+#define USIM_IRQENABLE_NATR_EN_MASK            (0x00000001U)
+
+#define USIM_IRQENABLE_STOP_CLK_SHIFT          (12U)
+#define USIM_IRQENABLE_STOP_CLK_MASK           (0x00001000U)
+
+#define USIM_IRQENABLE_PAR_ERR_LEVEL_REACHED_EN_SHIFT      (13U)
+#define USIM_IRQENABLE_PAR_ERR_LEVEL_REACHED_EN_MASK       (0x00002000U)
+
+#define USIM_IRQENABLE_FRAME_ERR_EN_SHIFT           (14U)
+#define USIM_IRQENABLE_FRAME_ERR_EN_MASK            (0x00004000U)
+
+#define USIM_IRQENABLE_RXDMA_RDY_EN_SHIFT           (15U)
+#define USIM_IRQENABLE_RXDMA_RDY_EN_MASK            (0x00008000U)
+
+#define USIM_IRQENABLE_ATR_START_EN_SHIFT           (16U)
+#define USIM_IRQENABLE_ATR_START_EN_MASK            (0x00010000U)
+
+#define USIM_IRQENABLE_ACT_DONE_EN_SHIFT            (17U)
+#define USIM_IRQENABLE_ACT_DONE_EN_MASK             (0x00020000U)
+
+#define USIM_IRQENABLE_DEACT_DONE_EN_SHIFT          (18U)
+#define USIM_IRQENABLE_DEACT_DONE_EN_MASK           (0x00040000U)
+
+#define USIM_IRQENABLE_TX_BLOCK_DONE_EN_SHIFT       (19U)
+#define USIM_IRQENABLE_TX_BLOCK_DONE_EN_MASK        (0x00080000U)
+
+#define USIM_IRQENABLE_TX_BLOCK_REQ_EN_SHIFT        (20U)
+#define USIM_IRQENABLE_TX_BLOCK_REQ_EN_MASK         (0x00100000U)
+
+#define USIM_WAKEUPEN_STOP_CLK_SHIFT                (12U)
+#define USIM_WAKEUPEN_STOP_CLK_MASK                 (0x00001000U)
+
+#define USIM_WAKEUPEN_NATR_EN_SHIFT                 (0U)
+#define USIM_WAKEUPEN_NATR_EN_MASK                  (0x00000001U)
+
+#define USIM_WAKEUPEN_WT_EN_SHIFT                   (1U)
+#define USIM_WAKEUPEN_WT_EN_MASK                    (0x00000002U)
+
+#define USIM_WAKEUPEN_RXFULL_EN_SHIFT               (2U)
+#define USIM_WAKEUPEN_RXFULL_EN_MASK                (0x00000004U)
+
+#define USIM_WAKEUPEN_TX_EN_SHIFT                   (3U)
+#define USIM_WAKEUPEN_TX_EN_MASK                    (0x00000008U)
+
+#define USIM_WAKEUPEN_RX_EN_SHIFT                   (4U)
+#define USIM_WAKEUPEN_RX_EN_MASK                    (0x00000010U)
+
+#define USIM_WAKEUPEN_CD_EN_SHIFT                   (5U)
+#define USIM_WAKEUPEN_CD_EN_MASK                    (0x00000020U)
+
+#define USIM_WAKEUPEN_EOB_EN_SHIFT                  (6U)
+#define USIM_WAKEUPEN_EOB_EN_MASK                   (0x00000040U)
+
+#define USIM_WAKEUPEN_TOC_EN_SHIFT                  (7U)
+#define USIM_WAKEUPEN_TOC_EN_MASK                   (0x00000080U)
+
+#define USIM_WAKEUPEN_TOB_EN_SHIFT                  (8U)
+#define USIM_WAKEUPEN_TOB_EN_MASK                   (0x00000100U)
+
+#define USIM_WAKEUPEN_RESENT_EN_SHIFT               (9U)
+#define USIM_WAKEUPEN_RESENT_EN_MASK                (0x00000200U)
+
+#define USIM_WAKEUPEN_TS_ERR_EN_SHIFT               (10U)
+#define USIM_WAKEUPEN_TS_ERR_EN_MASK                (0x00000400U)
+
+#define USIM_WAKEUPEN_EMV_ATR_LENGTH_TIME_OUT_EN_SHIFT    (11U)
+#define USIM_WAKEUPEN_EMV_ATR_LENGTH_TIME_OUT_EN_MASK     (0x00000800U)
+
+#define USIM_WAKEUPEN_RESERVED_SHIFT       (21U)
+#define USIM_WAKEUPEN_RESERVED_MASK        (0xffe00000U)
+
+#define USIM_WAKEUPEN_PAR_ERR_LEVEL_REACHED_EN_SHIFT     (13U)
+#define USIM_WAKEUPEN_PAR_ERR_LEVEL_REACHED_EN_MASK      (0x00002000U)
+
+#define USIM_WAKEUPEN_FRAME_ERR_EN_SHIFT        (14U)
+#define USIM_WAKEUPEN_FRAME_ERR_EN_MASK         (0x00004000U)
+
+#define USIM_WAKEUPEN_RXDMA_RDY_EN_SHIFT        (15U)
+#define USIM_WAKEUPEN_RXDMA_RDY_EN_MASK         (0x00008000U)
+
+#define USIM_WAKEUPEN_ATR_START_EN_SHIFT        (16U)
+#define USIM_WAKEUPEN_ATR_START_EN_MASK         (0x00010000U)
+
+#define USIM_WAKEUPEN_ACT_DONE_EN_SHIFT         (17U)
+#define USIM_WAKEUPEN_ACT_DONE_EN_MASK          (0x00020000U)
+
+#define USIM_WAKEUPEN_DEACT_DONE_EN_SHIFT       (18U)
+#define USIM_WAKEUPEN_DEACT_DONE_EN_MASK        (0x00040000U)
+
+#define USIM_WAKEUPEN_TX_BLOCK_DONE_EN_SHIFT         (19U)
+#define USIM_WAKEUPEN_TX_BLOCK_DONE_EN_MASK          (0x00080000U)
+
+#define USIM_WAKEUPEN_TX_BLOCK_REQ_EN_SHIFT          (20U)
+#define USIM_WAKEUPEN_TX_BLOCK_REQ_EN_MASK           (0x00100000U)
+
+#define USIM_CMD_RESERVED_0_SHIFT                    (0U)
+#define USIM_CMD_RESERVED_0_MASK                     (0x00000001U)
+
+#define USIM_CMD_CMDSTOP_SHIFT                       (1U)
+#define USIM_CMD_CMDSTOP_MASK                        (0x00000002U)
+#define USIM_CMD_CMDSTOP_CMDSTOP_VALUE_0              (0U)
+#define USIM_CMD_CMDSTOP_CMDSTOP_VALUE_1              (1U)
+
+#define USIM_CMD_CMDSTART_SHIFT                      (2U)
+#define USIM_CMD_CMDSTART_MASK                       (0x00000004U)
+#define USIM_CMD_CMDSTART_CMDSTART_VALUE_0            (0U)
+#define USIM_CMD_CMDSTART_CMDSTART_VALUE_1            (1U)
+
+#define USIM_CMD_MODULE_CLK_EN_SHIFT                 (3U)
+#define USIM_CMD_MODULE_CLK_EN_MASK                  (0x00000008U)
+#define USIM_CMD_MODULE_CLK_EN_0                      (0U)
+#define USIM_CMD_MODULE_CLK_EN_1                      (1U)
+
+#define USIM_CMD_CMD_WARM_RST_SHIFT                  (4U)
+#define USIM_CMD_CMD_WARM_RST_MASK                   (0x00000010U)
+#define USIM_CMD_CMD_WARM_RST_WARM_RST_VALUE_1        (1U)
+#define USIM_CMD_CMD_WARM_RST_WARM_RST_VALUE_0        (0U)
+
+#define USIM_CMD_CMD_CLOCK_STOP_SHIFT                (5U)
+#define USIM_CMD_CMD_CLOCK_STOP_MASK                 (0x00000020U)
+#define USIM_CMD_CMD_CLOCK_STOP_1                     (1U)
+#define USIM_CMD_CMD_CLOCK_STOP_0                     (0U)
+
+#define USIM_CMD_RESERVED_7_31_SHIFT                 (7U)
+#define USIM_CMD_RESERVED_7_31_MASK                  (0xffffff80U)
+
+#define USIM_CMD_STOP_EMV_ATR_LENGTH_TIMER_SHIFT     (6U)
+#define USIM_CMD_STOP_EMV_ATR_LENGTH_TIMER_MASK      (0x00000040U)
+#define USIM_CMD_STOP_EMV_ATR_LENGTH_TIMER_1          (1U)
+#define USIM_CMD_STOP_EMV_ATR_LENGTH_TIMER_0          (0U)
+
+#define USIM_STAT_STATNOCARD_SHIFT                   (0U)
+#define USIM_STAT_STATNOCARD_MASK                    (0x00000001U)
+#define USIM_STAT_STATNOCARD_STATNOCARD_VALUE_1       (1U)
+#define USIM_STAT_STATNOCARD_STATNOCARD_VALUE_0       (0U)
+#define USIM_STAT_STATNOCARD_WRITE0                   (0U)
+#define USIM_STAT_STATNOCARD_WRITE1                   (1U)
+
+#define USIM_STAT_RESERVED_7_31_SHIFT                (7U)
+#define USIM_STAT_RESERVED_7_31_MASK                 (0xffffff80U)
+
+#define USIM_STAT_STATTXPAR_SHIFT                    (1U)
+#define USIM_STAT_STATTXPAR_MASK                     (0x00000002U)
+#define USIM_STAT_STATTXPAR_STATTXPAR_VALUE_1         (1U)
+#define USIM_STAT_STATTXPAR_STATTXPAR_VALUE_0         (0U)
+
+#define USIM_STAT_STATLRC_SHIFT                      (2U)
+#define USIM_STAT_STATLRC_MASK                       (0x00000004U)
+#define USIM_STAT_STATLRC_STATLRC_VALUE_1             (1U)
+#define USIM_STAT_STATLRC_STATLRC_VALUE_0             (0U)
+
+#define USIM_STAT_CONFCODCONV_SHIFT                  (3U)
+#define USIM_STAT_CONFCODCONV_MASK                   (0x00000008U)
+#define USIM_STAT_CONFCODCONV_CONFCODCONV_VALUE_1     (1U)
+#define USIM_STAT_CONFCODCONV_CONFCODCONV_VALUE_0     (0U)
+
+#define USIM_STAT_RESERVED_SHIFT                     (4U)
+#define USIM_STAT_RESERVED_MASK                      (0x00000010U)
+
+#define USIM_STAT_FDDEACTSTATE_SHIFT                 (5U)
+#define USIM_STAT_FDDEACTSTATE_MASK                  (0x00000020U)
+#define USIM_STAT_FDDEACTSTATE_FDDEACTSTATE_VALUE_0    (0U)
+#define USIM_STAT_FDDEACTSTATE_FDDEACTSTATE_VALUE_1    (1U)
+
+#define USIM_STAT_ATRRX_AFTER_TIMEOUT_SHIFT           (6U)
+#define USIM_STAT_ATRRX_AFTER_TIMEOUT_MASK            (0x00000040U)
+
+#define USIM_CONF1_CONFSIOLOW_SHIFT                   (1U)
+#define USIM_CONF1_CONFSIOLOW_MASK                    (0x00000002U)
+#define USIM_CONF1_CONFSIOLOW_CONFSIOLOW_VALUE_0       (0U)
+#define USIM_CONF1_CONFSIOLOW_CONFSIOLOW_VALUE_1       (1U)
+
+#define USIM_CONF1_RESERVED_8_31_SHIFT                (8U)
+#define USIM_CONF1_RESERVED_8_31_MASK                 (0xffffff00U)
+
+#define USIM_CONF1_SCLKLEV_SHIFT                      (0U)
+#define USIM_CONF1_SCLKLEV_MASK                       (0x00000001U)
+#define USIM_CONF1_SCLKLEV_SCLKLEV_VALUE_0             (0U)
+#define USIM_CONF1_SCLKLEV_SCLKLEV_VALUE_1             (1U)
+
+#define USIM_CONF1_CONFBYPASS_SHIFT                   (2U)
+#define USIM_CONF1_CONFBYPASS_MASK                    (0x00000004U)
+#define USIM_CONF1_CONFBYPASS_CONFBYPASS_VALUE_0       (0U)
+#define USIM_CONF1_CONFBYPASS_CONFBYPASS_VALUE_1       (1U)
+
+#define USIM_CONF1_SVCCLEV_SHIFT                      (3U)
+#define USIM_CONF1_SVCCLEV_MASK                       (0x00000008U)
+#define USIM_CONF1_SVCCLEV_SVCCLEV_VALUE_0             (0U)
+#define USIM_CONF1_SVCCLEV_SVCCLEV_VALUE_1             (1U)
+
+#define USIM_CONF1_SRSTLEV_SHIFT                      (4U)
+#define USIM_CONF1_SRSTLEV_MASK                       (0x00000010U)
+#define USIM_CONF1_SRSTLEV_SRSTLEV_VALUE_0             (0U)
+#define USIM_CONF1_SRSTLEV_SRSTLEV_VALUE_1             (1U)
+
+#define USIM_CONF1_CONF_SCLK_EN_SHIFT                 (5U)
+#define USIM_CONF1_CONF_SCLK_EN_MASK                  (0x00000020U)
+#define USIM_CONF1_CONF_SCLK_EN_CONF_SCLK_EN_VALUE_0     (0U)
+#define USIM_CONF1_CONF_SCLK_EN_CONF_SCLK_EN_VALUE_1     (1U)
+#define USIM_CONF1_EMV_CONF_SHIFT                       (6U)
+#define USIM_CONF1_EMV_CONF_MASK                        (0x00000040U)
+#define USIM_CONF1_EMV_CONF_EMV_CONF_VALUE_0             (0U)
+#define USIM_CONF1_EMV_CONF_EMV_CONF_VALUE_1             (1U)
+#define USIM_CONF1_BYPASS_HW_AUTO_SHIFT                 (7U)
+#define USIM_CONF1_BYPASS_HW_AUTO_MASK                  (0x00000080U)
+#define USIM_CONF1_BYPASS_HW_AUTO_BYPASS_HW_AUTO_VALUE_0             (0U)
+#define USIM_CONF1_BYPASS_HW_AUTO_BYPASS_HW_AUTO_VALUE_1             (1U)
+
+#define USIM_CONF2_CONFCHKPAR_SHIFT                    (0U)
+#define USIM_CONF2_CONFCHKPAR_MASK                     (0x00000001U)
+#define USIM_CONF2_CONFCHKPAR_CONFCHKPAR_VALUE_0        (0U)
+#define USIM_CONF2_CONFCHKPAR_CONFCHKPAR_VALUE_1        (1U)
+#define USIM_CONF2_RESERVED_22_31_SHIFT                (22U)
+#define USIM_CONF2_RESERVED_22_31_MASK                 (0xffc00000U)
+#define USIM_CONF2_TX_EN_SHIFT                         (1U)
+#define USIM_CONF2_TX_EN_MASK                          (0x00000002U)
+#define USIM_CONF2_CONFSCLKDIV_SHIFT                   (2U)
+#define USIM_CONF2_CONFSCLKDIV_MASK                    (0x0000000cU)
+#define USIM_CONF2_ATR_ASYN_BYPASS_SHIFT               (4U)
+#define USIM_CONF2_ATR_ASYN_BYPASS_MASK                (0x00000010U)
+#define USIM_CONF2_ATR_ASYN_BYPASS_ATR_ASYN_BYPASS_VALUE_0           (0U)
+#define USIM_CONF2_ATR_ASYN_BYPASS_ATR_ASYN_BYPASS_VALUE_1           (1U)
+#define USIM_CONF2_CONFPROTOCOL_SHIFT                   (5U)
+#define USIM_CONF2_CONFPROTOCOL_MASK                    (0x00000020U)
+#define USIM_CONF2_CONFPROTOCOL_CONFPROTOCOL_VALUE_0     (0U)
+#define USIM_CONF2_CONFPROTOCOL_CONFPROTOCOL_VALUE_1     (1U)
+#define USIM_CONF2_CONFEDC_SHIFT                        (6U)
+#define USIM_CONF2_CONFEDC_MASK                         (0x00000040U)
+#define USIM_CONF2_CONFEDC_CONFEDC_VALUE_0               (0U)
+#define USIM_CONF2_CONFEDC_CONFEDC_VALUE_1               (1U)
+#define USIM_CONF2_CONFLRCCHECK_SHIFT                   (7U)
+#define USIM_CONF2_CONFLRCCHECK_MASK                    (0x00000080U)
+#define USIM_CONF2_CONFLRCCHECK_CONFLRCCHECK_VALUE_0     (0U)
+#define USIM_CONF2_CONFLRCCHECK_CONFLRCCHECK_VALUE_1     (1U)
+#define USIM_CONF2_CONFRESENT_SHIFT                     (8U)
+#define USIM_CONF2_CONFRESENT_MASK                      (0x00000700U)
+
+#define USIM_CONF2_CARD_POLARITY_SHIFT                  (11U)
+#define USIM_CONF2_CARD_POLARITY_MASK                   (0x00000800U)
+#define USIM_CONF2_CARD_POLARITY_CARD_POLARITY_VALUE_0     (0U)
+#define USIM_CONF2_CARD_POLARITY_CARD_POLARITY_VALUE_1     (1U)
+
+#define USIM_CONF2_HW_DEACTIV_EN_SHIFT                    (12U)
+#define USIM_CONF2_HW_DEACTIV_EN_MASK                     (0x00001000U)
+#define USIM_CONF2_HW_DEACTIV_EN_HW_DEACTIV_EN_VALUE_0     (0U)
+#define USIM_CONF2_HW_DEACTIV_EN_HW_DEACTIV_EN_VALUE_1     (1U)
+
+#define USIM_CONF2_DEBOUNCE_EN_SHIFT                      (13U)
+#define USIM_CONF2_DEBOUNCE_EN_MASK                       (0x00002000U)
+#define USIM_CONF2_DEBOUNCE_EN_DEBOUNCE_EN_VALUE0          (0U)
+#define USIM_CONF2_DEBOUNCE_EN_DEBOUNCE_EN_VALUE1          (1U)
+
+#define USIM_CONF2_PUT_ERR_IN_FIFO_SHIFT                  (14U)
+#define USIM_CONF2_PUT_ERR_IN_FIFO_MASK                   (0x00004000U)
+
+#define USIM_CONF2_NACKING_EN_SHIFT                       (15U)
+#define USIM_CONF2_NACKING_EN_MASK                        (0x00008000U)
+#define USIM_CONF2_NACKING_EN_DISABLED                     (0U)
+#define USIM_CONF2_NACKING_EN_RXFIFO_FULL_NACK             (1U)
+
+#define USIM_CONF2_PAR_ERR_LEVEL_SHIFT                    (16U)
+#define USIM_CONF2_PAR_ERR_LEVEL_MASK                     (0x00070000U)
+
+#define USIM_CONF2_CONFSCLKMODE_SHIFT                     (19U)
+#define USIM_CONF2_CONFSCLKMODE_MASK                      (0x00080000U)
+
+#define USIM_CONF2_STOP_RESEND_FAILURE_SHIFT              (20U)
+#define USIM_CONF2_STOP_RESEND_FAILURE_MASK               (0x00100000U)
+
+#define USIM_CONF2_STOP_RX_TIMEOUT_SHIFT                  (21U)
+#define USIM_CONF2_STOP_RX_TIMEOUT_MASK                   (0x00200000U)
+
+#define USIM_CONF3_TDUSIM_SHIFT                           (4U)
+#define USIM_CONF3_TDUSIM_MASK                            (0x000000f0U)
+
+#define USIM_CONF3_TFUSIM_SHIFT                           (0U)
+#define USIM_CONF3_TFUSIM_MASK                            (0x0000000fU)
+
+#define USIM_CONF3_RESERVED_8_31_SHIFT                    (8U)
+#define USIM_CONF3_RESERVED_8_31_MASK                     (0xffffff00U)
+
+#define USIM_DRX_USIMDRX_SHIFT                            (0U)
+#define USIM_DRX_USIMDRX_MASK                             (0x000000ffU)
+
+#define USIM_DRX_STATRXPAR_SHIFT                          (8U)
+#define USIM_DRX_STATRXPAR_MASK                           (0x00000100U)
+#define USIM_DRX_STATRXPAR_STATRXPAR_VALUE_1               (1U)
+#define USIM_DRX_STATRXPAR_STATRXPAR_VALUE_0               (0U)
+
+#define USIM_DRX_RESERVED_9_31_SHIFT                      (9U)
+#define USIM_DRX_RESERVED_9_31_MASK                       (0xfffffe00U)
+
+#define USIM_DTX_DTX_SHIFT                                (0U)
+#define USIM_DTX_DTX_MASK                                 (0x000000ffU)
+
+#define USIM_DTX_RESERVED_8_31_SHIFT                      (8U)
+#define USIM_DTX_RESERVED_8_31_MASK                       (0xffffff00U)
+
+#define USIM_FIFOS_DMA_MODE_SHIFT                         (0U)
+#define USIM_FIFOS_DMA_MODE_MASK                          (0x00000001U)
+#define USIM_FIFOS_DMA_MODE_DMA_MODE_VALUE_1               (1U)
+#define USIM_FIFOS_DMA_MODE_DMA_MODE_VALUE_0               (0U)
+
+#define USIM_FIFOS_FIFO_ENABLE_SHIFT                      (1U)
+#define USIM_FIFOS_FIFO_ENABLE_MASK                       (0x00000002U)
+#define USIM_FIFOS_FIFO_ENABLE_FIFO_ENABLE_VALUE_1         (1U)
+#define USIM_FIFOS_FIFO_ENABLE_FIFO_ENABLE_VALUE_0         (0U)
+
+#define USIM_FIFOS_FIFO_TX_TRIGGER_SHIFT                  (23U)
+#define USIM_FIFOS_FIFO_TX_TRIGGER_MASK                   (0xff800000U)
+
+#define USIM_FIFOS_FIFOTX_RESET_SHIFT                     (6U)
+#define USIM_FIFOS_FIFOTX_RESET_MASK                      (0x00000040U)
+#define USIM_FIFOS_FIFOTX_RESET_FIFOTX_RESET_VALUE_1       (1U)
+#define USIM_FIFOS_FIFOTX_RESET_FIFOTX_RESET_VALUE_0       (0U)
+
+#define USIM_FIFOS_FIFOTX_EMPTY_SHIFT                     (7U)
+#define USIM_FIFOS_FIFOTX_EMPTY_MASK                      (0x00000080U)
+#define USIM_FIFOS_FIFOTX_EMPTY_FIFOTX_EMPTY_VALUE_1       (1U)
+#define USIM_FIFOS_FIFOTX_EMPTY_FIFOTX_EMPTY_VALUE_0       (0U)
+
+#define USIM_FIFOS_FIFOTX_FULL_SHIFT                      (8U)
+#define USIM_FIFOS_FIFOTX_FULL_MASK                       (0x00000100U)
+#define USIM_FIFOS_FIFOTX_FULL_FIFOTX_FULL_VALUE_1         (1U)
+#define USIM_FIFOS_FIFOTX_FULL_FIFOTX_FULL_VALUE_0         (0U)
+
+#define USIM_FIFOS_FIFO_RX_TRIGGER_SHIFT                  (9U)
+#define USIM_FIFOS_FIFO_RX_TRIGGER_MASK                   (0x0003fe00U)
+
+#define USIM_FIFOS_FIFORX_RESET_SHIFT                     (18U)
+#define USIM_FIFOS_FIFORX_RESET_MASK                      (0x00040000U)
+#define USIM_FIFOS_FIFORX_RESET_FIFORX_RESET_VALUE_1       (1U)
+#define USIM_FIFOS_FIFORX_RESET_FIFORX_RESET_VALUE_0       (0U)
+
+#define USIM_FIFOS_FIFORX_EMPTY_SHIFT                     (19U)
+#define USIM_FIFOS_FIFORX_EMPTY_MASK                      (0x00080000U)
+#define USIM_FIFOS_FIFORX_EMPTY_FIFORX_EMPTY_VALUE_1       (1U)
+#define USIM_FIFOS_FIFORX_EMPTY_FIFORX_EMPTY_VALUE_0       (0U)
+
+#define USIM_FIFOS_FIFORX_FULL_SHIFT                      (20U)
+#define USIM_FIFOS_FIFORX_FULL_MASK                       (0x00100000U)
+#define USIM_FIFOS_FIFORX_FULL_FIFORX_FULL_VALUE_1         (1U)
+#define USIM_FIFOS_FIFORX_FULL_FIFORX_FULL_VALUE_0         (0U)
+
+#define USIM_FIFOS_RXDMA_TYPE_SHIFT                       (21U)
+#define USIM_FIFOS_RXDMA_TYPE_MASK                        (0x00600000U)
+#define USIM_FIFOS_RXDMA_TYPE_LEGACY                       (0U)
+#define USIM_FIFOS_RXDMA_TYPE_NEW1                         (2U)
+#define USIM_FIFOS_RXDMA_TYPE_NEW2                         (3U)
+
+#define USIM_FIFOS_RESERVED_SHIFT                         (2U)
+#define USIM_FIFOS_RESERVED_MASK                          (0x0000003cU)
+
+#define USIM_CGT_RESERVED_9_31_SHIFT                      (9U)
+#define USIM_CGT_RESERVED_9_31_MASK                       (0xfffffe00U)
+
+#define USIM_CGT_CGT_SHIFT                                (0U)
+#define USIM_CGT_CGT_MASK                                 (0x000001ffU)
+
+#define USIM_CWT_CWT_SHIFT                                (0U)
+#define USIM_CWT_CWT_MASK                                 (0xffffffffU)
+
+#define USIM_BWT_BWT_SHIFT                                (0U)
+#define USIM_BWT_BWT_MASK                                 (0xffffffffU)
+
+#define USIM_DEBUG_RESERVED_25_31_SHIFT                   (25U)
+#define USIM_DEBUG_RESERVED_25_31_MASK                    (0xfe000000U)
+
+#define USIM_DEBUG_MAIN_STATE_DEBUG_SHIFT                 (0U)
+#define USIM_DEBUG_MAIN_STATE_DEBUG_MASK                  (0x0000000fU)
+
+#define USIM_DEBUG_TX_STATE_MACHINE_SHIFT                 (4U)
+#define USIM_DEBUG_TX_STATE_MACHINE_MASK                  (0x00000030U)
+
+#define USIM_DEBUG_RX_STATE_MACHINE_SHIFT                 (6U)
+#define USIM_DEBUG_RX_STATE_MACHINE_MASK                  (0x000000c0U)
+
+#define USIM_DEBUG_RXFIFO_PEAK_SHIFT                      (8U)
+#define USIM_DEBUG_RXFIFO_PEAK_MASK                       (0x0003ff00U)
+
+#define USIM_DEBUG_RXDMA_SHIFT                            (18U)
+#define USIM_DEBUG_RXDMA_MASK                             (0x00040000U)
+
+#define USIM_DEBUG_TXDMA_SHIFT                            (19U)
+#define USIM_DEBUG_TXDMA_MASK                             (0x00080000U)
+
+#define USIM_DEBUG_EMV_MAIN_STATE_DEBUG_SHIFT             (20U)
+#define USIM_DEBUG_EMV_MAIN_STATE_DEBUG_MASK              (0x01f00000U)
+
+#define USIM_CONF_SAM1_DIV_RESERVED_12_31_SHIFT           (12U)
+#define USIM_CONF_SAM1_DIV_RESERVED_12_31_MASK            (0xfffff000U)
+
+#define USIM_CONF_SAM1_DIV_SAM1_DIV_SHIFT                 (0U)
+#define USIM_CONF_SAM1_DIV_SAM1_DIV_MASK                  (0x00000fffU)
+
+#define USIM_CONF4_RESERVED_16_31_SHIFT                   (16U)
+#define USIM_CONF4_RESERVED_16_31_MASK                    (0xffff0000U)
+
+#define USIM_CONF4_CONFWAITI_SHIFT                        (0U)
+#define USIM_CONF4_CONFWAITI_MASK                         (0x0000ffffU)
+
+#define USIM_ATR_CLK_PRD_NBS_RESERVED_16_31_SHIFT         (16U)
+#define USIM_ATR_CLK_PRD_NBS_RESERVED_16_31_MASK          (0xffff0000U)
+
+#define USIM_ATR_CLK_PRD_NBS_CLOCK_NUMBER_BEFORE_ATR_SHIFT   (0U)
+#define USIM_ATR_CLK_PRD_NBS_CLOCK_NUMBER_BEFORE_ATR_MASK    (0x0000ffffU)
+
+#define USIM_CONF_ETU_DIV_RESERVED_16_31_SHIFT       (16U)
+#define USIM_CONF_ETU_DIV_RESERVED_16_31_MASK        (0xffff0000U)
+
+#define USIM_CONF_ETU_DIV_ETU_DIV_SHIFT              (0U)
+#define USIM_CONF_ETU_DIV_ETU_DIV_MASK               (0x0000ffffU)
+
+#define USIM_CONF5_RESERVED_12_31_SHIFT              (9U)
+#define USIM_CONF5_RESERVED_12_31_MASK               (0xfffffe00U)
+
+#define USIM_CONF5_DI_SHIFT                          (0U)
+#define USIM_CONF5_DI_MASK                           (0x0000000fU)
+
+#define USIM_CONF5_FI_SHIFT                          (4U)
+#define USIM_CONF5_FI_MASK                           (0x000000f0U)
+
+#define USIM_CONF5_SOFT_NHARD_FIDI_PROG_SHIFT      (8U)
+#define USIM_CONF5_SOFT_NHARD_FIDI_PROG_MASK       (0x00000100U)
+#define USIM_CONF5_SOFT_NHARD_FIDI_PROG_HARDWARE    (0U)
+#define USIM_CONF5_SOFT_NHARD_FIDI_PROG_SOFTWARE    (1U)
+
+#define USIM_TC_GUARD_TIME_ADD_RESERVED_14_31_SHIFT  (14U)
+#define USIM_TC_GUARD_TIME_ADD_RESERVED_14_31_MASK   (0xffffc000U)
+
+#define USIM_TC_GUARD_TIME_ADD_SOFT_TC_GUARD_TIME_ADD_EN_SHIFT (13U)
+#define USIM_TC_GUARD_TIME_ADD_SOFT_TC_GUARD_TIME_ADD_EN_MASK  (0x00002000U)
+#define USIM_TC_GUARD_TIME_ADD_SOFT_TC_GUARD_TIME_ADD_EN_HW     (0U)
+#define USIM_TC_GUARD_TIME_ADD_SOFT_TC_GUARD_TIME_ADD_EN_SW     (1U)
+
+#define USIM_TC_GUARD_TIME_ADD_SOFT_TC_GUARD_TIME_ADD_SHIFT    (0U)
+#define USIM_TC_GUARD_TIME_ADD_SOFT_TC_GUARD_TIME_ADD_MASK     (0x00001fffU)
+
+#define USIM_RXFIFO_LEVEL_USIM_RXFIFO_LEVEL_SHIFT   (0U)
+#define USIM_RXFIFO_LEVEL_USIM_RXFIFO_LEVEL_MASK    (0x000003ffU)
+
+#define USIM_RXFIFO_LEVEL_RESERVED_SHIFT            (10U)
+#define USIM_RXFIFO_LEVEL_RESERVED_MASK             (0xfffffc00U)
+
+#define USIM_RXFIFO_BYTECNT_USIM_RXFIFO_BYTECNT_SHIFT   (0U)
+#define USIM_RXFIFO_BYTECNT_USIM_RXFIFO_BYTECNT_MASK    (0x000001ffU)
+
+#define USIM_RXFIFO_BYTECNT_RESERVED_SHIFT        (9U)
+#define USIM_RXFIFO_BYTECNT_RESERVED_MASK         (0xfffffe00U)
+
+#define USIM_WWT_WWT_SHIFT                        (0U)
+#define USIM_WWT_WWT_MASK                         (0xffffffffU)
+
+#define USIM_CONF6_MODE_SHIFT                     (0U)
+#define USIM_CONF6_MODE_MASK                      (0x00000007U)
+#define USIM_CONF6_MODE_NO_OVERRIDE                (0U)
+#define USIM_CONF6_MODE_FREEZE                     (1U)
+#define USIM_CONF6_MODE_RX_TX                      (2U)
+#define USIM_CONF6_MODE_ATR                        (3U)
+#define USIM_CONF6_MODE_ACTIVATE                   (4U)
+#define USIM_CONF6_MODE_DEACTIVATE                 (5U)
+#define USIM_CONF6_MODE_IDLE                       (6U)
+#define USIM_CONF6_MODE_RESERVED7                  (7U)
+
+#define USIM_CONF6_RST_POLARITY_SHIFT             (3U)
+#define USIM_CONF6_RST_POLARITY_MASK              (0x00000008U)
+#define USIM_CONF6_RST_POLARITY_ACTIVE_LOW         (0U)
+#define USIM_CONF6_RST_POLARITY_ACTIVE_HIGH        (1U)
+
+#define USIM_CONF6_RESERVED_SHIFT                 (12U)
+#define USIM_CONF6_RESERVED_MASK                  (0x0000f000U)
+
+#define USIM_CONF6_ATR_TIMER_BYPASS_SHIFT         (4U)
+#define USIM_CONF6_ATR_TIMER_BYPASS_MASK          (0x00000010U)
+
+#define USIM_CONF6_IO_BYPASS_SHIFT                (5U)
+#define USIM_CONF6_IO_BYPASS_MASK                 (0x00000060U)
+#define USIM_CONF6_IO_BYPASS_00                    (0U)
+#define USIM_CONF6_IO_BYPASS_10                    (2U)
+#define USIM_CONF6_IO_BYPASS_01                    (1U)
+#define USIM_CONF6_IO_BYPASS_11                    (3U)
+
+#define USIM_CONF6_SCLK0_BYPASS_SHIFT             (7U)
+#define USIM_CONF6_SCLK0_BYPASS_MASK              (0x00000080U)
+
+#define USIM_CONF6_LEN_BYPASS_MASK                (0x00000200U)
+
+#define USIM_CONF6_RST_BYPASS_SHIFT               (10U)
+#define USIM_CONF6_RST_BYPASS_MASK                (0x00000400U)
+
+#define USIM_CONF6_VCC_BYPASS_SHIFT               (11U)
+#define USIM_CONF6_VCC_BYPASS_MASK                (0x00000800U)
+
+#define USIM_CONF6_ATR_TIMEOUT_SHIFT              (16U)
+#define USIM_CONF6_ATR_TIMEOUT_MASK               (0xffff0000U)
+
+#define USIM_IO_DIRECT_SCLK0_SHIFT                (0U)
+#define USIM_IO_DIRECT_SCLK0_MASK                 (0x00000001U)
+
+#define USIM_IO_DIRECT_SIORX0_SHIFT               (2U)
+#define USIM_IO_DIRECT_SIORX0_MASK                (0x00000004U)
+
+#define USIM_IO_DIRECT_SIORX1_SHIFT               (3U)
+#define USIM_IO_DIRECT_SIORX1_MASK                (0x00000008U)
+
+#define USIM_IO_DIRECT_SIOTX0_SHIFT               (4U)
+#define USIM_IO_DIRECT_SIOTX0_MASK                (0x00000010U)
+
+#define USIM_IO_DIRECT_SIOEN0_SHIFT               (6U)
+#define USIM_IO_DIRECT_SIOEN0_MASK                (0x00000040U)
+
+#define USIM_IO_DIRECT_RST_SHIFT                  (8U)
+#define USIM_IO_DIRECT_RST_MASK                   (0x00000100U)
+
+#define USIM_IO_DIRECT_SVCC_SHIFT                 (9U)
+#define USIM_IO_DIRECT_SVCC_MASK                  (0x00000200U)
+
+#define USIM_IO_DIRECT_SINEX_SHIFT                (10U)
+#define USIM_IO_DIRECT_SINEX_MASK                 (0x00000400U)
+
+#define USIM_IO_DIRECT_LEN_SHIFT                  (11U)
+#define USIM_IO_DIRECT_LEN_MASK                   (0x00000800U)
+
+#define USIM_IO_DIRECT_RNW0_SHIFT                 (12U)
+#define USIM_IO_DIRECT_RNW0_MASK                  (0x00001000U)
+
+#define USIM_IO_DIRECT_RESERVED_SHIFT             (15U)
+#define USIM_IO_DIRECT_RESERVED_MASK              (0xffff8000U)
+
+#define USIM_IO_DIRECT_C4_SHIFT                   (14U)
+#define USIM_IO_DIRECT_C4_MASK                    (0x00004000U)
+
+#define USIM_TX_BLOCK_BLOCK_LENGTH_SHIFT          (0U)
+#define USIM_TX_BLOCK_BLOCK_LENGTH_MASK           (0x0000ffffU)
+
+#define USIM_TX_BLOCK_RESERVED_SHIFT              (16U)
+#define USIM_TX_BLOCK_RESERVED_MASK               (0xffff0000U)
+
+#endif /* __TI_USIM_HW_H__ */
diff --git a/drivers/char/ti-usim.c b/drivers/char/ti-usim.c
new file mode 100644
index 0000000..ffabf87
--- /dev/null
+++ b/drivers/char/ti-usim.c
@@ -0,0 +1,2213 @@
+/*
+ * usim.c - USIM driver for Smart Card module
+ *
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+/* for send_sig_info */
+#include <linux/rcupdate.h>
+#include <asm/siginfo.h>
+
+#include "ti-usim-hw.h"
+
+#define USIM_WRITEREG(base, offset, field, value)  \
+			usim_writereg(base+offset, offset##_##field##_MASK, \
+				offset##_##field##_SHIFT, value)
+
+#define USIM_READREG(base, offset, field)  \
+	usim_readreg(base+offset, offset##_##field##_MASK, \
+			offset##_##field##_SHIFT)
+
+#define USIM_SETFIELD(reg, offset, field, value)  \
+	usim_setfield(reg, offset##_##field##_MASK, \
+			offset##_##field##_SHIFT, value)
+
+/* calculation of max ATR waiting time
+ * 372 is default FI value, so etu for 1Mhz SC clock cycle would be
+ * etu = FI/f sec = 372/1Mhz = 372 micro second
+ * Max ATR waiting is - USIM_ATR_TIMEOUT_EMV etu
+ */
+#define MAX_ATR_WAITTIME_US (372 * USIM_ATR_TIMEOUT_EMV)
+
+/*
+ * phy states
+ */
+enum usim_phy_state {
+	USIM_PHY_NOT_PRESENT = 0x0,
+	USIM_PHY_PRESENT,
+	USIM_PHY_NOT_ATTACHED,
+};
+
+static struct miscdevice usim_dev;
+
+static DECLARE_WAIT_QUEUE_HEAD(rx_wait);
+static DECLARE_WAIT_QUEUE_HEAD(tx_wait);
+static DECLARE_WAIT_QUEUE_HEAD(atr_wait);
+
+static int usim_set_smartcardclock(struct usim *usim, u32 clock);
+static int usim_deactivate_card(struct usim *usim);
+
+static void usim_writereg(void __iomem *base, u32 mask, u32 shift, u32 value)
+{
+	u32 v = readl(base);
+
+	v &= ~mask;
+	v |= (value << shift) & mask;
+	writel(v, base);
+	v = readl(base);
+	return;
+}
+
+static u32 usim_readreg(void __iomem *base, u32 mask, u32 shift)
+{
+	u32 v = readl(base);
+
+	v &= mask;
+	v = (v >> shift);
+	return v;
+}
+
+static u32 usim_setfield(u32 reg, u32 mask, u32 shift, u32 value)
+{
+	reg &= ~mask;
+	reg |= (value << shift) & mask;
+	return reg;
+}
+
+
+static inline void usim_irq_enable(void __iomem *base, u32 irqs)
+{
+	u32 v = readl(base + USIM_IRQENABLE);
+
+	v |= irqs;
+	writel(v, base + USIM_IRQENABLE);
+}
+
+static inline void usim_irq_disable(void __iomem *base, u32 irqs)
+{
+	u32 v = readl(base + USIM_IRQENABLE);
+
+	v &= ~irqs;
+	writel(v, base + USIM_IRQENABLE);
+}
+
+static inline void usim_irq_get(void __iomem *base, u32 *irqs)
+{
+	*irqs = readl(base + USIM_IRQENABLE);
+}
+
+static inline u32 usim_irqstatus(void __iomem *base)
+{
+	return readl(base + USIM_IRQSTATUS);
+}
+
+static inline void usim_irqstatus_clear(void __iomem *base, u32 irqs)
+{
+	writel(irqs, base + USIM_IRQSTATUS);
+}
+
+static inline struct usim *dev_to_usim(struct device *dev)
+{
+	return dev_get_drvdata(dev);
+}
+
+static int usim_send_signal(struct usim *usim, int event)
+{
+	struct siginfo info;
+	struct task_struct *tid;
+	int ret = 0;
+	int pid = usim->user_pid;
+
+	if (pid == 0)
+		return -EINVAL;
+	info.si_signo = USIM_SIGID;
+	info.si_code = SI_QUEUE;
+
+	info.si_int = event;
+	rcu_read_lock();
+
+	/* find task structure associated with this pid */
+	tid = pid_task(find_vpid(pid), PIDTYPE_PID);
+	if (tid == NULL) {
+		dev_err(usim->dev, "usim-err:no such pid :%d\n", pid);
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+
+	rcu_read_unlock();
+
+	/* send the signal */
+	ret = send_sig_info(USIM_SIGID, &info, tid);
+	if (ret < 0) {
+		dev_err(usim->dev, "error sending signal:%d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void usim_getrx(struct usim *usim)
+{
+	u32 rxlen = 0;
+	u32 cnt = 0;
+
+	/* Check if FIFO contains some data */
+	rxlen = USIM_READREG(usim->base, USIM_RXFIFO_LEVEL,
+					USIM_RXFIFO_LEVEL);
+
+	usim->slot_ctx[usim->slot].rx_counter += rxlen;
+	if (rxlen > 0) {
+		for (cnt = 0; cnt < rxlen; cnt++) {
+			usim->slot_ctx[usim->slot].rxbuf[cnt] =
+				USIM_READREG(usim->base, USIM_DRX, USIMDRX);
+		}
+	}
+}
+
+static void usim_irq_atrhandler(struct usim *usim, u32 reg)
+{
+	u32 event = 0;
+	u32 val = 0;
+	u32 cnt = 0;
+	u32 rxval = 0;
+	if (usim->atrdone)
+		return;
+	do {
+		/* WWT would be used to identify end of ATR */
+		if (reg & (USIM_IRQ_WT | USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT)) {
+			event |= USIM_EVENT_TIMEOUT;
+			val = USIM_READREG(usim->base, USIM_STAT,
+						ATRRX_AFTER_TIMEOUT);
+			if (val) {
+				/* do not store rx character if it comes after
+				 * ATR timeout
+				 */
+				dev_dbg(usim->dev, "Error: Rx after ATR Timeout");
+				break;
+			}
+		}
+		if (reg & USIM_IRQ_TS_ERR) {
+			event |= USIM_EVENT_ERR_FRAME;
+			break;
+		}
+
+		/* check the rx fifo and store available bytes in atrbuf */
+		val = USIM_READREG(usim->base, USIM_RXFIFO_LEVEL,
+						USIM_RXFIFO_LEVEL);
+		cnt = usim->slot_ctx[usim->slot].atr_length;
+
+		while (val > 0) {
+			if (cnt < USIM_MAX_ATRLENGTH) {
+				rxval = readl(usim->base + USIM_DRX);
+				usim->slot_ctx[usim->slot].atr[cnt++] = rxval &
+							USIM_DRX_USIMDRX_MASK;
+				/* check of parity */
+				if (!(rxval & USIM_DRX_STATRXPAR_MASK)) {
+					dev_dbg(usim->dev,
+						"Error : incorrect parity:%0x"
+						, rxval);
+					event |= USIM_EVENT_ERR_PARITY;
+				}
+			}
+			val--;
+		}
+
+		usim->slot_ctx[usim->slot].atr_length = cnt;
+	} while (0);
+
+	if (event != 0) {
+		USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
+		usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
+		usim->slot_ctx[usim->slot].event = event;
+		usim->atrdone = 1;
+	}
+
+	if (usim->atrdone)
+		wake_up(&atr_wait);
+
+	return;
+}
+
+static void usim_irq_txhandler(struct usim *usim, u32 reg)
+{
+	u32 protocol	= 0;
+	u32 event	= 0;
+
+	if (usim->txdone)
+		return;
+
+	protocol = usim->slot_ctx[usim->slot].protocol;
+	do {
+		if (reg & USIM_IRQ_FRAME_ERR) {
+			event |= USIM_EVENT_ERR_FRAME;
+			break;
+		}
+		if (!protocol && (reg & USIM_IRQ_RESENT)) {
+			event |= USIM_EVENT_ERR_TXRETRY;
+			break;
+		}
+		if (reg & USIM_IRQ_TX_BLOCK_REQ) {
+			/* TODO : As per EMV max tx block will be of 256 bytes
+			 * and USIM controller has sufficient place for this.
+			 * Need to implement this case when it is practially
+			 * required
+			 */
+			dev_dbg(usim->dev, "Error: TX_BLOCK_REQ - Not Implemented");
+		}
+		if (reg & USIM_IRQ_TX_BLOCK_DONE) {
+			usim_irq_disable(usim->base, USIM_IRQ_TX_BLOCK_REQ
+						| USIM_IRQ_TX_BLOCK_DONE
+						| USIM_IRQ_TX);
+			usim->txdone = 1;
+			usim_irq_enable(usim->base, USIM_IRQ_RX | USIM_IRQ_EOB
+						| USIM_IRQ_RXDMA_RDY);
+			break;
+		}
+	} while (0);
+
+	if (event != 0) {
+		USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
+		usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
+		usim->slot_ctx[usim->slot].event = event;
+		usim->txdone = 1;
+		usim->rxdone = 1;
+	}
+	if (usim->txdone)
+		wake_up(&tx_wait);
+	return;
+}
+
+static void usim_irq_rxhandler(struct usim *usim, u32 reg)
+{
+	u32 event = 0;
+	u32 val	= 0;
+
+	u32 protocol = usim->slot_ctx[usim->slot].protocol;
+
+	/* if tx not done then do not check of any rx */
+	if (usim->rxdone || !usim->txdone)
+		return;
+
+	/* For T=0 protocol */
+	if (protocol == 0) {
+		do {
+			/* ignore interrupts if expected bytes recevied */
+			if (usim->slot_ctx[usim->slot].rx_counter >=
+					usim->slot_ctx[usim->slot].rx_explen) {
+				dev_dbg(usim->dev, "All bytes recvd,ignore this timeout\n");
+				usim->rxdone = 1;
+				break;
+			}
+
+			if (reg & USIM_IRQ_WT) {
+				dev_dbg(usim->dev, "Expected bytes not recvd counter = %d\n",
+					usim->slot_ctx[usim->slot].rx_counter);
+				usim_getrx(usim);
+				event |= USIM_EVENT_TIMEOUT;
+				break;
+			}
+
+			if (reg & USIM_IRQ_PAR_ERR_LEVEL_REACHED) {
+				dev_err(usim->dev,
+					"Rx parity level reached:%x\n"
+					, reg);
+				usim_getrx(usim);
+				event |= USIM_EVENT_ERR_PARITY;
+				break;
+			}
+
+			if (reg & (USIM_IRQ_RX | USIM_IRQ_RXDMA_RDY)) {
+				/* Read number of bytes present in the FIFO */
+				usim_getrx(usim);
+				usim->rxdone = 1;
+				break;
+			}
+		} while (0);
+	} else {
+		/* T=1 protocol */
+		do {
+			if (reg & (USIM_IRQ_TOB | USIM_IRQ_TOC)) {
+				usim_getrx(usim);
+				event |= USIM_EVENT_TIMEOUT;
+				break;
+			}
+			if (reg & USIM_IRQ_EOB) {
+				usim_getrx(usim);
+				usim->rxdone = 1;
+				val = USIM_READREG(usim->base, USIM_STAT,
+								STATLRC);
+				if (val != 0)
+					event |= USIM_EVENT_ERR_LRC;
+				break;
+			}
+		} while (0);
+	}
+
+	if (event != 0 || usim->rxdone == 1) {
+		USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
+		usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
+		usim->slot_ctx[usim->slot].event = event;
+		usim->rxdone = 1;
+	}
+
+	if (usim->rxdone)
+		wake_up(&rx_wait);
+
+	return;
+}
+
+static irqreturn_t usim_interrupt(int irq, void *_usim)
+{
+	u32 reg = 0;
+	u32 state = 0;
+	struct usim *usim = (struct usim *)_usim;
+
+	state = usim->slot_ctx[usim->slot].state;
+
+	spin_lock(&usim->lock);
+
+	reg = readl(usim->base + USIM_IRQSTATUS);
+
+	if (state == USIM_MODE_ATR)
+		usim_irq_atrhandler(usim, reg);
+
+	if (state == USIM_MODE_TXRX) {
+		usim_irq_txhandler(usim, reg);
+		usim_irq_rxhandler(usim, reg);
+	}
+
+	if (reg & USIM_IRQSTATUS_USIM_NATR_MASK)
+		dev_dbg(usim->dev, "NO ATR\n");
+
+	if (reg & USIM_IRQSTATUS_USIM_CD_MASK)
+		dev_dbg(usim->dev, "CARD Insert/Removed\n");
+
+	if (reg & USIM_IRQSTATUS_USIM_STOP_CLK_MASK)
+		dev_dbg(usim->dev, "SIM CLK STOPPED\n");
+
+	if (reg & USIM_IRQSTATUS_ACT_DONE_MASK)
+		dev_dbg(usim->dev, "Activation Sequence completed\n");
+
+	if (reg & USIM_IRQSTATUS_DEACT_DONE_MASK)
+		dev_dbg(usim->dev, "Deactivation Sequence complteted\n");
+
+	/* Clear the interrupt by writing the corresponding bit
+	 * in IRQ_STATUS register
+	 */
+	usim_irqstatus_clear(usim->base, reg);
+
+	spin_unlock(&usim->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int usim_configure(struct usim *usim)
+{
+	int reg = 0;
+	int count = 3;
+
+	/* perform softreset of IP */
+	USIM_WRITEREG(usim->base, USIM_SYSCONFIG, SOFTRESET, 1);
+
+	/* wait until reset get completed */
+	while (count > 0) {
+		reg = USIM_READREG(usim->base, USIM_SYSCONFIG, SOFTRESET);
+		if (reg == 0x0)
+			break;
+		mdelay(10);
+		count--;
+	}
+	if (reg != 0x0)
+		return -EIO;
+
+	/* activate phy */
+	if (usim->phy_present)
+		usim->phy->set_config(usim->phy, usim->slot, SC_PHY_MODE,
+				SC_PHY_ACTIVE);
+
+	/* Disable Auto Idle and set NO IDLE config */
+	reg = readl(usim->base + USIM_SYSCONFIG);
+	reg = USIM_SETFIELD(reg, USIM_SYSCONFIG, AUTOIDLE, 0);
+	reg = USIM_SETFIELD(reg, USIM_SYSCONFIG, IDLEMODE, 1);
+	writel(reg, usim->base + USIM_SYSCONFIG);
+
+	if (usim->phy_present) {
+		USIM_WRITEREG(usim->base, USIM_STAT, STATNOCARD, 1);
+		USIM_WRITEREG(usim->base, USIM_CONF1, BYPASS_HW_AUTO, 0);
+	} else {
+		USIM_WRITEREG(usim->base, USIM_STAT, STATNOCARD, 0);
+		USIM_WRITEREG(usim->base, USIM_CONF1, BYPASS_HW_AUTO, 1);
+	}
+
+	/* Set default card type as EMV, Force SIO to low level */
+	reg = readl(usim->base + USIM_CONF1);
+	reg = USIM_SETFIELD(reg, USIM_CONF1, EMV_CONF, 1);
+	reg = USIM_SETFIELD(reg, USIM_CONF1, CONFSIOLOW, 1);
+	writel(reg, usim->base + USIM_CONF1);
+
+	/* Set parity level to 1, auto resent to 2 on parity error,  */
+	reg = readl(usim->base + USIM_CONF2);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, NACKING_EN, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CARD_POLARITY, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFEDC, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFPROTOCOL, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, ATR_ASYN_BYPASS, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKMODE, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, PAR_ERR_LEVEL, 1);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFRESENT, 2);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, PUT_ERR_IN_FIFO, 1);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFLRCCHECK, 2);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFCHKPAR, 1);
+
+	if (usim->phy_present) {
+		reg = USIM_SETFIELD(reg, USIM_CONF2, HW_DEACTIV_EN, 0);
+		reg = USIM_SETFIELD(reg, USIM_CONF2, DEBOUNCE_EN, 0);
+	} else {
+		reg = USIM_SETFIELD(reg, USIM_CONF2, HW_DEACTIV_EN, 1);
+	}
+
+	writel(reg, usim->base + USIM_CONF2);
+
+	/* Reset Tx FIFO Pointer */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
+
+	/* Reset Rx FIFO Pointer */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
+
+	/* Configure FIFO settings */
+	/* Set Tx and Rx trigger to 1 byte */
+	reg = readl(usim->base + USIM_FIFOS);
+	reg = USIM_SETFIELD(reg, USIM_FIFOS, FIFO_TX_TRIGGER, 0);
+	reg = USIM_SETFIELD(reg, USIM_FIFOS, FIFO_RX_TRIGGER, 0);
+	reg = USIM_SETFIELD(reg, USIM_FIFOS, RXDMA_TYPE, 0x3);
+	reg = USIM_SETFIELD(reg, USIM_FIFOS, DMA_MODE, 0x0);
+	writel(reg, usim->base + USIM_FIFOS);
+
+	/* Enable FIFO access */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_ENABLE, 1);
+
+	/* Use HW mode for ETU calculation and set FI = 372 and DI = 1 */
+	reg = readl(usim->base + USIM_CONF5);
+	reg = USIM_SETFIELD(reg, USIM_CONF5, FI, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF5, DI, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
+	writel(reg, usim->base + USIM_CONF5);
+
+	/* Configure CONF6 settings */
+	reg = readl(usim->base + USIM_CONF6);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, VCC_BYPASS, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, RST_BYPASS, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, RST_POLARITY, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 1);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, MODE, USIM_CONF6_MODE_FREEZE);
+	writel(reg, usim->base + USIM_CONF6);
+
+	/* Clear all bits in IO_DIRECT register */
+	writel(0, usim->base + USIM_IO_DIRECT);
+
+	/* Disable legacy bypass mode */
+	USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 0);
+
+	/* Enable required interrupts */
+	reg = readl(usim->base + USIM_IRQENABLE);
+	writel(reg, usim->base + USIM_IRQENABLE);
+
+	/* Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
+	 * gets disable
+	 */
+	USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 1);
+	USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
+		      USIM_ATR_TIMEOUT_EMV);
+
+	/* Set STOP_RX_TIMEOUT */
+	/* Set STOP_RESEND_FAILURE */
+	USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RX_TIMEOUT, 1);
+	USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 1);
+
+	/* set smartcard clock */
+	usim_set_smartcardclock(usim, usim->slot_ctx[usim->slot].clock);
+
+	return 0;
+}
+
+static int usim_set_voltage(struct usim *usim, u32 voltage)
+{
+	int ret = 0;
+	struct sc_phy *phy = usim->phy;
+	/*
+	 * voltage = 0 for 5V,
+	 * voltage = 1 for 3V,
+	 * voltage = 2 for 1.8V,
+	 */
+	if (voltage > 3)
+		return -EINVAL;
+	if (usim->phy_present) {
+		ret = phy->set_config(phy, usim->slot,
+				SC_PHY_CARD_SUPPLY_VOLTAGE, voltage);
+	}
+	usim->slot_ctx[usim->slot].supply = voltage;
+	return ret;
+}
+
+static int usim_set_smartcardclock(struct usim *usim, u32 clock)
+{
+	int clkdiv;
+	int clkmode;
+	int reg = 0;
+	struct sc_phy *phy = usim->phy;
+
+	switch (clock) {
+	case USIM_SMARTCART_CLOCK_3_3MHZ:
+		clkmode	= USIM_CONFSCLKMODE_HF;
+		clkdiv	= 3;
+		break;
+
+	case USIM_SMARTCART_CLOCK_4MHZ:
+		clkmode	= USIM_CONFSCLKMODE_HF;
+		clkdiv	= 2;
+		break;
+
+	case USIM_SMARTCART_CLOCK_5MHZ:
+		clkmode	= USIM_CONFSCLKMODE_LEGACY;
+		clkdiv	= 3;
+		break;
+
+	case USIM_SMARTCART_CLOCK_6_6MHZ:
+		clkmode	= USIM_CONFSCLKMODE_LEGACY;
+		clkdiv	= 2;
+		break;
+
+	case USIM_SMARTCART_CLOCK_10MHZ:
+		clkmode	= USIM_CONFSCLKMODE_LEGACY;
+		clkdiv	= 1;
+		break;
+
+	case USIM_SMARTCART_CLOCK_20MHZ:
+		clkmode	= USIM_CONFSCLKMODE_LEGACY;
+		clkdiv	= 0;
+		break;
+
+	default:
+		dev_err(usim->dev, "Unsupported Clock configuration for smartcard\n");
+		return -EINVAL;
+		break;
+	}
+
+	/* Set default card type as EMV, Force SIO to low level */
+	reg = readl(usim->base + USIM_CONF2);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKMODE, clkmode);
+	reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, clkdiv);
+	writel(reg, usim->base + USIM_CONF2);
+
+	/* setting phy division to zero, as USIM samples smartcard clk line and
+	 * put the data in USIM fifo. Phy supply the clock to smartcard wihtout
+	 * furhter division
+	 */
+	if (usim->phy_present)
+		phy->set_config(phy, usim->slot, SC_PHY_CLKDIV, 0);
+
+	usim->slot_ctx[usim->slot].clock = clock;
+	return 0;
+}
+
+static int usim_set_etu(struct usim *usim, u32 fi, u32 di)
+{
+	USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
+	USIM_WRITEREG(usim->base, USIM_CONF5, FI, fi);
+	USIM_WRITEREG(usim->base, USIM_CONF5, DI, di);
+	return 0;
+}
+
+static int usim_set_rxparitycount(struct usim *usim, u32 rxcount)
+{
+	if (rxcount > USIM_MAX_PARITY_RETRIES)
+		return -EINVAL;
+
+	/* Program fields required for RX retry in USIM IP */
+	USIM_WRITEREG(usim->base, USIM_CONF2, PAR_ERR_LEVEL, rxcount);
+
+	/* Enable rx parity check */
+	if (rxcount > 0) {
+		USIM_WRITEREG(usim->base, USIM_CONF2, CONFCHKPAR, 1);
+		usim_irq_enable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
+	} else {
+		usim_irq_disable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
+	}
+	return 0;
+}
+
+static int usim_set_txretrycount(struct usim *usim, u32 txcount)
+{
+	if (txcount > USIM_MAX_PARITY_RETRIES)
+		return -EINVAL;
+
+	USIM_WRITEREG(usim->base, USIM_CONF2, CONFRESENT, txcount);
+	if (txcount > 0)
+		usim_irq_enable(usim->base, USIM_IRQ_RESENT);
+	else
+		usim_irq_disable(usim->base, USIM_IRQ_RESENT);
+
+	return 0;
+}
+
+static int usim_set_c4(struct usim *usim, int state)
+{
+	int ret = 0;
+	struct sc_phy *phy = usim->phy;
+	if (usim->phy_present)
+		ret = phy->set_config(phy, usim->slot, SC_PHY_PIN_C4, state);
+	else
+		 USIM_WRITEREG(usim->base, USIM_IO_DIRECT, C4, state);
+	return ret;
+}
+
+static int usim_set_c8(struct usim *usim, int state)
+{
+	int ret = 0;
+	struct sc_phy *phy = usim->phy;
+
+	if (usim->phy_present)
+		ret = phy->set_config(phy, usim->slot, SC_PHY_PIN_C8, state);
+	return ret;
+}
+static int usim_get_version(struct usim *usim)
+{
+	int version = 0x0;
+
+	/* last 16 bytes represents controller version
+	 * and first 16 bytes represents phy version (if connected)
+	 */
+	version = USIM_READREG(usim->base, USIM_REVISION, REV);
+	if (usim->phy_present)
+		version |= ((usim->phy->get_config(usim->phy, 0,
+					SC_PHY_VERSION)) << 0x10);
+	return version;
+}
+static int usim_init_emvusercard(struct usim *usim)
+{
+	int ret = 0;
+	struct sc_phy *phy = usim->phy;
+
+	USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, DMA_MODE, 0);
+
+	usim_set_etu(usim, 0, 0);
+
+	if (usim_set_txretrycount(usim, 5) != 0)
+		return -EINVAL;
+
+	if (usim_set_rxparitycount(usim, 5) != 0)
+		return -EINVAL;
+
+	usim_set_c4(usim, 0);
+	usim_set_c8(usim, 0);
+
+	if (usim->phy_present) {
+		/* Set early ATR and mute ATR in case of phy */
+		ret = phy->set_config(phy, usim->slot, SC_PHY_ATR_EARLY_TIME,
+				USIM_EMV_ATR_EARLY_TO);
+		if (ret != 0)
+			return ret;
+
+		ret = phy->set_config(phy, usim->slot, SC_PHY_ATR_MUTE_TIME,
+				USIM_EMV_ATR_MUTE_TO);
+		if (ret != 0)
+			return ret;
+
+		/* enable user slot */
+		ret = phy->set_config(phy, usim->slot, SC_PHY_IO, 1);
+		if (ret != 0)
+			return ret;
+	}
+	/* set cwt,wwt,cgt */
+	USIM_WRITEREG(usim->base, USIM_WWT, WWT, USIM_EMV_WWT);
+	USIM_WRITEREG(usim->base, USIM_CWT, CWT, USIM_EMV_WWT - 22);
+	USIM_WRITEREG(usim->base, USIM_CGT, CGT, USIM_EMV_CGT);
+
+	return 0;
+}
+
+static int usim_warmreset(struct usim *usim)
+{
+	int ret = 0;
+	struct sc_phy *phy = usim->phy;
+
+	/* reset ATR wait flag */
+	usim->atrdone = 0;
+
+	usim->slot_ctx[usim->slot].atr_length = 0;
+	USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
+	usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
+
+	/* reset FIFO pointer */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
+
+	USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x1);
+	USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x0);
+
+	/* Do store bytes with parity error in Rx FIFO */
+	USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0x1);
+
+	usim_irq_disable(usim->base, (USIM_IRQ_TX | USIM_IRQ_EOB));
+
+	usim->slot_ctx[usim->slot].state = USIM_MODE_ATR;
+
+	/* warm reset the card */
+	if (usim->phy_present) {
+		ret = phy->warm_reset(phy, usim->slot);
+		if (ret != 0)
+			return ret;
+	} else {
+		/* warm reset using USIM */
+		USIM_WRITEREG(usim->base, USIM_CMD, CMD_WARM_RST, 0x1);
+	}
+
+	USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_ATR);
+
+	return 0;
+}
+static int usim_set_cardmode(struct usim *usim, int slot, int card_mode)
+{
+	int val = 0;
+	struct sc_phy *phy = usim->phy;
+
+	if (card_mode !=  usim->slot_ctx[slot].card_mode) {
+		/* deactivate current card before changing the
+		 * mode of smart card
+		 */
+		usim_deactivate_card(usim);
+	} else {
+		dev_dbg(usim->dev, "mode is same as previous, no action!!");
+		return 0;
+	}
+
+	/* set card mode */
+	switch (card_mode) {
+	case USIM_CARD_MODE_ASYNC:
+		val = SC_PHY_ASYNC;
+		break;
+
+	case USIM_CARD_MODE_SYNC_TYPE1:
+		val = SC_PHY_SYNC_TYPE1;
+		break;
+
+	case USIM_CARD_MODE_SYNC_TYPE2:
+		val = SC_PHY_SYNC_TYPE2;
+		break;
+
+	case USIM_CARD_MODE_SYNC_OTHER:
+		val = SC_PHY_SYNC;
+		break;
+
+	default:
+		dev_err(usim->dev, "Invalid card mode");
+		return -EINVAL;
+		break;
+	}
+	if (usim->phy_present == USIM_PHY_PRESENT)
+		phy->set_config(usim->phy, slot, SC_PHY_CARD_MODE, val);
+	usim->slot_ctx[slot].card_mode = card_mode;
+	return 0;
+}
+
+static int usim_activate_synccard(struct usim *usim)
+{
+	int ret = 0;
+	int reg = 0;
+	struct sc_phy *phy = usim->phy;
+	if (usim->phy_present != USIM_PHY_PRESENT) {
+		dev_err(usim->dev, "Sync card w/o phy is not supported");
+		return -EPERM;
+	}
+
+	/* Enable legacy bypass mode */
+	USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 1);
+
+	/* set all lines to state L */
+	writel(0x0, usim->base + USIM_IO_DIRECT);
+
+	/* configure h/w control mode for select slot */
+	reg = readl(usim->base + USIM_CONF6);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 1);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 1);
+	/* lets put i/o line in SW ctrl */
+	reg = USIM_SETFIELD(reg, USIM_CONF6, IO_BYPASS, 0x3);
+	writel(reg, usim->base + USIM_CONF6);
+
+	/* activate the card */
+	ret = phy->activate_card(phy, usim->slot);
+	return ret;
+}
+
+static int usim_activate_card(struct usim *usim)
+{
+	int ret = 0;
+	int reg = 0;
+	struct sc_phy *phy = usim->phy;
+	int mode = usim->slot_ctx[usim->slot].card_mode;
+
+	usim->atrdone = 0;
+	usim->slot_ctx[usim->slot].atr_length = 0;
+
+	/* set card mode */
+	usim_set_cardmode(usim, usim->slot, mode);
+
+	if (usim->slot_ctx[usim->slot].card_mode != USIM_CARD_MODE_ASYNC) {
+		/* synchronous card activation */
+		ret = usim_activate_synccard(usim);
+		return ret;
+	}
+
+	if (usim->slot_ctx[usim->slot].emv)
+		usim_init_emvusercard(usim);
+
+	/* disable legacy bypass mode */
+	USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 0);
+
+	/* configure h/w control mode for select slot */
+	reg = readl(usim->base + USIM_CONF6);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 0);
+	reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 0);
+	/* lets put i/o line in h/w ctrl */
+	reg = USIM_SETFIELD(reg, USIM_CONF6, IO_BYPASS, 0x2);
+	writel(reg, usim->base + USIM_CONF6);
+
+	USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, 1);
+	USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER, 0x103);
+
+	/* RXDMA_TYPE = 0x1 - USIM_RXFIFO_BYTECNT value is ignored */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, RXDMA_TYPE, 0x1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_ENABLE, 0x1);
+
+	/* Do store bytes with parity error in Rx FIFO */
+	USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0x1);
+	usim_irq_disable(usim->base, (USIM_IRQ_TX | USIM_IRQ_EOB));
+
+	USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x1);
+	USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x0);
+
+	/*
+	 * Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
+	 * gets disable. EMVCo Test case ref#1703_21/22
+	 */
+	USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 0x1);
+	USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
+		      USIM_ATR_TIMEOUT_EMV);
+	USIM_WRITEREG(usim->base, USIM_CMD, MODULE_CLK_EN, 0x1);
+
+	usim->slot_ctx[usim->slot].state = USIM_MODE_ATR;
+
+	/* set smartcard clock */
+	usim_set_smartcardclock(usim, usim->slot_ctx[usim->slot].clock);
+
+	/* Activate card */
+	if (usim->phy_present) {
+		usim_irq_disable(usim->base, USIM_IRQ_TX|USIM_IRQ_ATR_START);
+		usim_irq_enable(usim->base, 0xFFFFFFF7);
+		usim_irq_disable(usim->base, USIM_IRQ_NATR);
+		usim_irq_enable(usim->base, USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT);
+		usim_irq_disable(usim->base, USIM_IRQ_TX|USIM_IRQ_ATR_START);
+
+		/* do no bypass ATR length timer, also do not
+		 * disturb the bypass setting of other param
+		 */
+		USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMER_BYPASS, 0x1);
+
+		usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
+
+		ret = phy->activate_card(phy, usim->slot);
+		if (ret != 0)
+			return ret;
+	} else {
+		/* Activate using USIM */
+		USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 0x0);
+		USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 0x1);
+	}
+	USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_ATR);
+	return 0;
+}
+
+static int usim_deactivate_card(struct usim *usim)
+{
+	int ret = 0;
+	int cnt = 0;
+	struct sc_phy *phy = usim->phy;
+
+	/* clear atr buffer */
+	for (cnt = 0; cnt < USIM_MAX_ATRLENGTH; cnt++)
+		usim->slot_ctx[usim->slot].atr[cnt] = 0x0;
+	usim->slot_ctx[usim->slot].atr_length = 0x0;
+
+	/* Use USIM IP for deactivation if there is no phy */
+	if (usim->phy_present == USIM_PHY_PRESENT) {
+		ret = phy->deactivate_card(phy, usim->slot);
+		if (ret != 0)
+			return ret;
+	} else {
+		USIM_WRITEREG(usim->base, USIM_CMD, CMDSTART, 0x0);
+		USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 1);
+	}
+
+	USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
+	USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, 0);
+
+	/* Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
+	 * gets disable TC Ref: 1703_21/22
+	 */
+	USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 1);
+	USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
+		      USIM_ATR_TIMEOUT_EMV);
+
+	/* stop ATR length timeout */
+	USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 1);
+	usim->slot_ctx[usim->slot].state = USIM_MODE_DEACT;
+	usim->atrdone = 0;
+
+	return 0;
+}
+
+static void usim_set_protocol(struct usim *usim, int protocol)
+{
+	u32 irq;
+
+	/* As per spec, mask all interrupts before switching
+	 * from one protocol to other.
+	 */
+	usim_irq_get(usim->base, &irq);
+
+	/* disable all interrupts */
+	usim_irq_disable(usim->base, 0xFFFFFFFF);
+
+	/* 0 for T=0 and 1 for T=1 protocol */
+	USIM_WRITEREG(usim->base, USIM_CONF2, CONFPROTOCOL, protocol);
+	usim->slot_ctx[usim->slot].protocol = protocol;
+
+	/* read and clear status */
+	usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
+
+	/* now renable interrupts */
+	usim_irq_enable(usim->base, irq);
+	return;
+}
+
+static int usim_get_cardpinlevel(struct usim *usim, int pin, int *level)
+{
+	struct sc_phy *phy = usim->phy;
+	int param = 0;
+
+	if (usim->slot_ctx[usim->slot].card_mode == USIM_CARD_MODE_ASYNC) {
+		dev_err(usim->dev, "Operation not permitted for async mode");
+		return -EPERM;
+	}
+	if (pin == USIM_PARAM_CARD_PIN_IO) {
+		/* For Rx, RNW:1, OEN:1 */
+		USIM_WRITEREG(usim->base, USIM_IO_DIRECT, RNW0, 1);
+		USIM_WRITEREG(usim->base, USIM_IO_DIRECT, SIOEN0, 1);
+		*level = USIM_READREG(usim->base, USIM_IO_DIRECT, SIORX0);
+		return 0;
+	}
+
+	if (usim->phy_present == USIM_PHY_PRESENT) {
+		switch (pin) {
+		case USIM_PARAM_CARD_PIN_VCC:
+			break;
+
+		case USIM_PARAM_CARD_PIN_RST:
+			param = SC_PHY_PIN_RST;
+			break;
+
+		case USIM_PARAM_CARD_PIN_CLK:
+			param = SC_PHY_PIN_CLK;
+			break;
+
+		default:
+			dev_err(usim->dev, "Invalid pin");
+			return -EINVAL;
+		}
+		*level = phy->get_config(phy, usim->slot, param);
+		return  0;
+	} else {
+		switch (pin) {
+		case USIM_PARAM_CARD_PIN_VCC:
+			*level = USIM_READREG(usim->base,
+					USIM_IO_DIRECT, SVCC);
+			break;
+
+		case USIM_PARAM_CARD_PIN_RST:
+			*level = USIM_READREG(usim->base,
+					USIM_IO_DIRECT, RST);
+			break;
+
+		case USIM_PARAM_CARD_PIN_CLK:
+			*level = USIM_READREG(usim->base,
+					USIM_IO_DIRECT, SCLK0);
+			break;
+
+		default:
+			dev_err(usim->dev, "Invalid pin");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int usim_set_cardpinlevel(struct usim *usim, int pin, int level)
+{
+	int ret = 0;
+	int param = 0;
+	int value = level > 0 ? 1 : 0;
+	struct sc_phy *phy = usim->phy;
+
+	if (usim->slot_ctx[usim->slot].card_mode == USIM_CARD_MODE_ASYNC) {
+		dev_err(usim->dev, "Operation not permitted for async mode");
+		return -EPERM;
+	}
+	if (pin == USIM_PARAM_CARD_PIN_IO) {
+		/* For Tx: RNW=0; OEN=Tx */
+		/* Tx line will be followed by OEN line, so setting OEN bit*/
+		USIM_WRITEREG(usim->base, USIM_IO_DIRECT, RNW0, 0);
+		USIM_WRITEREG(usim->base, USIM_IO_DIRECT, SIOEN0, value);
+		return 0;
+	}
+
+	if (usim->phy_present == USIM_PHY_PRESENT) {
+		switch (pin) {
+		case USIM_PARAM_CARD_PIN_VCC:
+			/* will be set by activation or deactivation */
+			break;
+
+		case USIM_PARAM_CARD_PIN_RST:
+			param = SC_PHY_PIN_RST;
+			break;
+
+		case USIM_PARAM_CARD_PIN_CLK:
+			param = SC_PHY_PIN_CLK;
+			break;
+
+		default:
+			dev_err(usim->dev, "Invalid pin");
+			return -EINVAL;
+		}
+		ret = phy->set_config(phy, usim->slot, param, value);
+		return  ret;
+	} else {
+		switch (pin) {
+		case USIM_PARAM_CARD_PIN_VCC:
+			USIM_WRITEREG(usim->base,
+				      USIM_IO_DIRECT, SVCC, value);
+			break;
+
+		case USIM_PARAM_CARD_PIN_RST:
+			USIM_WRITEREG(usim->base,
+				      USIM_IO_DIRECT, RST, value);
+			break;
+
+		case USIM_PARAM_CARD_PIN_CLK:
+			USIM_WRITEREG(usim->base,
+				      USIM_IO_DIRECT, SCLK0, value);
+			break;
+
+		default:
+			dev_err(usim->dev, "Invalid pin");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+static void usim_configure_rx_pio(struct usim *usim)
+{
+	/* Reset RX FIFO pointers */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
+
+	/* read and clear any pending interrupt status */
+	usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
+
+	/* Enable WWT underflow interupt,
+	 * RX FIFO full interrupt,
+	 * BWT, CWT and parity error level interrupts.
+	 */
+	usim_irq_enable(usim->base, USIM_IRQ_WT | USIM_IRQ_RXFULL |
+				USIM_IRQ_TOB |
+				USIM_IRQ_TOC |
+				USIM_IRQ_PAR_ERR_LEVEL_REACHED);
+
+	/* Lets disable key RX interrupts. We will enable them later
+	 * when we want to start RX
+	 */
+	usim_irq_disable(usim->base, USIM_IRQ_RX |
+			USIM_IRQ_RXDMA_RDY | USIM_IRQ_EOB);
+
+	/* We will use only RX FIFO threshold in RX */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, RXDMA_TYPE, 0x1);
+
+	if (usim->slot_ctx[usim->slot].protocol == 0) {
+		/* Set Rx FIFO Threshold to expected recv length
+		 * Subtract 1 from length as HW adds 1 to the trigger
+		 */
+		USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER,
+			      usim->slot_ctx[usim->slot].rx_explen - 1);
+	} else {
+		/* T=1 protocol */
+		/* for T1 we should not use parity error level interrupt */
+		usim_irq_disable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
+
+		/* set RX FIFO threshold to MAX_RX_FIFO size.
+		 * We will rely on End-Of-Block interrupt to
+		 * terminate reception in T1
+		 */
+		USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER,
+			      USIM_MAX_RX_FIFO_SIZE - 1);
+	}
+	return;
+}
+
+static void usim_configure_tx_pio(struct usim *usim)
+{
+	/* Make sure TX is stopped first by programming
+	 * TX_BLOCK to zero and disabling TX_BLOCK_DONE
+	 * and USIM_IRQ_TX_BLOCK_REQ interrupts
+	 */
+	USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, 0);
+	usim_irq_disable(usim->base, USIM_IRQ_TX_BLOCK_DONE |
+							USIM_IRQ_TX_BLOCK_REQ);
+
+	/* We will use Tx Block length feature so clear TX_EN bit */
+	USIM_WRITEREG(usim->base, USIM_CONF2, TX_EN, 0);
+	/* We will not use USIM_TX interrupt for transmit operation */
+	usim_irq_disable(usim->base, USIM_IRQ_TX);
+	/* Reset TX FIFO pointers */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
+	USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
+
+	/* Ensure PIO mode is programmed */
+	USIM_WRITEREG(usim->base, USIM_FIFOS, DMA_MODE, 0);
+}
+
+static int usim_send_data(struct usim *usim, char *txbuf, int len)
+{
+	u32 val;
+	int i;
+	int ret = 0;
+
+	usim->txdone = 0;
+	usim->rxdone = 0;
+
+	if (len == 0) {
+		dev_dbg(usim->dev, "Error: Invalid Tx length:%d", len);
+		return -EINVAL;
+	}
+
+	usim->slot_ctx[usim->slot].event = 0;
+
+	/* Configure Tx PIO mode patams */
+	usim_configure_tx_pio(usim);
+
+	/* Tx FIFO must be empty after reset */
+	val = USIM_READREG(usim->base, USIM_FIFOS, FIFOTX_EMPTY);
+	if (val == 0) {
+		dev_dbg(usim->dev, "Error: Tx FIFO is not empty");
+		return -EFAULT;
+	}
+
+	/* write data in Tx FIFO */
+	for (i = 0; i < len; i++) {
+		USIM_WRITEREG(usim->base, USIM_DTX, DTX, txbuf[i]);
+		dev_dbg(usim->dev, "txbyte %d = %x\n", i, txbuf[i]);
+	}
+
+	/* Finally re-enable TX_BLOCK_xxx interrupts and clear RX interrupts */
+	usim_irq_enable(usim->base, USIM_IRQ_TX_BLOCK_DONE |
+						USIM_IRQ_TX_BLOCK_REQ);
+
+	/* For T=0, stop re-tranmission after resend failure */
+	if (usim->slot_ctx[usim->slot].protocol == 0) {
+		USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 0);
+		USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 1);
+	}
+
+	/* Do not store bytes with parity error in Rx FIFO */
+	USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0);
+
+	usim_irq_enable(usim->base, USIM_IRQ_TOC);
+
+	if (usim->phy_present)
+		USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_TXRX);
+	else
+		USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_LEGACY);
+
+	usim->slot_ctx[usim->slot].state = USIM_MODE_TXRX;
+
+	/* Configure Rx settings before performing a Tx
+	 * As soon as we are done with Tx, card will send
+	 * data, which we should be ready to capture
+	 */
+	usim_configure_rx_pio(usim);
+	/* Start TX operation - program TX_BLOCK register to length
+	 * of the TX buffer to start the TX operation.
+	 */
+	USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, len);
+
+	/* We need to block the caller here */
+	ret = wait_event_interruptible(tx_wait, (usim->txdone == 1));
+	dev_dbg(usim->dev, "Tx WAIT OVER\n");
+	if (usim->slot_ctx[usim->slot].event == USIM_EVENT_TIMEOUT)
+		usim_send_signal(usim, USIM_EVENT_TIMEOUT);
+
+	return ret;
+}
+
+static int usim_set_config(struct usim *usim, struct usim_config *param)
+{
+	u32 ret = 0;
+	dev_dbg(usim->dev, "param:%d, value:%d\n", param->attr, param->value);
+
+	switch (param->attr) {
+	case USIM_PARAM_CWT:
+		USIM_WRITEREG(usim->base, USIM_CWT, CWT, param->value);
+		break;
+
+	case USIM_PARAM_WWT:
+		USIM_WRITEREG(usim->base, USIM_WWT, WWT, param->value);
+		break;
+
+	case USIM_PARAM_CGT:
+		USIM_WRITEREG(usim->base, USIM_CGT, CGT, param->value);
+		break;
+
+	case USIM_PARAM_BWT:
+		USIM_WRITEREG(usim->base, USIM_BWT, BWT, param->value);
+		break;
+
+	case USIM_PARAM_EDCTYPE:
+		/* 0 = LRC check, 1 = CRC check */
+		USIM_WRITEREG(usim->base, USIM_CONF2, CONFEDC, param->value);
+		break;
+
+	case USIM_PARAM_LRCCHECK:
+		/* 0 = No LRC check, 1 = LRC check */
+		USIM_WRITEREG(usim->base, USIM_CONF2, CONFLRCCHECK,
+			      param->value);
+		break;
+
+	case USIM_PARAM_C4:
+		usim_set_c4(usim, param->value);
+		break;
+
+	case USIM_PARAM_C8:
+		usim_set_c8(usim, param->value);
+		break;
+
+	case USIM_PARAM_PROTOCOL:
+		/* 0 for T=0 and 1 for T=1 */
+		usim_set_protocol(usim, param->value);
+		break;
+
+	case USIM_PARAM_VOLTAGE:
+		ret = usim_set_voltage(usim, param->value);
+		break;
+
+	case USIM_PARAM_EMV:
+		USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, param->value);
+		if (param->value)
+			usim->slot_ctx[usim->slot].emv = true;
+		else
+			usim->slot_ctx[usim->slot].emv = false;
+		break;
+
+	case USIM_PARAM_FI:
+		USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
+		USIM_WRITEREG(usim->base, USIM_CONF5, FI, param->value);
+		break;
+
+	case USIM_PARAM_DI:
+		USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
+		USIM_WRITEREG(usim->base, USIM_CONF5, DI, param->value);
+		break;
+
+	case USIM_PARAM_CODING_CONV:
+		USIM_WRITEREG(usim->base, USIM_STAT, CONFCODCONV, param->value);
+		break;
+
+	case USIM_PARAM_CLOCK_STOP:
+		USIM_WRITEREG(usim->base, USIM_CMD, CMD_CLOCK_STOP,
+			      param->value);
+		break;
+
+	case USIM_PARAM_SMARTCARD_CLOCK:
+		ret = usim_set_smartcardclock(usim, param->value);
+		break;
+
+	case USIM_PARAM_SMARTCARD_MODE:
+		ret = usim_set_cardmode(usim, usim->slot, param->value);
+		break;
+
+	case USIM_PARAM_CARD_PIN_VCC:
+	case USIM_PARAM_CARD_PIN_RST:
+	case USIM_PARAM_CARD_PIN_CLK:
+	case USIM_PARAM_CARD_PIN_IO:
+		ret = usim_set_cardpinlevel(usim, param->attr, param->value);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+static void usim_get_syncatr(struct usim *usim)
+{
+	int ret = 0;
+	struct sc_phy *phy = usim->phy;
+
+	/* Max ATR bytes for sync card is 4 */
+	usim->slot_ctx[usim->slot].atr_length = 0x4;
+	if (usim->phy_present != USIM_PHY_PRESENT) {
+		dev_err(usim->dev, "Sync card w/o phy is not supported");
+		return;
+	}
+	/* get sync ATR */
+	if (phy->get_syncatr == NULL)
+		return;
+	ret = phy->get_syncatr(phy,
+			usim->slot,
+			usim->slot_ctx[usim->slot].atr_length,
+			usim->slot_ctx[usim->slot].atr);
+	return;
+}
+
+static int usim_get_config(struct usim *usim, struct usim_config *param)
+{
+	u32 ret = 0;
+	dev_dbg(usim->dev, "param:%d, value:%d\n", param->attr, param->value);
+
+	switch (param->attr) {
+	case USIM_PARAM_CWT:
+		param->value = USIM_READREG(usim->base, USIM_CWT, CWT);
+		break;
+
+	case USIM_PARAM_WWT:
+		param->value = USIM_READREG(usim->base, USIM_WWT, WWT);
+		break;
+
+	case USIM_PARAM_CGT:
+		param->value = USIM_READREG(usim->base, USIM_CGT, CGT);
+		break;
+
+	case USIM_PARAM_BWT:
+		param->value = USIM_READREG(usim->base, USIM_BWT, BWT);
+		break;
+
+	case USIM_PARAM_EDCTYPE:
+		param->value = USIM_READREG(usim->base, USIM_CONF2, CONFEDC);
+		break;
+
+	case USIM_PARAM_LRCCHECK:
+		param->value = USIM_READREG(usim->base, USIM_CONF2,
+				CONFLRCCHECK);
+		break;
+
+	case USIM_PARAM_PROTOCOL:
+		/* 0 for T=0 and 1 for T=1 */
+		param->value = USIM_READREG(usim->base, USIM_CONF2,
+				CONFPROTOCOL);
+		break;
+
+	case USIM_PARAM_VOLTAGE:
+		param->value = usim->slot_ctx[usim->slot].supply;
+		break;
+
+	case USIM_PARAM_EMV:
+		param->value = USIM_READREG(usim->base, USIM_CONF1, EMV_CONF);
+		break;
+
+	case USIM_PARAM_FI:
+		param->value = USIM_READREG(usim->base, USIM_CONF5, FI);
+		break;
+
+	case USIM_PARAM_DI:
+		param->value = USIM_READREG(usim->base, USIM_CONF5, DI);
+		break;
+
+	case USIM_PARAM_CODING_CONV:
+		param->value = USIM_READREG(usim->base, USIM_STAT, CONFCODCONV);
+		break;
+
+	case USIM_PARAM_CLOCK_STOP:
+		param->value = USIM_READREG(usim->base, USIM_CMD,
+					    CMD_CLOCK_STOP);
+		break;
+
+	case USIM_PARAM_SMARTCARD_CLOCK:
+		param->value = usim->slot_ctx[usim->slot].clock;
+		break;
+
+	case USIM_PARAM_SMARTCARD_MODE:
+		param->value = usim->slot_ctx[usim->slot].card_mode;
+		break;
+
+	case USIM_PARAM_CARD_PIN_VCC:
+	case USIM_PARAM_CARD_PIN_RST:
+	case USIM_PARAM_CARD_PIN_CLK:
+	case USIM_PARAM_CARD_PIN_IO:
+		ret = usim_get_cardpinlevel(usim, param->attr, &param->value);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static long usim_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usim *usim = file->private_data;
+	struct usim_data data;
+	struct usim_config param;
+
+	int ret		= 0;
+	int cnt		= 0;
+	int version	= 0;
+	int u_pid	= 0;
+	int present	= 0;
+	unsigned long atr_timeout = 0;
+
+	if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
+		return -ENXIO;
+
+	switch (cmd) {
+	case USIM_IOCTL_GET_PROVIDER_VERSION:
+		dev_dbg(usim->dev, "IOCTL: GET PROVIDER VERSION\n");
+		version = usim_get_version(usim);
+		ret = copy_to_user((unsigned int *)arg, &version,
+				sizeof(unsigned int));
+		if (ret != 0)
+			ret = -EFAULT;
+		break;
+
+	case USIM_IOCTL_ACTIVATE_CARD:
+		dev_dbg(usim->dev, "IOCTL: ACTIVATE CARD\n");
+		if (usim->phy_present) {
+			present = usim->phy->get_config(usim->phy, usim->slot,
+							SC_PHY_CARD_PRESENCE);
+			if (present)
+				ret = usim_activate_card(usim);
+			else
+				ret = -EFAULT;
+		}
+		break;
+
+	case USIM_IOCTL_DEACTIVATE_CARD:
+		dev_dbg(usim->dev, "IOCTL: DEACTIVATE CARD\n");
+		ret = usim_deactivate_card(usim);
+		break;
+
+	case USIM_IOCTL_WARM_RESET:
+		dev_dbg(usim->dev, "IOCTL: WARM RESET\n");
+		ret = usim_warmreset(usim);
+		break;
+
+	case USIM_IOCTL_GET_ATR:
+		dev_dbg(usim->dev, "IOCTL: GET ATR\n");
+		/* waiting for max ATR response timeout */
+		atr_timeout = usecs_to_jiffies(MAX_ATR_WAITTIME_US);
+		dev_dbg(usim->dev,
+			"GET_ATR:atr timeout, us:%d, jiffies:%ld",
+			MAX_ATR_WAITTIME_US, atr_timeout);
+		wait_event_timeout(atr_wait, (usim->atrdone == 1), atr_timeout);
+		if (usim->slot_ctx[usim->slot].card_mode !=
+				USIM_CARD_MODE_ASYNC) {
+			usim_get_syncatr(usim);
+		}
+		ret = copy_to_user((char __user *)arg,
+					usim->slot_ctx[usim->slot].atr,
+					usim->slot_ctx[usim->slot].atr_length);
+		if (ret != 0)
+			ret = -EFAULT;
+		else
+			ret = usim->slot_ctx[usim->slot].atr_length;
+		break;
+
+	case USIM_IOCTL_SEND_DATA:
+		dev_dbg(usim->dev, "IOCTL: SEND DATA\n");
+		ret = copy_from_user(&data, (struct usim_data *)arg,
+						sizeof(struct usim_data));
+		if (ret != 0)
+			return -EFAULT;
+
+		usim->slot = data.slot;
+		usim->slot_ctx[usim->slot].rx_explen = data.rxexplen;
+		usim->slot_ctx[usim->slot].rx_counter = 0;
+		for (cnt = 0; cnt < data.txlen; cnt++)
+			dev_dbg(usim->dev, "apdu[%d] = %x\n", cnt,
+				data.apdu[cnt]);
+		ret = usim_send_data(usim, &data.apdu[0], data.txlen);
+		break;
+
+	case USIM_IOCTL_SET_CONFIG:
+		dev_dbg(usim->dev, "IOCTL: SET CONFIG\n");
+		ret = copy_from_user(&param, (struct usim_config *)arg,
+				sizeof(struct usim_config));
+		if (ret != 0)
+			return -EFAULT;
+
+		usim_set_config(usim, &param);
+		break;
+
+	case USIM_IOCTL_GET_CONFIG:
+		dev_dbg(usim->dev, "IOCTL: GET CONFIG\n");
+		ret = copy_from_user(&param, (struct usim_config *)arg,
+				sizeof(struct usim_config));
+		if (ret != 0)
+			return -EFAULT;
+
+		usim_get_config(usim, &param);
+		ret = copy_to_user((struct usim_config *)arg, &param,
+				sizeof(struct usim_config));
+		if (ret != 0)
+			ret = -EFAULT;
+		break;
+
+	case USIM_IOCTL_GET_CARD_PRESENCE:
+		dev_dbg(usim->dev, "IOCTL: CARD PRESENCE\n");
+		if (usim->phy_present) {
+			present = usim->phy->get_config(usim->phy, usim->slot,
+					SC_PHY_CARD_PRESENCE);
+			ret = copy_to_user((unsigned int *)arg, &present,
+					sizeof(unsigned int));
+			if (ret != 0)
+				ret = -EFAULT;
+		}
+		break;
+
+	case USIM_IOCTL_REGISTER_PID:
+		dev_dbg(usim->dev, "IOCTL: USIM_IOCTL_REGISTER_PID");
+		ret = copy_from_user(&u_pid, (int *)arg, sizeof(int));
+		if (ret != 0)
+			return -EFAULT;
+		usim->user_pid = u_pid;
+		break;
+	}
+	return ret;
+}
+
+static ssize_t usim_read(struct file *file, char *user_buf,
+		size_t count, loff_t *ppos)
+{
+	struct usim *usim = file->private_data;
+	if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
+		return -ENXIO;
+
+	wait_event_interruptible(rx_wait, (usim->rxdone == 1));
+	dev_dbg(usim->dev, "RX WAIT over\n");
+
+	/* check for timeout and send signal if any */
+	if (usim->slot_ctx[usim->slot].event == USIM_EVENT_TIMEOUT)
+		usim_send_signal(usim, USIM_EVENT_TIMEOUT);
+
+	if (copy_to_user(user_buf, usim->slot_ctx[usim->slot].rxbuf,
+			 usim->slot_ctx[usim->slot].rx_counter)) {
+		dev_err(usim->dev, "Copy failed\n");
+		return -EFAULT;
+	}
+	*ppos = usim->slot_ctx[usim->slot].rx_counter;
+	dev_dbg(usim->dev, "Card response returning %d bytes\n",
+		usim->slot_ctx[usim->slot].rx_counter);
+
+	return usim->slot_ctx[usim->slot].rx_counter;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DUMP_REG(r) seq_printf(s, "%-25s: %08x\n", #r, readl(usim->base + r));
+
+static int usim_regdump_show(struct seq_file *s, void *unused)
+{
+	struct usim	*usim = s->private;
+
+	seq_puts(s, "USIM Register Dump\n");
+
+	DUMP_REG(USIM_REVISION);
+	DUMP_REG(USIM_IDENT);
+	DUMP_REG(USIM_SYSCONFIG);
+	DUMP_REG(USIM_SYSSTATUS);
+	DUMP_REG(USIM_IRQSTATUS);
+	DUMP_REG(USIM_IRQENABLE);
+	DUMP_REG(USIM_WAKEUPEN);
+	DUMP_REG(USIM_CMD);
+	DUMP_REG(USIM_STAT);
+	DUMP_REG(USIM_CONF1);
+	DUMP_REG(USIM_CONF2);
+	DUMP_REG(USIM_CONF3);
+	DUMP_REG(USIM_DRX);
+	DUMP_REG(USIM_DTX);
+	DUMP_REG(USIM_FIFOS);
+	DUMP_REG(USIM_CGT);
+	DUMP_REG(USIM_BWT);
+	DUMP_REG(USIM_DEBUG);
+	DUMP_REG(USIM_CONF_SAM1_DIV);
+	DUMP_REG(USIM_CONF4);
+	DUMP_REG(USIM_ATR_CLK_PRD_NBS);
+	DUMP_REG(USIM_CONF_ETU_DIV);
+	DUMP_REG(USIM_CONF5);
+	DUMP_REG(USIM_TC_GUARD_TIME_ADD);
+	DUMP_REG(USIM_RXFIFO_LEVEL);
+	DUMP_REG(USIM_RXFIFO_BYTECNT);
+	DUMP_REG(USIM_WWT);
+	DUMP_REG(USIM_CONF6);
+	DUMP_REG(USIM_IO_DIRECT);
+	DUMP_REG(USIM_TX_BLOCK);
+
+	return 0;
+}
+
+static int usim_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, usim_regdump_show, inode->i_private);
+}
+
+static const struct file_operations usim_regdump_fops = {
+	.open		= usim_regdump_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int usim_init_debugfs(struct usim *usim)
+{
+	int ret;
+	struct dentry	*root;
+	struct dentry	*file;
+
+	root = debugfs_create_dir("usim", NULL);
+	if (!root) {
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	file = debugfs_create_file("regdump", S_IRUGO, root, usim,
+							&usim_regdump_fops);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	usim->debugfs_root = root;
+
+	return 0;
+err1:
+	debugfs_remove_recursive(root);
+err0:
+	return ret;
+}
+#endif
+
+static int usim_pm_init(struct usim *usim)
+{
+	int ret = 0;
+
+	usim->usim0_fck  = clk_get(usim->dev, "usim0_fck");
+	if (IS_ERR(usim->usim0_fck)) {
+		ret = PTR_ERR(usim->usim0_fck);
+		dev_err(usim->dev, "usim0_fck failed error:%d\n", ret);
+		return -1;
+	}
+	usim->dpll_core_m4_ck  = clk_get(usim->dev, "dpll_core_m4_ck");
+	if (IS_ERR(usim->dpll_core_m4_ck)) {
+		ret = PTR_ERR(usim->dpll_core_m4_ck);
+		dev_err(usim->dev, "dpll_core_m4_ck failed error:%d\n", ret);
+		return -1;
+	}
+	ret = clk_set_parent(usim->usim0_fck, usim->dpll_core_m4_ck);
+	if (ret != 0)
+		dev_dbg(usim->dev, "clk set  parent failed: %d\n", ret);
+
+	usim->usim_dbclk  = clk_get(usim->dev, "usim_dbck");
+	if (IS_ERR(usim->usim_dbclk)) {
+		ret = PTR_ERR(usim->usim_dbclk);
+		dev_err(usim->dev, "usim_dbck failed error:%d\n", ret);
+		return -1;
+	}
+
+	usim->clkdiv32k_ick  = clk_get(usim->dev, "clkdiv32k_ick");
+	if (IS_ERR(usim->usim_dbclk)) {
+		ret = PTR_ERR(usim->clkdiv32k_ick);
+		dev_err(usim->dev, "clkdiv32k_ick failed error:%d\n", ret);
+		return -1;
+	}
+
+	ret = clk_set_parent(usim->usim_dbclk, usim->clkdiv32k_ick);
+	if (ret != 0)
+		dev_dbg(usim->dev, "usim_dbclk set parent failed: %d\n", ret);
+
+	usim->opt_fclk = devm_clk_get(usim->dev, "opt_fck");
+	if (IS_ERR(usim->opt_fclk)) {
+		ret = PTR_ERR(usim->opt_fclk);
+		dev_err(usim->dev, "unable to get fck\n");
+		return ret;
+	}
+
+	usim->opt_fclk32 = devm_clk_get(usim->dev, "opt_fck32");
+	if (IS_ERR(usim->opt_fclk32)) {
+		ret = PTR_ERR(usim->opt_fclk32);
+		dev_err(usim->dev, "unable to get dbclk\n");
+		return ret;
+	}
+
+	return 0;
+}
+static int usim_enable(struct usim *usim)
+{
+	int ret = 0;
+	if (usim->enable == 1)
+		return 0;
+
+	/* enable the clk */
+	pm_runtime_get_sync(usim->dev);
+	clk_enable(usim->opt_fclk32);
+	clk_enable(usim->opt_fclk);
+
+	/* usim init */
+	ret = usim_configure(usim);
+	if (ret)
+		return -EIO;
+
+	usim->enable = 1;
+	return 0;
+}
+
+static void usim_disable(struct usim *usim)
+{
+	int cnt = 0;
+
+	if (usim->enable == 0)
+		return;
+
+	/* reset USIM state for deactivation */
+	for (cnt = 0; cnt < usim->max_slots; cnt++) {
+		usim->slot = cnt;
+		usim_deactivate_card(usim);
+	}
+
+	/* reset default slot and clock */
+	usim->slot = 0;
+	usim->slot_ctx[usim->slot].clock = USIM_SMARTCART_CLOCK_5MHZ;
+
+	/* shutdown phy */
+	if (usim->phy_present == USIM_PHY_PRESENT)
+		usim->phy->set_config(usim->phy, usim->slot, SC_PHY_MODE,
+				SC_PHY_SHUTDOWN);
+	/* disable clk */
+	clk_disable(usim->opt_fclk32);
+	clk_disable(usim->opt_fclk);
+	pm_runtime_put_sync_autosuspend(usim->dev);
+	usim->enable = 0;
+	return;
+}
+
+static int usim_open(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+	struct usim *usim = (struct usim *)dev_get_drvdata(usim_dev.parent);
+
+	if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
+		return -ENXIO;
+
+	file->private_data = usim;
+	ret = usim_enable(usim);
+	if (ret)
+		return  -ENXIO;
+
+	return 0;
+}
+
+static int usim_release(struct inode *inode, struct file *file)
+{
+	struct usim *usim = (struct usim *)dev_get_drvdata(usim_dev.parent);
+
+	usim_disable(usim);
+	usim->user_pid = 0;
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int usim_suspend(struct device *dev)
+{
+	/* struct usim *usim = dev_to_usim(dev); */
+	struct usim *usim = dev_to_usim(dev);
+	if (usim->atrdone == 1) {
+		dev_dbg(usim->dev, "card is active state, aborting suspend");
+		return -EBUSY;
+	}
+	usim_disable(usim);
+	return 0;
+}
+
+static int usim_resume(struct device *dev)
+{
+	/* struct usim *usim = dev_to_usim(dev); */
+	struct usim *usim = dev_to_usim(dev);
+	usim_enable(usim);
+	return 0;
+}
+
+static const struct dev_pm_ops usim_pm_ops = {
+	.suspend = usim_suspend,
+	.resume = usim_resume,
+};
+
+#define USIM_PM_OPS (&usim_pm_ops)
+#else
+#define USIM_PM_OPS NULL
+#endif
+
+static int usim_notify(struct notifier_block *self, unsigned long action, void
+		*data)
+{
+	struct usim *usim = (struct usim *)data;
+	int event = action & SC_PHY_NOTIFICATION_ACTION_MASK;
+	int slot = (action & SC_PHY_NOTIFICATION_SLOT_MASK) >>
+		SC_PHY_NOTIFICATION_SLOT_SHIFT;
+	int t_slot = 0;
+
+	dev_dbg(usim->dev, "%s:action:%ld", __func__, action);
+	/* if phy is removed using rmmod or by some other mech..
+	   * then put phy state in unknown, at this point usim also required to
+	   * gets removed from the system, if it is inserted as module and
+	   * dependent on phy
+	   */
+	if (action == SC_PHY_REMOVED)
+		usim->phy_present = USIM_PHY_NOT_ATTACHED;
+
+	if (event & SC_PHY_CARD_INSERTED)
+		usim_send_signal(usim, USIM_EVENT_CARD_INSERT);
+
+	if (action & SC_PHY_CARD_REMOVED) {
+		usim_send_signal(usim, USIM_EVENT_CARD_REMOVE);
+		dev_dbg(usim->dev, "slot is:%d", slot);
+		 /* de-activate USIM & PHY state machine for the slot */
+		t_slot = usim->slot;
+		usim->slot = slot;
+		usim_deactivate_card(usim);
+		usim->slot = t_slot;
+	}
+
+	if (action & SC_PHY_CARD_OVERHEAT)
+		usim_send_signal(usim, USIM_EVENT_CARD_OVERHEAT);
+
+	if (action & SC_PHY_CARD_ATR_TIMEOUT)
+		usim_send_signal(usim, USIM_EVENT_TIMEOUT);
+
+	if (action & SC_PHY_CARD_SYNC_ACT_COMPLETE) {
+		usim->atrdone = 1;
+		wake_up(&atr_wait);
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block usim_nb = {
+		 .notifier_call =	usim_notify,
+};
+
+static const struct file_operations usim_fops = {
+	.owner		= THIS_MODULE,
+	.read		= usim_read,
+	.open		= usim_open,
+	.unlocked_ioctl	= usim_ioctl,
+	.release	= usim_release,
+};
+
+static int usim_probe(struct platform_device *pdev)
+{
+	struct device_node *node		= pdev->dev.of_node;
+	struct device *dev			= &pdev->dev;
+
+	struct usim *usim			= NULL;
+	struct device_node *phy_node		= NULL;
+	struct resource *res			= NULL;
+	void __iomem	*base			= NULL;
+	const __be32 *parp			= NULL;
+	struct i2c_client *phy_i2c		= NULL;
+
+	int ret		= 0;
+	int version	= 0;
+	int cnt		= 0;
+	u32 prop	= 0;
+	int lenp	= 0;
+
+	if (!node) {
+		dev_err(dev, "device node not found\n");
+		return -EINVAL;
+	}
+
+	usim = devm_kzalloc(dev, sizeof(*usim), GFP_KERNEL);
+	if (!usim) {
+		dev_err(dev, "not enough memory\n");
+		return -ENOMEM;
+	}
+
+	usim->irq = platform_get_irq(pdev, 0);
+	if (usim->irq < 0) {
+		dev_err(dev, "missing IRQ resource\n");
+		ret = -EINVAL;
+		goto usim_err_ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing memory base resource\n");
+		ret = -EINVAL;
+		goto usim_err_ret;
+	}
+
+	base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!base) {
+		dev_err(dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto usim_err_ret;
+	}
+
+	usim->dev = &pdev->dev;
+	usim->base = base;
+	usim->max_slots = 1;
+	usim->phy_present = USIM_PHY_NOT_PRESENT;
+	usim->enable = 0;
+
+	/* default slot will be zero : user card */
+	usim->slot = 0;
+
+	ret = devm_request_irq(dev, usim->irq, usim_interrupt, 0,
+			"usim", usim);
+	if (ret) {
+		dev_err(dev, "fail request IRQ #%d --> %d\n", usim->irq, ret);
+		goto usim_err_ret;
+		return ret;
+	}
+
+	/*
+	 * Populate all the child nodes here...
+	 */
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+
+	/* get phy details */
+	parp = of_get_property(node, "phy", &lenp);
+	if (parp == NULL || lenp != (sizeof(void *))) {
+		dev_dbg(usim->dev, "parp is null!,no phy");
+	} else {
+		/* get phy node */
+		phy_node = of_find_node_by_phandle(be32_to_cpup(parp));
+		if (phy_node == NULL) {
+			dev_err(usim->dev, "\n phy node is null");
+			ret = -EPROBE_DEFER;
+			goto usim_err_ret;
+		}
+		phy_i2c = of_find_i2c_device_by_node(phy_node);
+		if (phy_i2c == NULL) {
+			dev_err(usim->dev, "\n phy i2c is null");
+			ret = -EPROBE_DEFER;
+			goto usim_err_ret;
+		}
+		/* get phy interface */
+		usim->phy = (struct sc_phy *)i2c_get_clientdata(phy_i2c);
+		if (usim->phy == NULL) {
+			dev_err(usim->dev, "phy data is null");
+			ret = -EPROBE_DEFER;
+			goto usim_err_ret;
+		}
+		usim->phy_present = USIM_PHY_PRESENT;
+
+		ret = of_property_read_u32(node, "phy-slots", &prop);
+		/* if phy-slot is not declared then assume one phy slot */
+		usim->max_slots = prop > 0 ? prop : 1;
+	}
+
+	dev_dbg(usim->dev, "usim max slot:%d", usim->max_slots);
+	/* initialize slot context*/
+	if (usim->max_slots > USIM_MAX_SLOTS) {
+		ret = -EINVAL;
+		goto usim_err_ret;
+	}
+
+	usim->slot_ctx = kmalloc(usim->max_slots *
+				 sizeof(struct usim_slotcontext), GFP_KERNEL);
+	if (!usim->slot_ctx)
+		return -ENOMEM;
+
+	for (cnt = 0; cnt < usim->max_slots; cnt++) {
+		/* default protocol */
+		usim->slot_ctx[cnt].protocol = 0;
+		usim->slot_ctx[cnt].emv = true;
+		usim_set_cardmode(usim, cnt, USIM_CARD_MODE_ASYNC);
+	}
+
+	dev_set_drvdata(dev, usim);
+	ret = usim_pm_init(usim);
+	if (ret)
+		goto usim_err_ret;
+
+	/* enable the clock */
+	pm_runtime_enable(usim->dev);
+	pm_runtime_set_active(usim->dev);
+	spin_lock_init(&usim->lock);
+
+	usim_dev.minor = MISC_DYNAMIC_MINOR;
+	usim_dev.name = "usim";
+	usim_dev.fops = &usim_fops;
+	usim_dev.parent = &(pdev->dev);
+
+	ret = misc_register(&usim_dev);
+	if (ret) {
+		pr_err("unable to register a misc device\n");
+		goto usim_err_reg;
+	}
+#ifdef CONFIG_DEBUG_FS
+	ret = usim_init_debugfs(usim);
+	if (ret) {
+		dev_err(dev, "Debugfs init failed\n");
+		goto usim_err_reg;
+	}
+#endif
+	/* set default ICC clock : 5Mhz */
+	usim->slot_ctx[usim->slot].clock = USIM_SMARTCART_CLOCK_5MHZ;
+
+	/* get the clock & do usim configuration */
+	usim_enable(usim);
+	if (ret)
+		goto usim_err_reg;
+	dev_info(usim->dev, "usim driver initialized\n");
+
+	/* register notifier */
+	if (usim->phy_present)
+		usim->phy->register_notify(usim->phy, &usim_nb, (void *)usim);
+
+	/* get usim version */
+	version = usim_get_version(usim);
+	dev_info(usim->dev, "version is:%0x", version);
+
+	usim_disable(usim);
+	return 0;
+
+usim_err_reg:
+	pm_runtime_set_suspended(usim->dev);
+	pm_runtime_disable(usim->dev);
+	misc_deregister(&usim_dev);
+
+usim_err_ret:
+	if (usim)
+		kfree(usim->slot_ctx);
+	return ret;
+}
+
+static int usim_remove(struct platform_device *pdev)
+{
+	struct device	*dev = &pdev->dev;
+	struct usim	*usim = dev_to_usim(dev);
+
+	usim_disable(usim);
+	/* unregister notifier, applicable only when phy present and phy state
+	 * is not unknown i.e. - phy has not been removed using rmmod */
+	if (usim->phy_present == USIM_PHY_PRESENT)
+		usim->phy->unregister_notify(usim->phy, &usim_nb);
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove_recursive(usim->debugfs_root);
+#endif
+	if (!IS_ERR(usim->usim_dbclk))
+		clk_put(usim->usim_dbclk);
+	if (!IS_ERR(usim->clkdiv32k_ick))
+		clk_put(usim->clkdiv32k_ick);
+	if (!IS_ERR(usim->usim0_fck))
+		clk_put(usim->usim0_fck);
+	if (!IS_ERR(usim->dpll_core_m4_ck))
+		clk_put(usim->dpll_core_m4_ck);
+
+	if (!IS_ERR(usim->opt_fclk))
+		devm_clk_put(usim->dev, usim->opt_fclk);
+	if (!IS_ERR(usim->opt_fclk32))
+		devm_clk_put(usim->dev, usim->opt_fclk32);
+	/* disable pm runtime */
+	pm_runtime_set_suspended(usim->dev);
+	pm_runtime_disable(usim->dev);
+
+	kfree(usim->slot_ctx);
+	misc_deregister(&usim_dev);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id usim_id_table[] = {
+	{ .compatible = "ti,usim" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, usim_id_table);
+#endif
+
+static struct platform_driver usim_driver = {
+	.driver = {
+		.name = "usim",
+		.owner	= THIS_MODULE,
+		.pm	= USIM_PM_OPS,
+		.of_match_table = of_match_ptr(usim_id_table),
+	},
+	.probe = usim_probe,
+	.remove = usim_remove,
+};
+
+static int __init usim_init(void)
+{
+	return platform_driver_register(&usim_driver);
+}
+
+static void __exit usim_exit(void)
+{
+	platform_driver_unregister(&usim_driver);
+}
+
+late_initcall(usim_init);
+module_exit(usim_exit);
+
+MODULE_AUTHOR("Maulik Mankad <maulik@ti.com>");
+MODULE_DESCRIPTION("USIM Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/ti-usim.h b/include/linux/ti-usim.h
new file mode 100644
index 0000000..e9794df
--- /dev/null
+++ b/include/linux/ti-usim.h
@@ -0,0 +1,111 @@
+/*
+ * ti-usim.h - Header file for USIM SmartCard interface
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __TI_USIM_H__
+#define __TI_USIM_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define USIM_IOCTL 0xFE
+
+enum usim_param {
+	USIM_PARAM_CWT = 0,
+	USIM_PARAM_WWT,
+	USIM_PARAM_CGT,
+	USIM_PARAM_BWT,
+	USIM_PARAM_EDCTYPE,
+	USIM_PARAM_LRCCHECK,
+	USIM_PARAM_C4,
+	USIM_PARAM_C8,
+	USIM_PARAM_PROTOCOL,
+	USIM_PARAM_VOLTAGE,
+	USIM_PARAM_EMV,
+	USIM_PARAM_FI,
+	USIM_PARAM_DI,
+	USIM_PARAM_CODING_CONV,
+	USIM_PARAM_CLOCK_STOP,
+	USIM_PARAM_SMARTCARD_CLOCK,
+	USIM_PARAM_SMARTCARD_MODE,
+	USIM_PARAM_CARD_PIN_VCC,
+	USIM_PARAM_CARD_PIN_RST,
+	USIM_PARAM_CARD_PIN_CLK,
+	USIM_PARAM_CARD_PIN_IO,
+	USIM_PARAM_CARD_PIN_C4,
+	USIM_PARAM_CARD_PIN_C8,
+};
+
+enum usim_card_mode {
+	USIM_CARD_MODE_ASYNC = 0,	/* asynchronous mode */
+	USIM_CARD_MODE_SYNC_TYPE1,	/* synchronous mode: Type 1 */
+	USIM_CARD_MODE_SYNC_TYPE2,	/* synchronous mode: Type 2 */
+	USIM_CARD_MODE_SYNC_OTHER,	/* Any other synchronous type */
+};
+struct usim_data {
+	int slot;
+	int rxexplen;
+	int txlen;
+	unsigned char apdu[256];
+};
+
+struct usim_config {
+	enum usim_param attr;
+	unsigned int value;
+};
+
+#define USIM_SIGID	51
+
+#define USIM_IOCTL_GET_PROVIDER_VERSION	_IOR(USIM_IOCTL, 0, int)
+#define	USIM_IOCTL_ACTIVATE_CARD	_IO(USIM_IOCTL, 1)
+#define	USIM_IOCTL_DEACTIVATE_CARD	_IO(USIM_IOCTL, 2)
+#define USIM_IOCTL_WARM_RESET		_IO(USIM_IOCTL, 3)
+#define USIM_IOCTL_GET_ATR		_IOR(USIM_IOCTL, 4, char *)
+#define USIM_IOCTL_SEND_DATA		_IOW(USIM_IOCTL, 5, struct usim_data)
+#define USIM_IOCTL_SET_CONFIG		_IOW(USIM_IOCTL, 6, struct usim_config)
+#define USIM_IOCTL_GET_CONFIG		_IOW(USIM_IOCTL, 7, struct usim_config)
+#define USIM_IOCTL_GET_CARD_PRESENCE	_IOR(USIM_IOCTL, 8, int)
+#define USIM_IOCTL_REGISTER_PID		_IOW(USIM_IOCTL, 9, int)
+
+#define USIM_MAX_ATRLENGTH	0xFF
+#define USIM_MAX_APDU_LENGTH	0xFE
+
+enum usim_smartcard_clock {
+	USIM_SMARTCART_CLOCK_3_3MHZ	= 0x1,
+	USIM_SMARTCART_CLOCK_4MHZ	= 0x2,
+	USIM_SMARTCART_CLOCK_5MHZ	= 0x3,
+	USIM_SMARTCART_CLOCK_6_6MHZ	= 0x4,
+	USIM_SMARTCART_CLOCK_10MHZ	= 0x5,
+	USIM_SMARTCART_CLOCK_20MHZ	= 0x6,
+};
+
+enum usim_event {
+	USIM_EVENT_CARD_INSERT	= 0x1,
+	USIM_EVENT_CARD_REMOVE	= 0x2,
+	USIM_EVENT_TIMEOUT	= 0x4,
+	USIM_EVENT_ERR_TXRETRY	= 0x8,
+	USIM_EVENT_ERR_LRC	= 0x10,
+	USIM_EVENT_ERR_PARITY	= 0x20,
+	USIM_EVENT_ERR_FRAME	= 0x40,
+	USIM_EVENT_PHYERR	= 0x80,
+	USIM_EVENT_CARD_OVERHEAT = 0x100,
+};
+
+enum usim_card_voltage {
+	USIM_CARD_5V = 0,
+	USIM_CARD_3V,
+	USIM_CARD_1_8V
+};
+
+#endif /* __TI_USIM_H__ */
-- 
1.7.9.5


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

* [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim
  2014-05-28  8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel
                   ` (2 preceding siblings ...)
  2014-05-28  8:57 ` [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx Satish Patel
@ 2014-05-28  8:57 ` Satish Patel
  2014-05-28  8:57 ` [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy Satish Patel
  4 siblings, 0 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-28  8:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-omap, devicetree, gregkh,
	rob, tony
  Cc: grant.likely, robh+dt, Satish Patel

SoC specific DT entries added for TI's USIM - smart card controller of AM43xx
platfrom.

Signed-off-by: Satish Patel <satish.patel@ti.com>
---
 arch/arm/boot/dts/am4372.dtsi |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index d1f8707..fe830dd 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -735,6 +735,18 @@
 			#size-cells = <1>;
 			status = "disabled";
 		};
+
+		usim0: usim@48034000 {
+			compatible = "ti,usim";
+			reg = <0x48034000 0x1000>;
+			interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+			ti,hwmods = "usim0";
+			clocks = <&usim0_opt_fck>, <&usim0_opt_fck32>,
+				 <&dpll_per_m2_div4_ck>;
+			clock-names = "opt_fck", "opt_fck32", "fck";
+			status = "disabled";
+		};
+
 	};
 };
 
-- 
1.7.9.5


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

* [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries  for ti-usim and phy
  2014-05-28  8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel
                   ` (3 preceding siblings ...)
  2014-05-28  8:57 ` [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim Satish Patel
@ 2014-05-28  8:57 ` Satish Patel
  4 siblings, 0 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-28  8:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-omap, devicetree, gregkh,
	rob, tony
  Cc: grant.likely, robh+dt, Satish Patel

- Board specific DT entries for TI's USIM - smart card controller of AM43xx
platfrom.These entries are used by USIM driver for various configurations.

- Shutdown line of NXP phy is maped to GPIO5. So enabling same to have support
for NXP phy.

- i2c2 pinmux configuration -  NxP tda8026 phy is connected to i2c2 lines

Signed-off-by: Satish Patel <satish.patel@ti.com>
---
 arch/arm/boot/dts/am43x-epos-evm.dts |   31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 167dbc8..ecc8b1a 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -115,6 +115,18 @@
 			>;
 		};
 
+		usim0_default: usim0_default {
+		       pinctrl-single,pins = <
+			       /* USIM 0 */
+			       0x1B4 (SLEWCTRL_FAST | PULL_DISABLE | MUX_MODE8)		/* CLK0  */
+			       0x1B0 (SLEWCTRL_FAST | PULL_DISABLE | MUX_MODE8)		/* CLK1  */
+			       0x1B8 (SLEWCTRL_FAST | INPUT_EN | PULL_DISABLE | MUX_MODE8)	/* DATA0 */
+			       0x1BC (SLEWCTRL_FAST | INPUT_EN | PULL_DISABLE | MUX_MODE8)	/* DATA1 */
+			       0x1C8 (SLEWCTRL_FAST | INPUT_EN | PULL_UP | MUX_MODE8)		/* IRQn  */
+			       >;
+	       };
+
+
 		spi0_pins: pinmux_spi0_pins {
 			pinctrl-single,pins = <
 				0x150 (PIN_INPUT | MUX_MODE0)           /* spi0_clk.spi0_clk */
@@ -238,10 +250,24 @@
 	};
 };
 
+&usim0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usim0_default>;
+	phy = <&tda8026>;
+	phy-slots = <1>;
+	status = "okay";
+};
+
 &i2c2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c2_pins>;
 	status = "okay";
+	tda8026: tda8026@48 {
+		compatible = "nxp,tda8026";
+		reg = <0x48>;
+		shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;   /* Bank5, pin19 */
+		interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+	};
 };
 
 &gpio0 {
@@ -260,6 +286,11 @@
 	status = "okay";
 };
 
+&gpio5 {
+	status = "okay";
+};
+
+
 &elm {
 	status = "okay";
 };
-- 
1.7.9.5


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

* Re: [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx
  2014-05-28  8:57 ` [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx Satish Patel
@ 2014-05-28 17:56   ` Rob Herring
  2014-05-29 10:05     ` Satish Patel
  0 siblings, 1 reply; 22+ messages in thread
From: Rob Herring @ 2014-05-28 17:56 UTC (permalink / raw)
  To: Satish Patel
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree,
	Greg Kroah-Hartman, Rob Landley, Tony Lindgren, Grant Likely,
	Rob Herring

On Wed, May 28, 2014 at 3:57 AM, Satish Patel <satish.patel@ti.com> wrote:
> TI-USIM driver is a platform driver that provides a character
> driver interface to user applications.
>
> It allows user applications to call IOCTL's to
> perform smart card operations.

What's the usecase? For cellular, isn't the SC typically attached to the modem?

>
> Driver currently supports
> - Cold & Warm Reset
> - T=0 & T=1 protocol
> - clock stop mode
> - smart card clock configuration
> - Tx/Rx application data units (APDU) to smart card
> - Interface to PHY using DT & phy interface
>
> Validation is done with ACOS3 smart cards
>
> Signed-off-by: Satish Patel <satish.patel@ti.com>
> ---
>  .../devicetree/bindings/ti-usim/ti-usim.txt        |   32 +
>  drivers/char/Kconfig                               |    7 +
>  drivers/char/Makefile                              |    1 +
>  drivers/char/ti-usim-hw.h                          |  864 ++++++++
>  drivers/char/ti-usim.c                             | 2213 ++++++++++++++++++++

Perhaps drivers/char/smartcard or drivers/smartcard would be a better
location. This should be designed assuming we get more than 1
SmartCard controller. Perhaps there already is one in the kernel.

>  include/linux/ti-usim.h                            |  111 +
>  6 files changed, 3228 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/ti-usim/ti-usim.txt
>  create mode 100644 drivers/char/ti-usim-hw.h
>  create mode 100644 drivers/char/ti-usim.c
>  create mode 100644 include/linux/ti-usim.h
>
> diff --git a/Documentation/devicetree/bindings/ti-usim/ti-usim.txt b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt
> new file mode 100644
> index 0000000..4e599e2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt
> @@ -0,0 +1,32 @@
> +ti-usim: USIM - Smart Card Controller
> +
> +Required Properties:
> +- compatible: Should be "ti,usim"

This should be more specific like "ti,am43xx-usim".

> +- reg: Specifies base physical address and size of the USIM registers
> +- interrupts:  Interrupt number for the USIM controller
> +- ti,hwmods: Name of the hwmod associated to the USIM controller
> +
> +- clocks        : list of clock specifiers, corresponding to entries in  the
> +                  clock-names property

How many clocks and what is their use and order?

> +- clock-names   : should contain "opt_fck" and "opt_fck32" entries, matching
> +                  entries in the clocks property
> +
> +Optional properties:
> +- pinctrl-0: Should specify pin control group used for this controller.
> +- pinctrl-names: Should contain only one value - "default", for more details
> +                 please refer to pinctrl-bindings.txt
> +- phy : Should specify <smart card phy> reference connected to controller
> +- phy-slots : No of slots to which controller will communicate
> +
> +Example:
> +
> +usim0: usim@48034000 {
> +              compatible = "ti,usim";
> +              reg = <0x48034000 0x1000>;
> +              interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
> +              ti,hwmods = "usim0";
> +              clocks = <&usim0_opt_fck>, <&usim0_opt_fck32>,
> +                     <&dpll_per_m2_div4_ck>;
> +              clock-names = "opt_fck", "opt_fck32", "fck";
> +              status = "disabled";
> +       };
> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index 6e9f74a..c7c5fae 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -600,5 +600,12 @@ config TILE_SROM
>           device appear much like a simple EEPROM, and knows
>           how to partition a single ROM for multiple purposes.
>
> +config TI_USIM
> +       tristate "Character device access to TI's USIM module on AM43X"
> +       depends on SOC_AM43XX

|| COMPILE_TEST

> +       help
> +       This device creates a character device interface that enables
> +       user applications to exchange data with TI's USIM module.
> +
>  endmenu
>
> diff --git a/drivers/char/Makefile b/drivers/char/Makefile
> index a324f93..f7ee777 100644
> --- a/drivers/char/Makefile
> +++ b/drivers/char/Makefile
> @@ -61,3 +61,4 @@ obj-$(CONFIG_JS_RTC)          += js-rtc.o
>  js-rtc-y = rtc.o
>
>  obj-$(CONFIG_TILE_SROM)                += tile-srom.o
> +obj-$(CONFIG_TI_USIM)          += ti-usim.o
> diff --git a/drivers/char/ti-usim-hw.h b/drivers/char/ti-usim-hw.h
> new file mode 100644
> index 0000000..1d3dd6e
> --- /dev/null
> +++ b/drivers/char/ti-usim-hw.h
> @@ -0,0 +1,864 @@
> +/*
> + * ti-usim-hw.h - Header file for USIM smart card interface

This can go into the .c file.

> + *
> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __TI_USIM_HW_H__
> +#define __TI_USIM_HW_H__
> +
> +#include <linux/types.h>
> +#include <linux/ioctl.h>
> +#include <linux/sc_phy.h>
> +#include <linux/ti-usim.h>
> +
> +
> +#define USIM_MAX_SLOTS 0x2
> +
> +/* WWT Work Wait Time */
> +#define USIM_EMV_WI      (10)
> +#define USIM_EMV_WWT     ((960 * USIM_EMV_WI) + (480))
> +/* CGT Character Guard Time */
> +#define USIM_EMV_CGT     (12)
> +
> +#define USIM_ATR_TIMEOUT_EMV   (20160)
> +#define USIM_EMV_ATR_EARLY_TO  (370)
> +#define USIM_EMV_ATR_MUTE_TO   (42000)
> +
> +#define USIM_MAX_RX_FIFO_SIZE    (260)
> +#define USIM_MAX_TX_FIFO_SIZE    (260)
> +#define USIM_MAX_PARITY_RETRIES  (7)
> +
> +#define USIM_IRQ_NATR           (0x00000001)
> +#define USIM_IRQ_WT            (0x00000002)
> +#define USIM_IRQ_RXFULL                (0x00000004)
> +#define USIM_IRQ_TX            (0x00000008)
> +#define USIM_IRQ_RX            (0x00000010)
> +#define USIM_IRQ_CD            (0x00000020)
> +#define USIM_IRQ_EOB           (0x00000040)
> +#define USIM_IRQ_TOC           (0x00000080)
> +#define USIM_IRQ_TOB           (0x00000100)
> +#define USIM_IRQ_RESENT                (0x00000200)
> +#define USIM_IRQ_TS_ERR                (0x00000400)
> +#define USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT       (0x00000800)
> +#define USIM_IRQ_STOP          (0x00001000)
> +#define USIM_IRQ_PAR_ERR_LEVEL_REACHED (0x00002000)
> +#define USIM_IRQ_FRAME_ERR     (0x00004000)
> +#define USIM_IRQ_RXDMA_RDY     (0x00008000)
> +#define USIM_IRQ_ATR_START     (0x00010000)
> +#define USIM_IRQ_ACT_DONE      (0x00020000)
> +#define USIM_IRQ_DEACT_DONE    (0x00040000)
> +#define USIM_IRQ_TX_BLOCK_DONE (0x00080000)
> +#define USIM_IRQ_TX_BLOCK_REQ  (0x00100000)
> +
> +#define USIM_CONFSCLKMODE_LEGACY       0x0
> +#define USIM_CONFSCLKMODE_HF           0x1
> +
> +/*
> + * Different operating modes supported in USIM.
> + * Programming USIM to a different mode from current mode would
> + * endup in state machine state change within the IPs FSM
> + */
> +enum usim_mode {
> +       USIM_MODE_LEGACY = 0x0,
> +       USIM_MODE_FREEZE = 0x1,
> +       USIM_MODE_TXRX   = 0x2,
> +       USIM_MODE_ATR    = 0x3,
> +       USIM_MODE_ACT    = 0x4,
> +       USIM_MODE_DEACT  = 0x5,
> +       USIM_MODE_IDLE   = 0x6,
> +};
> +
> +/*
> + * structure to store slot specific information
> + */
> +struct usim_slotcontext {
> +       char atr[USIM_MAX_ATRLENGTH];
> +       char rxbuf[USIM_MAX_APDU_LENGTH];
> +       bool emv;
> +       enum usim_mode state;
> +       int event;
> +       int protocol;
> +       enum usim_card_voltage supply;
> +       int rx_explen;
> +       int rx_counter;
> +       int atr_length;
> +       enum usim_smartcard_clock clock;
> +       enum usim_card_mode card_mode;
> +};
> +
> +struct usim {
> +       struct device *dev;
> +
> +       /* to protect interrput handling */
> +       spinlock_t      lock;
> +       int irq;
> +       void __iomem            *base;
> +       int slot;
> +       int max_slots;
> +       int phy_present;
> +       int txdone;
> +       int rxdone;
> +       int atrdone;
> +       int user_pid;
> +       int enable;
> +       struct sc_phy *phy;
> +       struct usim_slotcontext *slot_ctx;
> +
> +       struct clk      *opt_fclk;
> +       struct clk      *opt_fclk32;
> +       struct clk      *usim_dbclk;
> +       struct clk      *clkdiv32k_ick;
> +       struct clk      *usim0_fck;
> +       struct clk      *dpll_core_m4_ck;
> +
> +#ifdef CONFIG_DEBUG_FS
> +       struct dentry   *debugfs_root;
> +#endif
> +};
> +
> +/*
> + * Register Definitions: Taken from auto generated file
> + */
> +#define USIM_REVISION                    (0x0U)

Parenthesis and U are generally not needed throughout.

> +#define USIM_IDENT                       (0x4U)
> +#define USIM_SYSCONFIG                   (0x10U)
> +#define USIM_SYSSTATUS                   (0x14U)
> +#define USIM_IRQSTATUS                   (0x18U)
> +#define USIM_IRQENABLE                   (0x1cU)
> +#define USIM_WAKEUPEN                    (0x20U)
> +#define USIM_CMD                         (0x24U)
> +#define USIM_STAT                        (0x28U)
> +#define USIM_CONF1                       (0x2cU)
> +#define USIM_CONF2                       (0x30U)
> +#define USIM_CONF3                       (0x34U)
> +#define USIM_DRX                         (0x38U)
> +#define USIM_DTX                         (0x3cU)
> +#define USIM_FIFOS                       (0x40U)
> +#define USIM_CGT                         (0x44U)
> +#define USIM_CWT                         (0x48U)
> +#define USIM_BWT                         (0x4cU)
> +#define USIM_DEBUG                       (0x50U)
> +#define USIM_CONF_SAM1_DIV               (0x54U)
> +#define USIM_CONF4                       (0x58U)
> +#define USIM_ATR_CLK_PRD_NBS             (0x5cU)
> +#define USIM_CONF_ETU_DIV                (0x60U)
> +#define USIM_CONF5                       (0x64U)
> +#define USIM_TC_GUARD_TIME_ADD           (0x68U)
> +#define USIM_RXFIFO_LEVEL                (0x6cU)
> +#define USIM_RXFIFO_BYTECNT              (0x70U)
> +#define USIM_WWT                         (0x74U)
> +#define USIM_CONF6                       (0x78U)
> +#define USIM_IO_DIRECT                   (0x7cU)
> +#define USIM_TX_BLOCK                    (0x84U)
> +
> +/*
> + * Field Definition Macros
> + */
> +#define USIM_REVISION_REV_SHIFT                       (0U)
> +#define USIM_REVISION_REV_MASK                        (0x000000ffU)
> +
> +#define USIM_REVISION_RESERVED_24_SHIFT               (8U)
> +#define USIM_REVISION_RESERVED_24_MASK                (0xffffff00U)
> +
> +#define USIM_IDENT_VC_SHIFT                           (0U)
> +#define USIM_IDENT_VC_MASK                            (0x0000ffffU)
> +
> +#define USIM_IDENT_RESERVED_16_31_SHIFT               (16U)
> +#define USIM_IDENT_RESERVED_16_31_MASK                (0xffff0000U)
> +
> +#define USIM_SYSCONFIG_AUTOIDLE_SHIFT                 (0U)
> +#define USIM_SYSCONFIG_AUTOIDLE_MASK                  (0x00000001U)
> +#define USIM_SYSCONFIG_AUTOIDLE_AUTOIDLE_VALUE_1       (1U)
> +#define USIM_SYSCONFIG_AUTOIDLE_AUTOIDLE_VALUE_0       (0U)
> +
> +#define USIM_SYSCONFIG_SOFTRESET_SHIFT                (1U)
> +#define USIM_SYSCONFIG_SOFTRESET_MASK                 (0x00000002U)
> +#define USIM_SYSCONFIG_SOFTRESET_SOFTRESET_VALUE_1     (1U)
> +#define USIM_SYSCONFIG_SOFTRESET_SOFTRESET_VALUE_0     (0U)
> +
> +#define USIM_SYSCONFIG_ENAWAKEUP_SHIFT                (2U)
> +#define USIM_SYSCONFIG_ENAWAKEUP_MASK                 (0x00000004U)
> +#define USIM_SYSCONFIG_ENAWAKEUP_ENAWAKEUP_VALUE_1     (1U)
> +#define USIM_SYSCONFIG_ENAWAKEUP_ENAWAKEUP_VALUE_0     (0U)
> +
> +#define USIM_SYSCONFIG_IDLEMODE_SHIFT                 (3U)
> +#define USIM_SYSCONFIG_IDLEMODE_MASK                  (0x00000018U)
> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_3       (3U)
> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_2       (2U)
> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_1       (1U)
> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_0       (0U)
> +
> +#define USIM_SYSCONFIG_EMUFREE_SHIFT                  (5U)
> +#define USIM_SYSCONFIG_EMUFREE_MASK                   (0x00000020U)
> +#define USIM_SYSCONFIG_EMUFREE_EMUFREE_VALUE_0         (0U)
> +#define USIM_SYSCONFIG_EMUFREE_EMUFREE_VALUE_1         (1U)
> +
> +#define USIM_SYSCONFIG_RESERVED_6_7_SHIFT             (6U)
> +#define USIM_SYSCONFIG_RESERVED_6_7_MASK              (0x000000c0U)
> +
> +#define USIM_SYSCONFIG_CLOCKACTIVITY_SHIFT            (8U)
> +#define USIM_SYSCONFIG_CLOCKACTIVITY_MASK             (0x00000300U)
> +
> +#define USIM_SYSCONFIG_RESERVED_22_SHIFT              (10U)
> +#define USIM_SYSCONFIG_RESERVED_22_MASK               (0xfffffc00U)
> +
> +#define USIM_SYSSTATUS_RESETDONE_SHIFT                (0U)
> +#define USIM_SYSSTATUS_RESETDONE_MASK                 (0x00000001U)
> +#define USIM_SYSSTATUS_RESETDONE_RESETDONE_VALUE_1     (1U)
> +#define USIM_SYSSTATUS_RESETDONE_RESETDONE_VALUE_0     (0U)
> +
> +#define USIM_SYSSTATUS_RESERVED_31_SHIFT              (1U)
> +#define USIM_SYSSTATUS_RESERVED_31_MASK               (0xfffffffeU)
> +
> +#define USIM_IRQSTATUS_USIM_NATR_SHIFT                (0U)
> +#define USIM_IRQSTATUS_USIM_NATR_MASK                 (0x00000001U)
> +
> +#define USIM_IRQSTATUS_USIM_WT_SHIFT                  (1U)
> +#define USIM_IRQSTATUS_USIM_WT_MASK                   (0x00000002U)
> +
> +#define USIM_IRQSTATUS_USIM_RXFULL_SHIFT              (2U)
> +#define USIM_IRQSTATUS_USIM_RXFULL_MASK               (0x00000004U)
> +
> +#define USIM_IRQSTATUS_USIM_TX_SHIFT                  (3U)
> +#define USIM_IRQSTATUS_USIM_TX_MASK                   (0x00000008U)
> +
> +#define USIM_IRQSTATUS_USIM_RX_SHIFT                  (4U)
> +#define USIM_IRQSTATUS_USIM_RX_MASK                   (0x00000010U)
> +
> +#define USIM_IRQSTATUS_USIM_CD_SHIFT                  (5U)
> +#define USIM_IRQSTATUS_USIM_CD_MASK                   (0x00000020U)
> +
> +#define USIM_IRQSTATUS_USIM_EOB_SHIFT                 (6U)
> +#define USIM_IRQSTATUS_USIM_EOB_MASK                  (0x00000040U)
> +
> +#define USIM_IRQSTATUS_USIM_TOC_SHIFT                 (7U)
> +#define USIM_IRQSTATUS_USIM_TOC_MASK                  (0x00000080U)
> +
> +#define USIM_IRQSTATUS_USIM_TOB_SHIFT                 (8U)
> +#define USIM_IRQSTATUS_USIM_TOB_MASK                  (0x00000100U)
> +
> +#define USIM_IRQSTATUS_USIM_RESENT_SHIFT              (9U)
> +#define USIM_IRQSTATUS_USIM_RESENT_MASK               (0x00000200U)
> +
> +#define USIM_IRQSTATUS_TS_ERROR_SHIFT                 (10U)
> +#define USIM_IRQSTATUS_TS_ERROR_MASK                  (0x00000400U)
> +
> +#define USIM_IRQSTATUS_IT_EMV_ATR_LENGTH_TIME_OUT_SHIFT  (11U)
> +#define USIM_IRQSTATUS_IT_EMV_ATR_LENGTH_TIME_OUT_MASK   (0x00000800U)
> +
> +#define USIM_IRQSTATUS_RESERVED_SHIFT                    (21U)
> +#define USIM_IRQSTATUS_RESERVED_MASK                     (0xffe00000U)
> +
> +#define USIM_IRQSTATUS_USIM_STOP_CLK_SHIFT               (12U)
> +#define USIM_IRQSTATUS_USIM_STOP_CLK_MASK                (0x00001000U)
> +
> +#define USIM_IRQSTATUS_PAR_ERR_LEVEL_REACHED_SHIFT       (13U)
> +#define USIM_IRQSTATUS_PAR_ERR_LEVEL_REACHED_MASK        (0x00002000U)
> +
> +#define USIM_IRQSTATUS_FRAME_ERR_SHIFT            (14U)
> +#define USIM_IRQSTATUS_FRAME_ERR_MASK             (0x00004000U)
> +
> +#define USIM_IRQSTATUS_RXDMA_RDY_SHIFT            (15U)
> +#define USIM_IRQSTATUS_RXDMA_RDY_MASK             (0x00008000U)
> +
> +#define USIM_IRQSTATUS_ATR_START_SHIFT            (16U)
> +#define USIM_IRQSTATUS_ATR_START_MASK             (0x00010000U)
> +
> +#define USIM_IRQSTATUS_ACT_DONE_SHIFT             (17U)
> +#define USIM_IRQSTATUS_ACT_DONE_MASK              (0x00020000U)
> +
> +#define USIM_IRQSTATUS_DEACT_DONE_SHIFT           (18U)
> +#define USIM_IRQSTATUS_DEACT_DONE_MASK            (0x00040000U)
> +
> +#define USIM_IRQSTATUS_TX_BLOCK_DONE_SHIFT        (19U)
> +#define USIM_IRQSTATUS_TX_BLOCK_DONE_MASK         (0x00080000U)
> +
> +#define USIM_IRQSTATUS_TX_BLOCK_REQ_SHIFT         (20U)
> +#define USIM_IRQSTATUS_TX_BLOCK_REQ_MASK          (0x00100000U)
> +
> +#define USIM_IRQENABLE_RESERVED_SHIFT             (21U)
> +#define USIM_IRQENABLE_RESERVED_MASK              (0xffe00000U)
> +
> +#define USIM_IRQENABLE_EMV_ATR_LENGTH_TIME_OUT_EN_SHIFT    (11U)
> +#define USIM_IRQENABLE_EMV_ATR_LENGTH_TIME_OUT_EN_MASK     (0x00000800U)
> +
> +#define USIM_IRQENABLE_TS_ERR_EN_SHIFT         (10U)
> +#define USIM_IRQENABLE_TS_ERR_EN_MASK          (0x00000400U)
> +
> +#define USIM_IRQENABLE_RESENT_EN_SHIFT         (9U)
> +#define USIM_IRQENABLE_RESENT_EN_MASK          (0x00000200U)
> +
> +#define USIM_IRQENABLE_TOB_EN_SHIFT            (8U)
> +#define USIM_IRQENABLE_TOB_EN_MASK             (0x00000100U)
> +
> +#define USIM_IRQENABLE_TOC_EN_SHIFT            (7U)
> +#define USIM_IRQENABLE_TOC_EN_MASK             (0x00000080U)
> +
> +#define USIM_IRQENABLE_EOB_EN_SHIFT            (6U)
> +#define USIM_IRQENABLE_EOB_EN_MASK             (0x00000040U)
> +
> +#define USIM_IRQENABLE_CD_EN_SHIFT             (5U)
> +#define USIM_IRQENABLE_CD_EN_MASK              (0x00000020U)
> +
> +#define USIM_IRQENABLE_RX_EN_SHIFT             (4U)
> +#define USIM_IRQENABLE_RX_EN_MASK              (0x00000010U)
> +
> +#define USIM_IRQENABLE_TX_EN_SHIFT             (3U)
> +#define USIM_IRQENABLE_TX_EN_MASK              (0x00000008U)
> +
> +#define USIM_IRQENABLE_RXFULL_EN_SHIFT         (2U)
> +#define USIM_IRQENABLE_RXFULL_EN_MASK          (0x00000004U)
> +
> +#define USIM_IRQENABLE_WT_EN_SHIFT             (1U)
> +#define USIM_IRQENABLE_WT_EN_MASK              (0x00000002U)
> +
> +#define USIM_IRQENABLE_NATR_EN_SHIFT           (0U)
> +#define USIM_IRQENABLE_NATR_EN_MASK            (0x00000001U)
> +
> +#define USIM_IRQENABLE_STOP_CLK_SHIFT          (12U)
> +#define USIM_IRQENABLE_STOP_CLK_MASK           (0x00001000U)
> +
> +#define USIM_IRQENABLE_PAR_ERR_LEVEL_REACHED_EN_SHIFT      (13U)
> +#define USIM_IRQENABLE_PAR_ERR_LEVEL_REACHED_EN_MASK       (0x00002000U)
> +
> +#define USIM_IRQENABLE_FRAME_ERR_EN_SHIFT           (14U)
> +#define USIM_IRQENABLE_FRAME_ERR_EN_MASK            (0x00004000U)
> +
> +#define USIM_IRQENABLE_RXDMA_RDY_EN_SHIFT           (15U)
> +#define USIM_IRQENABLE_RXDMA_RDY_EN_MASK            (0x00008000U)
> +
> +#define USIM_IRQENABLE_ATR_START_EN_SHIFT           (16U)
> +#define USIM_IRQENABLE_ATR_START_EN_MASK            (0x00010000U)
> +
> +#define USIM_IRQENABLE_ACT_DONE_EN_SHIFT            (17U)
> +#define USIM_IRQENABLE_ACT_DONE_EN_MASK             (0x00020000U)
> +
> +#define USIM_IRQENABLE_DEACT_DONE_EN_SHIFT          (18U)
> +#define USIM_IRQENABLE_DEACT_DONE_EN_MASK           (0x00040000U)
> +
> +#define USIM_IRQENABLE_TX_BLOCK_DONE_EN_SHIFT       (19U)
> +#define USIM_IRQENABLE_TX_BLOCK_DONE_EN_MASK        (0x00080000U)
> +
> +#define USIM_IRQENABLE_TX_BLOCK_REQ_EN_SHIFT        (20U)
> +#define USIM_IRQENABLE_TX_BLOCK_REQ_EN_MASK         (0x00100000U)
> +
> +#define USIM_WAKEUPEN_STOP_CLK_SHIFT                (12U)
> +#define USIM_WAKEUPEN_STOP_CLK_MASK                 (0x00001000U)

Can't you have common defines for IRQSTATUS, IRQENABLE and WAKEUPEN?
They seem to all be the same bit positions. And you already have IRQ
bit defines above.

[lots more register defines...]

> +
> +#define USIM_TX_BLOCK_RESERVED_SHIFT              (16U)
> +#define USIM_TX_BLOCK_RESERVED_MASK               (0xffff0000U)

In general, trim these defines down to what you actually use. Single
bit fields rarely need both a shift and mask.

> +
> +#endif /* __TI_USIM_HW_H__ */
> diff --git a/drivers/char/ti-usim.c b/drivers/char/ti-usim.c
> new file mode 100644
> index 0000000..ffabf87
> --- /dev/null
> +++ b/drivers/char/ti-usim.c
> @@ -0,0 +1,2213 @@
> +/*
> + * usim.c - USIM driver for Smart Card module
> + *
> + *
> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/interrupt.h>
> +#include <linux/spinlock.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/io.h>
> +#include <linux/fs.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/i2c.h>
> +#include <linux/miscdevice.h>
> +#include <linux/uaccess.h>
> +#include <linux/ctype.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +#include <linux/debugfs.h>
> +#include <linux/notifier.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +/* for send_sig_info */
> +#include <linux/rcupdate.h>
> +#include <asm/siginfo.h>
> +
> +#include "ti-usim-hw.h"
> +
> +#define USIM_WRITEREG(base, offset, field, value)  \
> +                       usim_writereg(base+offset, offset##_##field##_MASK, \
> +                               offset##_##field##_SHIFT, value)
> +
> +#define USIM_READREG(base, offset, field)  \
> +       usim_readreg(base+offset, offset##_##field##_MASK, \
> +                       offset##_##field##_SHIFT)
> +
> +#define USIM_SETFIELD(reg, offset, field, value)  \
> +       usim_setfield(reg, offset##_##field##_MASK, \
> +                       offset##_##field##_SHIFT, value)

Get rid of this.

> +
> +/* calculation of max ATR waiting time
> + * 372 is default FI value, so etu for 1Mhz SC clock cycle would be
> + * etu = FI/f sec = 372/1Mhz = 372 micro second
> + * Max ATR waiting is - USIM_ATR_TIMEOUT_EMV etu
> + */
> +#define MAX_ATR_WAITTIME_US (372 * USIM_ATR_TIMEOUT_EMV)
> +
> +/*
> + * phy states
> + */
> +enum usim_phy_state {
> +       USIM_PHY_NOT_PRESENT = 0x0,
> +       USIM_PHY_PRESENT,
> +       USIM_PHY_NOT_ATTACHED,
> +};
> +
> +static struct miscdevice usim_dev;
> +
> +static DECLARE_WAIT_QUEUE_HEAD(rx_wait);
> +static DECLARE_WAIT_QUEUE_HEAD(tx_wait);
> +static DECLARE_WAIT_QUEUE_HEAD(atr_wait);
> +
> +static int usim_set_smartcardclock(struct usim *usim, u32 clock);
> +static int usim_deactivate_card(struct usim *usim);
> +
> +static void usim_writereg(void __iomem *base, u32 mask, u32 shift, u32 value)
> +{
> +       u32 v = readl(base);
> +
> +       v &= ~mask;
> +       v |= (value << shift) & mask;
> +       writel(v, base);
> +       v = readl(base);
> +       return;
> +}
> +
> +static u32 usim_readreg(void __iomem *base, u32 mask, u32 shift)
> +{
> +       u32 v = readl(base);
> +
> +       v &= mask;
> +       v = (v >> shift);
> +       return v;
> +}
> +
> +static u32 usim_setfield(u32 reg, u32 mask, u32 shift, u32 value)
> +{
> +       reg &= ~mask;
> +       reg |= (value << shift) & mask;
> +       return reg;
> +}

Use readl/writel directly. If we wanted drivers written with accessors
like these, then there would be common ones to use.

> +
> +
> +static inline void usim_irq_enable(void __iomem *base, u32 irqs)
> +{
> +       u32 v = readl(base + USIM_IRQENABLE);
> +
> +       v |= irqs;
> +       writel(v, base + USIM_IRQENABLE);
> +}
> +
> +static inline void usim_irq_disable(void __iomem *base, u32 irqs)
> +{
> +       u32 v = readl(base + USIM_IRQENABLE);
> +
> +       v &= ~irqs;
> +       writel(v, base + USIM_IRQENABLE);

I assume these are called with appropriate locking?

> +}
> +
> +static inline void usim_irq_get(void __iomem *base, u32 *irqs)
> +{
> +       *irqs = readl(base + USIM_IRQENABLE);
> +}
> +
> +static inline u32 usim_irqstatus(void __iomem *base)
> +{
> +       return readl(base + USIM_IRQSTATUS);
> +}
> +
> +static inline void usim_irqstatus_clear(void __iomem *base, u32 irqs)
> +{
> +       writel(irqs, base + USIM_IRQSTATUS);
> +}

Use readl/writel directly.

> +
> +static inline struct usim *dev_to_usim(struct device *dev)
> +{
> +       return dev_get_drvdata(dev);
> +}
> +
> +static int usim_send_signal(struct usim *usim, int event)
> +{

Using signals is not a typical driver interface.

> +       struct siginfo info;
> +       struct task_struct *tid;
> +       int ret = 0;
> +       int pid = usim->user_pid;
> +
> +       if (pid == 0)
> +               return -EINVAL;
> +       info.si_signo = USIM_SIGID;
> +       info.si_code = SI_QUEUE;
> +
> +       info.si_int = event;
> +       rcu_read_lock();
> +
> +       /* find task structure associated with this pid */
> +       tid = pid_task(find_vpid(pid), PIDTYPE_PID);
> +       if (tid == NULL) {
> +               dev_err(usim->dev, "usim-err:no such pid :%d\n", pid);
> +               rcu_read_unlock();
> +               return -ENODEV;
> +       }
> +
> +       rcu_read_unlock();
> +
> +       /* send the signal */
> +       ret = send_sig_info(USIM_SIGID, &info, tid);
> +       if (ret < 0) {
> +               dev_err(usim->dev, "error sending signal:%d\n", ret);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static void usim_getrx(struct usim *usim)
> +{
> +       u32 rxlen = 0;
> +       u32 cnt = 0;
> +
> +       /* Check if FIFO contains some data */
> +       rxlen = USIM_READREG(usim->base, USIM_RXFIFO_LEVEL,
> +                                       USIM_RXFIFO_LEVEL);

More register accessors?

> +
> +       usim->slot_ctx[usim->slot].rx_counter += rxlen;
> +       if (rxlen > 0) {
> +               for (cnt = 0; cnt < rxlen; cnt++) {
> +                       usim->slot_ctx[usim->slot].rxbuf[cnt] =
> +                               USIM_READREG(usim->base, USIM_DRX, USIMDRX);
> +               }
> +       }
> +}
> +
> +static void usim_irq_atrhandler(struct usim *usim, u32 reg)
> +{
> +       u32 event = 0;
> +       u32 val = 0;
> +       u32 cnt = 0;
> +       u32 rxval = 0;
> +       if (usim->atrdone)
> +               return;
> +       do {
> +               /* WWT would be used to identify end of ATR */
> +               if (reg & (USIM_IRQ_WT | USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT)) {
> +                       event |= USIM_EVENT_TIMEOUT;
> +                       val = USIM_READREG(usim->base, USIM_STAT,
> +                                               ATRRX_AFTER_TIMEOUT);
> +                       if (val) {
> +                               /* do not store rx character if it comes after
> +                                * ATR timeout
> +                                */
> +                               dev_dbg(usim->dev, "Error: Rx after ATR Timeout");
> +                               break;
> +                       }
> +               }
> +               if (reg & USIM_IRQ_TS_ERR) {
> +                       event |= USIM_EVENT_ERR_FRAME;
> +                       break;
> +               }
> +
> +               /* check the rx fifo and store available bytes in atrbuf */
> +               val = USIM_READREG(usim->base, USIM_RXFIFO_LEVEL,
> +                                               USIM_RXFIFO_LEVEL);
> +               cnt = usim->slot_ctx[usim->slot].atr_length;
> +
> +               while (val > 0) {
> +                       if (cnt < USIM_MAX_ATRLENGTH) {
> +                               rxval = readl(usim->base + USIM_DRX);
> +                               usim->slot_ctx[usim->slot].atr[cnt++] = rxval &
> +                                                       USIM_DRX_USIMDRX_MASK;
> +                               /* check of parity */
> +                               if (!(rxval & USIM_DRX_STATRXPAR_MASK)) {
> +                                       dev_dbg(usim->dev,
> +                                               "Error : incorrect parity:%0x"
> +                                               , rxval);
> +                                       event |= USIM_EVENT_ERR_PARITY;
> +                               }
> +                       }
> +                       val--;
> +               }
> +
> +               usim->slot_ctx[usim->slot].atr_length = cnt;
> +       } while (0);

It would be nicer to see these written w/o all these while (0) loops.

> +
> +       if (event != 0) {
> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
> +               usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
> +               usim->slot_ctx[usim->slot].event = event;
> +               usim->atrdone = 1;
> +       }
> +
> +       if (usim->atrdone)
> +               wake_up(&atr_wait);
> +
> +       return;
> +}
> +
> +static void usim_irq_txhandler(struct usim *usim, u32 reg)
> +{
> +       u32 protocol    = 0;

This does not need to be initialized.

> +       u32 event       = 0;
> +
> +       if (usim->txdone)
> +               return;
> +
> +       protocol = usim->slot_ctx[usim->slot].protocol;
> +       do {
> +               if (reg & USIM_IRQ_FRAME_ERR) {
> +                       event |= USIM_EVENT_ERR_FRAME;
> +                       break;
> +               }
> +               if (!protocol && (reg & USIM_IRQ_RESENT)) {
> +                       event |= USIM_EVENT_ERR_TXRETRY;
> +                       break;
> +               }
> +               if (reg & USIM_IRQ_TX_BLOCK_REQ) {
> +                       /* TODO : As per EMV max tx block will be of 256 bytes
> +                        * and USIM controller has sufficient place for this.
> +                        * Need to implement this case when it is practially
> +                        * required
> +                        */
> +                       dev_dbg(usim->dev, "Error: TX_BLOCK_REQ - Not Implemented");
> +               }
> +               if (reg & USIM_IRQ_TX_BLOCK_DONE) {
> +                       usim_irq_disable(usim->base, USIM_IRQ_TX_BLOCK_REQ
> +                                               | USIM_IRQ_TX_BLOCK_DONE
> +                                               | USIM_IRQ_TX);
> +                       usim->txdone = 1;
> +                       usim_irq_enable(usim->base, USIM_IRQ_RX | USIM_IRQ_EOB
> +                                               | USIM_IRQ_RXDMA_RDY);
> +                       break;
> +               }
> +       } while (0);
> +
> +       if (event != 0) {
> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
> +               usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
> +               usim->slot_ctx[usim->slot].event = event;
> +               usim->txdone = 1;
> +               usim->rxdone = 1;
> +       }
> +       if (usim->txdone)
> +               wake_up(&tx_wait);
> +       return;
> +}
> +
> +static void usim_irq_rxhandler(struct usim *usim, u32 reg)
> +{
> +       u32 event = 0;
> +       u32 val = 0;
> +
> +       u32 protocol = usim->slot_ctx[usim->slot].protocol;
> +
> +       /* if tx not done then do not check of any rx */
> +       if (usim->rxdone || !usim->txdone)
> +               return;
> +
> +       /* For T=0 protocol */
> +       if (protocol == 0) {
> +               do {
> +                       /* ignore interrupts if expected bytes recevied */
> +                       if (usim->slot_ctx[usim->slot].rx_counter >=
> +                                       usim->slot_ctx[usim->slot].rx_explen) {
> +                               dev_dbg(usim->dev, "All bytes recvd,ignore this timeout\n");
> +                               usim->rxdone = 1;
> +                               break;

How about using "else if" instead of all these breaks. Can't you have
multiple interrupt bits set?

> +                       }
> +
> +                       if (reg & USIM_IRQ_WT) {
> +                               dev_dbg(usim->dev, "Expected bytes not recvd counter = %d\n",
> +                                       usim->slot_ctx[usim->slot].rx_counter);
> +                               usim_getrx(usim);
> +                               event |= USIM_EVENT_TIMEOUT;
> +                               break;
> +                       }
> +
> +                       if (reg & USIM_IRQ_PAR_ERR_LEVEL_REACHED) {
> +                               dev_err(usim->dev,
> +                                       "Rx parity level reached:%x\n"
> +                                       , reg);
> +                               usim_getrx(usim);
> +                               event |= USIM_EVENT_ERR_PARITY;
> +                               break;
> +                       }
> +
> +                       if (reg & (USIM_IRQ_RX | USIM_IRQ_RXDMA_RDY)) {
> +                               /* Read number of bytes present in the FIFO */
> +                               usim_getrx(usim);
> +                               usim->rxdone = 1;
> +                               break;
> +                       }
> +               } while (0);
> +       } else {
> +               /* T=1 protocol */
> +               do {
> +                       if (reg & (USIM_IRQ_TOB | USIM_IRQ_TOC)) {
> +                               usim_getrx(usim);
> +                               event |= USIM_EVENT_TIMEOUT;
> +                               break;
> +                       }
> +                       if (reg & USIM_IRQ_EOB) {
> +                               usim_getrx(usim);
> +                               usim->rxdone = 1;
> +                               val = USIM_READREG(usim->base, USIM_STAT,
> +                                                               STATLRC);
> +                               if (val != 0)
> +                                       event |= USIM_EVENT_ERR_LRC;
> +                               break;
> +                       }
> +               } while (0);
> +       }
> +
> +       if (event != 0 || usim->rxdone == 1) {
> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
> +               usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
> +               usim->slot_ctx[usim->slot].event = event;
> +               usim->rxdone = 1;
> +       }
> +
> +       if (usim->rxdone)
> +               wake_up(&rx_wait);
> +
> +       return;
> +}
> +
> +static irqreturn_t usim_interrupt(int irq, void *_usim)
> +{
> +       u32 reg = 0;
> +       u32 state = 0;
> +       struct usim *usim = (struct usim *)_usim;
> +
> +       state = usim->slot_ctx[usim->slot].state;
> +
> +       spin_lock(&usim->lock);
> +
> +       reg = readl(usim->base + USIM_IRQSTATUS);
> +
> +       if (state == USIM_MODE_ATR)
> +               usim_irq_atrhandler(usim, reg);
> +
> +       if (state == USIM_MODE_TXRX) {
> +               usim_irq_txhandler(usim, reg);
> +               usim_irq_rxhandler(usim, reg);
> +       }
> +
> +       if (reg & USIM_IRQSTATUS_USIM_NATR_MASK)
> +               dev_dbg(usim->dev, "NO ATR\n");
> +
> +       if (reg & USIM_IRQSTATUS_USIM_CD_MASK)
> +               dev_dbg(usim->dev, "CARD Insert/Removed\n");
> +
> +       if (reg & USIM_IRQSTATUS_USIM_STOP_CLK_MASK)
> +               dev_dbg(usim->dev, "SIM CLK STOPPED\n");
> +
> +       if (reg & USIM_IRQSTATUS_ACT_DONE_MASK)
> +               dev_dbg(usim->dev, "Activation Sequence completed\n");
> +
> +       if (reg & USIM_IRQSTATUS_DEACT_DONE_MASK)
> +               dev_dbg(usim->dev, "Deactivation Sequence complteted\n");
> +
> +       /* Clear the interrupt by writing the corresponding bit
> +        * in IRQ_STATUS register
> +        */
> +       usim_irqstatus_clear(usim->base, reg);
> +
> +       spin_unlock(&usim->lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static int usim_configure(struct usim *usim)
> +{
> +       int reg = 0;
> +       int count = 3;
> +
> +       /* perform softreset of IP */
> +       USIM_WRITEREG(usim->base, USIM_SYSCONFIG, SOFTRESET, 1);
> +
> +       /* wait until reset get completed */
> +       while (count > 0) {
> +               reg = USIM_READREG(usim->base, USIM_SYSCONFIG, SOFTRESET);
> +               if (reg == 0x0)
> +                       break;
> +               mdelay(10);

Does this really need to be a delay loop rather than a sleep? If not,
use msleep and time_after or time_before.

> +               count--;
> +       }
> +       if (reg != 0x0)
> +               return -EIO;
> +
> +       /* activate phy */
> +       if (usim->phy_present)
> +               usim->phy->set_config(usim->phy, usim->slot, SC_PHY_MODE,
> +                               SC_PHY_ACTIVE);
> +
> +       /* Disable Auto Idle and set NO IDLE config */
> +       reg = readl(usim->base + USIM_SYSCONFIG);
> +       reg = USIM_SETFIELD(reg, USIM_SYSCONFIG, AUTOIDLE, 0);
> +       reg = USIM_SETFIELD(reg, USIM_SYSCONFIG, IDLEMODE, 1);
> +       writel(reg, usim->base + USIM_SYSCONFIG);
> +
> +       if (usim->phy_present) {
> +               USIM_WRITEREG(usim->base, USIM_STAT, STATNOCARD, 1);
> +               USIM_WRITEREG(usim->base, USIM_CONF1, BYPASS_HW_AUTO, 0);
> +       } else {
> +               USIM_WRITEREG(usim->base, USIM_STAT, STATNOCARD, 0);
> +               USIM_WRITEREG(usim->base, USIM_CONF1, BYPASS_HW_AUTO, 1);
> +       }
> +
> +       /* Set default card type as EMV, Force SIO to low level */
> +       reg = readl(usim->base + USIM_CONF1);
> +       reg = USIM_SETFIELD(reg, USIM_CONF1, EMV_CONF, 1);
> +       reg = USIM_SETFIELD(reg, USIM_CONF1, CONFSIOLOW, 1);
> +       writel(reg, usim->base + USIM_CONF1);
> +
> +       /* Set parity level to 1, auto resent to 2 on parity error,  */
> +       reg = readl(usim->base + USIM_CONF2);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, NACKING_EN, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CARD_POLARITY, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFEDC, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFPROTOCOL, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, ATR_ASYN_BYPASS, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKMODE, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, PAR_ERR_LEVEL, 1);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFRESENT, 2);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, PUT_ERR_IN_FIFO, 1);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFLRCCHECK, 2);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFCHKPAR, 1);
> +
> +       if (usim->phy_present) {
> +               reg = USIM_SETFIELD(reg, USIM_CONF2, HW_DEACTIV_EN, 0);
> +               reg = USIM_SETFIELD(reg, USIM_CONF2, DEBOUNCE_EN, 0);
> +       } else {
> +               reg = USIM_SETFIELD(reg, USIM_CONF2, HW_DEACTIV_EN, 1);
> +       }
> +
> +       writel(reg, usim->base + USIM_CONF2);
> +
> +       /* Reset Tx FIFO Pointer */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
> +
> +       /* Reset Rx FIFO Pointer */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
> +
> +       /* Configure FIFO settings */
> +       /* Set Tx and Rx trigger to 1 byte */
> +       reg = readl(usim->base + USIM_FIFOS);
> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, FIFO_TX_TRIGGER, 0);
> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, FIFO_RX_TRIGGER, 0);
> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, RXDMA_TYPE, 0x3);
> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, DMA_MODE, 0x0);
> +       writel(reg, usim->base + USIM_FIFOS);
> +
> +       /* Enable FIFO access */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_ENABLE, 1);
> +
> +       /* Use HW mode for ETU calculation and set FI = 372 and DI = 1 */
> +       reg = readl(usim->base + USIM_CONF5);
> +       reg = USIM_SETFIELD(reg, USIM_CONF5, FI, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF5, DI, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
> +       writel(reg, usim->base + USIM_CONF5);
> +
> +       /* Configure CONF6 settings */
> +       reg = readl(usim->base + USIM_CONF6);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, VCC_BYPASS, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, RST_BYPASS, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, RST_POLARITY, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 1);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, MODE, USIM_CONF6_MODE_FREEZE);
> +       writel(reg, usim->base + USIM_CONF6);
> +
> +       /* Clear all bits in IO_DIRECT register */
> +       writel(0, usim->base + USIM_IO_DIRECT);
> +
> +       /* Disable legacy bypass mode */
> +       USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 0);
> +
> +       /* Enable required interrupts */
> +       reg = readl(usim->base + USIM_IRQENABLE);
> +       writel(reg, usim->base + USIM_IRQENABLE);
> +
> +       /* Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
> +        * gets disable
> +        */
> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 1);
> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
> +                     USIM_ATR_TIMEOUT_EMV);
> +
> +       /* Set STOP_RX_TIMEOUT */
> +       /* Set STOP_RESEND_FAILURE */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RX_TIMEOUT, 1);
> +       USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 1);
> +
> +       /* set smartcard clock */
> +       usim_set_smartcardclock(usim, usim->slot_ctx[usim->slot].clock);
> +
> +       return 0;
> +}
> +
> +static int usim_set_voltage(struct usim *usim, u32 voltage)
> +{
> +       int ret = 0;
> +       struct sc_phy *phy = usim->phy;
> +       /*
> +        * voltage = 0 for 5V,
> +        * voltage = 1 for 3V,
> +        * voltage = 2 for 1.8V,
> +        */
> +       if (voltage > 3)
> +               return -EINVAL;
> +       if (usim->phy_present) {
> +               ret = phy->set_config(phy, usim->slot,
> +                               SC_PHY_CARD_SUPPLY_VOLTAGE, voltage);
> +       }
> +       usim->slot_ctx[usim->slot].supply = voltage;
> +       return ret;
> +}
> +
> +static int usim_set_smartcardclock(struct usim *usim, u32 clock)
> +{
> +       int clkdiv;
> +       int clkmode;
> +       int reg = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       switch (clock) {
> +       case USIM_SMARTCART_CLOCK_3_3MHZ:
> +               clkmode = USIM_CONFSCLKMODE_HF;
> +               clkdiv  = 3;
> +               break;
> +
> +       case USIM_SMARTCART_CLOCK_4MHZ:
> +               clkmode = USIM_CONFSCLKMODE_HF;
> +               clkdiv  = 2;
> +               break;
> +
> +       case USIM_SMARTCART_CLOCK_5MHZ:
> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
> +               clkdiv  = 3;
> +               break;
> +
> +       case USIM_SMARTCART_CLOCK_6_6MHZ:
> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
> +               clkdiv  = 2;
> +               break;
> +
> +       case USIM_SMARTCART_CLOCK_10MHZ:
> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
> +               clkdiv  = 1;
> +               break;
> +
> +       case USIM_SMARTCART_CLOCK_20MHZ:
> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
> +               clkdiv  = 0;
> +               break;
> +
> +       default:
> +               dev_err(usim->dev, "Unsupported Clock configuration for smartcard\n");
> +               return -EINVAL;
> +               break;
> +       }
> +
> +       /* Set default card type as EMV, Force SIO to low level */
> +       reg = readl(usim->base + USIM_CONF2);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKMODE, clkmode);
> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, clkdiv);
> +       writel(reg, usim->base + USIM_CONF2);
> +
> +       /* setting phy division to zero, as USIM samples smartcard clk line and
> +        * put the data in USIM fifo. Phy supply the clock to smartcard wihtout
> +        * furhter division
> +        */
> +       if (usim->phy_present)
> +               phy->set_config(phy, usim->slot, SC_PHY_CLKDIV, 0);
> +
> +       usim->slot_ctx[usim->slot].clock = clock;
> +       return 0;
> +}
> +
> +static int usim_set_etu(struct usim *usim, u32 fi, u32 di)
> +{
> +       USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
> +       USIM_WRITEREG(usim->base, USIM_CONF5, FI, fi);
> +       USIM_WRITEREG(usim->base, USIM_CONF5, DI, di);
> +       return 0;
> +}
> +
> +static int usim_set_rxparitycount(struct usim *usim, u32 rxcount)
> +{
> +       if (rxcount > USIM_MAX_PARITY_RETRIES)
> +               return -EINVAL;
> +
> +       /* Program fields required for RX retry in USIM IP */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, PAR_ERR_LEVEL, rxcount);
> +
> +       /* Enable rx parity check */
> +       if (rxcount > 0) {
> +               USIM_WRITEREG(usim->base, USIM_CONF2, CONFCHKPAR, 1);
> +               usim_irq_enable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
> +       } else {
> +               usim_irq_disable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
> +       }
> +       return 0;
> +}
> +
> +static int usim_set_txretrycount(struct usim *usim, u32 txcount)
> +{
> +       if (txcount > USIM_MAX_PARITY_RETRIES)
> +               return -EINVAL;
> +
> +       USIM_WRITEREG(usim->base, USIM_CONF2, CONFRESENT, txcount);
> +       if (txcount > 0)
> +               usim_irq_enable(usim->base, USIM_IRQ_RESENT);
> +       else
> +               usim_irq_disable(usim->base, USIM_IRQ_RESENT);
> +
> +       return 0;
> +}
> +
> +static int usim_set_c4(struct usim *usim, int state)
> +{
> +       int ret = 0;
> +       struct sc_phy *phy = usim->phy;
> +       if (usim->phy_present)
> +               ret = phy->set_config(phy, usim->slot, SC_PHY_PIN_C4, state);
> +       else
> +                USIM_WRITEREG(usim->base, USIM_IO_DIRECT, C4, state);
> +       return ret;
> +}
> +
> +static int usim_set_c8(struct usim *usim, int state)
> +{
> +       int ret = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       if (usim->phy_present)
> +               ret = phy->set_config(phy, usim->slot, SC_PHY_PIN_C8, state);
> +       return ret;
> +}
> +static int usim_get_version(struct usim *usim)
> +{
> +       int version = 0x0;
> +
> +       /* last 16 bytes represents controller version
> +        * and first 16 bytes represents phy version (if connected)
> +        */
> +       version = USIM_READREG(usim->base, USIM_REVISION, REV);
> +       if (usim->phy_present)
> +               version |= ((usim->phy->get_config(usim->phy, 0,
> +                                       SC_PHY_VERSION)) << 0x10);
> +       return version;
> +}
> +static int usim_init_emvusercard(struct usim *usim)
> +{
> +       int ret = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, DMA_MODE, 0);
> +
> +       usim_set_etu(usim, 0, 0);
> +
> +       if (usim_set_txretrycount(usim, 5) != 0)
> +               return -EINVAL;
> +
> +       if (usim_set_rxparitycount(usim, 5) != 0)
> +               return -EINVAL;
> +
> +       usim_set_c4(usim, 0);
> +       usim_set_c8(usim, 0);
> +
> +       if (usim->phy_present) {
> +               /* Set early ATR and mute ATR in case of phy */
> +               ret = phy->set_config(phy, usim->slot, SC_PHY_ATR_EARLY_TIME,
> +                               USIM_EMV_ATR_EARLY_TO);
> +               if (ret != 0)
> +                       return ret;
> +
> +               ret = phy->set_config(phy, usim->slot, SC_PHY_ATR_MUTE_TIME,
> +                               USIM_EMV_ATR_MUTE_TO);
> +               if (ret != 0)
> +                       return ret;
> +
> +               /* enable user slot */
> +               ret = phy->set_config(phy, usim->slot, SC_PHY_IO, 1);
> +               if (ret != 0)
> +                       return ret;
> +       }
> +       /* set cwt,wwt,cgt */
> +       USIM_WRITEREG(usim->base, USIM_WWT, WWT, USIM_EMV_WWT);
> +       USIM_WRITEREG(usim->base, USIM_CWT, CWT, USIM_EMV_WWT - 22);
> +       USIM_WRITEREG(usim->base, USIM_CGT, CGT, USIM_EMV_CGT);
> +
> +       return 0;
> +}
> +
> +static int usim_warmreset(struct usim *usim)
> +{
> +       int ret = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       /* reset ATR wait flag */
> +       usim->atrdone = 0;
> +
> +       usim->slot_ctx[usim->slot].atr_length = 0;
> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
> +       usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
> +
> +       /* reset FIFO pointer */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
> +
> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x1);
> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x0);
> +
> +       /* Do store bytes with parity error in Rx FIFO */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0x1);
> +
> +       usim_irq_disable(usim->base, (USIM_IRQ_TX | USIM_IRQ_EOB));
> +
> +       usim->slot_ctx[usim->slot].state = USIM_MODE_ATR;
> +
> +       /* warm reset the card */
> +       if (usim->phy_present) {
> +               ret = phy->warm_reset(phy, usim->slot);
> +               if (ret != 0)
> +                       return ret;
> +       } else {
> +               /* warm reset using USIM */
> +               USIM_WRITEREG(usim->base, USIM_CMD, CMD_WARM_RST, 0x1);
> +       }
> +
> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_ATR);
> +
> +       return 0;
> +}
> +static int usim_set_cardmode(struct usim *usim, int slot, int card_mode)
> +{
> +       int val = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       if (card_mode !=  usim->slot_ctx[slot].card_mode) {
> +               /* deactivate current card before changing the
> +                * mode of smart card
> +                */
> +               usim_deactivate_card(usim);
> +       } else {
> +               dev_dbg(usim->dev, "mode is same as previous, no action!!");
> +               return 0;
> +       }
> +
> +       /* set card mode */
> +       switch (card_mode) {
> +       case USIM_CARD_MODE_ASYNC:
> +               val = SC_PHY_ASYNC;
> +               break;
> +
> +       case USIM_CARD_MODE_SYNC_TYPE1:
> +               val = SC_PHY_SYNC_TYPE1;
> +               break;
> +
> +       case USIM_CARD_MODE_SYNC_TYPE2:
> +               val = SC_PHY_SYNC_TYPE2;
> +               break;
> +
> +       case USIM_CARD_MODE_SYNC_OTHER:
> +               val = SC_PHY_SYNC;
> +               break;
> +
> +       default:
> +               dev_err(usim->dev, "Invalid card mode");
> +               return -EINVAL;
> +               break;
> +       }
> +       if (usim->phy_present == USIM_PHY_PRESENT)
> +               phy->set_config(usim->phy, slot, SC_PHY_CARD_MODE, val);
> +       usim->slot_ctx[slot].card_mode = card_mode;
> +       return 0;
> +}
> +
> +static int usim_activate_synccard(struct usim *usim)
> +{
> +       int ret = 0;
> +       int reg = 0;

These don't need to be initialized and can be 1 line.

> +       struct sc_phy *phy = usim->phy;
> +       if (usim->phy_present != USIM_PHY_PRESENT) {
> +               dev_err(usim->dev, "Sync card w/o phy is not supported");
> +               return -EPERM;
> +       }
> +
> +       /* Enable legacy bypass mode */
> +       USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 1);
> +
> +       /* set all lines to state L */
> +       writel(0x0, usim->base + USIM_IO_DIRECT);
> +
> +       /* configure h/w control mode for select slot */
> +       reg = readl(usim->base + USIM_CONF6);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 1);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 1);
> +       /* lets put i/o line in SW ctrl */
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, IO_BYPASS, 0x3);
> +       writel(reg, usim->base + USIM_CONF6);
> +
> +       /* activate the card */
> +       ret = phy->activate_card(phy, usim->slot);
> +       return ret;
> +}
> +
> +static int usim_activate_card(struct usim *usim)
> +{
> +       int ret = 0;
> +       int reg = 0;
> +       struct sc_phy *phy = usim->phy;
> +       int mode = usim->slot_ctx[usim->slot].card_mode;
> +
> +       usim->atrdone = 0;
> +       usim->slot_ctx[usim->slot].atr_length = 0;
> +
> +       /* set card mode */
> +       usim_set_cardmode(usim, usim->slot, mode);
> +
> +       if (usim->slot_ctx[usim->slot].card_mode != USIM_CARD_MODE_ASYNC) {
> +               /* synchronous card activation */
> +               ret = usim_activate_synccard(usim);
> +               return ret;
> +       }
> +
> +       if (usim->slot_ctx[usim->slot].emv)
> +               usim_init_emvusercard(usim);
> +
> +       /* disable legacy bypass mode */
> +       USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 0);
> +
> +       /* configure h/w control mode for select slot */
> +       reg = readl(usim->base + USIM_CONF6);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 0);
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 0);
> +       /* lets put i/o line in h/w ctrl */
> +       reg = USIM_SETFIELD(reg, USIM_CONF6, IO_BYPASS, 0x2);
> +       writel(reg, usim->base + USIM_CONF6);
> +
> +       USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, 1);
> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER, 0x103);
> +
> +       /* RXDMA_TYPE = 0x1 - USIM_RXFIFO_BYTECNT value is ignored */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, RXDMA_TYPE, 0x1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_ENABLE, 0x1);
> +
> +       /* Do store bytes with parity error in Rx FIFO */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0x1);
> +       usim_irq_disable(usim->base, (USIM_IRQ_TX | USIM_IRQ_EOB));
> +
> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x1);
> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x0);
> +
> +       /*
> +        * Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
> +        * gets disable. EMVCo Test case ref#1703_21/22
> +        */
> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 0x1);
> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
> +                     USIM_ATR_TIMEOUT_EMV);
> +       USIM_WRITEREG(usim->base, USIM_CMD, MODULE_CLK_EN, 0x1);
> +
> +       usim->slot_ctx[usim->slot].state = USIM_MODE_ATR;
> +
> +       /* set smartcard clock */
> +       usim_set_smartcardclock(usim, usim->slot_ctx[usim->slot].clock);
> +
> +       /* Activate card */
> +       if (usim->phy_present) {
> +               usim_irq_disable(usim->base, USIM_IRQ_TX|USIM_IRQ_ATR_START);
> +               usim_irq_enable(usim->base, 0xFFFFFFF7);
> +               usim_irq_disable(usim->base, USIM_IRQ_NATR);
> +               usim_irq_enable(usim->base, USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT);
> +               usim_irq_disable(usim->base, USIM_IRQ_TX|USIM_IRQ_ATR_START);
> +
> +               /* do no bypass ATR length timer, also do not
> +                * disturb the bypass setting of other param
> +                */
> +               USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMER_BYPASS, 0x1);
> +
> +               usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
> +
> +               ret = phy->activate_card(phy, usim->slot);
> +               if (ret != 0)
> +                       return ret;
> +       } else {
> +               /* Activate using USIM */
> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 0x0);
> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 0x1);
> +       }
> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_ATR);
> +       return 0;
> +}
> +
> +static int usim_deactivate_card(struct usim *usim)
> +{
> +       int ret = 0;
> +       int cnt = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       /* clear atr buffer */
> +       for (cnt = 0; cnt < USIM_MAX_ATRLENGTH; cnt++)
> +               usim->slot_ctx[usim->slot].atr[cnt] = 0x0;
> +       usim->slot_ctx[usim->slot].atr_length = 0x0;
> +
> +       /* Use USIM IP for deactivation if there is no phy */
> +       if (usim->phy_present == USIM_PHY_PRESENT) {
> +               ret = phy->deactivate_card(phy, usim->slot);
> +               if (ret != 0)
> +                       return ret;
> +       } else {
> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTART, 0x0);
> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 1);
> +       }
> +
> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
> +       USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, 0);
> +
> +       /* Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
> +        * gets disable TC Ref: 1703_21/22
> +        */
> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 1);
> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
> +                     USIM_ATR_TIMEOUT_EMV);
> +
> +       /* stop ATR length timeout */
> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 1);
> +       usim->slot_ctx[usim->slot].state = USIM_MODE_DEACT;
> +       usim->atrdone = 0;
> +
> +       return 0;
> +}
> +
> +static void usim_set_protocol(struct usim *usim, int protocol)
> +{
> +       u32 irq;
> +
> +       /* As per spec, mask all interrupts before switching
> +        * from one protocol to other.
> +        */
> +       usim_irq_get(usim->base, &irq);
> +
> +       /* disable all interrupts */
> +       usim_irq_disable(usim->base, 0xFFFFFFFF);
> +
> +       /* 0 for T=0 and 1 for T=1 protocol */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, CONFPROTOCOL, protocol);
> +       usim->slot_ctx[usim->slot].protocol = protocol;
> +
> +       /* read and clear status */
> +       usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
> +
> +       /* now renable interrupts */
> +       usim_irq_enable(usim->base, irq);
> +       return;
> +}
> +
> +static int usim_get_cardpinlevel(struct usim *usim, int pin, int *level)
> +{
> +       struct sc_phy *phy = usim->phy;
> +       int param = 0;
> +
> +       if (usim->slot_ctx[usim->slot].card_mode == USIM_CARD_MODE_ASYNC) {
> +               dev_err(usim->dev, "Operation not permitted for async mode");
> +               return -EPERM;
> +       }
> +       if (pin == USIM_PARAM_CARD_PIN_IO) {
> +               /* For Rx, RNW:1, OEN:1 */
> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, RNW0, 1);
> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, SIOEN0, 1);
> +               *level = USIM_READREG(usim->base, USIM_IO_DIRECT, SIORX0);
> +               return 0;
> +       }
> +
> +       if (usim->phy_present == USIM_PHY_PRESENT) {
> +               switch (pin) {
> +               case USIM_PARAM_CARD_PIN_VCC:
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_RST:
> +                       param = SC_PHY_PIN_RST;
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_CLK:
> +                       param = SC_PHY_PIN_CLK;
> +                       break;
> +
> +               default:
> +                       dev_err(usim->dev, "Invalid pin");
> +                       return -EINVAL;
> +               }
> +               *level = phy->get_config(phy, usim->slot, param);
> +               return  0;
> +       } else {
> +               switch (pin) {
> +               case USIM_PARAM_CARD_PIN_VCC:
> +                       *level = USIM_READREG(usim->base,
> +                                       USIM_IO_DIRECT, SVCC);
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_RST:
> +                       *level = USIM_READREG(usim->base,
> +                                       USIM_IO_DIRECT, RST);
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_CLK:
> +                       *level = USIM_READREG(usim->base,
> +                                       USIM_IO_DIRECT, SCLK0);
> +                       break;
> +
> +               default:
> +                       dev_err(usim->dev, "Invalid pin");
> +                       return -EINVAL;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int usim_set_cardpinlevel(struct usim *usim, int pin, int level)
> +{
> +       int ret = 0;
> +       int param = 0;
> +       int value = level > 0 ? 1 : 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       if (usim->slot_ctx[usim->slot].card_mode == USIM_CARD_MODE_ASYNC) {
> +               dev_err(usim->dev, "Operation not permitted for async mode");
> +               return -EPERM;
> +       }
> +       if (pin == USIM_PARAM_CARD_PIN_IO) {
> +               /* For Tx: RNW=0; OEN=Tx */
> +               /* Tx line will be followed by OEN line, so setting OEN bit*/
> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, RNW0, 0);
> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, SIOEN0, value);
> +               return 0;
> +       }
> +
> +       if (usim->phy_present == USIM_PHY_PRESENT) {
> +               switch (pin) {
> +               case USIM_PARAM_CARD_PIN_VCC:
> +                       /* will be set by activation or deactivation */
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_RST:
> +                       param = SC_PHY_PIN_RST;
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_CLK:
> +                       param = SC_PHY_PIN_CLK;
> +                       break;
> +
> +               default:
> +                       dev_err(usim->dev, "Invalid pin");
> +                       return -EINVAL;
> +               }


Make this switch a helper function. Same code exists above.

> +               ret = phy->set_config(phy, usim->slot, param, value);
> +               return  ret;
> +       } else {
> +               switch (pin) {
> +               case USIM_PARAM_CARD_PIN_VCC:
> +                       USIM_WRITEREG(usim->base,
> +                                     USIM_IO_DIRECT, SVCC, value);
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_RST:
> +                       USIM_WRITEREG(usim->base,
> +                                     USIM_IO_DIRECT, RST, value);
> +                       break;
> +
> +               case USIM_PARAM_CARD_PIN_CLK:
> +                       USIM_WRITEREG(usim->base,
> +                                     USIM_IO_DIRECT, SCLK0, value);
> +                       break;
> +
> +               default:
> +                       dev_err(usim->dev, "Invalid pin");
> +                       return -EINVAL;
> +               }

Probably something similar can be done here. Perhaps you should have
default phy ops which is built-in. Then you can always just call
phy->set_config.


> +       }
> +       return 0;
> +}
> +static void usim_configure_rx_pio(struct usim *usim)
> +{
> +       /* Reset RX FIFO pointers */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
> +
> +       /* read and clear any pending interrupt status */
> +       usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
> +
> +       /* Enable WWT underflow interupt,
> +        * RX FIFO full interrupt,
> +        * BWT, CWT and parity error level interrupts.
> +        */
> +       usim_irq_enable(usim->base, USIM_IRQ_WT | USIM_IRQ_RXFULL |
> +                               USIM_IRQ_TOB |
> +                               USIM_IRQ_TOC |
> +                               USIM_IRQ_PAR_ERR_LEVEL_REACHED);
> +
> +       /* Lets disable key RX interrupts. We will enable them later
> +        * when we want to start RX
> +        */
> +       usim_irq_disable(usim->base, USIM_IRQ_RX |
> +                       USIM_IRQ_RXDMA_RDY | USIM_IRQ_EOB);
> +
> +       /* We will use only RX FIFO threshold in RX */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, RXDMA_TYPE, 0x1);
> +
> +       if (usim->slot_ctx[usim->slot].protocol == 0) {
> +               /* Set Rx FIFO Threshold to expected recv length
> +                * Subtract 1 from length as HW adds 1 to the trigger
> +                */
> +               USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER,
> +                             usim->slot_ctx[usim->slot].rx_explen - 1);
> +       } else {
> +               /* T=1 protocol */
> +               /* for T1 we should not use parity error level interrupt */
> +               usim_irq_disable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
> +
> +               /* set RX FIFO threshold to MAX_RX_FIFO size.
> +                * We will rely on End-Of-Block interrupt to
> +                * terminate reception in T1
> +                */
> +               USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER,
> +                             USIM_MAX_RX_FIFO_SIZE - 1);
> +       }
> +       return;
> +}
> +
> +static void usim_configure_tx_pio(struct usim *usim)
> +{
> +       /* Make sure TX is stopped first by programming
> +        * TX_BLOCK to zero and disabling TX_BLOCK_DONE
> +        * and USIM_IRQ_TX_BLOCK_REQ interrupts
> +        */
> +       USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, 0);
> +       usim_irq_disable(usim->base, USIM_IRQ_TX_BLOCK_DONE |
> +                                                       USIM_IRQ_TX_BLOCK_REQ);
> +
> +       /* We will use Tx Block length feature so clear TX_EN bit */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, TX_EN, 0);
> +       /* We will not use USIM_TX interrupt for transmit operation */
> +       usim_irq_disable(usim->base, USIM_IRQ_TX);
> +       /* Reset TX FIFO pointers */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
> +
> +       /* Ensure PIO mode is programmed */
> +       USIM_WRITEREG(usim->base, USIM_FIFOS, DMA_MODE, 0);
> +}
> +
> +static int usim_send_data(struct usim *usim, char *txbuf, int len)
> +{
> +       u32 val;
> +       int i;
> +       int ret = 0;
> +
> +       usim->txdone = 0;
> +       usim->rxdone = 0;
> +
> +       if (len == 0) {
> +               dev_dbg(usim->dev, "Error: Invalid Tx length:%d", len);
> +               return -EINVAL;
> +       }
> +
> +       usim->slot_ctx[usim->slot].event = 0;
> +
> +       /* Configure Tx PIO mode patams */
> +       usim_configure_tx_pio(usim);
> +
> +       /* Tx FIFO must be empty after reset */
> +       val = USIM_READREG(usim->base, USIM_FIFOS, FIFOTX_EMPTY);
> +       if (val == 0) {
> +               dev_dbg(usim->dev, "Error: Tx FIFO is not empty");
> +               return -EFAULT;
> +       }
> +
> +       /* write data in Tx FIFO */
> +       for (i = 0; i < len; i++) {
> +               USIM_WRITEREG(usim->base, USIM_DTX, DTX, txbuf[i]);
> +               dev_dbg(usim->dev, "txbyte %d = %x\n", i, txbuf[i]);
> +       }
> +
> +       /* Finally re-enable TX_BLOCK_xxx interrupts and clear RX interrupts */
> +       usim_irq_enable(usim->base, USIM_IRQ_TX_BLOCK_DONE |
> +                                               USIM_IRQ_TX_BLOCK_REQ);
> +
> +       /* For T=0, stop re-tranmission after resend failure */
> +       if (usim->slot_ctx[usim->slot].protocol == 0) {
> +               USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 0);
> +               USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 1);
> +       }
> +
> +       /* Do not store bytes with parity error in Rx FIFO */
> +       USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0);
> +
> +       usim_irq_enable(usim->base, USIM_IRQ_TOC);
> +
> +       if (usim->phy_present)
> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_TXRX);
> +       else
> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_LEGACY);
> +
> +       usim->slot_ctx[usim->slot].state = USIM_MODE_TXRX;
> +
> +       /* Configure Rx settings before performing a Tx
> +        * As soon as we are done with Tx, card will send
> +        * data, which we should be ready to capture
> +        */
> +       usim_configure_rx_pio(usim);
> +       /* Start TX operation - program TX_BLOCK register to length
> +        * of the TX buffer to start the TX operation.
> +        */
> +       USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, len);
> +
> +       /* We need to block the caller here */
> +       ret = wait_event_interruptible(tx_wait, (usim->txdone == 1));
> +       dev_dbg(usim->dev, "Tx WAIT OVER\n");
> +       if (usim->slot_ctx[usim->slot].event == USIM_EVENT_TIMEOUT)
> +               usim_send_signal(usim, USIM_EVENT_TIMEOUT);
> +
> +       return ret;
> +}
> +
> +static int usim_set_config(struct usim *usim, struct usim_config *param)
> +{
> +       u32 ret = 0;
> +       dev_dbg(usim->dev, "param:%d, value:%d\n", param->attr, param->value);
> +
> +       switch (param->attr) {
> +       case USIM_PARAM_CWT:
> +               USIM_WRITEREG(usim->base, USIM_CWT, CWT, param->value);
> +               break;
> +
> +       case USIM_PARAM_WWT:
> +               USIM_WRITEREG(usim->base, USIM_WWT, WWT, param->value);
> +               break;
> +
> +       case USIM_PARAM_CGT:
> +               USIM_WRITEREG(usim->base, USIM_CGT, CGT, param->value);
> +               break;
> +
> +       case USIM_PARAM_BWT:
> +               USIM_WRITEREG(usim->base, USIM_BWT, BWT, param->value);
> +               break;
> +
> +       case USIM_PARAM_EDCTYPE:
> +               /* 0 = LRC check, 1 = CRC check */
> +               USIM_WRITEREG(usim->base, USIM_CONF2, CONFEDC, param->value);
> +               break;
> +
> +       case USIM_PARAM_LRCCHECK:
> +               /* 0 = No LRC check, 1 = LRC check */
> +               USIM_WRITEREG(usim->base, USIM_CONF2, CONFLRCCHECK,
> +                             param->value);
> +               break;
> +
> +       case USIM_PARAM_C4:
> +               usim_set_c4(usim, param->value);
> +               break;
> +
> +       case USIM_PARAM_C8:
> +               usim_set_c8(usim, param->value);
> +               break;
> +
> +       case USIM_PARAM_PROTOCOL:
> +               /* 0 for T=0 and 1 for T=1 */
> +               usim_set_protocol(usim, param->value);
> +               break;
> +
> +       case USIM_PARAM_VOLTAGE:
> +               ret = usim_set_voltage(usim, param->value);
> +               break;
> +
> +       case USIM_PARAM_EMV:
> +               USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, param->value);
> +               if (param->value)
> +                       usim->slot_ctx[usim->slot].emv = true;
> +               else
> +                       usim->slot_ctx[usim->slot].emv = false;
> +               break;
> +
> +       case USIM_PARAM_FI:
> +               USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
> +               USIM_WRITEREG(usim->base, USIM_CONF5, FI, param->value);
> +               break;
> +
> +       case USIM_PARAM_DI:
> +               USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
> +               USIM_WRITEREG(usim->base, USIM_CONF5, DI, param->value);
> +               break;
> +
> +       case USIM_PARAM_CODING_CONV:
> +               USIM_WRITEREG(usim->base, USIM_STAT, CONFCODCONV, param->value);
> +               break;
> +
> +       case USIM_PARAM_CLOCK_STOP:
> +               USIM_WRITEREG(usim->base, USIM_CMD, CMD_CLOCK_STOP,
> +                             param->value);
> +               break;
> +
> +       case USIM_PARAM_SMARTCARD_CLOCK:
> +               ret = usim_set_smartcardclock(usim, param->value);
> +               break;
> +
> +       case USIM_PARAM_SMARTCARD_MODE:
> +               ret = usim_set_cardmode(usim, usim->slot, param->value);
> +               break;
> +
> +       case USIM_PARAM_CARD_PIN_VCC:
> +       case USIM_PARAM_CARD_PIN_RST:
> +       case USIM_PARAM_CARD_PIN_CLK:
> +       case USIM_PARAM_CARD_PIN_IO:
> +               ret = usim_set_cardpinlevel(usim, param->attr, param->value);
> +               break;
> +
> +       default:
> +               ret = -EINVAL;
> +               break;
> +       }
> +       return ret;
> +}
> +static void usim_get_syncatr(struct usim *usim)
> +{
> +       int ret = 0;
> +       struct sc_phy *phy = usim->phy;
> +
> +       /* Max ATR bytes for sync card is 4 */
> +       usim->slot_ctx[usim->slot].atr_length = 0x4;
> +       if (usim->phy_present != USIM_PHY_PRESENT) {
> +               dev_err(usim->dev, "Sync card w/o phy is not supported");
> +               return;
> +       }
> +       /* get sync ATR */
> +       if (phy->get_syncatr == NULL)
> +               return;
> +       ret = phy->get_syncatr(phy,
> +                       usim->slot,
> +                       usim->slot_ctx[usim->slot].atr_length,
> +                       usim->slot_ctx[usim->slot].atr);
> +       return;
> +}
> +
> +static int usim_get_config(struct usim *usim, struct usim_config *param)
> +{
> +       u32 ret = 0;
> +       dev_dbg(usim->dev, "param:%d, value:%d\n", param->attr, param->value);
> +
> +       switch (param->attr) {
> +       case USIM_PARAM_CWT:
> +               param->value = USIM_READREG(usim->base, USIM_CWT, CWT);
> +               break;
> +
> +       case USIM_PARAM_WWT:
> +               param->value = USIM_READREG(usim->base, USIM_WWT, WWT);
> +               break;
> +
> +       case USIM_PARAM_CGT:
> +               param->value = USIM_READREG(usim->base, USIM_CGT, CGT);
> +               break;
> +
> +       case USIM_PARAM_BWT:
> +               param->value = USIM_READREG(usim->base, USIM_BWT, BWT);
> +               break;
> +
> +       case USIM_PARAM_EDCTYPE:
> +               param->value = USIM_READREG(usim->base, USIM_CONF2, CONFEDC);
> +               break;
> +
> +       case USIM_PARAM_LRCCHECK:
> +               param->value = USIM_READREG(usim->base, USIM_CONF2,
> +                               CONFLRCCHECK);
> +               break;
> +
> +       case USIM_PARAM_PROTOCOL:
> +               /* 0 for T=0 and 1 for T=1 */
> +               param->value = USIM_READREG(usim->base, USIM_CONF2,
> +                               CONFPROTOCOL);
> +               break;
> +
> +       case USIM_PARAM_VOLTAGE:
> +               param->value = usim->slot_ctx[usim->slot].supply;
> +               break;
> +
> +       case USIM_PARAM_EMV:
> +               param->value = USIM_READREG(usim->base, USIM_CONF1, EMV_CONF);
> +               break;
> +
> +       case USIM_PARAM_FI:
> +               param->value = USIM_READREG(usim->base, USIM_CONF5, FI);
> +               break;
> +
> +       case USIM_PARAM_DI:
> +               param->value = USIM_READREG(usim->base, USIM_CONF5, DI);
> +               break;
> +
> +       case USIM_PARAM_CODING_CONV:
> +               param->value = USIM_READREG(usim->base, USIM_STAT, CONFCODCONV);
> +               break;
> +
> +       case USIM_PARAM_CLOCK_STOP:
> +               param->value = USIM_READREG(usim->base, USIM_CMD,
> +                                           CMD_CLOCK_STOP);
> +               break;
> +
> +       case USIM_PARAM_SMARTCARD_CLOCK:
> +               param->value = usim->slot_ctx[usim->slot].clock;
> +               break;
> +
> +       case USIM_PARAM_SMARTCARD_MODE:
> +               param->value = usim->slot_ctx[usim->slot].card_mode;
> +               break;
> +
> +       case USIM_PARAM_CARD_PIN_VCC:
> +       case USIM_PARAM_CARD_PIN_RST:
> +       case USIM_PARAM_CARD_PIN_CLK:
> +       case USIM_PARAM_CARD_PIN_IO:
> +               ret = usim_get_cardpinlevel(usim, param->attr, &param->value);
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               break;
> +       }
> +       return ret;
> +}
> +
> +static long usim_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> +       struct usim *usim = file->private_data;
> +       struct usim_data data;
> +       struct usim_config param;
> +
> +       int ret         = 0;
> +       int cnt         = 0;
> +       int version     = 0;
> +       int u_pid       = 0;
> +       int present     = 0;
> +       unsigned long atr_timeout = 0;
> +
> +       if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
> +               return -ENXIO;
> +
> +       switch (cmd) {
> +       case USIM_IOCTL_GET_PROVIDER_VERSION:
> +               dev_dbg(usim->dev, "IOCTL: GET PROVIDER VERSION\n");
> +               version = usim_get_version(usim);
> +               ret = copy_to_user((unsigned int *)arg, &version,
> +                               sizeof(unsigned int));
> +               if (ret != 0)
> +                       ret = -EFAULT;
> +               break;
> +
> +       case USIM_IOCTL_ACTIVATE_CARD:
> +               dev_dbg(usim->dev, "IOCTL: ACTIVATE CARD\n");
> +               if (usim->phy_present) {
> +                       present = usim->phy->get_config(usim->phy, usim->slot,
> +                                                       SC_PHY_CARD_PRESENCE);
> +                       if (present)
> +                               ret = usim_activate_card(usim);
> +                       else
> +                               ret = -EFAULT;
> +               }
> +               break;
> +
> +       case USIM_IOCTL_DEACTIVATE_CARD:
> +               dev_dbg(usim->dev, "IOCTL: DEACTIVATE CARD\n");
> +               ret = usim_deactivate_card(usim);
> +               break;
> +
> +       case USIM_IOCTL_WARM_RESET:
> +               dev_dbg(usim->dev, "IOCTL: WARM RESET\n");
> +               ret = usim_warmreset(usim);
> +               break;
> +
> +       case USIM_IOCTL_GET_ATR:
> +               dev_dbg(usim->dev, "IOCTL: GET ATR\n");
> +               /* waiting for max ATR response timeout */
> +               atr_timeout = usecs_to_jiffies(MAX_ATR_WAITTIME_US);
> +               dev_dbg(usim->dev,
> +                       "GET_ATR:atr timeout, us:%d, jiffies:%ld",
> +                       MAX_ATR_WAITTIME_US, atr_timeout);
> +               wait_event_timeout(atr_wait, (usim->atrdone == 1), atr_timeout);
> +               if (usim->slot_ctx[usim->slot].card_mode !=
> +                               USIM_CARD_MODE_ASYNC) {
> +                       usim_get_syncatr(usim);
> +               }
> +               ret = copy_to_user((char __user *)arg,
> +                                       usim->slot_ctx[usim->slot].atr,
> +                                       usim->slot_ctx[usim->slot].atr_length);
> +               if (ret != 0)
> +                       ret = -EFAULT;
> +               else
> +                       ret = usim->slot_ctx[usim->slot].atr_length;
> +               break;
> +
> +       case USIM_IOCTL_SEND_DATA:
> +               dev_dbg(usim->dev, "IOCTL: SEND DATA\n");
> +               ret = copy_from_user(&data, (struct usim_data *)arg,
> +                                               sizeof(struct usim_data));
> +               if (ret != 0)
> +                       return -EFAULT;
> +
> +               usim->slot = data.slot;
> +               usim->slot_ctx[usim->slot].rx_explen = data.rxexplen;
> +               usim->slot_ctx[usim->slot].rx_counter = 0;
> +               for (cnt = 0; cnt < data.txlen; cnt++)
> +                       dev_dbg(usim->dev, "apdu[%d] = %x\n", cnt,
> +                               data.apdu[cnt]);
> +               ret = usim_send_data(usim, &data.apdu[0], data.txlen);
> +               break;
> +
> +       case USIM_IOCTL_SET_CONFIG:
> +               dev_dbg(usim->dev, "IOCTL: SET CONFIG\n");
> +               ret = copy_from_user(&param, (struct usim_config *)arg,
> +                               sizeof(struct usim_config));
> +               if (ret != 0)
> +                       return -EFAULT;
> +
> +               usim_set_config(usim, &param);
> +               break;
> +
> +       case USIM_IOCTL_GET_CONFIG:
> +               dev_dbg(usim->dev, "IOCTL: GET CONFIG\n");
> +               ret = copy_from_user(&param, (struct usim_config *)arg,
> +                               sizeof(struct usim_config));
> +               if (ret != 0)
> +                       return -EFAULT;
> +
> +               usim_get_config(usim, &param);
> +               ret = copy_to_user((struct usim_config *)arg, &param,
> +                               sizeof(struct usim_config));
> +               if (ret != 0)
> +                       ret = -EFAULT;
> +               break;
> +
> +       case USIM_IOCTL_GET_CARD_PRESENCE:
> +               dev_dbg(usim->dev, "IOCTL: CARD PRESENCE\n");
> +               if (usim->phy_present) {
> +                       present = usim->phy->get_config(usim->phy, usim->slot,
> +                                       SC_PHY_CARD_PRESENCE);
> +                       ret = copy_to_user((unsigned int *)arg, &present,
> +                                       sizeof(unsigned int));
> +                       if (ret != 0)
> +                               ret = -EFAULT;
> +               }
> +               break;
> +
> +       case USIM_IOCTL_REGISTER_PID:
> +               dev_dbg(usim->dev, "IOCTL: USIM_IOCTL_REGISTER_PID");
> +               ret = copy_from_user(&u_pid, (int *)arg, sizeof(int));
> +               if (ret != 0)
> +                       return -EFAULT;
> +               usim->user_pid = u_pid;
> +               break;
> +       }
> +       return ret;
> +}
> +
> +static ssize_t usim_read(struct file *file, char *user_buf,
> +               size_t count, loff_t *ppos)
> +{
> +       struct usim *usim = file->private_data;
> +       if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
> +               return -ENXIO;
> +
> +       wait_event_interruptible(rx_wait, (usim->rxdone == 1));
> +       dev_dbg(usim->dev, "RX WAIT over\n");
> +
> +       /* check for timeout and send signal if any */
> +       if (usim->slot_ctx[usim->slot].event == USIM_EVENT_TIMEOUT)
> +               usim_send_signal(usim, USIM_EVENT_TIMEOUT);
> +
> +       if (copy_to_user(user_buf, usim->slot_ctx[usim->slot].rxbuf,
> +                        usim->slot_ctx[usim->slot].rx_counter)) {
> +               dev_err(usim->dev, "Copy failed\n");
> +               return -EFAULT;
> +       }
> +       *ppos = usim->slot_ctx[usim->slot].rx_counter;
> +       dev_dbg(usim->dev, "Card response returning %d bytes\n",
> +               usim->slot_ctx[usim->slot].rx_counter);
> +
> +       return usim->slot_ctx[usim->slot].rx_counter;
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +
> +#define DUMP_REG(r) seq_printf(s, "%-25s: %08x\n", #r, readl(usim->base + r));
> +
> +static int usim_regdump_show(struct seq_file *s, void *unused)
> +{

devmem2 will not work for this purpose?

> +       struct usim     *usim = s->private;
> +
> +       seq_puts(s, "USIM Register Dump\n");
> +
> +       DUMP_REG(USIM_REVISION);
> +       DUMP_REG(USIM_IDENT);
> +       DUMP_REG(USIM_SYSCONFIG);
> +       DUMP_REG(USIM_SYSSTATUS);
> +       DUMP_REG(USIM_IRQSTATUS);
> +       DUMP_REG(USIM_IRQENABLE);
> +       DUMP_REG(USIM_WAKEUPEN);
> +       DUMP_REG(USIM_CMD);
> +       DUMP_REG(USIM_STAT);
> +       DUMP_REG(USIM_CONF1);
> +       DUMP_REG(USIM_CONF2);
> +       DUMP_REG(USIM_CONF3);
> +       DUMP_REG(USIM_DRX);
> +       DUMP_REG(USIM_DTX);
> +       DUMP_REG(USIM_FIFOS);
> +       DUMP_REG(USIM_CGT);
> +       DUMP_REG(USIM_BWT);
> +       DUMP_REG(USIM_DEBUG);
> +       DUMP_REG(USIM_CONF_SAM1_DIV);
> +       DUMP_REG(USIM_CONF4);
> +       DUMP_REG(USIM_ATR_CLK_PRD_NBS);
> +       DUMP_REG(USIM_CONF_ETU_DIV);
> +       DUMP_REG(USIM_CONF5);
> +       DUMP_REG(USIM_TC_GUARD_TIME_ADD);
> +       DUMP_REG(USIM_RXFIFO_LEVEL);
> +       DUMP_REG(USIM_RXFIFO_BYTECNT);
> +       DUMP_REG(USIM_WWT);
> +       DUMP_REG(USIM_CONF6);
> +       DUMP_REG(USIM_IO_DIRECT);
> +       DUMP_REG(USIM_TX_BLOCK);
> +
> +       return 0;
> +}
> +
> +static int usim_regdump_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, usim_regdump_show, inode->i_private);
> +}
> +
> +static const struct file_operations usim_regdump_fops = {
> +       .open           = usim_regdump_open,
> +       .read           = seq_read,
> +       .llseek         = seq_lseek,
> +       .release        = single_release,
> +};
> +
> +static int usim_init_debugfs(struct usim *usim)
> +{
> +       int ret;
> +       struct dentry   *root;
> +       struct dentry   *file;
> +
> +       root = debugfs_create_dir("usim", NULL);
> +       if (!root) {
> +               ret = -ENOMEM;
> +               goto err0;
> +       }
> +
> +       file = debugfs_create_file("regdump", S_IRUGO, root, usim,
> +                                                       &usim_regdump_fops);
> +       if (!file) {
> +               ret = -ENOMEM;
> +               goto err1;
> +       }
> +
> +       usim->debugfs_root = root;
> +
> +       return 0;
> +err1:
> +       debugfs_remove_recursive(root);
> +err0:
> +       return ret;
> +}
> +#endif
> +
> +static int usim_pm_init(struct usim *usim)
> +{
> +       int ret = 0;
> +
> +       usim->usim0_fck  = clk_get(usim->dev, "usim0_fck");
> +       if (IS_ERR(usim->usim0_fck)) {
> +               ret = PTR_ERR(usim->usim0_fck);
> +               dev_err(usim->dev, "usim0_fck failed error:%d\n", ret);
> +               return -1;
> +       }
> +       usim->dpll_core_m4_ck  = clk_get(usim->dev, "dpll_core_m4_ck");
> +       if (IS_ERR(usim->dpll_core_m4_ck)) {
> +               ret = PTR_ERR(usim->dpll_core_m4_ck);
> +               dev_err(usim->dev, "dpll_core_m4_ck failed error:%d\n", ret);
> +               return -1;
> +       }
> +       ret = clk_set_parent(usim->usim0_fck, usim->dpll_core_m4_ck);
> +       if (ret != 0)
> +               dev_dbg(usim->dev, "clk set  parent failed: %d\n", ret);
> +
> +       usim->usim_dbclk  = clk_get(usim->dev, "usim_dbck");
> +       if (IS_ERR(usim->usim_dbclk)) {
> +               ret = PTR_ERR(usim->usim_dbclk);
> +               dev_err(usim->dev, "usim_dbck failed error:%d\n", ret);
> +               return -1;
> +       }
> +
> +       usim->clkdiv32k_ick  = clk_get(usim->dev, "clkdiv32k_ick");
> +       if (IS_ERR(usim->usim_dbclk)) {
> +               ret = PTR_ERR(usim->clkdiv32k_ick);
> +               dev_err(usim->dev, "clkdiv32k_ick failed error:%d\n", ret);
> +               return -1;
> +       }
> +
> +       ret = clk_set_parent(usim->usim_dbclk, usim->clkdiv32k_ick);
> +       if (ret != 0)
> +               dev_dbg(usim->dev, "usim_dbclk set parent failed: %d\n", ret);
> +
> +       usim->opt_fclk = devm_clk_get(usim->dev, "opt_fck");
> +       if (IS_ERR(usim->opt_fclk)) {
> +               ret = PTR_ERR(usim->opt_fclk);
> +               dev_err(usim->dev, "unable to get fck\n");
> +               return ret;
> +       }
> +
> +       usim->opt_fclk32 = devm_clk_get(usim->dev, "opt_fck32");
> +       if (IS_ERR(usim->opt_fclk32)) {
> +               ret = PTR_ERR(usim->opt_fclk32);
> +               dev_err(usim->dev, "unable to get dbclk\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +static int usim_enable(struct usim *usim)
> +{
> +       int ret = 0;
> +       if (usim->enable == 1)
> +               return 0;
> +
> +       /* enable the clk */
> +       pm_runtime_get_sync(usim->dev);
> +       clk_enable(usim->opt_fclk32);
> +       clk_enable(usim->opt_fclk);
> +
> +       /* usim init */
> +       ret = usim_configure(usim);
> +       if (ret)
> +               return -EIO;
> +
> +       usim->enable = 1;
> +       return 0;
> +}
> +
> +static void usim_disable(struct usim *usim)
> +{
> +       int cnt = 0;
> +
> +       if (usim->enable == 0)
> +               return;
> +
> +       /* reset USIM state for deactivation */
> +       for (cnt = 0; cnt < usim->max_slots; cnt++) {
> +               usim->slot = cnt;
> +               usim_deactivate_card(usim);
> +       }
> +
> +       /* reset default slot and clock */
> +       usim->slot = 0;
> +       usim->slot_ctx[usim->slot].clock = USIM_SMARTCART_CLOCK_5MHZ;
> +
> +       /* shutdown phy */
> +       if (usim->phy_present == USIM_PHY_PRESENT)
> +               usim->phy->set_config(usim->phy, usim->slot, SC_PHY_MODE,
> +                               SC_PHY_SHUTDOWN);
> +       /* disable clk */
> +       clk_disable(usim->opt_fclk32);
> +       clk_disable(usim->opt_fclk);
> +       pm_runtime_put_sync_autosuspend(usim->dev);
> +       usim->enable = 0;
> +       return;
> +}
> +
> +static int usim_open(struct inode *inode, struct file *file)
> +{
> +       int ret = 0;
> +       struct usim *usim = (struct usim *)dev_get_drvdata(usim_dev.parent);
> +
> +       if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
> +               return -ENXIO;
> +
> +       file->private_data = usim;
> +       ret = usim_enable(usim);
> +       if (ret)
> +               return  -ENXIO;
> +
> +       return 0;
> +}
> +
> +static int usim_release(struct inode *inode, struct file *file)
> +{
> +       struct usim *usim = (struct usim *)dev_get_drvdata(usim_dev.parent);
> +
> +       usim_disable(usim);
> +       usim->user_pid = 0;
> +       return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int usim_suspend(struct device *dev)
> +{
> +       /* struct usim *usim = dev_to_usim(dev); */
> +       struct usim *usim = dev_to_usim(dev);
> +       if (usim->atrdone == 1) {
> +               dev_dbg(usim->dev, "card is active state, aborting suspend");
> +               return -EBUSY;
> +       }
> +       usim_disable(usim);
> +       return 0;
> +}
> +
> +static int usim_resume(struct device *dev)
> +{
> +       /* struct usim *usim = dev_to_usim(dev); */
> +       struct usim *usim = dev_to_usim(dev);
> +       usim_enable(usim);
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops usim_pm_ops = {
> +       .suspend = usim_suspend,
> +       .resume = usim_resume,
> +};
> +
> +#define USIM_PM_OPS (&usim_pm_ops)
> +#else
> +#define USIM_PM_OPS NULL
> +#endif
> +
> +static int usim_notify(struct notifier_block *self, unsigned long action, void
> +               *data)
> +{
> +       struct usim *usim = (struct usim *)data;
> +       int event = action & SC_PHY_NOTIFICATION_ACTION_MASK;
> +       int slot = (action & SC_PHY_NOTIFICATION_SLOT_MASK) >>
> +               SC_PHY_NOTIFICATION_SLOT_SHIFT;
> +       int t_slot = 0;
> +
> +       dev_dbg(usim->dev, "%s:action:%ld", __func__, action);
> +       /* if phy is removed using rmmod or by some other mech..
> +          * then put phy state in unknown, at this point usim also required to
> +          * gets removed from the system, if it is inserted as module and
> +          * dependent on phy
> +          */

Why would the phy be removed? A better mechanism than signals and
notifiers is needed here.


> +       if (action == SC_PHY_REMOVED)
> +               usim->phy_present = USIM_PHY_NOT_ATTACHED;
> +
> +       if (event & SC_PHY_CARD_INSERTED)
> +               usim_send_signal(usim, USIM_EVENT_CARD_INSERT);
> +
> +       if (action & SC_PHY_CARD_REMOVED) {
> +               usim_send_signal(usim, USIM_EVENT_CARD_REMOVE);
> +               dev_dbg(usim->dev, "slot is:%d", slot);
> +                /* de-activate USIM & PHY state machine for the slot */
> +               t_slot = usim->slot;
> +               usim->slot = slot;
> +               usim_deactivate_card(usim);
> +               usim->slot = t_slot;
> +       }
> +
> +       if (action & SC_PHY_CARD_OVERHEAT)
> +               usim_send_signal(usim, USIM_EVENT_CARD_OVERHEAT);
> +
> +       if (action & SC_PHY_CARD_ATR_TIMEOUT)
> +               usim_send_signal(usim, USIM_EVENT_TIMEOUT);
> +
> +       if (action & SC_PHY_CARD_SYNC_ACT_COMPLETE) {
> +               usim->atrdone = 1;
> +               wake_up(&atr_wait);
> +       }
> +       return NOTIFY_OK;
> +}
> +
> +static struct notifier_block usim_nb = {
> +                .notifier_call =       usim_notify,
> +};
> +
> +static const struct file_operations usim_fops = {
> +       .owner          = THIS_MODULE,
> +       .read           = usim_read,
> +       .open           = usim_open,
> +       .unlocked_ioctl = usim_ioctl,
> +       .release        = usim_release,
> +};
> +
> +static int usim_probe(struct platform_device *pdev)
> +{
> +       struct device_node *node                = pdev->dev.of_node;
> +       struct device *dev                      = &pdev->dev;
> +
> +       struct usim *usim                       = NULL;
> +       struct device_node *phy_node            = NULL;
> +       struct resource *res                    = NULL;
> +       void __iomem    *base                   = NULL;
> +       const __be32 *parp                      = NULL;
> +       struct i2c_client *phy_i2c              = NULL;
> +
> +       int ret         = 0;
> +       int version     = 0;
> +       int cnt         = 0;
> +       u32 prop        = 0;
> +       int lenp        = 0;

Remove unnecessary initialization.

> +
> +       if (!node) {
> +               dev_err(dev, "device node not found\n");
> +               return -EINVAL;
> +       }
> +
> +       usim = devm_kzalloc(dev, sizeof(*usim), GFP_KERNEL);
> +       if (!usim) {
> +               dev_err(dev, "not enough memory\n");
> +               return -ENOMEM;
> +       }
> +
> +       usim->irq = platform_get_irq(pdev, 0);
> +       if (usim->irq < 0) {
> +               dev_err(dev, "missing IRQ resource\n");
> +               ret = -EINVAL;
> +               goto usim_err_ret;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!res) {
> +               dev_err(dev, "missing memory base resource\n");
> +               ret = -EINVAL;

ENODEV is probably more appropriate.

> +               goto usim_err_ret;
> +       }
> +
> +       base = devm_ioremap_nocache(dev, res->start, resource_size(res));

devm_ioremap_resource

> +       if (!base) {
> +               dev_err(dev, "ioremap failed\n");
> +               ret = -ENOMEM;
> +               goto usim_err_ret;
> +       }
> +
> +       usim->dev = &pdev->dev;
> +       usim->base = base;
> +       usim->max_slots = 1;
> +       usim->phy_present = USIM_PHY_NOT_PRESENT;
> +       usim->enable = 0;
> +
> +       /* default slot will be zero : user card */
> +       usim->slot = 0;
> +
> +       ret = devm_request_irq(dev, usim->irq, usim_interrupt, 0,
> +                       "usim", usim);
> +       if (ret) {
> +               dev_err(dev, "fail request IRQ #%d --> %d\n", usim->irq, ret);
> +               goto usim_err_ret;
> +               return ret;
> +       }
> +
> +       /*
> +        * Populate all the child nodes here...
> +        */
> +       ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
> +
> +       /* get phy details */
> +       parp = of_get_property(node, "phy", &lenp);
> +       if (parp == NULL || lenp != (sizeof(void *))) {
> +               dev_dbg(usim->dev, "parp is null!,no phy");
> +       } else {
> +               /* get phy node */
> +               phy_node = of_find_node_by_phandle(be32_to_cpup(parp));
> +               if (phy_node == NULL) {
> +                       dev_err(usim->dev, "\n phy node is null");
> +                       ret = -EPROBE_DEFER;
> +                       goto usim_err_ret;
> +               }
> +               phy_i2c = of_find_i2c_device_by_node(phy_node);
> +               if (phy_i2c == NULL) {
> +                       dev_err(usim->dev, "\n phy i2c is null");
> +                       ret = -EPROBE_DEFER;
> +                       goto usim_err_ret;
> +               }
> +               /* get phy interface */
> +               usim->phy = (struct sc_phy *)i2c_get_clientdata(phy_i2c);
> +               if (usim->phy == NULL) {
> +                       dev_err(usim->dev, "phy data is null");
> +                       ret = -EPROBE_DEFER;
> +                       goto usim_err_ret;
> +               }
> +               usim->phy_present = USIM_PHY_PRESENT;
> +
> +               ret = of_property_read_u32(node, "phy-slots", &prop);
> +               /* if phy-slot is not declared then assume one phy slot */
> +               usim->max_slots = prop > 0 ? prop : 1;
> +       }
> +
> +       dev_dbg(usim->dev, "usim max slot:%d", usim->max_slots);
> +       /* initialize slot context*/
> +       if (usim->max_slots > USIM_MAX_SLOTS) {
> +               ret = -EINVAL;
> +               goto usim_err_ret;
> +       }
> +
> +       usim->slot_ctx = kmalloc(usim->max_slots *
> +                                sizeof(struct usim_slotcontext), GFP_KERNEL);
> +       if (!usim->slot_ctx)
> +               return -ENOMEM;
> +
> +       for (cnt = 0; cnt < usim->max_slots; cnt++) {
> +               /* default protocol */
> +               usim->slot_ctx[cnt].protocol = 0;
> +               usim->slot_ctx[cnt].emv = true;
> +               usim_set_cardmode(usim, cnt, USIM_CARD_MODE_ASYNC);
> +       }
> +
> +       dev_set_drvdata(dev, usim);
> +       ret = usim_pm_init(usim);
> +       if (ret)
> +               goto usim_err_ret;
> +
> +       /* enable the clock */
> +       pm_runtime_enable(usim->dev);
> +       pm_runtime_set_active(usim->dev);
> +       spin_lock_init(&usim->lock);
> +
> +       usim_dev.minor = MISC_DYNAMIC_MINOR;
> +       usim_dev.name = "usim";
> +       usim_dev.fops = &usim_fops;
> +       usim_dev.parent = &(pdev->dev);
> +
> +       ret = misc_register(&usim_dev);
> +       if (ret) {
> +               pr_err("unable to register a misc device\n");
> +               goto usim_err_reg;
> +       }
> +#ifdef CONFIG_DEBUG_FS
> +       ret = usim_init_debugfs(usim);
> +       if (ret) {
> +               dev_err(dev, "Debugfs init failed\n");
> +               goto usim_err_reg;
> +       }
> +#endif
> +       /* set default ICC clock : 5Mhz */
> +       usim->slot_ctx[usim->slot].clock = USIM_SMARTCART_CLOCK_5MHZ;
> +
> +       /* get the clock & do usim configuration */
> +       usim_enable(usim);
> +       if (ret)
> +               goto usim_err_reg;
> +       dev_info(usim->dev, "usim driver initialized\n");
> +
> +       /* register notifier */
> +       if (usim->phy_present)
> +               usim->phy->register_notify(usim->phy, &usim_nb, (void *)usim);
> +
> +       /* get usim version */
> +       version = usim_get_version(usim);
> +       dev_info(usim->dev, "version is:%0x", version);
> +
> +       usim_disable(usim);
> +       return 0;
> +
> +usim_err_reg:
> +       pm_runtime_set_suspended(usim->dev);
> +       pm_runtime_disable(usim->dev);
> +       misc_deregister(&usim_dev);
> +
> +usim_err_ret:
> +       if (usim)
> +               kfree(usim->slot_ctx);
> +       return ret;
> +}
> +
> +static int usim_remove(struct platform_device *pdev)
> +{
> +       struct device   *dev = &pdev->dev;
> +       struct usim     *usim = dev_to_usim(dev);
> +
> +       usim_disable(usim);
> +       /* unregister notifier, applicable only when phy present and phy state
> +        * is not unknown i.e. - phy has not been removed using rmmod */
> +       if (usim->phy_present == USIM_PHY_PRESENT)
> +               usim->phy->unregister_notify(usim->phy, &usim_nb);
> +
> +#ifdef CONFIG_DEBUG_FS
> +       debugfs_remove_recursive(usim->debugfs_root);
> +#endif
> +       if (!IS_ERR(usim->usim_dbclk))
> +               clk_put(usim->usim_dbclk);
> +       if (!IS_ERR(usim->clkdiv32k_ick))
> +               clk_put(usim->clkdiv32k_ick);
> +       if (!IS_ERR(usim->usim0_fck))
> +               clk_put(usim->usim0_fck);
> +       if (!IS_ERR(usim->dpll_core_m4_ck))
> +               clk_put(usim->dpll_core_m4_ck);
> +
> +       if (!IS_ERR(usim->opt_fclk))
> +               devm_clk_put(usim->dev, usim->opt_fclk);
> +       if (!IS_ERR(usim->opt_fclk32))
> +               devm_clk_put(usim->dev, usim->opt_fclk32);
> +       /* disable pm runtime */
> +       pm_runtime_set_suspended(usim->dev);
> +       pm_runtime_disable(usim->dev);
> +
> +       kfree(usim->slot_ctx);
> +       misc_deregister(&usim_dev);
> +       return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id usim_id_table[] = {
> +       { .compatible = "ti,usim" },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, usim_id_table);
> +#endif
> +
> +static struct platform_driver usim_driver = {
> +       .driver = {
> +               .name = "usim",
> +               .owner  = THIS_MODULE,
> +               .pm     = USIM_PM_OPS,
> +               .of_match_table = of_match_ptr(usim_id_table),
> +       },
> +       .probe = usim_probe,
> +       .remove = usim_remove,
> +};
> +
> +static int __init usim_init(void)
> +{
> +       return platform_driver_register(&usim_driver);
> +}
> +
> +static void __exit usim_exit(void)
> +{
> +       platform_driver_unregister(&usim_driver);
> +}
> +
> +late_initcall(usim_init);
> +module_exit(usim_exit);
> +
> +MODULE_AUTHOR("Maulik Mankad <maulik@ti.com>");
> +MODULE_DESCRIPTION("USIM Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/ti-usim.h b/include/linux/ti-usim.h
> new file mode 100644
> index 0000000..e9794df
> --- /dev/null
> +++ b/include/linux/ti-usim.h

Isn't this a uapi header?

> @@ -0,0 +1,111 @@
> +/*
> + * ti-usim.h - Header file for USIM SmartCard interface
> + *
> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __TI_USIM_H__
> +#define __TI_USIM_H__
> +
> +#include <linux/types.h>
> +#include <linux/ioctl.h>
> +
> +#define USIM_IOCTL 0xFE
> +
> +enum usim_param {
> +       USIM_PARAM_CWT = 0,
> +       USIM_PARAM_WWT,
> +       USIM_PARAM_CGT,
> +       USIM_PARAM_BWT,
> +       USIM_PARAM_EDCTYPE,
> +       USIM_PARAM_LRCCHECK,
> +       USIM_PARAM_C4,
> +       USIM_PARAM_C8,
> +       USIM_PARAM_PROTOCOL,
> +       USIM_PARAM_VOLTAGE,
> +       USIM_PARAM_EMV,
> +       USIM_PARAM_FI,
> +       USIM_PARAM_DI,
> +       USIM_PARAM_CODING_CONV,
> +       USIM_PARAM_CLOCK_STOP,
> +       USIM_PARAM_SMARTCARD_CLOCK,
> +       USIM_PARAM_SMARTCARD_MODE,
> +       USIM_PARAM_CARD_PIN_VCC,
> +       USIM_PARAM_CARD_PIN_RST,
> +       USIM_PARAM_CARD_PIN_CLK,
> +       USIM_PARAM_CARD_PIN_IO,
> +       USIM_PARAM_CARD_PIN_C4,
> +       USIM_PARAM_CARD_PIN_C8,
> +};
> +
> +enum usim_card_mode {
> +       USIM_CARD_MODE_ASYNC = 0,       /* asynchronous mode */
> +       USIM_CARD_MODE_SYNC_TYPE1,      /* synchronous mode: Type 1 */
> +       USIM_CARD_MODE_SYNC_TYPE2,      /* synchronous mode: Type 2 */
> +       USIM_CARD_MODE_SYNC_OTHER,      /* Any other synchronous type */
> +};
> +struct usim_data {
> +       int slot;
> +       int rxexplen;
> +       int txlen;
> +       unsigned char apdu[256];
> +};
> +
> +struct usim_config {
> +       enum usim_param attr;

Probably not a good idea to have an undefined size element in a user
ABI struct...

> +       unsigned int value;
> +};
> +
> +#define USIM_SIGID     51
> +
> +#define USIM_IOCTL_GET_PROVIDER_VERSION        _IOR(USIM_IOCTL, 0, int)
> +#define        USIM_IOCTL_ACTIVATE_CARD        _IO(USIM_IOCTL, 1)
> +#define        USIM_IOCTL_DEACTIVATE_CARD      _IO(USIM_IOCTL, 2)
> +#define USIM_IOCTL_WARM_RESET          _IO(USIM_IOCTL, 3)
> +#define USIM_IOCTL_GET_ATR             _IOR(USIM_IOCTL, 4, char *)
> +#define USIM_IOCTL_SEND_DATA           _IOW(USIM_IOCTL, 5, struct usim_data)
> +#define USIM_IOCTL_SET_CONFIG          _IOW(USIM_IOCTL, 6, struct usim_config)
> +#define USIM_IOCTL_GET_CONFIG          _IOW(USIM_IOCTL, 7, struct usim_config)
> +#define USIM_IOCTL_GET_CARD_PRESENCE   _IOR(USIM_IOCTL, 8, int)
> +#define USIM_IOCTL_REGISTER_PID                _IOW(USIM_IOCTL, 9, int)
> +
> +#define USIM_MAX_ATRLENGTH     0xFF
> +#define USIM_MAX_APDU_LENGTH   0xFE
> +
> +enum usim_smartcard_clock {
> +       USIM_SMARTCART_CLOCK_3_3MHZ     = 0x1,
> +       USIM_SMARTCART_CLOCK_4MHZ       = 0x2,
> +       USIM_SMARTCART_CLOCK_5MHZ       = 0x3,
> +       USIM_SMARTCART_CLOCK_6_6MHZ     = 0x4,
> +       USIM_SMARTCART_CLOCK_10MHZ      = 0x5,
> +       USIM_SMARTCART_CLOCK_20MHZ      = 0x6,
> +};
> +
> +enum usim_event {
> +       USIM_EVENT_CARD_INSERT  = 0x1,
> +       USIM_EVENT_CARD_REMOVE  = 0x2,
> +       USIM_EVENT_TIMEOUT      = 0x4,
> +       USIM_EVENT_ERR_TXRETRY  = 0x8,
> +       USIM_EVENT_ERR_LRC      = 0x10,
> +       USIM_EVENT_ERR_PARITY   = 0x20,
> +       USIM_EVENT_ERR_FRAME    = 0x40,
> +       USIM_EVENT_PHYERR       = 0x80,
> +       USIM_EVENT_CARD_OVERHEAT = 0x100,
> +};
> +
> +enum usim_card_voltage {
> +       USIM_CARD_5V = 0,
> +       USIM_CARD_3V,
> +       USIM_CARD_1_8V
> +};
> +
> +#endif /* __TI_USIM_H__ */
> --
> 1.7.9.5
>

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-28  8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel
@ 2014-05-28 18:44   ` Greg KH
  2014-05-29  8:56     ` Satish Patel
  2014-05-28 18:53   ` Greg KH
  1 sibling, 1 reply; 22+ messages in thread
From: Greg KH @ 2014-05-28 18:44 UTC (permalink / raw)
  To: Satish Patel
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt

On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
> +/**
> + * struct sc_phy - The basic smart card phy structure
> + *
> + * @dev: phy device
> + * @pdata: pointer to phy's private data structure
> + * @set_config: called to set phy's configuration
> + * @get_config: called to get phy's configuration
> + * @activate_card: perform smart card activation
> + * @deactivate_card: perform smart card de-activation
> + * @warm_reset: execute smart card warm reset sequence
> + * @register_card_activity_cb: register call back to phy device.
> + * This call back will be called on card insert or remove event
> + *
> + * smart card controller uses this interface to communicate with
> + * smart card via phy.Some smart card phy has multiple slots for
> + * cards. This inerface also enables controller to communicate with
> + * one or more smart card connected over phy.
> + */
> +struct sc_phy {
> +	/* phy's device pointer */
> +	struct device *dev;

So this is the "parent", right?  Why not embed a struct device into this
structure as well, further streaching out the device tree.

> +
> +	/* phy's private data */
> +	void *pdata;

If you do the above, then this pointer is not needed.


> +
> +	/* notify data, passed by interface user as a part of
> +	 * register_notify API. Data should be passed back when
> +	 * notification raised to the interface user
> +	 */
> +	void *notify_data;

What makes this different from the pdata?


> +
> +	int	(*set_config)(struct sc_phy *phy, u8 slot,
> +			enum sc_phy_config attr, int value);
> +	int	(*get_config)(struct sc_phy *phy, u8 slot, enum
> +			sc_phy_config attr);
> +	int	(*activate_card)(struct sc_phy *phy, u8 slot);
> +	int	(*deactivate_card)(struct sc_phy *phy, u8 slot);
> +	int	(*get_syncatr)(struct sc_phy *phy, u8 slot, u8 len, char *atr);
> +	int	(*warm_reset)(struct sc_phy *phy, u8 slot);
> +	int	(*register_notify)(struct sc_phy *phy,
> +			 struct	notifier_block *nb, void *notify_data);
> +	int	(*unregister_notify)(struct sc_phy *phy,
> +			struct	notifier_block *nb);
> +};
> +
> +#endif /* __SC_PHY_H__ */
> -- 
> 1.7.9.5

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

* Re: [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver
  2014-05-28  8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel
@ 2014-05-28 18:44   ` Greg KH
  2014-05-29  8:37     ` Satish Patel
  0 siblings, 1 reply; 22+ messages in thread
From: Greg KH @ 2014-05-28 18:44 UTC (permalink / raw)
  To: Satish Patel
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt

On Wed, May 28, 2014 at 02:27:14PM +0530, Satish Patel wrote:
> TDA8026 is a SmartCard PHY from NXP.
> 
> The PHY interfaces with the main processor over the
> I2C interface and acts as a slave device.
> 
> The driver also exposes the phy interface
> (defined@include/linux/sc_phy.h) for SmartCard controller.
> Controller uses this interface to communicate with smart card
> inserted to the phy's slot.
> 
> Note: gpio irq is not validated as I do not have device with that.
> I have validated interrupt with dedicated interrupt line on my device.
> 
> Signed-off-by: Satish Patel <satish.patel@ti.com>
> ---
>  Documentation/devicetree/bindings/misc/tda8026.txt |   19 +
>  drivers/misc/Kconfig                               |    7 +
>  drivers/misc/Makefile                              |    1 +
>  drivers/misc/tda8026.c                             | 1258 ++++++++++++++++++++
>  4 files changed, 1285 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt
>  create mode 100644 drivers/misc/tda8026.c
> 
> diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt
> new file mode 100644
> index 0000000..f115c9c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/tda8026.txt
> @@ -0,0 +1,19 @@
> +TDA8026 smart card slot interface
> +
> +This is an i2c based smart card interface device forming the electrical
> +interface between a microcontroller and smart cards. This device supports
> +asynchronous cards (micro controller-based IC cards) as well as synchronous
> +cards (mainly memory cards)
> +
> +Required properties:
> +- compatible: "nxp,tda8026"
> +- shutdown-gpio = GPIO pin mapping for SDWNN pin
> +- reg = i2c interface address
> +
> +
> +Example:
> +tda8026: tda8026@48 {
> +		 compatible = "nxp,tda8026";
> +		 reg = <0x48>;
> +		 shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */
> +	 };
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 8baff0e..80b21d7 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -515,6 +515,13 @@ config SRAM
>  	  the genalloc API. It is supposed to be used for small on-chip SRAM
>  	  areas found on many SoCs.
>  
> +config NXP_TDA8026_PHY
> +        tristate "NXP PHY Driver for Smart Card PHY"
> +        depends on I2C=y
> +        help
> +          If you say yes here you get support for the TDA8026 Smart card PHY
> +	  with I2C interface.
> +
>  source "drivers/misc/c2port/Kconfig"
>  source "drivers/misc/eeprom/Kconfig"
>  source "drivers/misc/cb710/Kconfig"
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 7eb4b69..f262c0b 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM)		+= sram.o
>  obj-y				+= mic/
>  obj-$(CONFIG_GENWQE)		+= genwqe/
>  obj-$(CONFIG_ECHO)		+= echo/
> +obj-$(CONFIG_NXP_TDA8026_PHY)	+= tda8026.o
> diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c
> new file mode 100644
> index 0000000..38df33e
> --- /dev/null
> +++ b/drivers/misc/tda8026.c
> @@ -0,0 +1,1258 @@
> +/*
> + * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY
> + *
> + *
> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/interrupt.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/mfd/core.h>
> +#include <linux/notifier.h>
> +#include <linux/sc_phy.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_device.h>
> +#include <linux/delay.h>

I think you just broke the build if this driver is enabled now right?

Not good :(


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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-28  8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel
  2014-05-28 18:44   ` Greg KH
@ 2014-05-28 18:53   ` Greg KH
  2014-05-29  8:34     ` Satish Patel
  1 sibling, 1 reply; 22+ messages in thread
From: Greg KH @ 2014-05-28 18:53 UTC (permalink / raw)
  To: Satish Patel
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt

On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
> SmartCard controller uses this interface to communicate with
> SmartCard via PHY
> 
> Some SmartCard PHY has multiple slots for cards.
> This inerface also enables controller to communicate
> with one or more SmartCard connected over phy.
> 
> interface structure includes following APIs
> - set/get config
> - activate/deactivate smart card
> - warm reset
> - register_notify (for card insert/remove/overheat)
> - unregister_notify
> 
> Signed-off-by: Satish Patel <satish.patel@ti.com>
> ---
>  Documentation/sc_phy.txt |  171 ++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/sc_phy.h   |  136 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 307 insertions(+)
>  create mode 100644 Documentation/sc_phy.txt
>  create mode 100644 include/linux/sc_phy.h

These are .h files, but where is the "api" functions that use
these structures defined at?

confused,

greg k-h

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-28 18:53   ` Greg KH
@ 2014-05-29  8:34     ` Satish Patel
  2014-05-29 13:47       ` Rob Herring
  0 siblings, 1 reply; 22+ messages in thread
From: Satish Patel @ 2014-05-29  8:34 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt



On 5/29/2014 12:23 AM, Greg KH wrote:
> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
>> SmartCard controller uses this interface to communicate with
>> SmartCard via PHY
>>
>> Some SmartCard PHY has multiple slots for cards.
>> This inerface also enables controller to communicate
>> with one or more SmartCard connected over phy.
>>
>> interface structure includes following APIs
>> - set/get config
>> - activate/deactivate smart card
>> - warm reset
>> - register_notify (for card insert/remove/overheat)
>> - unregister_notify
>>
>> Signed-off-by: Satish Patel <satish.patel@ti.com>
>> ---
>>   Documentation/sc_phy.txt |  171 ++++++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/sc_phy.h   |  136 ++++++++++++++++++++++++++++++++++++
>>   2 files changed, 307 insertions(+)
>>   create mode 100644 Documentation/sc_phy.txt
>>   create mode 100644 include/linux/sc_phy.h
>
> These are .h files, but where is the "api" functions that use
> these structures defined at?
>
This is like template/wrappers, smart card phy driver will write API 
functions. And smartcard controller will call these functions.
With proposed approach, smartcard controller can communicate with any 
smart card phy (TI/NxP) without change in code. Using DT entry smartcard 
and PHY will gets connected with each other.
Refer diagram given @Documentation/sc_phy.txt.


> confused,
>
> greg k-h
>

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

* Re: [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver
  2014-05-28 18:44   ` Greg KH
@ 2014-05-29  8:37     ` Satish Patel
  2014-05-29 15:52       ` Greg KH
  0 siblings, 1 reply; 22+ messages in thread
From: Satish Patel @ 2014-05-29  8:37 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt



On 5/29/2014 12:14 AM, Greg KH wrote:
> On Wed, May 28, 2014 at 02:27:14PM +0530, Satish Patel wrote:
>> TDA8026 is a SmartCard PHY from NXP.
>>
>> The PHY interfaces with the main processor over the
>> I2C interface and acts as a slave device.
>>
>> The driver also exposes the phy interface
>> (defined@include/linux/sc_phy.h) for SmartCard controller.
>> Controller uses this interface to communicate with smart card
>> inserted to the phy's slot.
>>
>> Note: gpio irq is not validated as I do not have device with that.
>> I have validated interrupt with dedicated interrupt line on my device.
>>
>> Signed-off-by: Satish Patel <satish.patel@ti.com>
>> ---
>>   Documentation/devicetree/bindings/misc/tda8026.txt |   19 +
>>   drivers/misc/Kconfig                               |    7 +
>>   drivers/misc/Makefile                              |    1 +
>>   drivers/misc/tda8026.c                             | 1258 ++++++++++++++++++++
>>   4 files changed, 1285 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt
>>   create mode 100644 drivers/misc/tda8026.c
>>
>> diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt
>> new file mode 100644
>> index 0000000..f115c9c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/misc/tda8026.txt
>> @@ -0,0 +1,19 @@
>> +TDA8026 smart card slot interface
>> +
>> +This is an i2c based smart card interface device forming the electrical
>> +interface between a microcontroller and smart cards. This device supports
>> +asynchronous cards (micro controller-based IC cards) as well as synchronous
>> +cards (mainly memory cards)
>> +
>> +Required properties:
>> +- compatible: "nxp,tda8026"
>> +- shutdown-gpio = GPIO pin mapping for SDWNN pin
>> +- reg = i2c interface address
>> +
>> +
>> +Example:
>> +tda8026: tda8026@48 {
>> +		 compatible = "nxp,tda8026";
>> +		 reg = <0x48>;
>> +		 shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */
>> +	 };
>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>> index 8baff0e..80b21d7 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -515,6 +515,13 @@ config SRAM
>>   	  the genalloc API. It is supposed to be used for small on-chip SRAM
>>   	  areas found on many SoCs.
>>
>> +config NXP_TDA8026_PHY
>> +        tristate "NXP PHY Driver for Smart Card PHY"
>> +        depends on I2C=y
>> +        help
>> +          If you say yes here you get support for the TDA8026 Smart card PHY
>> +	  with I2C interface.
>> +
>>   source "drivers/misc/c2port/Kconfig"
>>   source "drivers/misc/eeprom/Kconfig"
>>   source "drivers/misc/cb710/Kconfig"
>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>> index 7eb4b69..f262c0b 100644
>> --- a/drivers/misc/Makefile
>> +++ b/drivers/misc/Makefile
>> @@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM)		+= sram.o
>>   obj-y				+= mic/
>>   obj-$(CONFIG_GENWQE)		+= genwqe/
>>   obj-$(CONFIG_ECHO)		+= echo/
>> +obj-$(CONFIG_NXP_TDA8026_PHY)	+= tda8026.o
>> diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c
>> new file mode 100644
>> index 0000000..38df33e
>> --- /dev/null
>> +++ b/drivers/misc/tda8026.c
>> @@ -0,0 +1,1258 @@
>> +/*
>> + * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY
>> + *
>> + *
>> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
>> + *
>> + * 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 version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/init.h>
>> +#include <linux/slab.h>
>> +#include <linux/gpio.h>
>> +#include <linux/i2c.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/notifier.h>
>> +#include <linux/sc_phy.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/of_device.h>
>> +#include <linux/delay.h>
>
> I think you just broke the build if this driver is enabled now right?
>
> Not good :(
Before sending, I have applied these patches to "v3.15-rc7" and build 
with both the option ti-usim & tda8026 as module, as well as part of 
kernel. Any specific tree you would like me to rebase these patches against.

>

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-28 18:44   ` Greg KH
@ 2014-05-29  8:56     ` Satish Patel
  2014-05-29 15:51       ` Greg KH
  0 siblings, 1 reply; 22+ messages in thread
From: Satish Patel @ 2014-05-29  8:56 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt



On 5/29/2014 12:14 AM, Greg KH wrote:
> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
>> +/**
>> + * struct sc_phy - The basic smart card phy structure
>> + *
>> + * @dev: phy device
>> + * @pdata: pointer to phy's private data structure
>> + * @set_config: called to set phy's configuration
>> + * @get_config: called to get phy's configuration
>> + * @activate_card: perform smart card activation
>> + * @deactivate_card: perform smart card de-activation
>> + * @warm_reset: execute smart card warm reset sequence
>> + * @register_card_activity_cb: register call back to phy device.
>> + * This call back will be called on card insert or remove event
>> + *
>> + * smart card controller uses this interface to communicate with
>> + * smart card via phy.Some smart card phy has multiple slots for
>> + * cards. This inerface also enables controller to communicate with
>> + * one or more smart card connected over phy.
>> + */
>> +struct sc_phy {
>> +	/* phy's device pointer */
>> +	struct device *dev;
>
> So this is the "parent", right?  Why not embed a struct device into this
> structure as well, further streaching out the device tree.
>
Do you mean to use "dev->p" for pdata ?
I have kept it outside, to give easeness/pragmatic focal for new phy 
driver development. Driver can make this pointer null and use above pointer.
>> +
>> +	/* phy's private data */
>> +	void *pdata;
>
> If you do the above, then this pointer is not needed.
>
>
>> +
>> +	/* notify data, passed by interface user as a part of
>> +	 * register_notify API. Data should be passed back when
>> +	 * notification raised to the interface user
>> +	 */
>> +	void *notify_data;
>
> What makes this different from the pdata?
pdata is phy's private data, while notify_data is something phy will 
send to smart card controller on some event, like card 
remove/insert/timeout etc..
>
>
>> +
>> +	int	(*set_config)(struct sc_phy *phy, u8 slot,
>> +			enum sc_phy_config attr, int value);
>> +	int	(*get_config)(struct sc_phy *phy, u8 slot, enum
>> +			sc_phy_config attr);
>> +	int	(*activate_card)(struct sc_phy *phy, u8 slot);
>> +	int	(*deactivate_card)(struct sc_phy *phy, u8 slot);
>> +	int	(*get_syncatr)(struct sc_phy *phy, u8 slot, u8 len, char *atr);
>> +	int	(*warm_reset)(struct sc_phy *phy, u8 slot);
>> +	int	(*register_notify)(struct sc_phy *phy,
>> +			 struct	notifier_block *nb, void *notify_data);
>> +	int	(*unregister_notify)(struct sc_phy *phy,
>> +			struct	notifier_block *nb);
>> +};
>> +
>> +#endif /* __SC_PHY_H__ */
>> --
>> 1.7.9.5

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

* Re: [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx
  2014-05-28 17:56   ` Rob Herring
@ 2014-05-29 10:05     ` Satish Patel
  2014-05-29 15:53       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 22+ messages in thread
From: Satish Patel @ 2014-05-29 10:05 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree,
	Greg Kroah-Hartman, Rob Landley, Tony Lindgren, Grant Likely,
	Rob Herring



On 5/28/2014 11:26 PM, Rob Herring wrote:
> On Wed, May 28, 2014 at 3:57 AM, Satish Patel <satish.patel@ti.com> wrote:
>> TI-USIM driver is a platform driver that provides a character
>> driver interface to user applications.
>>
>> It allows user applications to call IOCTL's to
>> perform smart card operations.
>
> What's the usecase? For cellular, isn't the SC typically attached to the modem?
This for ePOS -Point of Sale domain. Where we swipe out pin based 
EMV(Europay/Master/Visa) smartcard. EMVCo defines specification for this.
>
>>
>> Driver currently supports
>> - Cold & Warm Reset
>> - T=0 & T=1 protocol
>> - clock stop mode
>> - smart card clock configuration
>> - Tx/Rx application data units (APDU) to smart card
>> - Interface to PHY using DT & phy interface
>>
>> Validation is done with ACOS3 smart cards
>>
>> Signed-off-by: Satish Patel <satish.patel@ti.com>
>> ---
>>   .../devicetree/bindings/ti-usim/ti-usim.txt        |   32 +
>>   drivers/char/Kconfig                               |    7 +
>>   drivers/char/Makefile                              |    1 +
>>   drivers/char/ti-usim-hw.h                          |  864 ++++++++
>>   drivers/char/ti-usim.c                             | 2213 ++++++++++++++++++++
>
> Perhaps drivers/char/smartcard or drivers/smartcard would be a better
> location. This should be designed assuming we get more than 1
> SmartCard controller. Perhaps there already is one in the kernel.
One which present inside kernel is USB based smartcard, which 
communicates over USB serial line.
This is independent smartcard which is integrated in SoC itsself. I 
thought of creating new directory as you have suggested, but with 
internal review I went with using existing path.
>
>>   include/linux/ti-usim.h                            |  111 +
>>   6 files changed, 3228 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/ti-usim/ti-usim.txt
>>   create mode 100644 drivers/char/ti-usim-hw.h
>>   create mode 100644 drivers/char/ti-usim.c
>>   create mode 100644 include/linux/ti-usim.h
>>
>> diff --git a/Documentation/devicetree/bindings/ti-usim/ti-usim.txt b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt
>> new file mode 100644
>> index 0000000..4e599e2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt
>> @@ -0,0 +1,32 @@
>> +ti-usim: USIM - Smart Card Controller
>> +
>> +Required Properties:
>> +- compatible: Should be "ti,usim"
>
> This should be more specific like "ti,am43xx-usim".
IP can be introduced to future SoCs by TI.
>
>> +- reg: Specifies base physical address and size of the USIM registers
>> +- interrupts:  Interrupt number for the USIM controller
>> +- ti,hwmods: Name of the hwmod associated to the USIM controller
>> +
>> +- clocks        : list of clock specifiers, corresponding to entries in  the
>> +                  clock-names property
>
> How many clocks and what is their use and order?
Depends on IP integration inside SoC. In am43xx, we have 2 options to 
use - 26Mhz/40Mhz
>
>> +- clock-names   : should contain "opt_fck" and "opt_fck32" entries, matching
>> +                  entries in the clocks property
>> +
>> +Optional properties:
>> +- pinctrl-0: Should specify pin control group used for this controller.
>> +- pinctrl-names: Should contain only one value - "default", for more details
>> +                 please refer to pinctrl-bindings.txt
>> +- phy : Should specify <smart card phy> reference connected to controller
>> +- phy-slots : No of slots to which controller will communicate
>> +
>> +Example:
>> +
>> +usim0: usim@48034000 {
>> +              compatible = "ti,usim";
>> +              reg = <0x48034000 0x1000>;
>> +              interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
>> +              ti,hwmods = "usim0";
>> +              clocks = <&usim0_opt_fck>, <&usim0_opt_fck32>,
>> +                     <&dpll_per_m2_div4_ck>;
>> +              clock-names = "opt_fck", "opt_fck32", "fck";
>> +              status = "disabled";
>> +       };
>> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
>> index 6e9f74a..c7c5fae 100644
>> --- a/drivers/char/Kconfig
>> +++ b/drivers/char/Kconfig
>> @@ -600,5 +600,12 @@ config TILE_SROM
>>            device appear much like a simple EEPROM, and knows
>>            how to partition a single ROM for multiple purposes.
>>
>> +config TI_USIM
>> +       tristate "Character device access to TI's USIM module on AM43X"
>> +       depends on SOC_AM43XX
>
> || COMPILE_TEST
Built against "v3.15-rc7"
>
>> +       help
>> +       This device creates a character device interface that enables
>> +       user applications to exchange data with TI's USIM module.
>> +
>>   endmenu
>>
>> diff --git a/drivers/char/Makefile b/drivers/char/Makefile
>> index a324f93..f7ee777 100644
>> --- a/drivers/char/Makefile
>> +++ b/drivers/char/Makefile
>> @@ -61,3 +61,4 @@ obj-$(CONFIG_JS_RTC)          += js-rtc.o
>>   js-rtc-y = rtc.o
>>
>>   obj-$(CONFIG_TILE_SROM)                += tile-srom.o
>> +obj-$(CONFIG_TI_USIM)          += ti-usim.o
>> diff --git a/drivers/char/ti-usim-hw.h b/drivers/char/ti-usim-hw.h
>> new file mode 100644
>> index 0000000..1d3dd6e
>> --- /dev/null
>> +++ b/drivers/char/ti-usim-hw.h
>> @@ -0,0 +1,864 @@
>> +/*
>> + * ti-usim-hw.h - Header file for USIM smart card interface
>
> This can go into the .c file.
>
>> + *
>> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
>> + *
>> + * 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 version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __TI_USIM_HW_H__
>> +#define __TI_USIM_HW_H__
>> +
>> +#include <linux/types.h>
>> +#include <linux/ioctl.h>
>> +#include <linux/sc_phy.h>
>> +#include <linux/ti-usim.h>
>> +
>> +
>> +#define USIM_MAX_SLOTS 0x2
>> +
>> +/* WWT Work Wait Time */
>> +#define USIM_EMV_WI      (10)
>> +#define USIM_EMV_WWT     ((960 * USIM_EMV_WI) + (480))
>> +/* CGT Character Guard Time */
>> +#define USIM_EMV_CGT     (12)
>> +
>> +#define USIM_ATR_TIMEOUT_EMV   (20160)
>> +#define USIM_EMV_ATR_EARLY_TO  (370)
>> +#define USIM_EMV_ATR_MUTE_TO   (42000)
>> +
>> +#define USIM_MAX_RX_FIFO_SIZE    (260)
>> +#define USIM_MAX_TX_FIFO_SIZE    (260)
>> +#define USIM_MAX_PARITY_RETRIES  (7)
>> +
>> +#define USIM_IRQ_NATR           (0x00000001)
>> +#define USIM_IRQ_WT            (0x00000002)
>> +#define USIM_IRQ_RXFULL                (0x00000004)
>> +#define USIM_IRQ_TX            (0x00000008)
>> +#define USIM_IRQ_RX            (0x00000010)
>> +#define USIM_IRQ_CD            (0x00000020)
>> +#define USIM_IRQ_EOB           (0x00000040)
>> +#define USIM_IRQ_TOC           (0x00000080)
>> +#define USIM_IRQ_TOB           (0x00000100)
>> +#define USIM_IRQ_RESENT                (0x00000200)
>> +#define USIM_IRQ_TS_ERR                (0x00000400)
>> +#define USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT       (0x00000800)
>> +#define USIM_IRQ_STOP          (0x00001000)
>> +#define USIM_IRQ_PAR_ERR_LEVEL_REACHED (0x00002000)
>> +#define USIM_IRQ_FRAME_ERR     (0x00004000)
>> +#define USIM_IRQ_RXDMA_RDY     (0x00008000)
>> +#define USIM_IRQ_ATR_START     (0x00010000)
>> +#define USIM_IRQ_ACT_DONE      (0x00020000)
>> +#define USIM_IRQ_DEACT_DONE    (0x00040000)
>> +#define USIM_IRQ_TX_BLOCK_DONE (0x00080000)
>> +#define USIM_IRQ_TX_BLOCK_REQ  (0x00100000)
>> +
>> +#define USIM_CONFSCLKMODE_LEGACY       0x0
>> +#define USIM_CONFSCLKMODE_HF           0x1
>> +
>> +/*
>> + * Different operating modes supported in USIM.
>> + * Programming USIM to a different mode from current mode would
>> + * endup in state machine state change within the IPs FSM
>> + */
>> +enum usim_mode {
>> +       USIM_MODE_LEGACY = 0x0,
>> +       USIM_MODE_FREEZE = 0x1,
>> +       USIM_MODE_TXRX   = 0x2,
>> +       USIM_MODE_ATR    = 0x3,
>> +       USIM_MODE_ACT    = 0x4,
>> +       USIM_MODE_DEACT  = 0x5,
>> +       USIM_MODE_IDLE   = 0x6,
>> +};
>> +
>> +/*
>> + * structure to store slot specific information
>> + */
>> +struct usim_slotcontext {
>> +       char atr[USIM_MAX_ATRLENGTH];
>> +       char rxbuf[USIM_MAX_APDU_LENGTH];
>> +       bool emv;
>> +       enum usim_mode state;
>> +       int event;
>> +       int protocol;
>> +       enum usim_card_voltage supply;
>> +       int rx_explen;
>> +       int rx_counter;
>> +       int atr_length;
>> +       enum usim_smartcard_clock clock;
>> +       enum usim_card_mode card_mode;
>> +};
>> +
>> +struct usim {
>> +       struct device *dev;
>> +
>> +       /* to protect interrput handling */
>> +       spinlock_t      lock;
>> +       int irq;
>> +       void __iomem            *base;
>> +       int slot;
>> +       int max_slots;
>> +       int phy_present;
>> +       int txdone;
>> +       int rxdone;
>> +       int atrdone;
>> +       int user_pid;
>> +       int enable;
>> +       struct sc_phy *phy;
>> +       struct usim_slotcontext *slot_ctx;
>> +
>> +       struct clk      *opt_fclk;
>> +       struct clk      *opt_fclk32;
>> +       struct clk      *usim_dbclk;
>> +       struct clk      *clkdiv32k_ick;
>> +       struct clk      *usim0_fck;
>> +       struct clk      *dpll_core_m4_ck;
>> +
>> +#ifdef CONFIG_DEBUG_FS
>> +       struct dentry   *debugfs_root;
>> +#endif
>> +};
>> +
>> +/*
>> + * Register Definitions: Taken from auto generated file
>> + */
>> +#define USIM_REVISION                    (0x0U)
>
> Parenthesis and U are generally not needed throughout.
To avoid mistake, usually I preferred to used file generated by design team.
>
>> +#define USIM_IDENT                       (0x4U)
>> +#define USIM_SYSCONFIG                   (0x10U)
>> +#define USIM_SYSSTATUS                   (0x14U)
>> +#define USIM_IRQSTATUS                   (0x18U)
>> +#define USIM_IRQENABLE                   (0x1cU)
>> +#define USIM_WAKEUPEN                    (0x20U)
>> +#define USIM_CMD                         (0x24U)
>> +#define USIM_STAT                        (0x28U)
>> +#define USIM_CONF1                       (0x2cU)
>> +#define USIM_CONF2                       (0x30U)
>> +#define USIM_CONF3                       (0x34U)
>> +#define USIM_DRX                         (0x38U)
>> +#define USIM_DTX                         (0x3cU)
>> +#define USIM_FIFOS                       (0x40U)
>> +#define USIM_CGT                         (0x44U)
>> +#define USIM_CWT                         (0x48U)
>> +#define USIM_BWT                         (0x4cU)
>> +#define USIM_DEBUG                       (0x50U)
>> +#define USIM_CONF_SAM1_DIV               (0x54U)
>> +#define USIM_CONF4                       (0x58U)
>> +#define USIM_ATR_CLK_PRD_NBS             (0x5cU)
>> +#define USIM_CONF_ETU_DIV                (0x60U)
>> +#define USIM_CONF5                       (0x64U)
>> +#define USIM_TC_GUARD_TIME_ADD           (0x68U)
>> +#define USIM_RXFIFO_LEVEL                (0x6cU)
>> +#define USIM_RXFIFO_BYTECNT              (0x70U)
>> +#define USIM_WWT                         (0x74U)
>> +#define USIM_CONF6                       (0x78U)
>> +#define USIM_IO_DIRECT                   (0x7cU)
>> +#define USIM_TX_BLOCK                    (0x84U)
>> +
>> +/*
>> + * Field Definition Macros
>> + */
>> +#define USIM_REVISION_REV_SHIFT                       (0U)
>> +#define USIM_REVISION_REV_MASK                        (0x000000ffU)
>> +
>> +#define USIM_REVISION_RESERVED_24_SHIFT               (8U)
>> +#define USIM_REVISION_RESERVED_24_MASK                (0xffffff00U)
>> +
>> +#define USIM_IDENT_VC_SHIFT                           (0U)
>> +#define USIM_IDENT_VC_MASK                            (0x0000ffffU)
>> +
>> +#define USIM_IDENT_RESERVED_16_31_SHIFT               (16U)
>> +#define USIM_IDENT_RESERVED_16_31_MASK                (0xffff0000U)
>> +
>> +#define USIM_SYSCONFIG_AUTOIDLE_SHIFT                 (0U)
>> +#define USIM_SYSCONFIG_AUTOIDLE_MASK                  (0x00000001U)
>> +#define USIM_SYSCONFIG_AUTOIDLE_AUTOIDLE_VALUE_1       (1U)
>> +#define USIM_SYSCONFIG_AUTOIDLE_AUTOIDLE_VALUE_0       (0U)
>> +
>> +#define USIM_SYSCONFIG_SOFTRESET_SHIFT                (1U)
>> +#define USIM_SYSCONFIG_SOFTRESET_MASK                 (0x00000002U)
>> +#define USIM_SYSCONFIG_SOFTRESET_SOFTRESET_VALUE_1     (1U)
>> +#define USIM_SYSCONFIG_SOFTRESET_SOFTRESET_VALUE_0     (0U)
>> +
>> +#define USIM_SYSCONFIG_ENAWAKEUP_SHIFT                (2U)
>> +#define USIM_SYSCONFIG_ENAWAKEUP_MASK                 (0x00000004U)
>> +#define USIM_SYSCONFIG_ENAWAKEUP_ENAWAKEUP_VALUE_1     (1U)
>> +#define USIM_SYSCONFIG_ENAWAKEUP_ENAWAKEUP_VALUE_0     (0U)
>> +
>> +#define USIM_SYSCONFIG_IDLEMODE_SHIFT                 (3U)
>> +#define USIM_SYSCONFIG_IDLEMODE_MASK                  (0x00000018U)
>> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_3       (3U)
>> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_2       (2U)
>> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_1       (1U)
>> +#define USIM_SYSCONFIG_IDLEMODE_IDLEMODE_VALUE_0       (0U)
>> +
>> +#define USIM_SYSCONFIG_EMUFREE_SHIFT                  (5U)
>> +#define USIM_SYSCONFIG_EMUFREE_MASK                   (0x00000020U)
>> +#define USIM_SYSCONFIG_EMUFREE_EMUFREE_VALUE_0         (0U)
>> +#define USIM_SYSCONFIG_EMUFREE_EMUFREE_VALUE_1         (1U)
>> +
>> +#define USIM_SYSCONFIG_RESERVED_6_7_SHIFT             (6U)
>> +#define USIM_SYSCONFIG_RESERVED_6_7_MASK              (0x000000c0U)
>> +
>> +#define USIM_SYSCONFIG_CLOCKACTIVITY_SHIFT            (8U)
>> +#define USIM_SYSCONFIG_CLOCKACTIVITY_MASK             (0x00000300U)
>> +
>> +#define USIM_SYSCONFIG_RESERVED_22_SHIFT              (10U)
>> +#define USIM_SYSCONFIG_RESERVED_22_MASK               (0xfffffc00U)
>> +
>> +#define USIM_SYSSTATUS_RESETDONE_SHIFT                (0U)
>> +#define USIM_SYSSTATUS_RESETDONE_MASK                 (0x00000001U)
>> +#define USIM_SYSSTATUS_RESETDONE_RESETDONE_VALUE_1     (1U)
>> +#define USIM_SYSSTATUS_RESETDONE_RESETDONE_VALUE_0     (0U)
>> +
>> +#define USIM_SYSSTATUS_RESERVED_31_SHIFT              (1U)
>> +#define USIM_SYSSTATUS_RESERVED_31_MASK               (0xfffffffeU)
>> +
>> +#define USIM_IRQSTATUS_USIM_NATR_SHIFT                (0U)
>> +#define USIM_IRQSTATUS_USIM_NATR_MASK                 (0x00000001U)
>> +
>> +#define USIM_IRQSTATUS_USIM_WT_SHIFT                  (1U)
>> +#define USIM_IRQSTATUS_USIM_WT_MASK                   (0x00000002U)
>> +
>> +#define USIM_IRQSTATUS_USIM_RXFULL_SHIFT              (2U)
>> +#define USIM_IRQSTATUS_USIM_RXFULL_MASK               (0x00000004U)
>> +
>> +#define USIM_IRQSTATUS_USIM_TX_SHIFT                  (3U)
>> +#define USIM_IRQSTATUS_USIM_TX_MASK                   (0x00000008U)
>> +
>> +#define USIM_IRQSTATUS_USIM_RX_SHIFT                  (4U)
>> +#define USIM_IRQSTATUS_USIM_RX_MASK                   (0x00000010U)
>> +
>> +#define USIM_IRQSTATUS_USIM_CD_SHIFT                  (5U)
>> +#define USIM_IRQSTATUS_USIM_CD_MASK                   (0x00000020U)
>> +
>> +#define USIM_IRQSTATUS_USIM_EOB_SHIFT                 (6U)
>> +#define USIM_IRQSTATUS_USIM_EOB_MASK                  (0x00000040U)
>> +
>> +#define USIM_IRQSTATUS_USIM_TOC_SHIFT                 (7U)
>> +#define USIM_IRQSTATUS_USIM_TOC_MASK                  (0x00000080U)
>> +
>> +#define USIM_IRQSTATUS_USIM_TOB_SHIFT                 (8U)
>> +#define USIM_IRQSTATUS_USIM_TOB_MASK                  (0x00000100U)
>> +
>> +#define USIM_IRQSTATUS_USIM_RESENT_SHIFT              (9U)
>> +#define USIM_IRQSTATUS_USIM_RESENT_MASK               (0x00000200U)
>> +
>> +#define USIM_IRQSTATUS_TS_ERROR_SHIFT                 (10U)
>> +#define USIM_IRQSTATUS_TS_ERROR_MASK                  (0x00000400U)
>> +
>> +#define USIM_IRQSTATUS_IT_EMV_ATR_LENGTH_TIME_OUT_SHIFT  (11U)
>> +#define USIM_IRQSTATUS_IT_EMV_ATR_LENGTH_TIME_OUT_MASK   (0x00000800U)
>> +
>> +#define USIM_IRQSTATUS_RESERVED_SHIFT                    (21U)
>> +#define USIM_IRQSTATUS_RESERVED_MASK                     (0xffe00000U)
>> +
>> +#define USIM_IRQSTATUS_USIM_STOP_CLK_SHIFT               (12U)
>> +#define USIM_IRQSTATUS_USIM_STOP_CLK_MASK                (0x00001000U)
>> +
>> +#define USIM_IRQSTATUS_PAR_ERR_LEVEL_REACHED_SHIFT       (13U)
>> +#define USIM_IRQSTATUS_PAR_ERR_LEVEL_REACHED_MASK        (0x00002000U)
>> +
>> +#define USIM_IRQSTATUS_FRAME_ERR_SHIFT            (14U)
>> +#define USIM_IRQSTATUS_FRAME_ERR_MASK             (0x00004000U)
>> +
>> +#define USIM_IRQSTATUS_RXDMA_RDY_SHIFT            (15U)
>> +#define USIM_IRQSTATUS_RXDMA_RDY_MASK             (0x00008000U)
>> +
>> +#define USIM_IRQSTATUS_ATR_START_SHIFT            (16U)
>> +#define USIM_IRQSTATUS_ATR_START_MASK             (0x00010000U)
>> +
>> +#define USIM_IRQSTATUS_ACT_DONE_SHIFT             (17U)
>> +#define USIM_IRQSTATUS_ACT_DONE_MASK              (0x00020000U)
>> +
>> +#define USIM_IRQSTATUS_DEACT_DONE_SHIFT           (18U)
>> +#define USIM_IRQSTATUS_DEACT_DONE_MASK            (0x00040000U)
>> +
>> +#define USIM_IRQSTATUS_TX_BLOCK_DONE_SHIFT        (19U)
>> +#define USIM_IRQSTATUS_TX_BLOCK_DONE_MASK         (0x00080000U)
>> +
>> +#define USIM_IRQSTATUS_TX_BLOCK_REQ_SHIFT         (20U)
>> +#define USIM_IRQSTATUS_TX_BLOCK_REQ_MASK          (0x00100000U)
>> +
>> +#define USIM_IRQENABLE_RESERVED_SHIFT             (21U)
>> +#define USIM_IRQENABLE_RESERVED_MASK              (0xffe00000U)
>> +
>> +#define USIM_IRQENABLE_EMV_ATR_LENGTH_TIME_OUT_EN_SHIFT    (11U)
>> +#define USIM_IRQENABLE_EMV_ATR_LENGTH_TIME_OUT_EN_MASK     (0x00000800U)
>> +
>> +#define USIM_IRQENABLE_TS_ERR_EN_SHIFT         (10U)
>> +#define USIM_IRQENABLE_TS_ERR_EN_MASK          (0x00000400U)
>> +
>> +#define USIM_IRQENABLE_RESENT_EN_SHIFT         (9U)
>> +#define USIM_IRQENABLE_RESENT_EN_MASK          (0x00000200U)
>> +
>> +#define USIM_IRQENABLE_TOB_EN_SHIFT            (8U)
>> +#define USIM_IRQENABLE_TOB_EN_MASK             (0x00000100U)
>> +
>> +#define USIM_IRQENABLE_TOC_EN_SHIFT            (7U)
>> +#define USIM_IRQENABLE_TOC_EN_MASK             (0x00000080U)
>> +
>> +#define USIM_IRQENABLE_EOB_EN_SHIFT            (6U)
>> +#define USIM_IRQENABLE_EOB_EN_MASK             (0x00000040U)
>> +
>> +#define USIM_IRQENABLE_CD_EN_SHIFT             (5U)
>> +#define USIM_IRQENABLE_CD_EN_MASK              (0x00000020U)
>> +
>> +#define USIM_IRQENABLE_RX_EN_SHIFT             (4U)
>> +#define USIM_IRQENABLE_RX_EN_MASK              (0x00000010U)
>> +
>> +#define USIM_IRQENABLE_TX_EN_SHIFT             (3U)
>> +#define USIM_IRQENABLE_TX_EN_MASK              (0x00000008U)
>> +
>> +#define USIM_IRQENABLE_RXFULL_EN_SHIFT         (2U)
>> +#define USIM_IRQENABLE_RXFULL_EN_MASK          (0x00000004U)
>> +
>> +#define USIM_IRQENABLE_WT_EN_SHIFT             (1U)
>> +#define USIM_IRQENABLE_WT_EN_MASK              (0x00000002U)
>> +
>> +#define USIM_IRQENABLE_NATR_EN_SHIFT           (0U)
>> +#define USIM_IRQENABLE_NATR_EN_MASK            (0x00000001U)
>> +
>> +#define USIM_IRQENABLE_STOP_CLK_SHIFT          (12U)
>> +#define USIM_IRQENABLE_STOP_CLK_MASK           (0x00001000U)
>> +
>> +#define USIM_IRQENABLE_PAR_ERR_LEVEL_REACHED_EN_SHIFT      (13U)
>> +#define USIM_IRQENABLE_PAR_ERR_LEVEL_REACHED_EN_MASK       (0x00002000U)
>> +
>> +#define USIM_IRQENABLE_FRAME_ERR_EN_SHIFT           (14U)
>> +#define USIM_IRQENABLE_FRAME_ERR_EN_MASK            (0x00004000U)
>> +
>> +#define USIM_IRQENABLE_RXDMA_RDY_EN_SHIFT           (15U)
>> +#define USIM_IRQENABLE_RXDMA_RDY_EN_MASK            (0x00008000U)
>> +
>> +#define USIM_IRQENABLE_ATR_START_EN_SHIFT           (16U)
>> +#define USIM_IRQENABLE_ATR_START_EN_MASK            (0x00010000U)
>> +
>> +#define USIM_IRQENABLE_ACT_DONE_EN_SHIFT            (17U)
>> +#define USIM_IRQENABLE_ACT_DONE_EN_MASK             (0x00020000U)
>> +
>> +#define USIM_IRQENABLE_DEACT_DONE_EN_SHIFT          (18U)
>> +#define USIM_IRQENABLE_DEACT_DONE_EN_MASK           (0x00040000U)
>> +
>> +#define USIM_IRQENABLE_TX_BLOCK_DONE_EN_SHIFT       (19U)
>> +#define USIM_IRQENABLE_TX_BLOCK_DONE_EN_MASK        (0x00080000U)
>> +
>> +#define USIM_IRQENABLE_TX_BLOCK_REQ_EN_SHIFT        (20U)
>> +#define USIM_IRQENABLE_TX_BLOCK_REQ_EN_MASK         (0x00100000U)
>> +
>> +#define USIM_WAKEUPEN_STOP_CLK_SHIFT                (12U)
>> +#define USIM_WAKEUPEN_STOP_CLK_MASK                 (0x00001000U)
>
> Can't you have common defines for IRQSTATUS, IRQENABLE and WAKEUPEN?
> They seem to all be the same bit positions. And you already have IRQ
> bit defines above.
>
> [lots more register defines...]
>
All three register's definition/usage are different. It make ease while 
handling interrupt and checking the status.
>> +
>> +#define USIM_TX_BLOCK_RESERVED_SHIFT              (16U)
>> +#define USIM_TX_BLOCK_RESERVED_MASK               (0xffff0000U)
>
> In general, trim these defines down to what you actually use. Single
> bit fields rarely need both a shift and mask.
Again, used file generated by Tool to avoid minor mistakes.
>
>> +
>> +#endif /* __TI_USIM_HW_H__ */
>> diff --git a/drivers/char/ti-usim.c b/drivers/char/ti-usim.c
>> new file mode 100644
>> index 0000000..ffabf87
>> --- /dev/null
>> +++ b/drivers/char/ti-usim.c
>> @@ -0,0 +1,2213 @@
>> +/*
>> + * usim.c - USIM driver for Smart Card module
>> + *
>> + *
>> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
>> + *
>> + * 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 version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/slab.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/io.h>
>> +#include <linux/fs.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/i2c.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/ctype.h>
>> +#include <linux/wait.h>
>> +#include <linux/sched.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/notifier.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +/* for send_sig_info */
>> +#include <linux/rcupdate.h>
>> +#include <asm/siginfo.h>
>> +
>> +#include "ti-usim-hw.h"
>> +
>> +#define USIM_WRITEREG(base, offset, field, value)  \
>> +                       usim_writereg(base+offset, offset##_##field##_MASK, \
>> +                               offset##_##field##_SHIFT, value)
>> +
>> +#define USIM_READREG(base, offset, field)  \
>> +       usim_readreg(base+offset, offset##_##field##_MASK, \
>> +                       offset##_##field##_SHIFT)
>> +
>> +#define USIM_SETFIELD(reg, offset, field, value)  \
>> +       usim_setfield(reg, offset##_##field##_MASK, \
>> +                       offset##_##field##_SHIFT, value)
>
> Get rid of this.
Any specific reason ?
It gives flexibility to seperate reg vs bit field name.
ex.
USIM_READREG(usim->base, USIM_STAT, ATRRX_AFTER_TIMEOUT);
looks better than
usim_readreg(usim->base, 
USIM_STAT_ATRRX_AFTER_TIMEOUT_MASK,USIM_STAT_ATRRX_AFTER_TIMEOUT_SHIFT)

- USIM_SETFIELD similarly allows to set multiple bit one by one and then 
single write updates all the bits.

Gives more readability for code.
>
>> +
>> +/* calculation of max ATR waiting time
>> + * 372 is default FI value, so etu for 1Mhz SC clock cycle would be
>> + * etu = FI/f sec = 372/1Mhz = 372 micro second
>> + * Max ATR waiting is - USIM_ATR_TIMEOUT_EMV etu
>> + */
>> +#define MAX_ATR_WAITTIME_US (372 * USIM_ATR_TIMEOUT_EMV)
>> +
>> +/*
>> + * phy states
>> + */
>> +enum usim_phy_state {
>> +       USIM_PHY_NOT_PRESENT = 0x0,
>> +       USIM_PHY_PRESENT,
>> +       USIM_PHY_NOT_ATTACHED,
>> +};
>> +
>> +static struct miscdevice usim_dev;
>> +
>> +static DECLARE_WAIT_QUEUE_HEAD(rx_wait);
>> +static DECLARE_WAIT_QUEUE_HEAD(tx_wait);
>> +static DECLARE_WAIT_QUEUE_HEAD(atr_wait);
>> +
>> +static int usim_set_smartcardclock(struct usim *usim, u32 clock);
>> +static int usim_deactivate_card(struct usim *usim);
>> +
>> +static void usim_writereg(void __iomem *base, u32 mask, u32 shift, u32 value)
>> +{
>> +       u32 v = readl(base);
>> +
>> +       v &= ~mask;
>> +       v |= (value << shift) & mask;
>> +       writel(v, base);
>> +       v = readl(base);
>> +       return;
>> +}
>> +
>> +static u32 usim_readreg(void __iomem *base, u32 mask, u32 shift)
>> +{
>> +       u32 v = readl(base);
>> +
>> +       v &= mask;
>> +       v = (v >> shift);
>> +       return v;
>> +}
>> +
>> +static u32 usim_setfield(u32 reg, u32 mask, u32 shift, u32 value)
>> +{
>> +       reg &= ~mask;
>> +       reg |= (value << shift) & mask;
>> +       return reg;
>> +}
>
> Use readl/writel directly. If we wanted drivers written with accessors
> like these, then there would be common ones to use.
>
>> +
>> +
>> +static inline void usim_irq_enable(void __iomem *base, u32 irqs)
>> +{
>> +       u32 v = readl(base + USIM_IRQENABLE);
>> +
>> +       v |= irqs;
>> +       writel(v, base + USIM_IRQENABLE);
>> +}
>> +
>> +static inline void usim_irq_disable(void __iomem *base, u32 irqs)
>> +{
>> +       u32 v = readl(base + USIM_IRQENABLE);
>> +
>> +       v &= ~irqs;
>> +       writel(v, base + USIM_IRQENABLE);
>
> I assume these are called with appropriate locking?
yes, using locks inside irq handling.
>
>> +}
>> +
>> +static inline void usim_irq_get(void __iomem *base, u32 *irqs)
>> +{
>> +       *irqs = readl(base + USIM_IRQENABLE);
>> +}
>> +
>> +static inline u32 usim_irqstatus(void __iomem *base)
>> +{
>> +       return readl(base + USIM_IRQSTATUS);
>> +}
>> +
>> +static inline void usim_irqstatus_clear(void __iomem *base, u32 irqs)
>> +{
>> +       writel(irqs, base + USIM_IRQSTATUS);
>> +}
>
> Use readl/writel directly.
>
>> +
>> +static inline struct usim *dev_to_usim(struct device *dev)
>> +{
>> +       return dev_get_drvdata(dev);
>> +}
>> +
>> +static int usim_send_signal(struct usim *usim, int event)
>> +{
>
> Using signals is not a typical driver interface.
>
There is a use case for this. We need to send immediate signal to 
application for card insert/remove. So used this approach after internal 
discussion.

>> +       struct siginfo info;
>> +       struct task_struct *tid;
>> +       int ret = 0;
>> +       int pid = usim->user_pid;
>> +
>> +       if (pid == 0)
>> +               return -EINVAL;
>> +       info.si_signo = USIM_SIGID;
>> +       info.si_code = SI_QUEUE;
>> +
>> +       info.si_int = event;
>> +       rcu_read_lock();
>> +
>> +       /* find task structure associated with this pid */
>> +       tid = pid_task(find_vpid(pid), PIDTYPE_PID);
>> +       if (tid == NULL) {
>> +               dev_err(usim->dev, "usim-err:no such pid :%d\n", pid);
>> +               rcu_read_unlock();
>> +               return -ENODEV;
>> +       }
>> +
>> +       rcu_read_unlock();
>> +
>> +       /* send the signal */
>> +       ret = send_sig_info(USIM_SIGID, &info, tid);
>> +       if (ret < 0) {
>> +               dev_err(usim->dev, "error sending signal:%d\n", ret);
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void usim_getrx(struct usim *usim)
>> +{
>> +       u32 rxlen = 0;
>> +       u32 cnt = 0;
>> +
>> +       /* Check if FIFO contains some data */
>> +       rxlen = USIM_READREG(usim->base, USIM_RXFIFO_LEVEL,
>> +                                       USIM_RXFIFO_LEVEL);
>
> More register accessors?
>
>> +
>> +       usim->slot_ctx[usim->slot].rx_counter += rxlen;
>> +       if (rxlen > 0) {
>> +               for (cnt = 0; cnt < rxlen; cnt++) {
>> +                       usim->slot_ctx[usim->slot].rxbuf[cnt] =
>> +                               USIM_READREG(usim->base, USIM_DRX, USIMDRX);
>> +               }
>> +       }
>> +}
>> +
>> +static void usim_irq_atrhandler(struct usim *usim, u32 reg)
>> +{
>> +       u32 event = 0;
>> +       u32 val = 0;
>> +       u32 cnt = 0;
>> +       u32 rxval = 0;
>> +       if (usim->atrdone)
>> +               return;
>> +       do {
>> +               /* WWT would be used to identify end of ATR */
>> +               if (reg & (USIM_IRQ_WT | USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT)) {
>> +                       event |= USIM_EVENT_TIMEOUT;
>> +                       val = USIM_READREG(usim->base, USIM_STAT,
>> +                                               ATRRX_AFTER_TIMEOUT);
>> +                       if (val) {
>> +                               /* do not store rx character if it comes after
>> +                                * ATR timeout
>> +                                */
>> +                               dev_dbg(usim->dev, "Error: Rx after ATR Timeout");
>> +                               break;
>> +                       }
>> +               }
>> +               if (reg & USIM_IRQ_TS_ERR) {
>> +                       event |= USIM_EVENT_ERR_FRAME;
>> +                       break;
>> +               }
>> +
>> +               /* check the rx fifo and store available bytes in atrbuf */
>> +               val = USIM_READREG(usim->base, USIM_RXFIFO_LEVEL,
>> +                                               USIM_RXFIFO_LEVEL);
>> +               cnt = usim->slot_ctx[usim->slot].atr_length;
>> +
>> +               while (val > 0) {
>> +                       if (cnt < USIM_MAX_ATRLENGTH) {
>> +                               rxval = readl(usim->base + USIM_DRX);
>> +                               usim->slot_ctx[usim->slot].atr[cnt++] = rxval &
>> +                                                       USIM_DRX_USIMDRX_MASK;
>> +                               /* check of parity */
>> +                               if (!(rxval & USIM_DRX_STATRXPAR_MASK)) {
>> +                                       dev_dbg(usim->dev,
>> +                                               "Error : incorrect parity:%0x"
>> +                                               , rxval);
>> +                                       event |= USIM_EVENT_ERR_PARITY;
>> +                               }
>> +                       }
>> +                       val--;
>> +               }
>> +
>> +               usim->slot_ctx[usim->slot].atr_length = cnt;
>> +       } while (0);
>
> It would be nicer to see these written w/o all these while (0) loops.
>
>> +
>> +       if (event != 0) {
>> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
>> +               usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
>> +               usim->slot_ctx[usim->slot].event = event;
>> +               usim->atrdone = 1;
>> +       }
>> +
>> +       if (usim->atrdone)
>> +               wake_up(&atr_wait);
>> +
>> +       return;
>> +}
>> +
>> +static void usim_irq_txhandler(struct usim *usim, u32 reg)
>> +{
>> +       u32 protocol    = 0;
>
> This does not need to be initialized.
>
>> +       u32 event       = 0;
>> +
>> +       if (usim->txdone)
>> +               return;
>> +
>> +       protocol = usim->slot_ctx[usim->slot].protocol;
>> +       do {
>> +               if (reg & USIM_IRQ_FRAME_ERR) {
>> +                       event |= USIM_EVENT_ERR_FRAME;
>> +                       break;
>> +               }
>> +               if (!protocol && (reg & USIM_IRQ_RESENT)) {
>> +                       event |= USIM_EVENT_ERR_TXRETRY;
>> +                       break;
>> +               }
>> +               if (reg & USIM_IRQ_TX_BLOCK_REQ) {
>> +                       /* TODO : As per EMV max tx block will be of 256 bytes
>> +                        * and USIM controller has sufficient place for this.
>> +                        * Need to implement this case when it is practially
>> +                        * required
>> +                        */
>> +                       dev_dbg(usim->dev, "Error: TX_BLOCK_REQ - Not Implemented");
>> +               }
>> +               if (reg & USIM_IRQ_TX_BLOCK_DONE) {
>> +                       usim_irq_disable(usim->base, USIM_IRQ_TX_BLOCK_REQ
>> +                                               | USIM_IRQ_TX_BLOCK_DONE
>> +                                               | USIM_IRQ_TX);
>> +                       usim->txdone = 1;
>> +                       usim_irq_enable(usim->base, USIM_IRQ_RX | USIM_IRQ_EOB
>> +                                               | USIM_IRQ_RXDMA_RDY);
>> +                       break;
>> +               }
>> +       } while (0);
>> +
>> +       if (event != 0) {
>> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
>> +               usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
>> +               usim->slot_ctx[usim->slot].event = event;
>> +               usim->txdone = 1;
>> +               usim->rxdone = 1;
>> +       }
>> +       if (usim->txdone)
>> +               wake_up(&tx_wait);
>> +       return;
>> +}
>> +
>> +static void usim_irq_rxhandler(struct usim *usim, u32 reg)
>> +{
>> +       u32 event = 0;
>> +       u32 val = 0;
>> +
>> +       u32 protocol = usim->slot_ctx[usim->slot].protocol;
>> +
>> +       /* if tx not done then do not check of any rx */
>> +       if (usim->rxdone || !usim->txdone)
>> +               return;
>> +
>> +       /* For T=0 protocol */
>> +       if (protocol == 0) {
>> +               do {
>> +                       /* ignore interrupts if expected bytes recevied */
>> +                       if (usim->slot_ctx[usim->slot].rx_counter >=
>> +                                       usim->slot_ctx[usim->slot].rx_explen) {
>> +                               dev_dbg(usim->dev, "All bytes recvd,ignore this timeout\n");
>> +                               usim->rxdone = 1;
>> +                               break;
>
> How about using "else if" instead of all these breaks. Can't you have
> multiple interrupt bits set?
handling interrput in order of priority.
ex. if all expected rx bytes are received then need to ignore other 
timeout interrupts. Useful while doing EMV validation.
>
>> +                       }
>> +
>> +                       if (reg & USIM_IRQ_WT) {
>> +                               dev_dbg(usim->dev, "Expected bytes not recvd counter = %d\n",
>> +                                       usim->slot_ctx[usim->slot].rx_counter);
>> +                               usim_getrx(usim);
>> +                               event |= USIM_EVENT_TIMEOUT;
>> +                               break;
>> +                       }
>> +
>> +                       if (reg & USIM_IRQ_PAR_ERR_LEVEL_REACHED) {
>> +                               dev_err(usim->dev,
>> +                                       "Rx parity level reached:%x\n"
>> +                                       , reg);
>> +                               usim_getrx(usim);
>> +                               event |= USIM_EVENT_ERR_PARITY;
>> +                               break;
>> +                       }
>> +
>> +                       if (reg & (USIM_IRQ_RX | USIM_IRQ_RXDMA_RDY)) {
>> +                               /* Read number of bytes present in the FIFO */
>> +                               usim_getrx(usim);
>> +                               usim->rxdone = 1;
>> +                               break;
>> +                       }
>> +               } while (0);
>> +       } else {
>> +               /* T=1 protocol */
>> +               do {
>> +                       if (reg & (USIM_IRQ_TOB | USIM_IRQ_TOC)) {
>> +                               usim_getrx(usim);
>> +                               event |= USIM_EVENT_TIMEOUT;
>> +                               break;
>> +                       }
>> +                       if (reg & USIM_IRQ_EOB) {
>> +                               usim_getrx(usim);
>> +                               usim->rxdone = 1;
>> +                               val = USIM_READREG(usim->base, USIM_STAT,
>> +                                                               STATLRC);
>> +                               if (val != 0)
>> +                                       event |= USIM_EVENT_ERR_LRC;
>> +                               break;
>> +                       }
>> +               } while (0);
>> +       }
>> +
>> +       if (event != 0 || usim->rxdone == 1) {
>> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
>> +               usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
>> +               usim->slot_ctx[usim->slot].event = event;
>> +               usim->rxdone = 1;
>> +       }
>> +
>> +       if (usim->rxdone)
>> +               wake_up(&rx_wait);
>> +
>> +       return;
>> +}
>> +
>> +static irqreturn_t usim_interrupt(int irq, void *_usim)
>> +{
>> +       u32 reg = 0;
>> +       u32 state = 0;
>> +       struct usim *usim = (struct usim *)_usim;
>> +
>> +       state = usim->slot_ctx[usim->slot].state;
>> +
>> +       spin_lock(&usim->lock);
>> +
>> +       reg = readl(usim->base + USIM_IRQSTATUS);
>> +
>> +       if (state == USIM_MODE_ATR)
>> +               usim_irq_atrhandler(usim, reg);
>> +
>> +       if (state == USIM_MODE_TXRX) {
>> +               usim_irq_txhandler(usim, reg);
>> +               usim_irq_rxhandler(usim, reg);
>> +       }
>> +
>> +       if (reg & USIM_IRQSTATUS_USIM_NATR_MASK)
>> +               dev_dbg(usim->dev, "NO ATR\n");
>> +
>> +       if (reg & USIM_IRQSTATUS_USIM_CD_MASK)
>> +               dev_dbg(usim->dev, "CARD Insert/Removed\n");
>> +
>> +       if (reg & USIM_IRQSTATUS_USIM_STOP_CLK_MASK)
>> +               dev_dbg(usim->dev, "SIM CLK STOPPED\n");
>> +
>> +       if (reg & USIM_IRQSTATUS_ACT_DONE_MASK)
>> +               dev_dbg(usim->dev, "Activation Sequence completed\n");
>> +
>> +       if (reg & USIM_IRQSTATUS_DEACT_DONE_MASK)
>> +               dev_dbg(usim->dev, "Deactivation Sequence complteted\n");
>> +
>> +       /* Clear the interrupt by writing the corresponding bit
>> +        * in IRQ_STATUS register
>> +        */
>> +       usim_irqstatus_clear(usim->base, reg);
>> +
>> +       spin_unlock(&usim->lock);
>> +
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static int usim_configure(struct usim *usim)
>> +{
>> +       int reg = 0;
>> +       int count = 3;
>> +
>> +       /* perform softreset of IP */
>> +       USIM_WRITEREG(usim->base, USIM_SYSCONFIG, SOFTRESET, 1);
>> +
>> +       /* wait until reset get completed */
>> +       while (count > 0) {
>> +               reg = USIM_READREG(usim->base, USIM_SYSCONFIG, SOFTRESET);
>> +               if (reg == 0x0)
>> +                       break;
>> +               mdelay(10);
>
> Does this really need to be a delay loop rather than a sleep? If not,
> use msleep and time_after or time_before.
As for POS application, opening device is high priority, so used delay.
This will be used to do soft reset of IP,every time application opens 
device.
>
>> +               count--;
>> +       }
>> +       if (reg != 0x0)
>> +               return -EIO;
>> +
>> +       /* activate phy */
>> +       if (usim->phy_present)
>> +               usim->phy->set_config(usim->phy, usim->slot, SC_PHY_MODE,
>> +                               SC_PHY_ACTIVE);
>> +
>> +       /* Disable Auto Idle and set NO IDLE config */
>> +       reg = readl(usim->base + USIM_SYSCONFIG);
>> +       reg = USIM_SETFIELD(reg, USIM_SYSCONFIG, AUTOIDLE, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_SYSCONFIG, IDLEMODE, 1);
>> +       writel(reg, usim->base + USIM_SYSCONFIG);
>> +
>> +       if (usim->phy_present) {
>> +               USIM_WRITEREG(usim->base, USIM_STAT, STATNOCARD, 1);
>> +               USIM_WRITEREG(usim->base, USIM_CONF1, BYPASS_HW_AUTO, 0);
>> +       } else {
>> +               USIM_WRITEREG(usim->base, USIM_STAT, STATNOCARD, 0);
>> +               USIM_WRITEREG(usim->base, USIM_CONF1, BYPASS_HW_AUTO, 1);
>> +       }
>> +
>> +       /* Set default card type as EMV, Force SIO to low level */
>> +       reg = readl(usim->base + USIM_CONF1);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF1, EMV_CONF, 1);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF1, CONFSIOLOW, 1);
>> +       writel(reg, usim->base + USIM_CONF1);
>> +
>> +       /* Set parity level to 1, auto resent to 2 on parity error,  */
>> +       reg = readl(usim->base + USIM_CONF2);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, NACKING_EN, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CARD_POLARITY, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFEDC, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFPROTOCOL, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, ATR_ASYN_BYPASS, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKMODE, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, PAR_ERR_LEVEL, 1);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFRESENT, 2);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, PUT_ERR_IN_FIFO, 1);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFLRCCHECK, 2);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFCHKPAR, 1);
>> +
>> +       if (usim->phy_present) {
>> +               reg = USIM_SETFIELD(reg, USIM_CONF2, HW_DEACTIV_EN, 0);
>> +               reg = USIM_SETFIELD(reg, USIM_CONF2, DEBOUNCE_EN, 0);
>> +       } else {
>> +               reg = USIM_SETFIELD(reg, USIM_CONF2, HW_DEACTIV_EN, 1);
>> +       }
>> +
>> +       writel(reg, usim->base + USIM_CONF2);
>> +
>> +       /* Reset Tx FIFO Pointer */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
>> +
>> +       /* Reset Rx FIFO Pointer */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
>> +
>> +       /* Configure FIFO settings */
>> +       /* Set Tx and Rx trigger to 1 byte */
>> +       reg = readl(usim->base + USIM_FIFOS);
>> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, FIFO_TX_TRIGGER, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, FIFO_RX_TRIGGER, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, RXDMA_TYPE, 0x3);
>> +       reg = USIM_SETFIELD(reg, USIM_FIFOS, DMA_MODE, 0x0);
>> +       writel(reg, usim->base + USIM_FIFOS);
>> +
>> +       /* Enable FIFO access */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_ENABLE, 1);
>> +
>> +       /* Use HW mode for ETU calculation and set FI = 372 and DI = 1 */
>> +       reg = readl(usim->base + USIM_CONF5);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF5, FI, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF5, DI, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
>> +       writel(reg, usim->base + USIM_CONF5);
>> +
>> +       /* Configure CONF6 settings */
>> +       reg = readl(usim->base + USIM_CONF6);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, VCC_BYPASS, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, RST_BYPASS, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, RST_POLARITY, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 1);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, MODE, USIM_CONF6_MODE_FREEZE);
>> +       writel(reg, usim->base + USIM_CONF6);
>> +
>> +       /* Clear all bits in IO_DIRECT register */
>> +       writel(0, usim->base + USIM_IO_DIRECT);
>> +
>> +       /* Disable legacy bypass mode */
>> +       USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 0);
>> +
>> +       /* Enable required interrupts */
>> +       reg = readl(usim->base + USIM_IRQENABLE);
>> +       writel(reg, usim->base + USIM_IRQENABLE);
>> +
>> +       /* Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
>> +        * gets disable
>> +        */
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 1);
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
>> +                     USIM_ATR_TIMEOUT_EMV);
>> +
>> +       /* Set STOP_RX_TIMEOUT */
>> +       /* Set STOP_RESEND_FAILURE */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RX_TIMEOUT, 1);
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 1);
>> +
>> +       /* set smartcard clock */
>> +       usim_set_smartcardclock(usim, usim->slot_ctx[usim->slot].clock);
>> +
>> +       return 0;
>> +}
>> +
>> +static int usim_set_voltage(struct usim *usim, u32 voltage)
>> +{
>> +       int ret = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +       /*
>> +        * voltage = 0 for 5V,
>> +        * voltage = 1 for 3V,
>> +        * voltage = 2 for 1.8V,
>> +        */
>> +       if (voltage > 3)
>> +               return -EINVAL;
>> +       if (usim->phy_present) {
>> +               ret = phy->set_config(phy, usim->slot,
>> +                               SC_PHY_CARD_SUPPLY_VOLTAGE, voltage);
>> +       }
>> +       usim->slot_ctx[usim->slot].supply = voltage;
>> +       return ret;
>> +}
>> +
>> +static int usim_set_smartcardclock(struct usim *usim, u32 clock)
>> +{
>> +       int clkdiv;
>> +       int clkmode;
>> +       int reg = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       switch (clock) {
>> +       case USIM_SMARTCART_CLOCK_3_3MHZ:
>> +               clkmode = USIM_CONFSCLKMODE_HF;
>> +               clkdiv  = 3;
>> +               break;
>> +
>> +       case USIM_SMARTCART_CLOCK_4MHZ:
>> +               clkmode = USIM_CONFSCLKMODE_HF;
>> +               clkdiv  = 2;
>> +               break;
>> +
>> +       case USIM_SMARTCART_CLOCK_5MHZ:
>> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
>> +               clkdiv  = 3;
>> +               break;
>> +
>> +       case USIM_SMARTCART_CLOCK_6_6MHZ:
>> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
>> +               clkdiv  = 2;
>> +               break;
>> +
>> +       case USIM_SMARTCART_CLOCK_10MHZ:
>> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
>> +               clkdiv  = 1;
>> +               break;
>> +
>> +       case USIM_SMARTCART_CLOCK_20MHZ:
>> +               clkmode = USIM_CONFSCLKMODE_LEGACY;
>> +               clkdiv  = 0;
>> +               break;
>> +
>> +       default:
>> +               dev_err(usim->dev, "Unsupported Clock configuration for smartcard\n");
>> +               return -EINVAL;
>> +               break;
>> +       }
>> +
>> +       /* Set default card type as EMV, Force SIO to low level */
>> +       reg = readl(usim->base + USIM_CONF2);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKMODE, clkmode);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF2, CONFSCLKDIV, clkdiv);
>> +       writel(reg, usim->base + USIM_CONF2);
>> +
>> +       /* setting phy division to zero, as USIM samples smartcard clk line and
>> +        * put the data in USIM fifo. Phy supply the clock to smartcard wihtout
>> +        * furhter division
>> +        */
>> +       if (usim->phy_present)
>> +               phy->set_config(phy, usim->slot, SC_PHY_CLKDIV, 0);
>> +
>> +       usim->slot_ctx[usim->slot].clock = clock;
>> +       return 0;
>> +}
>> +
>> +static int usim_set_etu(struct usim *usim, u32 fi, u32 di)
>> +{
>> +       USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
>> +       USIM_WRITEREG(usim->base, USIM_CONF5, FI, fi);
>> +       USIM_WRITEREG(usim->base, USIM_CONF5, DI, di);
>> +       return 0;
>> +}
>> +
>> +static int usim_set_rxparitycount(struct usim *usim, u32 rxcount)
>> +{
>> +       if (rxcount > USIM_MAX_PARITY_RETRIES)
>> +               return -EINVAL;
>> +
>> +       /* Program fields required for RX retry in USIM IP */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, PAR_ERR_LEVEL, rxcount);
>> +
>> +       /* Enable rx parity check */
>> +       if (rxcount > 0) {
>> +               USIM_WRITEREG(usim->base, USIM_CONF2, CONFCHKPAR, 1);
>> +               usim_irq_enable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
>> +       } else {
>> +               usim_irq_disable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int usim_set_txretrycount(struct usim *usim, u32 txcount)
>> +{
>> +       if (txcount > USIM_MAX_PARITY_RETRIES)
>> +               return -EINVAL;
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, CONFRESENT, txcount);
>> +       if (txcount > 0)
>> +               usim_irq_enable(usim->base, USIM_IRQ_RESENT);
>> +       else
>> +               usim_irq_disable(usim->base, USIM_IRQ_RESENT);
>> +
>> +       return 0;
>> +}
>> +
>> +static int usim_set_c4(struct usim *usim, int state)
>> +{
>> +       int ret = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +       if (usim->phy_present)
>> +               ret = phy->set_config(phy, usim->slot, SC_PHY_PIN_C4, state);
>> +       else
>> +                USIM_WRITEREG(usim->base, USIM_IO_DIRECT, C4, state);
>> +       return ret;
>> +}
>> +
>> +static int usim_set_c8(struct usim *usim, int state)
>> +{
>> +       int ret = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       if (usim->phy_present)
>> +               ret = phy->set_config(phy, usim->slot, SC_PHY_PIN_C8, state);
>> +       return ret;
>> +}
>> +static int usim_get_version(struct usim *usim)
>> +{
>> +       int version = 0x0;
>> +
>> +       /* last 16 bytes represents controller version
>> +        * and first 16 bytes represents phy version (if connected)
>> +        */
>> +       version = USIM_READREG(usim->base, USIM_REVISION, REV);
>> +       if (usim->phy_present)
>> +               version |= ((usim->phy->get_config(usim->phy, 0,
>> +                                       SC_PHY_VERSION)) << 0x10);
>> +       return version;
>> +}
>> +static int usim_init_emvusercard(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, DMA_MODE, 0);
>> +
>> +       usim_set_etu(usim, 0, 0);
>> +
>> +       if (usim_set_txretrycount(usim, 5) != 0)
>> +               return -EINVAL;
>> +
>> +       if (usim_set_rxparitycount(usim, 5) != 0)
>> +               return -EINVAL;
>> +
>> +       usim_set_c4(usim, 0);
>> +       usim_set_c8(usim, 0);
>> +
>> +       if (usim->phy_present) {
>> +               /* Set early ATR and mute ATR in case of phy */
>> +               ret = phy->set_config(phy, usim->slot, SC_PHY_ATR_EARLY_TIME,
>> +                               USIM_EMV_ATR_EARLY_TO);
>> +               if (ret != 0)
>> +                       return ret;
>> +
>> +               ret = phy->set_config(phy, usim->slot, SC_PHY_ATR_MUTE_TIME,
>> +                               USIM_EMV_ATR_MUTE_TO);
>> +               if (ret != 0)
>> +                       return ret;
>> +
>> +               /* enable user slot */
>> +               ret = phy->set_config(phy, usim->slot, SC_PHY_IO, 1);
>> +               if (ret != 0)
>> +                       return ret;
>> +       }
>> +       /* set cwt,wwt,cgt */
>> +       USIM_WRITEREG(usim->base, USIM_WWT, WWT, USIM_EMV_WWT);
>> +       USIM_WRITEREG(usim->base, USIM_CWT, CWT, USIM_EMV_WWT - 22);
>> +       USIM_WRITEREG(usim->base, USIM_CGT, CGT, USIM_EMV_CGT);
>> +
>> +       return 0;
>> +}
>> +
>> +static int usim_warmreset(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       /* reset ATR wait flag */
>> +       usim->atrdone = 0;
>> +
>> +       usim->slot_ctx[usim->slot].atr_length = 0;
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
>> +       usim->slot_ctx[usim->slot].state = USIM_MODE_IDLE;
>> +
>> +       /* reset FIFO pointer */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x1);
>> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x0);
>> +
>> +       /* Do store bytes with parity error in Rx FIFO */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0x1);
>> +
>> +       usim_irq_disable(usim->base, (USIM_IRQ_TX | USIM_IRQ_EOB));
>> +
>> +       usim->slot_ctx[usim->slot].state = USIM_MODE_ATR;
>> +
>> +       /* warm reset the card */
>> +       if (usim->phy_present) {
>> +               ret = phy->warm_reset(phy, usim->slot);
>> +               if (ret != 0)
>> +                       return ret;
>> +       } else {
>> +               /* warm reset using USIM */
>> +               USIM_WRITEREG(usim->base, USIM_CMD, CMD_WARM_RST, 0x1);
>> +       }
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_ATR);
>> +
>> +       return 0;
>> +}
>> +static int usim_set_cardmode(struct usim *usim, int slot, int card_mode)
>> +{
>> +       int val = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       if (card_mode !=  usim->slot_ctx[slot].card_mode) {
>> +               /* deactivate current card before changing the
>> +                * mode of smart card
>> +                */
>> +               usim_deactivate_card(usim);
>> +       } else {
>> +               dev_dbg(usim->dev, "mode is same as previous, no action!!");
>> +               return 0;
>> +       }
>> +
>> +       /* set card mode */
>> +       switch (card_mode) {
>> +       case USIM_CARD_MODE_ASYNC:
>> +               val = SC_PHY_ASYNC;
>> +               break;
>> +
>> +       case USIM_CARD_MODE_SYNC_TYPE1:
>> +               val = SC_PHY_SYNC_TYPE1;
>> +               break;
>> +
>> +       case USIM_CARD_MODE_SYNC_TYPE2:
>> +               val = SC_PHY_SYNC_TYPE2;
>> +               break;
>> +
>> +       case USIM_CARD_MODE_SYNC_OTHER:
>> +               val = SC_PHY_SYNC;
>> +               break;
>> +
>> +       default:
>> +               dev_err(usim->dev, "Invalid card mode");
>> +               return -EINVAL;
>> +               break;
>> +       }
>> +       if (usim->phy_present == USIM_PHY_PRESENT)
>> +               phy->set_config(usim->phy, slot, SC_PHY_CARD_MODE, val);
>> +       usim->slot_ctx[slot].card_mode = card_mode;
>> +       return 0;
>> +}
>> +
>> +static int usim_activate_synccard(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       int reg = 0;
>
> These don't need to be initialized and can be 1 line.
Agree
>
>> +       struct sc_phy *phy = usim->phy;
>> +       if (usim->phy_present != USIM_PHY_PRESENT) {
>> +               dev_err(usim->dev, "Sync card w/o phy is not supported");
>> +               return -EPERM;
>> +       }
>> +
>> +       /* Enable legacy bypass mode */
>> +       USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 1);
>> +
>> +       /* set all lines to state L */
>> +       writel(0x0, usim->base + USIM_IO_DIRECT);
>> +
>> +       /* configure h/w control mode for select slot */
>> +       reg = readl(usim->base + USIM_CONF6);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 1);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 1);
>> +       /* lets put i/o line in SW ctrl */
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, IO_BYPASS, 0x3);
>> +       writel(reg, usim->base + USIM_CONF6);
>> +
>> +       /* activate the card */
>> +       ret = phy->activate_card(phy, usim->slot);
>> +       return ret;
>> +}
>> +
>> +static int usim_activate_card(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       int reg = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +       int mode = usim->slot_ctx[usim->slot].card_mode;
>> +
>> +       usim->atrdone = 0;
>> +       usim->slot_ctx[usim->slot].atr_length = 0;
>> +
>> +       /* set card mode */
>> +       usim_set_cardmode(usim, usim->slot, mode);
>> +
>> +       if (usim->slot_ctx[usim->slot].card_mode != USIM_CARD_MODE_ASYNC) {
>> +               /* synchronous card activation */
>> +               ret = usim_activate_synccard(usim);
>> +               return ret;
>> +       }
>> +
>> +       if (usim->slot_ctx[usim->slot].emv)
>> +               usim_init_emvusercard(usim);
>> +
>> +       /* disable legacy bypass mode */
>> +       USIM_WRITEREG(usim->base, USIM_CONF1, CONFBYPASS, 0);
>> +
>> +       /* configure h/w control mode for select slot */
>> +       reg = readl(usim->base + USIM_CONF6);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, SCLK0_BYPASS, 0);
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, ATR_TIMER_BYPASS, 0);
>> +       /* lets put i/o line in h/w ctrl */
>> +       reg = USIM_SETFIELD(reg, USIM_CONF6, IO_BYPASS, 0x2);
>> +       writel(reg, usim->base + USIM_CONF6);
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, 1);
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER, 0x103);
>> +
>> +       /* RXDMA_TYPE = 0x1 - USIM_RXFIFO_BYTECNT value is ignored */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, RXDMA_TYPE, 0x1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_ENABLE, 0x1);
>> +
>> +       /* Do store bytes with parity error in Rx FIFO */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0x1);
>> +       usim_irq_disable(usim->base, (USIM_IRQ_TX | USIM_IRQ_EOB));
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x1);
>> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 0x0);
>> +
>> +       /*
>> +        * Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
>> +        * gets disable. EMVCo Test case ref#1703_21/22
>> +        */
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 0x1);
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
>> +                     USIM_ATR_TIMEOUT_EMV);
>> +       USIM_WRITEREG(usim->base, USIM_CMD, MODULE_CLK_EN, 0x1);
>> +
>> +       usim->slot_ctx[usim->slot].state = USIM_MODE_ATR;
>> +
>> +       /* set smartcard clock */
>> +       usim_set_smartcardclock(usim, usim->slot_ctx[usim->slot].clock);
>> +
>> +       /* Activate card */
>> +       if (usim->phy_present) {
>> +               usim_irq_disable(usim->base, USIM_IRQ_TX|USIM_IRQ_ATR_START);
>> +               usim_irq_enable(usim->base, 0xFFFFFFF7);
>> +               usim_irq_disable(usim->base, USIM_IRQ_NATR);
>> +               usim_irq_enable(usim->base, USIM_IRQ_EMV_ATR_LENGTH_TIME_OUT);
>> +               usim_irq_disable(usim->base, USIM_IRQ_TX|USIM_IRQ_ATR_START);
>> +
>> +               /* do no bypass ATR length timer, also do not
>> +                * disturb the bypass setting of other param
>> +                */
>> +               USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMER_BYPASS, 0x1);
>> +
>> +               usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
>> +
>> +               ret = phy->activate_card(phy, usim->slot);
>> +               if (ret != 0)
>> +                       return ret;
>> +       } else {
>> +               /* Activate using USIM */
>> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 0x0);
>> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 0x1);
>> +       }
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_ATR);
>> +       return 0;
>> +}
>> +
>> +static int usim_deactivate_card(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       int cnt = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       /* clear atr buffer */
>> +       for (cnt = 0; cnt < USIM_MAX_ATRLENGTH; cnt++)
>> +               usim->slot_ctx[usim->slot].atr[cnt] = 0x0;
>> +       usim->slot_ctx[usim->slot].atr_length = 0x0;
>> +
>> +       /* Use USIM IP for deactivation if there is no phy */
>> +       if (usim->phy_present == USIM_PHY_PRESENT) {
>> +               ret = phy->deactivate_card(phy, usim->slot);
>> +               if (ret != 0)
>> +                       return ret;
>> +       } else {
>> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTART, 0x0);
>> +               USIM_WRITEREG(usim->base, USIM_CMD, CMDSTOP, 1);
>> +       }
>> +
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_IDLE);
>> +       USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, 0);
>> +
>> +       /* Toggling ATR length to ensure 'USIM_STAT_ATRRX_AFTER_TIMEOUT'
>> +        * gets disable TC Ref: 1703_21/22
>> +        */
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT, 1);
>> +       USIM_WRITEREG(usim->base, USIM_CONF6, ATR_TIMEOUT,
>> +                     USIM_ATR_TIMEOUT_EMV);
>> +
>> +       /* stop ATR length timeout */
>> +       USIM_WRITEREG(usim->base, USIM_CMD, STOP_EMV_ATR_LENGTH_TIMER, 1);
>> +       usim->slot_ctx[usim->slot].state = USIM_MODE_DEACT;
>> +       usim->atrdone = 0;
>> +
>> +       return 0;
>> +}
>> +
>> +static void usim_set_protocol(struct usim *usim, int protocol)
>> +{
>> +       u32 irq;
>> +
>> +       /* As per spec, mask all interrupts before switching
>> +        * from one protocol to other.
>> +        */
>> +       usim_irq_get(usim->base, &irq);
>> +
>> +       /* disable all interrupts */
>> +       usim_irq_disable(usim->base, 0xFFFFFFFF);
>> +
>> +       /* 0 for T=0 and 1 for T=1 protocol */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, CONFPROTOCOL, protocol);
>> +       usim->slot_ctx[usim->slot].protocol = protocol;
>> +
>> +       /* read and clear status */
>> +       usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
>> +
>> +       /* now renable interrupts */
>> +       usim_irq_enable(usim->base, irq);
>> +       return;
>> +}
>> +
>> +static int usim_get_cardpinlevel(struct usim *usim, int pin, int *level)
>> +{
>> +       struct sc_phy *phy = usim->phy;
>> +       int param = 0;
>> +
>> +       if (usim->slot_ctx[usim->slot].card_mode == USIM_CARD_MODE_ASYNC) {
>> +               dev_err(usim->dev, "Operation not permitted for async mode");
>> +               return -EPERM;
>> +       }
>> +       if (pin == USIM_PARAM_CARD_PIN_IO) {
>> +               /* For Rx, RNW:1, OEN:1 */
>> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, RNW0, 1);
>> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, SIOEN0, 1);
>> +               *level = USIM_READREG(usim->base, USIM_IO_DIRECT, SIORX0);
>> +               return 0;
>> +       }
>> +
>> +       if (usim->phy_present == USIM_PHY_PRESENT) {
>> +               switch (pin) {
>> +               case USIM_PARAM_CARD_PIN_VCC:
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_RST:
>> +                       param = SC_PHY_PIN_RST;
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_CLK:
>> +                       param = SC_PHY_PIN_CLK;
>> +                       break;
>> +
>> +               default:
>> +                       dev_err(usim->dev, "Invalid pin");
>> +                       return -EINVAL;
>> +               }
>> +               *level = phy->get_config(phy, usim->slot, param);
>> +               return  0;
>> +       } else {
>> +               switch (pin) {
>> +               case USIM_PARAM_CARD_PIN_VCC:
>> +                       *level = USIM_READREG(usim->base,
>> +                                       USIM_IO_DIRECT, SVCC);
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_RST:
>> +                       *level = USIM_READREG(usim->base,
>> +                                       USIM_IO_DIRECT, RST);
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_CLK:
>> +                       *level = USIM_READREG(usim->base,
>> +                                       USIM_IO_DIRECT, SCLK0);
>> +                       break;
>> +
>> +               default:
>> +                       dev_err(usim->dev, "Invalid pin");
>> +                       return -EINVAL;
>> +               }
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int usim_set_cardpinlevel(struct usim *usim, int pin, int level)
>> +{
>> +       int ret = 0;
>> +       int param = 0;
>> +       int value = level > 0 ? 1 : 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       if (usim->slot_ctx[usim->slot].card_mode == USIM_CARD_MODE_ASYNC) {
>> +               dev_err(usim->dev, "Operation not permitted for async mode");
>> +               return -EPERM;
>> +       }
>> +       if (pin == USIM_PARAM_CARD_PIN_IO) {
>> +               /* For Tx: RNW=0; OEN=Tx */
>> +               /* Tx line will be followed by OEN line, so setting OEN bit*/
>> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, RNW0, 0);
>> +               USIM_WRITEREG(usim->base, USIM_IO_DIRECT, SIOEN0, value);
>> +               return 0;
>> +       }
>> +
>> +       if (usim->phy_present == USIM_PHY_PRESENT) {
>> +               switch (pin) {
>> +               case USIM_PARAM_CARD_PIN_VCC:
>> +                       /* will be set by activation or deactivation */
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_RST:
>> +                       param = SC_PHY_PIN_RST;
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_CLK:
>> +                       param = SC_PHY_PIN_CLK;
>> +                       break;
>> +
>> +               default:
>> +                       dev_err(usim->dev, "Invalid pin");
>> +                       return -EINVAL;
>> +               }
>
>
> Make this switch a helper function. Same code exists above.
>
will do
>> +               ret = phy->set_config(phy, usim->slot, param, value);
>> +               return  ret;
>> +       } else {
>> +               switch (pin) {
>> +               case USIM_PARAM_CARD_PIN_VCC:
>> +                       USIM_WRITEREG(usim->base,
>> +                                     USIM_IO_DIRECT, SVCC, value);
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_RST:
>> +                       USIM_WRITEREG(usim->base,
>> +                                     USIM_IO_DIRECT, RST, value);
>> +                       break;
>> +
>> +               case USIM_PARAM_CARD_PIN_CLK:
>> +                       USIM_WRITEREG(usim->base,
>> +                                     USIM_IO_DIRECT, SCLK0, value);
>> +                       break;
>> +
>> +               default:
>> +                       dev_err(usim->dev, "Invalid pin");
>> +                       return -EINVAL;
>> +               }
>
> Probably something similar can be done here. Perhaps you should have
> default phy ops which is built-in. Then you can always just call
> phy->set_config.
>
Actually, there are mutliple combination possible.
- Smartcard controller without PHY, Where smart card slot will be 
directly connected to controller
- Smartcard controller with phy, where smart card slot will be connected 
to phy and communication happens using phy.
That is why I have used case for PHY and W/O PHY
>
>> +       }
>> +       return 0;
>> +}
>> +static void usim_configure_rx_pio(struct usim *usim)
>> +{
>> +       /* Reset RX FIFO pointers */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFORX_RESET, 0);
>> +
>> +       /* read and clear any pending interrupt status */
>> +       usim_irqstatus_clear(usim->base, usim_irqstatus(usim->base));
>> +
>> +       /* Enable WWT underflow interupt,
>> +        * RX FIFO full interrupt,
>> +        * BWT, CWT and parity error level interrupts.
>> +        */
>> +       usim_irq_enable(usim->base, USIM_IRQ_WT | USIM_IRQ_RXFULL |
>> +                               USIM_IRQ_TOB |
>> +                               USIM_IRQ_TOC |
>> +                               USIM_IRQ_PAR_ERR_LEVEL_REACHED);
>> +
>> +       /* Lets disable key RX interrupts. We will enable them later
>> +        * when we want to start RX
>> +        */
>> +       usim_irq_disable(usim->base, USIM_IRQ_RX |
>> +                       USIM_IRQ_RXDMA_RDY | USIM_IRQ_EOB);
>> +
>> +       /* We will use only RX FIFO threshold in RX */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, RXDMA_TYPE, 0x1);
>> +
>> +       if (usim->slot_ctx[usim->slot].protocol == 0) {
>> +               /* Set Rx FIFO Threshold to expected recv length
>> +                * Subtract 1 from length as HW adds 1 to the trigger
>> +                */
>> +               USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER,
>> +                             usim->slot_ctx[usim->slot].rx_explen - 1);
>> +       } else {
>> +               /* T=1 protocol */
>> +               /* for T1 we should not use parity error level interrupt */
>> +               usim_irq_disable(usim->base, USIM_IRQ_PAR_ERR_LEVEL_REACHED);
>> +
>> +               /* set RX FIFO threshold to MAX_RX_FIFO size.
>> +                * We will rely on End-Of-Block interrupt to
>> +                * terminate reception in T1
>> +                */
>> +               USIM_WRITEREG(usim->base, USIM_FIFOS, FIFO_RX_TRIGGER,
>> +                             USIM_MAX_RX_FIFO_SIZE - 1);
>> +       }
>> +       return;
>> +}
>> +
>> +static void usim_configure_tx_pio(struct usim *usim)
>> +{
>> +       /* Make sure TX is stopped first by programming
>> +        * TX_BLOCK to zero and disabling TX_BLOCK_DONE
>> +        * and USIM_IRQ_TX_BLOCK_REQ interrupts
>> +        */
>> +       USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, 0);
>> +       usim_irq_disable(usim->base, USIM_IRQ_TX_BLOCK_DONE |
>> +                                                       USIM_IRQ_TX_BLOCK_REQ);
>> +
>> +       /* We will use Tx Block length feature so clear TX_EN bit */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, TX_EN, 0);
>> +       /* We will not use USIM_TX interrupt for transmit operation */
>> +       usim_irq_disable(usim->base, USIM_IRQ_TX);
>> +       /* Reset TX FIFO pointers */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 1);
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, FIFOTX_RESET, 0);
>> +
>> +       /* Ensure PIO mode is programmed */
>> +       USIM_WRITEREG(usim->base, USIM_FIFOS, DMA_MODE, 0);
>> +}
>> +
>> +static int usim_send_data(struct usim *usim, char *txbuf, int len)
>> +{
>> +       u32 val;
>> +       int i;
>> +       int ret = 0;
>> +
>> +       usim->txdone = 0;
>> +       usim->rxdone = 0;
>> +
>> +       if (len == 0) {
>> +               dev_dbg(usim->dev, "Error: Invalid Tx length:%d", len);
>> +               return -EINVAL;
>> +       }
>> +
>> +       usim->slot_ctx[usim->slot].event = 0;
>> +
>> +       /* Configure Tx PIO mode patams */
>> +       usim_configure_tx_pio(usim);
>> +
>> +       /* Tx FIFO must be empty after reset */
>> +       val = USIM_READREG(usim->base, USIM_FIFOS, FIFOTX_EMPTY);
>> +       if (val == 0) {
>> +               dev_dbg(usim->dev, "Error: Tx FIFO is not empty");
>> +               return -EFAULT;
>> +       }
>> +
>> +       /* write data in Tx FIFO */
>> +       for (i = 0; i < len; i++) {
>> +               USIM_WRITEREG(usim->base, USIM_DTX, DTX, txbuf[i]);
>> +               dev_dbg(usim->dev, "txbyte %d = %x\n", i, txbuf[i]);
>> +       }
>> +
>> +       /* Finally re-enable TX_BLOCK_xxx interrupts and clear RX interrupts */
>> +       usim_irq_enable(usim->base, USIM_IRQ_TX_BLOCK_DONE |
>> +                                               USIM_IRQ_TX_BLOCK_REQ);
>> +
>> +       /* For T=0, stop re-tranmission after resend failure */
>> +       if (usim->slot_ctx[usim->slot].protocol == 0) {
>> +               USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 0);
>> +               USIM_WRITEREG(usim->base, USIM_CONF2, STOP_RESEND_FAILURE, 1);
>> +       }
>> +
>> +       /* Do not store bytes with parity error in Rx FIFO */
>> +       USIM_WRITEREG(usim->base, USIM_CONF2, PUT_ERR_IN_FIFO, 0);
>> +
>> +       usim_irq_enable(usim->base, USIM_IRQ_TOC);
>> +
>> +       if (usim->phy_present)
>> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_TXRX);
>> +       else
>> +               USIM_WRITEREG(usim->base, USIM_CONF6, MODE, USIM_MODE_LEGACY);
>> +
>> +       usim->slot_ctx[usim->slot].state = USIM_MODE_TXRX;
>> +
>> +       /* Configure Rx settings before performing a Tx
>> +        * As soon as we are done with Tx, card will send
>> +        * data, which we should be ready to capture
>> +        */
>> +       usim_configure_rx_pio(usim);
>> +       /* Start TX operation - program TX_BLOCK register to length
>> +        * of the TX buffer to start the TX operation.
>> +        */
>> +       USIM_WRITEREG(usim->base, USIM_TX_BLOCK, BLOCK_LENGTH, len);
>> +
>> +       /* We need to block the caller here */
>> +       ret = wait_event_interruptible(tx_wait, (usim->txdone == 1));
>> +       dev_dbg(usim->dev, "Tx WAIT OVER\n");
>> +       if (usim->slot_ctx[usim->slot].event == USIM_EVENT_TIMEOUT)
>> +               usim_send_signal(usim, USIM_EVENT_TIMEOUT);
>> +
>> +       return ret;
>> +}
>> +
>> +static int usim_set_config(struct usim *usim, struct usim_config *param)
>> +{
>> +       u32 ret = 0;
>> +       dev_dbg(usim->dev, "param:%d, value:%d\n", param->attr, param->value);
>> +
>> +       switch (param->attr) {
>> +       case USIM_PARAM_CWT:
>> +               USIM_WRITEREG(usim->base, USIM_CWT, CWT, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_WWT:
>> +               USIM_WRITEREG(usim->base, USIM_WWT, WWT, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_CGT:
>> +               USIM_WRITEREG(usim->base, USIM_CGT, CGT, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_BWT:
>> +               USIM_WRITEREG(usim->base, USIM_BWT, BWT, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_EDCTYPE:
>> +               /* 0 = LRC check, 1 = CRC check */
>> +               USIM_WRITEREG(usim->base, USIM_CONF2, CONFEDC, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_LRCCHECK:
>> +               /* 0 = No LRC check, 1 = LRC check */
>> +               USIM_WRITEREG(usim->base, USIM_CONF2, CONFLRCCHECK,
>> +                             param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_C4:
>> +               usim_set_c4(usim, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_C8:
>> +               usim_set_c8(usim, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_PROTOCOL:
>> +               /* 0 for T=0 and 1 for T=1 */
>> +               usim_set_protocol(usim, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_VOLTAGE:
>> +               ret = usim_set_voltage(usim, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_EMV:
>> +               USIM_WRITEREG(usim->base, USIM_CONF1, EMV_CONF, param->value);
>> +               if (param->value)
>> +                       usim->slot_ctx[usim->slot].emv = true;
>> +               else
>> +                       usim->slot_ctx[usim->slot].emv = false;
>> +               break;
>> +
>> +       case USIM_PARAM_FI:
>> +               USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
>> +               USIM_WRITEREG(usim->base, USIM_CONF5, FI, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_DI:
>> +               USIM_WRITEREG(usim->base, USIM_CONF5, SOFT_NHARD_FIDI_PROG, 0);
>> +               USIM_WRITEREG(usim->base, USIM_CONF5, DI, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_CODING_CONV:
>> +               USIM_WRITEREG(usim->base, USIM_STAT, CONFCODCONV, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_CLOCK_STOP:
>> +               USIM_WRITEREG(usim->base, USIM_CMD, CMD_CLOCK_STOP,
>> +                             param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_SMARTCARD_CLOCK:
>> +               ret = usim_set_smartcardclock(usim, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_SMARTCARD_MODE:
>> +               ret = usim_set_cardmode(usim, usim->slot, param->value);
>> +               break;
>> +
>> +       case USIM_PARAM_CARD_PIN_VCC:
>> +       case USIM_PARAM_CARD_PIN_RST:
>> +       case USIM_PARAM_CARD_PIN_CLK:
>> +       case USIM_PARAM_CARD_PIN_IO:
>> +               ret = usim_set_cardpinlevel(usim, param->attr, param->value);
>> +               break;
>> +
>> +       default:
>> +               ret = -EINVAL;
>> +               break;
>> +       }
>> +       return ret;
>> +}
>> +static void usim_get_syncatr(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       struct sc_phy *phy = usim->phy;
>> +
>> +       /* Max ATR bytes for sync card is 4 */
>> +       usim->slot_ctx[usim->slot].atr_length = 0x4;
>> +       if (usim->phy_present != USIM_PHY_PRESENT) {
>> +               dev_err(usim->dev, "Sync card w/o phy is not supported");
>> +               return;
>> +       }
>> +       /* get sync ATR */
>> +       if (phy->get_syncatr == NULL)
>> +               return;
>> +       ret = phy->get_syncatr(phy,
>> +                       usim->slot,
>> +                       usim->slot_ctx[usim->slot].atr_length,
>> +                       usim->slot_ctx[usim->slot].atr);
>> +       return;
>> +}
>> +
>> +static int usim_get_config(struct usim *usim, struct usim_config *param)
>> +{
>> +       u32 ret = 0;
>> +       dev_dbg(usim->dev, "param:%d, value:%d\n", param->attr, param->value);
>> +
>> +       switch (param->attr) {
>> +       case USIM_PARAM_CWT:
>> +               param->value = USIM_READREG(usim->base, USIM_CWT, CWT);
>> +               break;
>> +
>> +       case USIM_PARAM_WWT:
>> +               param->value = USIM_READREG(usim->base, USIM_WWT, WWT);
>> +               break;
>> +
>> +       case USIM_PARAM_CGT:
>> +               param->value = USIM_READREG(usim->base, USIM_CGT, CGT);
>> +               break;
>> +
>> +       case USIM_PARAM_BWT:
>> +               param->value = USIM_READREG(usim->base, USIM_BWT, BWT);
>> +               break;
>> +
>> +       case USIM_PARAM_EDCTYPE:
>> +               param->value = USIM_READREG(usim->base, USIM_CONF2, CONFEDC);
>> +               break;
>> +
>> +       case USIM_PARAM_LRCCHECK:
>> +               param->value = USIM_READREG(usim->base, USIM_CONF2,
>> +                               CONFLRCCHECK);
>> +               break;
>> +
>> +       case USIM_PARAM_PROTOCOL:
>> +               /* 0 for T=0 and 1 for T=1 */
>> +               param->value = USIM_READREG(usim->base, USIM_CONF2,
>> +                               CONFPROTOCOL);
>> +               break;
>> +
>> +       case USIM_PARAM_VOLTAGE:
>> +               param->value = usim->slot_ctx[usim->slot].supply;
>> +               break;
>> +
>> +       case USIM_PARAM_EMV:
>> +               param->value = USIM_READREG(usim->base, USIM_CONF1, EMV_CONF);
>> +               break;
>> +
>> +       case USIM_PARAM_FI:
>> +               param->value = USIM_READREG(usim->base, USIM_CONF5, FI);
>> +               break;
>> +
>> +       case USIM_PARAM_DI:
>> +               param->value = USIM_READREG(usim->base, USIM_CONF5, DI);
>> +               break;
>> +
>> +       case USIM_PARAM_CODING_CONV:
>> +               param->value = USIM_READREG(usim->base, USIM_STAT, CONFCODCONV);
>> +               break;
>> +
>> +       case USIM_PARAM_CLOCK_STOP:
>> +               param->value = USIM_READREG(usim->base, USIM_CMD,
>> +                                           CMD_CLOCK_STOP);
>> +               break;
>> +
>> +       case USIM_PARAM_SMARTCARD_CLOCK:
>> +               param->value = usim->slot_ctx[usim->slot].clock;
>> +               break;
>> +
>> +       case USIM_PARAM_SMARTCARD_MODE:
>> +               param->value = usim->slot_ctx[usim->slot].card_mode;
>> +               break;
>> +
>> +       case USIM_PARAM_CARD_PIN_VCC:
>> +       case USIM_PARAM_CARD_PIN_RST:
>> +       case USIM_PARAM_CARD_PIN_CLK:
>> +       case USIM_PARAM_CARD_PIN_IO:
>> +               ret = usim_get_cardpinlevel(usim, param->attr, &param->value);
>> +               break;
>> +       default:
>> +               ret = -EINVAL;
>> +               break;
>> +       }
>> +       return ret;
>> +}
>> +
>> +static long usim_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>> +{
>> +       struct usim *usim = file->private_data;
>> +       struct usim_data data;
>> +       struct usim_config param;
>> +
>> +       int ret         = 0;
>> +       int cnt         = 0;
>> +       int version     = 0;
>> +       int u_pid       = 0;
>> +       int present     = 0;
>> +       unsigned long atr_timeout = 0;
>> +
>> +       if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
>> +               return -ENXIO;
>> +
>> +       switch (cmd) {
>> +       case USIM_IOCTL_GET_PROVIDER_VERSION:
>> +               dev_dbg(usim->dev, "IOCTL: GET PROVIDER VERSION\n");
>> +               version = usim_get_version(usim);
>> +               ret = copy_to_user((unsigned int *)arg, &version,
>> +                               sizeof(unsigned int));
>> +               if (ret != 0)
>> +                       ret = -EFAULT;
>> +               break;
>> +
>> +       case USIM_IOCTL_ACTIVATE_CARD:
>> +               dev_dbg(usim->dev, "IOCTL: ACTIVATE CARD\n");
>> +               if (usim->phy_present) {
>> +                       present = usim->phy->get_config(usim->phy, usim->slot,
>> +                                                       SC_PHY_CARD_PRESENCE);
>> +                       if (present)
>> +                               ret = usim_activate_card(usim);
>> +                       else
>> +                               ret = -EFAULT;
>> +               }
>> +               break;
>> +
>> +       case USIM_IOCTL_DEACTIVATE_CARD:
>> +               dev_dbg(usim->dev, "IOCTL: DEACTIVATE CARD\n");
>> +               ret = usim_deactivate_card(usim);
>> +               break;
>> +
>> +       case USIM_IOCTL_WARM_RESET:
>> +               dev_dbg(usim->dev, "IOCTL: WARM RESET\n");
>> +               ret = usim_warmreset(usim);
>> +               break;
>> +
>> +       case USIM_IOCTL_GET_ATR:
>> +               dev_dbg(usim->dev, "IOCTL: GET ATR\n");
>> +               /* waiting for max ATR response timeout */
>> +               atr_timeout = usecs_to_jiffies(MAX_ATR_WAITTIME_US);
>> +               dev_dbg(usim->dev,
>> +                       "GET_ATR:atr timeout, us:%d, jiffies:%ld",
>> +                       MAX_ATR_WAITTIME_US, atr_timeout);
>> +               wait_event_timeout(atr_wait, (usim->atrdone == 1), atr_timeout);
>> +               if (usim->slot_ctx[usim->slot].card_mode !=
>> +                               USIM_CARD_MODE_ASYNC) {
>> +                       usim_get_syncatr(usim);
>> +               }
>> +               ret = copy_to_user((char __user *)arg,
>> +                                       usim->slot_ctx[usim->slot].atr,
>> +                                       usim->slot_ctx[usim->slot].atr_length);
>> +               if (ret != 0)
>> +                       ret = -EFAULT;
>> +               else
>> +                       ret = usim->slot_ctx[usim->slot].atr_length;
>> +               break;
>> +
>> +       case USIM_IOCTL_SEND_DATA:
>> +               dev_dbg(usim->dev, "IOCTL: SEND DATA\n");
>> +               ret = copy_from_user(&data, (struct usim_data *)arg,
>> +                                               sizeof(struct usim_data));
>> +               if (ret != 0)
>> +                       return -EFAULT;
>> +
>> +               usim->slot = data.slot;
>> +               usim->slot_ctx[usim->slot].rx_explen = data.rxexplen;
>> +               usim->slot_ctx[usim->slot].rx_counter = 0;
>> +               for (cnt = 0; cnt < data.txlen; cnt++)
>> +                       dev_dbg(usim->dev, "apdu[%d] = %x\n", cnt,
>> +                               data.apdu[cnt]);
>> +               ret = usim_send_data(usim, &data.apdu[0], data.txlen);
>> +               break;
>> +
>> +       case USIM_IOCTL_SET_CONFIG:
>> +               dev_dbg(usim->dev, "IOCTL: SET CONFIG\n");
>> +               ret = copy_from_user(&param, (struct usim_config *)arg,
>> +                               sizeof(struct usim_config));
>> +               if (ret != 0)
>> +                       return -EFAULT;
>> +
>> +               usim_set_config(usim, &param);
>> +               break;
>> +
>> +       case USIM_IOCTL_GET_CONFIG:
>> +               dev_dbg(usim->dev, "IOCTL: GET CONFIG\n");
>> +               ret = copy_from_user(&param, (struct usim_config *)arg,
>> +                               sizeof(struct usim_config));
>> +               if (ret != 0)
>> +                       return -EFAULT;
>> +
>> +               usim_get_config(usim, &param);
>> +               ret = copy_to_user((struct usim_config *)arg, &param,
>> +                               sizeof(struct usim_config));
>> +               if (ret != 0)
>> +                       ret = -EFAULT;
>> +               break;
>> +
>> +       case USIM_IOCTL_GET_CARD_PRESENCE:
>> +               dev_dbg(usim->dev, "IOCTL: CARD PRESENCE\n");
>> +               if (usim->phy_present) {
>> +                       present = usim->phy->get_config(usim->phy, usim->slot,
>> +                                       SC_PHY_CARD_PRESENCE);
>> +                       ret = copy_to_user((unsigned int *)arg, &present,
>> +                                       sizeof(unsigned int));
>> +                       if (ret != 0)
>> +                               ret = -EFAULT;
>> +               }
>> +               break;
>> +
>> +       case USIM_IOCTL_REGISTER_PID:
>> +               dev_dbg(usim->dev, "IOCTL: USIM_IOCTL_REGISTER_PID");
>> +               ret = copy_from_user(&u_pid, (int *)arg, sizeof(int));
>> +               if (ret != 0)
>> +                       return -EFAULT;
>> +               usim->user_pid = u_pid;
>> +               break;
>> +       }
>> +       return ret;
>> +}
>> +
>> +static ssize_t usim_read(struct file *file, char *user_buf,
>> +               size_t count, loff_t *ppos)
>> +{
>> +       struct usim *usim = file->private_data;
>> +       if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
>> +               return -ENXIO;
>> +
>> +       wait_event_interruptible(rx_wait, (usim->rxdone == 1));
>> +       dev_dbg(usim->dev, "RX WAIT over\n");
>> +
>> +       /* check for timeout and send signal if any */
>> +       if (usim->slot_ctx[usim->slot].event == USIM_EVENT_TIMEOUT)
>> +               usim_send_signal(usim, USIM_EVENT_TIMEOUT);
>> +
>> +       if (copy_to_user(user_buf, usim->slot_ctx[usim->slot].rxbuf,
>> +                        usim->slot_ctx[usim->slot].rx_counter)) {
>> +               dev_err(usim->dev, "Copy failed\n");
>> +               return -EFAULT;
>> +       }
>> +       *ppos = usim->slot_ctx[usim->slot].rx_counter;
>> +       dev_dbg(usim->dev, "Card response returning %d bytes\n",
>> +               usim->slot_ctx[usim->slot].rx_counter);
>> +
>> +       return usim->slot_ctx[usim->slot].rx_counter;
>> +}
>> +
>> +#ifdef CONFIG_DEBUG_FS
>> +
>> +#define DUMP_REG(r) seq_printf(s, "%-25s: %08x\n", #r, readl(usim->base + r));
>> +
>> +static int usim_regdump_show(struct seq_file *s, void *unused)
>> +{
>
> devmem2 will not work for this purpose?
This is to give complete register dump using sysfs. It helped me a lot 
while doing IP validation against EMV compliance. Easy to share reg dump 
to various team (IP design team, customer etc.)
>
>> +       struct usim     *usim = s->private;
>> +
>> +       seq_puts(s, "USIM Register Dump\n");
>> +
>> +       DUMP_REG(USIM_REVISION);
>> +       DUMP_REG(USIM_IDENT);
>> +       DUMP_REG(USIM_SYSCONFIG);
>> +       DUMP_REG(USIM_SYSSTATUS);
>> +       DUMP_REG(USIM_IRQSTATUS);
>> +       DUMP_REG(USIM_IRQENABLE);
>> +       DUMP_REG(USIM_WAKEUPEN);
>> +       DUMP_REG(USIM_CMD);
>> +       DUMP_REG(USIM_STAT);
>> +       DUMP_REG(USIM_CONF1);
>> +       DUMP_REG(USIM_CONF2);
>> +       DUMP_REG(USIM_CONF3);
>> +       DUMP_REG(USIM_DRX);
>> +       DUMP_REG(USIM_DTX);
>> +       DUMP_REG(USIM_FIFOS);
>> +       DUMP_REG(USIM_CGT);
>> +       DUMP_REG(USIM_BWT);
>> +       DUMP_REG(USIM_DEBUG);
>> +       DUMP_REG(USIM_CONF_SAM1_DIV);
>> +       DUMP_REG(USIM_CONF4);
>> +       DUMP_REG(USIM_ATR_CLK_PRD_NBS);
>> +       DUMP_REG(USIM_CONF_ETU_DIV);
>> +       DUMP_REG(USIM_CONF5);
>> +       DUMP_REG(USIM_TC_GUARD_TIME_ADD);
>> +       DUMP_REG(USIM_RXFIFO_LEVEL);
>> +       DUMP_REG(USIM_RXFIFO_BYTECNT);
>> +       DUMP_REG(USIM_WWT);
>> +       DUMP_REG(USIM_CONF6);
>> +       DUMP_REG(USIM_IO_DIRECT);
>> +       DUMP_REG(USIM_TX_BLOCK);
>> +
>> +       return 0;
>> +}
>> +
>> +static int usim_regdump_open(struct inode *inode, struct file *file)
>> +{
>> +       return single_open(file, usim_regdump_show, inode->i_private);
>> +}
>> +
>> +static const struct file_operations usim_regdump_fops = {
>> +       .open           = usim_regdump_open,
>> +       .read           = seq_read,
>> +       .llseek         = seq_lseek,
>> +       .release        = single_release,
>> +};
>> +
>> +static int usim_init_debugfs(struct usim *usim)
>> +{
>> +       int ret;
>> +       struct dentry   *root;
>> +       struct dentry   *file;
>> +
>> +       root = debugfs_create_dir("usim", NULL);
>> +       if (!root) {
>> +               ret = -ENOMEM;
>> +               goto err0;
>> +       }
>> +
>> +       file = debugfs_create_file("regdump", S_IRUGO, root, usim,
>> +                                                       &usim_regdump_fops);
>> +       if (!file) {
>> +               ret = -ENOMEM;
>> +               goto err1;
>> +       }
>> +
>> +       usim->debugfs_root = root;
>> +
>> +       return 0;
>> +err1:
>> +       debugfs_remove_recursive(root);
>> +err0:
>> +       return ret;
>> +}
>> +#endif
>> +
>> +static int usim_pm_init(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +
>> +       usim->usim0_fck  = clk_get(usim->dev, "usim0_fck");
>> +       if (IS_ERR(usim->usim0_fck)) {
>> +               ret = PTR_ERR(usim->usim0_fck);
>> +               dev_err(usim->dev, "usim0_fck failed error:%d\n", ret);
>> +               return -1;
>> +       }
>> +       usim->dpll_core_m4_ck  = clk_get(usim->dev, "dpll_core_m4_ck");
>> +       if (IS_ERR(usim->dpll_core_m4_ck)) {
>> +               ret = PTR_ERR(usim->dpll_core_m4_ck);
>> +               dev_err(usim->dev, "dpll_core_m4_ck failed error:%d\n", ret);
>> +               return -1;
>> +       }
>> +       ret = clk_set_parent(usim->usim0_fck, usim->dpll_core_m4_ck);
>> +       if (ret != 0)
>> +               dev_dbg(usim->dev, "clk set  parent failed: %d\n", ret);
>> +
>> +       usim->usim_dbclk  = clk_get(usim->dev, "usim_dbck");
>> +       if (IS_ERR(usim->usim_dbclk)) {
>> +               ret = PTR_ERR(usim->usim_dbclk);
>> +               dev_err(usim->dev, "usim_dbck failed error:%d\n", ret);
>> +               return -1;
>> +       }
>> +
>> +       usim->clkdiv32k_ick  = clk_get(usim->dev, "clkdiv32k_ick");
>> +       if (IS_ERR(usim->usim_dbclk)) {
>> +               ret = PTR_ERR(usim->clkdiv32k_ick);
>> +               dev_err(usim->dev, "clkdiv32k_ick failed error:%d\n", ret);
>> +               return -1;
>> +       }
>> +
>> +       ret = clk_set_parent(usim->usim_dbclk, usim->clkdiv32k_ick);
>> +       if (ret != 0)
>> +               dev_dbg(usim->dev, "usim_dbclk set parent failed: %d\n", ret);
>> +
>> +       usim->opt_fclk = devm_clk_get(usim->dev, "opt_fck");
>> +       if (IS_ERR(usim->opt_fclk)) {
>> +               ret = PTR_ERR(usim->opt_fclk);
>> +               dev_err(usim->dev, "unable to get fck\n");
>> +               return ret;
>> +       }
>> +
>> +       usim->opt_fclk32 = devm_clk_get(usim->dev, "opt_fck32");
>> +       if (IS_ERR(usim->opt_fclk32)) {
>> +               ret = PTR_ERR(usim->opt_fclk32);
>> +               dev_err(usim->dev, "unable to get dbclk\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +static int usim_enable(struct usim *usim)
>> +{
>> +       int ret = 0;
>> +       if (usim->enable == 1)
>> +               return 0;
>> +
>> +       /* enable the clk */
>> +       pm_runtime_get_sync(usim->dev);
>> +       clk_enable(usim->opt_fclk32);
>> +       clk_enable(usim->opt_fclk);
>> +
>> +       /* usim init */
>> +       ret = usim_configure(usim);
>> +       if (ret)
>> +               return -EIO;
>> +
>> +       usim->enable = 1;
>> +       return 0;
>> +}
>> +
>> +static void usim_disable(struct usim *usim)
>> +{
>> +       int cnt = 0;
>> +
>> +       if (usim->enable == 0)
>> +               return;
>> +
>> +       /* reset USIM state for deactivation */
>> +       for (cnt = 0; cnt < usim->max_slots; cnt++) {
>> +               usim->slot = cnt;
>> +               usim_deactivate_card(usim);
>> +       }
>> +
>> +       /* reset default slot and clock */
>> +       usim->slot = 0;
>> +       usim->slot_ctx[usim->slot].clock = USIM_SMARTCART_CLOCK_5MHZ;
>> +
>> +       /* shutdown phy */
>> +       if (usim->phy_present == USIM_PHY_PRESENT)
>> +               usim->phy->set_config(usim->phy, usim->slot, SC_PHY_MODE,
>> +                               SC_PHY_SHUTDOWN);
>> +       /* disable clk */
>> +       clk_disable(usim->opt_fclk32);
>> +       clk_disable(usim->opt_fclk);
>> +       pm_runtime_put_sync_autosuspend(usim->dev);
>> +       usim->enable = 0;
>> +       return;
>> +}
>> +
>> +static int usim_open(struct inode *inode, struct file *file)
>> +{
>> +       int ret = 0;
>> +       struct usim *usim = (struct usim *)dev_get_drvdata(usim_dev.parent);
>> +
>> +       if (usim->phy_present == USIM_PHY_NOT_ATTACHED)
>> +               return -ENXIO;
>> +
>> +       file->private_data = usim;
>> +       ret = usim_enable(usim);
>> +       if (ret)
>> +               return  -ENXIO;
>> +
>> +       return 0;
>> +}
>> +
>> +static int usim_release(struct inode *inode, struct file *file)
>> +{
>> +       struct usim *usim = (struct usim *)dev_get_drvdata(usim_dev.parent);
>> +
>> +       usim_disable(usim);
>> +       usim->user_pid = 0;
>> +       return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int usim_suspend(struct device *dev)
>> +{
>> +       /* struct usim *usim = dev_to_usim(dev); */
>> +       struct usim *usim = dev_to_usim(dev);
>> +       if (usim->atrdone == 1) {
>> +               dev_dbg(usim->dev, "card is active state, aborting suspend");
>> +               return -EBUSY;
>> +       }
>> +       usim_disable(usim);
>> +       return 0;
>> +}
>> +
>> +static int usim_resume(struct device *dev)
>> +{
>> +       /* struct usim *usim = dev_to_usim(dev); */
>> +       struct usim *usim = dev_to_usim(dev);
>> +       usim_enable(usim);
>> +       return 0;
>> +}
>> +
>> +static const struct dev_pm_ops usim_pm_ops = {
>> +       .suspend = usim_suspend,
>> +       .resume = usim_resume,
>> +};
>> +
>> +#define USIM_PM_OPS (&usim_pm_ops)
>> +#else
>> +#define USIM_PM_OPS NULL
>> +#endif
>> +
>> +static int usim_notify(struct notifier_block *self, unsigned long action, void
>> +               *data)
>> +{
>> +       struct usim *usim = (struct usim *)data;
>> +       int event = action & SC_PHY_NOTIFICATION_ACTION_MASK;
>> +       int slot = (action & SC_PHY_NOTIFICATION_SLOT_MASK) >>
>> +               SC_PHY_NOTIFICATION_SLOT_SHIFT;
>> +       int t_slot = 0;
>> +
>> +       dev_dbg(usim->dev, "%s:action:%ld", __func__, action);
>> +       /* if phy is removed using rmmod or by some other mech..
>> +          * then put phy state in unknown, at this point usim also required to
>> +          * gets removed from the system, if it is inserted as module and
>> +          * dependent on phy
>> +          */
>
> Why would the phy be removed? A better mechanism than signals and
> notifiers is needed here.
PHY is indepent entiry and can be build & inserted as module. So 
handling the detachment senario over here.
>
>
>> +       if (action == SC_PHY_REMOVED)
>> +               usim->phy_present = USIM_PHY_NOT_ATTACHED;
>> +
>> +       if (event & SC_PHY_CARD_INSERTED)
>> +               usim_send_signal(usim, USIM_EVENT_CARD_INSERT);
>> +
>> +       if (action & SC_PHY_CARD_REMOVED) {
>> +               usim_send_signal(usim, USIM_EVENT_CARD_REMOVE);
>> +               dev_dbg(usim->dev, "slot is:%d", slot);
>> +                /* de-activate USIM & PHY state machine for the slot */
>> +               t_slot = usim->slot;
>> +               usim->slot = slot;
>> +               usim_deactivate_card(usim);
>> +               usim->slot = t_slot;
>> +       }
>> +
>> +       if (action & SC_PHY_CARD_OVERHEAT)
>> +               usim_send_signal(usim, USIM_EVENT_CARD_OVERHEAT);
>> +
>> +       if (action & SC_PHY_CARD_ATR_TIMEOUT)
>> +               usim_send_signal(usim, USIM_EVENT_TIMEOUT);
>> +
>> +       if (action & SC_PHY_CARD_SYNC_ACT_COMPLETE) {
>> +               usim->atrdone = 1;
>> +               wake_up(&atr_wait);
>> +       }
>> +       return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block usim_nb = {
>> +                .notifier_call =       usim_notify,
>> +};
>> +
>> +static const struct file_operations usim_fops = {
>> +       .owner          = THIS_MODULE,
>> +       .read           = usim_read,
>> +       .open           = usim_open,
>> +       .unlocked_ioctl = usim_ioctl,
>> +       .release        = usim_release,
>> +};
>> +
>> +static int usim_probe(struct platform_device *pdev)
>> +{
>> +       struct device_node *node                = pdev->dev.of_node;
>> +       struct device *dev                      = &pdev->dev;
>> +
>> +       struct usim *usim                       = NULL;
>> +       struct device_node *phy_node            = NULL;
>> +       struct resource *res                    = NULL;
>> +       void __iomem    *base                   = NULL;
>> +       const __be32 *parp                      = NULL;
>> +       struct i2c_client *phy_i2c              = NULL;
>> +
>> +       int ret         = 0;
>> +       int version     = 0;
>> +       int cnt         = 0;
>> +       u32 prop        = 0;
>> +       int lenp        = 0;
>
> Remove unnecessary initialization.
>
>> +
>> +       if (!node) {
>> +               dev_err(dev, "device node not found\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       usim = devm_kzalloc(dev, sizeof(*usim), GFP_KERNEL);
>> +       if (!usim) {
>> +               dev_err(dev, "not enough memory\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       usim->irq = platform_get_irq(pdev, 0);
>> +       if (usim->irq < 0) {
>> +               dev_err(dev, "missing IRQ resource\n");
>> +               ret = -EINVAL;
>> +               goto usim_err_ret;
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       if (!res) {
>> +               dev_err(dev, "missing memory base resource\n");
>> +               ret = -EINVAL;
>
> ENODEV is probably more appropriate.
OK
>
>> +               goto usim_err_ret;
>> +       }
>> +
>> +       base = devm_ioremap_nocache(dev, res->start, resource_size(res));
>
> devm_ioremap_resource
OK
>
>> +       if (!base) {
>> +               dev_err(dev, "ioremap failed\n");
>> +               ret = -ENOMEM;
>> +               goto usim_err_ret;
>> +       }
>> +
>> +       usim->dev = &pdev->dev;
>> +       usim->base = base;
>> +       usim->max_slots = 1;
>> +       usim->phy_present = USIM_PHY_NOT_PRESENT;
>> +       usim->enable = 0;
>> +
>> +       /* default slot will be zero : user card */
>> +       usim->slot = 0;
>> +
>> +       ret = devm_request_irq(dev, usim->irq, usim_interrupt, 0,
>> +                       "usim", usim);
>> +       if (ret) {
>> +               dev_err(dev, "fail request IRQ #%d --> %d\n", usim->irq, ret);
>> +               goto usim_err_ret;
>> +               return ret;
>> +       }
>> +
>> +       /*
>> +        * Populate all the child nodes here...
>> +        */
>> +       ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
>> +
>> +       /* get phy details */
>> +       parp = of_get_property(node, "phy", &lenp);
>> +       if (parp == NULL || lenp != (sizeof(void *))) {
>> +               dev_dbg(usim->dev, "parp is null!,no phy");
>> +       } else {
>> +               /* get phy node */
>> +               phy_node = of_find_node_by_phandle(be32_to_cpup(parp));
>> +               if (phy_node == NULL) {
>> +                       dev_err(usim->dev, "\n phy node is null");
>> +                       ret = -EPROBE_DEFER;
>> +                       goto usim_err_ret;
>> +               }
>> +               phy_i2c = of_find_i2c_device_by_node(phy_node);
>> +               if (phy_i2c == NULL) {
>> +                       dev_err(usim->dev, "\n phy i2c is null");
>> +                       ret = -EPROBE_DEFER;
>> +                       goto usim_err_ret;
>> +               }
>> +               /* get phy interface */
>> +               usim->phy = (struct sc_phy *)i2c_get_clientdata(phy_i2c);
>> +               if (usim->phy == NULL) {
>> +                       dev_err(usim->dev, "phy data is null");
>> +                       ret = -EPROBE_DEFER;
>> +                       goto usim_err_ret;
>> +               }
>> +               usim->phy_present = USIM_PHY_PRESENT;
>> +
>> +               ret = of_property_read_u32(node, "phy-slots", &prop);
>> +               /* if phy-slot is not declared then assume one phy slot */
>> +               usim->max_slots = prop > 0 ? prop : 1;
>> +       }
>> +
>> +       dev_dbg(usim->dev, "usim max slot:%d", usim->max_slots);
>> +       /* initialize slot context*/
>> +       if (usim->max_slots > USIM_MAX_SLOTS) {
>> +               ret = -EINVAL;
>> +               goto usim_err_ret;
>> +       }
>> +
>> +       usim->slot_ctx = kmalloc(usim->max_slots *
>> +                                sizeof(struct usim_slotcontext), GFP_KERNEL);
>> +       if (!usim->slot_ctx)
>> +               return -ENOMEM;
>> +
>> +       for (cnt = 0; cnt < usim->max_slots; cnt++) {
>> +               /* default protocol */
>> +               usim->slot_ctx[cnt].protocol = 0;
>> +               usim->slot_ctx[cnt].emv = true;
>> +               usim_set_cardmode(usim, cnt, USIM_CARD_MODE_ASYNC);
>> +       }
>> +
>> +       dev_set_drvdata(dev, usim);
>> +       ret = usim_pm_init(usim);
>> +       if (ret)
>> +               goto usim_err_ret;
>> +
>> +       /* enable the clock */
>> +       pm_runtime_enable(usim->dev);
>> +       pm_runtime_set_active(usim->dev);
>> +       spin_lock_init(&usim->lock);
>> +
>> +       usim_dev.minor = MISC_DYNAMIC_MINOR;
>> +       usim_dev.name = "usim";
>> +       usim_dev.fops = &usim_fops;
>> +       usim_dev.parent = &(pdev->dev);
>> +
>> +       ret = misc_register(&usim_dev);
>> +       if (ret) {
>> +               pr_err("unable to register a misc device\n");
>> +               goto usim_err_reg;
>> +       }
>> +#ifdef CONFIG_DEBUG_FS
>> +       ret = usim_init_debugfs(usim);
>> +       if (ret) {
>> +               dev_err(dev, "Debugfs init failed\n");
>> +               goto usim_err_reg;
>> +       }
>> +#endif
>> +       /* set default ICC clock : 5Mhz */
>> +       usim->slot_ctx[usim->slot].clock = USIM_SMARTCART_CLOCK_5MHZ;
>> +
>> +       /* get the clock & do usim configuration */
>> +       usim_enable(usim);
>> +       if (ret)
>> +               goto usim_err_reg;
>> +       dev_info(usim->dev, "usim driver initialized\n");
>> +
>> +       /* register notifier */
>> +       if (usim->phy_present)
>> +               usim->phy->register_notify(usim->phy, &usim_nb, (void *)usim);
>> +
>> +       /* get usim version */
>> +       version = usim_get_version(usim);
>> +       dev_info(usim->dev, "version is:%0x", version);
>> +
>> +       usim_disable(usim);
>> +       return 0;
>> +
>> +usim_err_reg:
>> +       pm_runtime_set_suspended(usim->dev);
>> +       pm_runtime_disable(usim->dev);
>> +       misc_deregister(&usim_dev);
>> +
>> +usim_err_ret:
>> +       if (usim)
>> +               kfree(usim->slot_ctx);
>> +       return ret;
>> +}
>> +
>> +static int usim_remove(struct platform_device *pdev)
>> +{
>> +       struct device   *dev = &pdev->dev;
>> +       struct usim     *usim = dev_to_usim(dev);
>> +
>> +       usim_disable(usim);
>> +       /* unregister notifier, applicable only when phy present and phy state
>> +        * is not unknown i.e. - phy has not been removed using rmmod */
>> +       if (usim->phy_present == USIM_PHY_PRESENT)
>> +               usim->phy->unregister_notify(usim->phy, &usim_nb);
>> +
>> +#ifdef CONFIG_DEBUG_FS
>> +       debugfs_remove_recursive(usim->debugfs_root);
>> +#endif
>> +       if (!IS_ERR(usim->usim_dbclk))
>> +               clk_put(usim->usim_dbclk);
>> +       if (!IS_ERR(usim->clkdiv32k_ick))
>> +               clk_put(usim->clkdiv32k_ick);
>> +       if (!IS_ERR(usim->usim0_fck))
>> +               clk_put(usim->usim0_fck);
>> +       if (!IS_ERR(usim->dpll_core_m4_ck))
>> +               clk_put(usim->dpll_core_m4_ck);
>> +
>> +       if (!IS_ERR(usim->opt_fclk))
>> +               devm_clk_put(usim->dev, usim->opt_fclk);
>> +       if (!IS_ERR(usim->opt_fclk32))
>> +               devm_clk_put(usim->dev, usim->opt_fclk32);
>> +       /* disable pm runtime */
>> +       pm_runtime_set_suspended(usim->dev);
>> +       pm_runtime_disable(usim->dev);
>> +
>> +       kfree(usim->slot_ctx);
>> +       misc_deregister(&usim_dev);
>> +       return 0;
>> +}
>> +
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id usim_id_table[] = {
>> +       { .compatible = "ti,usim" },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, usim_id_table);
>> +#endif
>> +
>> +static struct platform_driver usim_driver = {
>> +       .driver = {
>> +               .name = "usim",
>> +               .owner  = THIS_MODULE,
>> +               .pm     = USIM_PM_OPS,
>> +               .of_match_table = of_match_ptr(usim_id_table),
>> +       },
>> +       .probe = usim_probe,
>> +       .remove = usim_remove,
>> +};
>> +
>> +static int __init usim_init(void)
>> +{
>> +       return platform_driver_register(&usim_driver);
>> +}
>> +
>> +static void __exit usim_exit(void)
>> +{
>> +       platform_driver_unregister(&usim_driver);
>> +}
>> +
>> +late_initcall(usim_init);
>> +module_exit(usim_exit);
>> +
>> +MODULE_AUTHOR("Maulik Mankad <maulik@ti.com>");
>> +MODULE_DESCRIPTION("USIM Driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/include/linux/ti-usim.h b/include/linux/ti-usim.h
>> new file mode 100644
>> index 0000000..e9794df
>> --- /dev/null
>> +++ b/include/linux/ti-usim.h
>
> Isn't this a uapi header?
>
>> @@ -0,0 +1,111 @@
>> +/*
>> + * ti-usim.h - Header file for USIM SmartCard interface
>> + *
>> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
>> + *
>> + * 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 version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __TI_USIM_H__
>> +#define __TI_USIM_H__
>> +
>> +#include <linux/types.h>
>> +#include <linux/ioctl.h>
>> +
>> +#define USIM_IOCTL 0xFE
>> +
>> +enum usim_param {
>> +       USIM_PARAM_CWT = 0,
>> +       USIM_PARAM_WWT,
>> +       USIM_PARAM_CGT,
>> +       USIM_PARAM_BWT,
>> +       USIM_PARAM_EDCTYPE,
>> +       USIM_PARAM_LRCCHECK,
>> +       USIM_PARAM_C4,
>> +       USIM_PARAM_C8,
>> +       USIM_PARAM_PROTOCOL,
>> +       USIM_PARAM_VOLTAGE,
>> +       USIM_PARAM_EMV,
>> +       USIM_PARAM_FI,
>> +       USIM_PARAM_DI,
>> +       USIM_PARAM_CODING_CONV,
>> +       USIM_PARAM_CLOCK_STOP,
>> +       USIM_PARAM_SMARTCARD_CLOCK,
>> +       USIM_PARAM_SMARTCARD_MODE,
>> +       USIM_PARAM_CARD_PIN_VCC,
>> +       USIM_PARAM_CARD_PIN_RST,
>> +       USIM_PARAM_CARD_PIN_CLK,
>> +       USIM_PARAM_CARD_PIN_IO,
>> +       USIM_PARAM_CARD_PIN_C4,
>> +       USIM_PARAM_CARD_PIN_C8,
>> +};
>> +
>> +enum usim_card_mode {
>> +       USIM_CARD_MODE_ASYNC = 0,       /* asynchronous mode */
>> +       USIM_CARD_MODE_SYNC_TYPE1,      /* synchronous mode: Type 1 */
>> +       USIM_CARD_MODE_SYNC_TYPE2,      /* synchronous mode: Type 2 */
>> +       USIM_CARD_MODE_SYNC_OTHER,      /* Any other synchronous type */
>> +};
>> +struct usim_data {
>> +       int slot;
>> +       int rxexplen;
>> +       int txlen;
>> +       unsigned char apdu[256];
>> +};
>> +
>> +struct usim_config {
>> +       enum usim_param attr;
>
> Probably not a good idea to have an undefined size element in a user
> ABI struct...
>
Undefined ? I couldn't get your point. Could you explain bit more.
>> +       unsigned int value;
>> +};
>> +
>> +#define USIM_SIGID     51
>> +
>> +#define USIM_IOCTL_GET_PROVIDER_VERSION        _IOR(USIM_IOCTL, 0, int)
>> +#define        USIM_IOCTL_ACTIVATE_CARD        _IO(USIM_IOCTL, 1)
>> +#define        USIM_IOCTL_DEACTIVATE_CARD      _IO(USIM_IOCTL, 2)
>> +#define USIM_IOCTL_WARM_RESET          _IO(USIM_IOCTL, 3)
>> +#define USIM_IOCTL_GET_ATR             _IOR(USIM_IOCTL, 4, char *)
>> +#define USIM_IOCTL_SEND_DATA           _IOW(USIM_IOCTL, 5, struct usim_data)
>> +#define USIM_IOCTL_SET_CONFIG          _IOW(USIM_IOCTL, 6, struct usim_config)
>> +#define USIM_IOCTL_GET_CONFIG          _IOW(USIM_IOCTL, 7, struct usim_config)
>> +#define USIM_IOCTL_GET_CARD_PRESENCE   _IOR(USIM_IOCTL, 8, int)
>> +#define USIM_IOCTL_REGISTER_PID                _IOW(USIM_IOCTL, 9, int)
>> +
>> +#define USIM_MAX_ATRLENGTH     0xFF
>> +#define USIM_MAX_APDU_LENGTH   0xFE
>> +
>> +enum usim_smartcard_clock {
>> +       USIM_SMARTCART_CLOCK_3_3MHZ     = 0x1,
>> +       USIM_SMARTCART_CLOCK_4MHZ       = 0x2,
>> +       USIM_SMARTCART_CLOCK_5MHZ       = 0x3,
>> +       USIM_SMARTCART_CLOCK_6_6MHZ     = 0x4,
>> +       USIM_SMARTCART_CLOCK_10MHZ      = 0x5,
>> +       USIM_SMARTCART_CLOCK_20MHZ      = 0x6,
>> +};
>> +
>> +enum usim_event {
>> +       USIM_EVENT_CARD_INSERT  = 0x1,
>> +       USIM_EVENT_CARD_REMOVE  = 0x2,
>> +       USIM_EVENT_TIMEOUT      = 0x4,
>> +       USIM_EVENT_ERR_TXRETRY  = 0x8,
>> +       USIM_EVENT_ERR_LRC      = 0x10,
>> +       USIM_EVENT_ERR_PARITY   = 0x20,
>> +       USIM_EVENT_ERR_FRAME    = 0x40,
>> +       USIM_EVENT_PHYERR       = 0x80,
>> +       USIM_EVENT_CARD_OVERHEAT = 0x100,
>> +};
>> +
>> +enum usim_card_voltage {
>> +       USIM_CARD_5V = 0,
>> +       USIM_CARD_3V,
>> +       USIM_CARD_1_8V
>> +};
>> +
>> +#endif /* __TI_USIM_H__ */
>> --
>> 1.7.9.5
>>

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-29  8:34     ` Satish Patel
@ 2014-05-29 13:47       ` Rob Herring
  2014-05-29 15:52         ` Greg KH
  2014-05-30  3:51         ` Satish Patel
  0 siblings, 2 replies; 22+ messages in thread
From: Rob Herring @ 2014-05-29 13:47 UTC (permalink / raw)
  To: Satish Patel
  Cc: Greg KH, linux-kernel, linux-arm-kernel, linux-omap, devicetree,
	Rob Landley, Tony Lindgren, Grant Likely, Rob Herring

On Thu, May 29, 2014 at 3:34 AM, Satish Patel <satish.patel@ti.com> wrote:
>
>
> On 5/29/2014 12:23 AM, Greg KH wrote:
>>
>> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
>>>
>>> SmartCard controller uses this interface to communicate with
>>> SmartCard via PHY
>>>
>>> Some SmartCard PHY has multiple slots for cards.
>>> This inerface also enables controller to communicate
>>> with one or more SmartCard connected over phy.
>>>
>>> interface structure includes following APIs
>>> - set/get config
>>> - activate/deactivate smart card
>>> - warm reset
>>> - register_notify (for card insert/remove/overheat)
>>> - unregister_notify
>>>
>>> Signed-off-by: Satish Patel <satish.patel@ti.com>
>>> ---
>>>   Documentation/sc_phy.txt |  171
>>> ++++++++++++++++++++++++++++++++++++++++++++++
>>>   include/linux/sc_phy.h   |  136 ++++++++++++++++++++++++++++++++++++
>>>   2 files changed, 307 insertions(+)
>>>   create mode 100644 Documentation/sc_phy.txt
>>>   create mode 100644 include/linux/sc_phy.h
>>
>>
>> These are .h files, but where is the "api" functions that use
>> these structures defined at?
>>
> This is like template/wrappers, smart card phy driver will write API
> functions. And smartcard controller will call these functions.
> With proposed approach, smartcard controller can communicate with any smart
> card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY
> will gets connected with each other.
> Refer diagram given @Documentation/sc_phy.txt.
>
>
>> confused,

I believe the api Greg is wondering about is the notifier which as I
commented is not a good design.

There is now a phy subsystem. I don't know if it has what you need,
but you should look at it to determine if it will work or could be
extended to work.

Rob

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-29  8:56     ` Satish Patel
@ 2014-05-29 15:51       ` Greg KH
  2014-05-30  5:05         ` Satish Patel
  0 siblings, 1 reply; 22+ messages in thread
From: Greg KH @ 2014-05-29 15:51 UTC (permalink / raw)
  To: Satish Patel
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt

On Thu, May 29, 2014 at 02:26:55PM +0530, Satish Patel wrote:
> 
> 
> On 5/29/2014 12:14 AM, Greg KH wrote:
> >On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
> >>+/**
> >>+ * struct sc_phy - The basic smart card phy structure
> >>+ *
> >>+ * @dev: phy device
> >>+ * @pdata: pointer to phy's private data structure
> >>+ * @set_config: called to set phy's configuration
> >>+ * @get_config: called to get phy's configuration
> >>+ * @activate_card: perform smart card activation
> >>+ * @deactivate_card: perform smart card de-activation
> >>+ * @warm_reset: execute smart card warm reset sequence
> >>+ * @register_card_activity_cb: register call back to phy device.
> >>+ * This call back will be called on card insert or remove event
> >>+ *
> >>+ * smart card controller uses this interface to communicate with
> >>+ * smart card via phy.Some smart card phy has multiple slots for
> >>+ * cards. This inerface also enables controller to communicate with
> >>+ * one or more smart card connected over phy.
> >>+ */
> >>+struct sc_phy {
> >>+	/* phy's device pointer */
> >>+	struct device *dev;
> >
> >So this is the "parent", right?  Why not embed a struct device into this
> >structure as well, further streaching out the device tree.
> >
> Do you mean to use "dev->p" for pdata ?

No, use the device itself.

> I have kept it outside, to give easeness/pragmatic focal for new phy driver
> development. Driver can make this pointer null and use above pointer.

Ick, no, that's not how the driver model works.  Each device in the
system needs a struct device, don't try to "chain" off of an existing
device like this.  Make it a "real" one.

> >>+
> >>+	/* phy's private data */
> >>+	void *pdata;
> >
> >If you do the above, then this pointer is not needed.
> >
> >
> >>+
> >>+	/* notify data, passed by interface user as a part of
> >>+	 * register_notify API. Data should be passed back when
> >>+	 * notification raised to the interface user
> >>+	 */
> >>+	void *notify_data;
> >
> >What makes this different from the pdata?
> pdata is phy's private data, while notify_data is something phy will send to
> smart card controller on some event, like card remove/insert/timeout etc..

That doesn't make much sense to me, why not just put that in the notify
function callback itself?

Please either use the existing phy layer of the kernel, or make a "real"
subsystem here, don't try to put a tiny shim on top of an existing
struct device for this driver, that's not how subsystems in Linux are
done.

thanks,

greg k-h

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-29 13:47       ` Rob Herring
@ 2014-05-29 15:52         ` Greg KH
  2014-05-30  3:51         ` Satish Patel
  1 sibling, 0 replies; 22+ messages in thread
From: Greg KH @ 2014-05-29 15:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: Satish Patel, linux-kernel, linux-arm-kernel, linux-omap,
	devicetree, Rob Landley, Tony Lindgren, Grant Likely,
	Rob Herring

On Thu, May 29, 2014 at 08:47:31AM -0500, Rob Herring wrote:
> On Thu, May 29, 2014 at 3:34 AM, Satish Patel <satish.patel@ti.com> wrote:
> >
> >
> > On 5/29/2014 12:23 AM, Greg KH wrote:
> >>
> >> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
> >>>
> >>> SmartCard controller uses this interface to communicate with
> >>> SmartCard via PHY
> >>>
> >>> Some SmartCard PHY has multiple slots for cards.
> >>> This inerface also enables controller to communicate
> >>> with one or more SmartCard connected over phy.
> >>>
> >>> interface structure includes following APIs
> >>> - set/get config
> >>> - activate/deactivate smart card
> >>> - warm reset
> >>> - register_notify (for card insert/remove/overheat)
> >>> - unregister_notify
> >>>
> >>> Signed-off-by: Satish Patel <satish.patel@ti.com>
> >>> ---
> >>>   Documentation/sc_phy.txt |  171
> >>> ++++++++++++++++++++++++++++++++++++++++++++++
> >>>   include/linux/sc_phy.h   |  136 ++++++++++++++++++++++++++++++++++++
> >>>   2 files changed, 307 insertions(+)
> >>>   create mode 100644 Documentation/sc_phy.txt
> >>>   create mode 100644 include/linux/sc_phy.h
> >>
> >>
> >> These are .h files, but where is the "api" functions that use
> >> these structures defined at?
> >>
> > This is like template/wrappers, smart card phy driver will write API
> > functions. And smartcard controller will call these functions.
> > With proposed approach, smartcard controller can communicate with any smart
> > card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY
> > will gets connected with each other.
> > Refer diagram given @Documentation/sc_phy.txt.
> >
> >
> >> confused,
> 
> I believe the api Greg is wondering about is the notifier which as I
> commented is not a good design.

That, and the fact that if this really is an "api", there are no .c
files for it like a "normal" api is in the kernel.

> There is now a phy subsystem. I don't know if it has what you need,
> but you should look at it to determine if it will work or could be
> extended to work.

I agree.  Satish, what's wrong with our existing phy layer?

greg k-h

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

* Re: [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver
  2014-05-29  8:37     ` Satish Patel
@ 2014-05-29 15:52       ` Greg KH
  0 siblings, 0 replies; 22+ messages in thread
From: Greg KH @ 2014-05-29 15:52 UTC (permalink / raw)
  To: Satish Patel
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt

On Thu, May 29, 2014 at 02:07:59PM +0530, Satish Patel wrote:
> 
> 
> On 5/29/2014 12:14 AM, Greg KH wrote:
> >On Wed, May 28, 2014 at 02:27:14PM +0530, Satish Patel wrote:
> >>TDA8026 is a SmartCard PHY from NXP.
> >>
> >>The PHY interfaces with the main processor over the
> >>I2C interface and acts as a slave device.
> >>
> >>The driver also exposes the phy interface
> >>(defined@include/linux/sc_phy.h) for SmartCard controller.
> >>Controller uses this interface to communicate with smart card
> >>inserted to the phy's slot.
> >>
> >>Note: gpio irq is not validated as I do not have device with that.
> >>I have validated interrupt with dedicated interrupt line on my device.
> >>
> >>Signed-off-by: Satish Patel <satish.patel@ti.com>
> >>---
> >>  Documentation/devicetree/bindings/misc/tda8026.txt |   19 +
> >>  drivers/misc/Kconfig                               |    7 +
> >>  drivers/misc/Makefile                              |    1 +
> >>  drivers/misc/tda8026.c                             | 1258 ++++++++++++++++++++
> >>  4 files changed, 1285 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt
> >>  create mode 100644 drivers/misc/tda8026.c
> >>
> >>diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt
> >>new file mode 100644
> >>index 0000000..f115c9c
> >>--- /dev/null
> >>+++ b/Documentation/devicetree/bindings/misc/tda8026.txt
> >>@@ -0,0 +1,19 @@
> >>+TDA8026 smart card slot interface
> >>+
> >>+This is an i2c based smart card interface device forming the electrical
> >>+interface between a microcontroller and smart cards. This device supports
> >>+asynchronous cards (micro controller-based IC cards) as well as synchronous
> >>+cards (mainly memory cards)
> >>+
> >>+Required properties:
> >>+- compatible: "nxp,tda8026"
> >>+- shutdown-gpio = GPIO pin mapping for SDWNN pin
> >>+- reg = i2c interface address
> >>+
> >>+
> >>+Example:
> >>+tda8026: tda8026@48 {
> >>+		 compatible = "nxp,tda8026";
> >>+		 reg = <0x48>;
> >>+		 shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */
> >>+	 };
> >>diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> >>index 8baff0e..80b21d7 100644
> >>--- a/drivers/misc/Kconfig
> >>+++ b/drivers/misc/Kconfig
> >>@@ -515,6 +515,13 @@ config SRAM
> >>  	  the genalloc API. It is supposed to be used for small on-chip SRAM
> >>  	  areas found on many SoCs.
> >>
> >>+config NXP_TDA8026_PHY
> >>+        tristate "NXP PHY Driver for Smart Card PHY"
> >>+        depends on I2C=y
> >>+        help
> >>+          If you say yes here you get support for the TDA8026 Smart card PHY
> >>+	  with I2C interface.
> >>+
> >>  source "drivers/misc/c2port/Kconfig"
> >>  source "drivers/misc/eeprom/Kconfig"
> >>  source "drivers/misc/cb710/Kconfig"
> >>diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> >>index 7eb4b69..f262c0b 100644
> >>--- a/drivers/misc/Makefile
> >>+++ b/drivers/misc/Makefile
> >>@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM)		+= sram.o
> >>  obj-y				+= mic/
> >>  obj-$(CONFIG_GENWQE)		+= genwqe/
> >>  obj-$(CONFIG_ECHO)		+= echo/
> >>+obj-$(CONFIG_NXP_TDA8026_PHY)	+= tda8026.o
> >>diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c
> >>new file mode 100644
> >>index 0000000..38df33e
> >>--- /dev/null
> >>+++ b/drivers/misc/tda8026.c
> >>@@ -0,0 +1,1258 @@
> >>+/*
> >>+ * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY
> >>+ *
> >>+ *
> >>+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
> >>+ *
> >>+ * 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 version 2.
> >>+ *
> >>+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> >>+ * kind, whether express or implied; without even the implied warranty
> >>+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >>+ * GNU General Public License for more details.
> >>+ */
> >>+
> >>+#include <linux/module.h>
> >>+#include <linux/moduleparam.h>
> >>+#include <linux/interrupt.h>
> >>+#include <linux/init.h>
> >>+#include <linux/slab.h>
> >>+#include <linux/gpio.h>
> >>+#include <linux/i2c.h>
> >>+#include <linux/mfd/core.h>
> >>+#include <linux/notifier.h>
> >>+#include <linux/sc_phy.h>
> >>+#include <linux/of_gpio.h>
> >>+#include <linux/of_device.h>
> >>+#include <linux/delay.h>
> >
> >I think you just broke the build if this driver is enabled now right?
> >
> >Not good :(
> Before sending, I have applied these patches to "v3.15-rc7" and build with
> both the option ti-usim & tda8026 as module, as well as part of kernel. Any
> specific tree you would like me to rebase these patches against.

Did you try applying the patches one-by-one and building afterwards
between each one?  In looking at this further, I think it will work, but
please test and make sure.  You can not break the build with any
individual patch.

thanks,

greg k-h

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

* Re: [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx
  2014-05-29 10:05     ` Satish Patel
@ 2014-05-29 15:53       ` Greg Kroah-Hartman
  2014-05-30  4:08         ` Satish Patel
  0 siblings, 1 reply; 22+ messages in thread
From: Greg Kroah-Hartman @ 2014-05-29 15:53 UTC (permalink / raw)
  To: Satish Patel
  Cc: Rob Herring, linux-kernel, linux-arm-kernel, linux-omap,
	devicetree, Rob Landley, Tony Lindgren, Grant Likely,
	Rob Herring

On Thu, May 29, 2014 at 03:35:37PM +0530, Satish Patel wrote:
> >>+enum usim_card_mode {
> >>+       USIM_CARD_MODE_ASYNC = 0,       /* asynchronous mode */
> >>+       USIM_CARD_MODE_SYNC_TYPE1,      /* synchronous mode: Type 1 */
> >>+       USIM_CARD_MODE_SYNC_TYPE2,      /* synchronous mode: Type 2 */
> >>+       USIM_CARD_MODE_SYNC_OTHER,      /* Any other synchronous type */
> >>+};
> >>+struct usim_data {
> >>+       int slot;
> >>+       int rxexplen;
> >>+       int txlen;
> >>+       unsigned char apdu[256];
> >>+};

You need to use the proper variable types for a structure that is going
to cross the user/kernel boundry in an ioctl :(


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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-29 13:47       ` Rob Herring
  2014-05-29 15:52         ` Greg KH
@ 2014-05-30  3:51         ` Satish Patel
  1 sibling, 0 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-30  3:51 UTC (permalink / raw)
  To: Rob Herring
  Cc: Greg KH, linux-kernel, linux-arm-kernel, linux-omap, devicetree,
	Rob Landley, Tony Lindgren, Grant Likely, Rob Herring



On 5/29/2014 7:17 PM, Rob Herring wrote:
> On Thu, May 29, 2014 at 3:34 AM, Satish Patel <satish.patel@ti.com> wrote:
>>
>>
>> On 5/29/2014 12:23 AM, Greg KH wrote:
>>>
>>> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
>>>>
>>>> SmartCard controller uses this interface to communicate with
>>>> SmartCard via PHY
>>>>
>>>> Some SmartCard PHY has multiple slots for cards.
>>>> This inerface also enables controller to communicate
>>>> with one or more SmartCard connected over phy.
>>>>
>>>> interface structure includes following APIs
>>>> - set/get config
>>>> - activate/deactivate smart card
>>>> - warm reset
>>>> - register_notify (for card insert/remove/overheat)
>>>> - unregister_notify
>>>>
>>>> Signed-off-by: Satish Patel <satish.patel@ti.com>
>>>> ---
>>>>    Documentation/sc_phy.txt |  171
>>>> ++++++++++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/sc_phy.h   |  136 ++++++++++++++++++++++++++++++++++++
>>>>    2 files changed, 307 insertions(+)
>>>>    create mode 100644 Documentation/sc_phy.txt
>>>>    create mode 100644 include/linux/sc_phy.h
>>>
>>>
>>> These are .h files, but where is the "api" functions that use
>>> these structures defined at?
>>>
>> This is like template/wrappers, smart card phy driver will write API
>> functions. And smartcard controller will call these functions.
>> With proposed approach, smartcard controller can communicate with any smart
>> card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY
>> will gets connected with each other.
>> Refer diagram given @Documentation/sc_phy.txt.
>>
>>
>>> confused,
>
> I believe the api Greg is wondering about is the notifier which as I
> commented is not a good design.
>
> There is now a phy subsystem. I don't know if it has what you need,
> but you should look at it to determine if it will work or could be
> extended to work.
>
I have given my comments on notifier, it is required to notify real time 
events like card insert/remove to the smart card controller. As this 
interrupts tied to phy (in case phy is present) not with controller.

Existing phy subsystem does not support generic operations for the phy. 
If at all it adds supports for these, in future I am ok to get align 
with it.

> Rob
>

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

* Re: [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx
  2014-05-29 15:53       ` Greg Kroah-Hartman
@ 2014-05-30  4:08         ` Satish Patel
  0 siblings, 0 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-30  4:08 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Rob Herring, linux-kernel, linux-arm-kernel, linux-omap,
	devicetree, Rob Landley, Tony Lindgren, Grant Likely,
	Rob Herring



On 5/29/2014 9:23 PM, Greg Kroah-Hartman wrote:
> On Thu, May 29, 2014 at 03:35:37PM +0530, Satish Patel wrote:
>>>> +enum usim_card_mode {
>>>> +       USIM_CARD_MODE_ASYNC = 0,       /* asynchronous mode */
>>>> +       USIM_CARD_MODE_SYNC_TYPE1,      /* synchronous mode: Type 1 */
>>>> +       USIM_CARD_MODE_SYNC_TYPE2,      /* synchronous mode: Type 2 */
>>>> +       USIM_CARD_MODE_SYNC_OTHER,      /* Any other synchronous type */
>>>> +};
>>>> +struct usim_data {
>>>> +       int slot;
>>>> +       int rxexplen;
>>>> +       int txlen;
>>>> +       unsigned char apdu[256];
>>>> +};
>
> You need to use the proper variable types for a structure that is going
> to cross the user/kernel boundry in an ioctl :(
Do you mean to use __u32 instead int ? make use of types defined in 
types.h ? if yes, I will make that change :). Thanks for pointing out.
>

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

* Re: [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller
  2014-05-29 15:51       ` Greg KH
@ 2014-05-30  5:05         ` Satish Patel
  0 siblings, 0 replies; 22+ messages in thread
From: Satish Patel @ 2014-05-30  5:05 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, linux-arm-kernel, linux-omap, devicetree, rob,
	tony, grant.likely, robh+dt



On 5/29/2014 9:21 PM, Greg KH wrote:
> On Thu, May 29, 2014 at 02:26:55PM +0530, Satish Patel wrote:
>>
>>
>> On 5/29/2014 12:14 AM, Greg KH wrote:
>>> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote:
>>>> +/**
>>>> + * struct sc_phy - The basic smart card phy structure
>>>> + *
>>>> + * @dev: phy device
>>>> + * @pdata: pointer to phy's private data structure
>>>> + * @set_config: called to set phy's configuration
>>>> + * @get_config: called to get phy's configuration
>>>> + * @activate_card: perform smart card activation
>>>> + * @deactivate_card: perform smart card de-activation
>>>> + * @warm_reset: execute smart card warm reset sequence
>>>> + * @register_card_activity_cb: register call back to phy device.
>>>> + * This call back will be called on card insert or remove event
>>>> + *
>>>> + * smart card controller uses this interface to communicate with
>>>> + * smart card via phy.Some smart card phy has multiple slots for
>>>> + * cards. This inerface also enables controller to communicate with
>>>> + * one or more smart card connected over phy.
>>>> + */
>>>> +struct sc_phy {
>>>> +	/* phy's device pointer */
>>>> +	struct device *dev;
>>>
>>> So this is the "parent", right?  Why not embed a struct device into this
>>> structure as well, further streaching out the device tree.
>>>
>> Do you mean to use "dev->p" for pdata ?
>
> No, use the device itself.
>
>> I have kept it outside, to give easeness/pragmatic focal for new phy driver
>> development. Driver can make this pointer null and use above pointer.
>
> Ick, no, that's not how the driver model works.  Each device in the
> system needs a struct device, don't try to "chain" off of an existing
> device like this.  Make it a "real" one.
>
>>>> +
>>>> +	/* phy's private data */
>>>> +	void *pdata;
>>>
>>> If you do the above, then this pointer is not needed.
>>>
>>>
>>>> +
>>>> +	/* notify data, passed by interface user as a part of
>>>> +	 * register_notify API. Data should be passed back when
>>>> +	 * notification raised to the interface user
>>>> +	 */
>>>> +	void *notify_data;
>>>
>>> What makes this different from the pdata?
>> pdata is phy's private data, while notify_data is something phy will send to
>> smart card controller on some event, like card remove/insert/timeout etc..
>
> That doesn't make much sense to me, why not just put that in the notify
> function callback itself?
>
Little correction over here..
Here is brief flow
USIM(Smart Card Controller) register notification callback to smarcard phy.

usim->phy->register_notify(<phy handle>, <callback fn>, <notify_data>);
notify_data : pass back when callback function will be called by PHY


Smartcard PHY -> USIM
blocking_notifier_call_chain(<notifier>, action, <notify_data>);

action : card insert/remove/overheat etc..
notify data: USIM data passing back (supplied at the time of cb 
registration)


> Please either use the existing phy layer of the kernel, or make a "real"
> subsystem here, don't try to put a tiny shim on top of an existing
> struct device for this driver, that's not how subsystems in Linux are
> done.
Why I am not using exiting PHY framework ?

We will be more than happy to adapt generic phy if it
includes/add support for smart card requirements like

1) Some smart card phy (TDA8026-NxP) has multiple slots for smart
cards. This interface enables controller to communicate with specific
smart card inserted to the specific phy's slot.
2) Warm reset to smart card inserted to phy slot.
3) Bit banging of smart card pins to support vendor specific memory
cards.
4) Notification of card insert/remove/overheat etc.
5) synchronous and asynchronous modes for smart card transaction


>
> thanks,
>
> greg k-h
>

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

end of thread, other threads:[~2014-05-30  5:06 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-28  8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel
2014-05-28  8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel
2014-05-28 18:44   ` Greg KH
2014-05-29  8:56     ` Satish Patel
2014-05-29 15:51       ` Greg KH
2014-05-30  5:05         ` Satish Patel
2014-05-28 18:53   ` Greg KH
2014-05-29  8:34     ` Satish Patel
2014-05-29 13:47       ` Rob Herring
2014-05-29 15:52         ` Greg KH
2014-05-30  3:51         ` Satish Patel
2014-05-28  8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel
2014-05-28 18:44   ` Greg KH
2014-05-29  8:37     ` Satish Patel
2014-05-29 15:52       ` Greg KH
2014-05-28  8:57 ` [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx Satish Patel
2014-05-28 17:56   ` Rob Herring
2014-05-29 10:05     ` Satish Patel
2014-05-29 15:53       ` Greg Kroah-Hartman
2014-05-30  4:08         ` Satish Patel
2014-05-28  8:57 ` [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim Satish Patel
2014-05-28  8:57 ` [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy Satish Patel

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).