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 - ATR - 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@xxxxxx> --- .../devicetree/bindings/ti-usim/ti-usim.txt | 31 + drivers/char/Kconfig | 7 + drivers/char/Makefile | 1 + drivers/char/ti-usim-hw.h | 863 +++++++++ drivers/char/ti-usim.c | 1859 ++++++++++++++++++++ include/linux/ti-usim.h | 98 + 6 files changed, 2859 insertions(+), 0 deletions(-) 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..6dc5d9c --- /dev/null +++ b/Documentation/devicetree/bindings/ti-usim/ti-usim.txt @@ -0,0 +1,31 @@ +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>; + clock-names = "opt_fck", "opt_fck32"; + }; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fa3243d..dee0209 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -599,5 +599,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 7ff1d0d..763fd3d 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -62,3 +62,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..b6d69ff --- /dev/null +++ b/drivers/char/ti-usim-hw.h @@ -0,0 +1,863 @@ +/* + * 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; +}; + +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..a2af409 --- /dev/null +++ b/drivers/char/ti-usim.c @@ -0,0 +1,1859 @@ +/* + * 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> +/* 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) + +/* + * 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 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; + + /* 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; + 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; + } + + USIM_WRITEREG(usim->base, USIM_CONF2, CONFSCLKMODE, clkmode); + USIM_WRITEREG(usim->base, USIM_CONF2, CONFSCLKDIV, clkdiv); + + /* 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; + + 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_activate_card(struct usim *usim) +{ + int ret = 0; + struct sc_phy *phy = usim->phy; + + usim->atrdone = 0; + usim->slot_ctx[usim->slot].atr_length = 0; + + if (usim->slot_ctx[usim->slot].emv) + usim_init_emvusercard(usim); + + 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; + struct sc_phy *phy = usim->phy; + + /* 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; + + 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 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; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +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; + + 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; + + 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"); + wait_event_interruptible(atr_wait, (usim->atrdone == 1)); + 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(¶m, (struct usim_config *)arg, + sizeof(struct usim_config)); + if (ret != 0) + return -EFAULT; + + usim_set_config(usim, ¶m); + break; + + case USIM_IOCTL_GET_CONFIG: + dev_dbg(usim->dev, "IOCTL: GET CONFIG\n"); + ret = copy_from_user(¶m, (struct usim_config *)arg, + sizeof(struct usim_config)); + if (ret != 0) + return -EFAULT; + + usim_get_config(usim, ¶m); + ret = copy_to_user((struct usim_config *)arg, ¶m, + 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)) + dev_err(usim->dev, "unable to get fck\n"); + else + clk_enable(usim->opt_fclk); + + usim->opt_fclk32 = devm_clk_get(usim->dev, "opt_fck32"); + if (IS_ERR(usim->opt_fclk32)) + dev_err(usim->dev, "unable to get dbclk\n"); + else + clk_enable(usim->opt_fclk32); + + return 0; +} +static void usim_enable(struct usim *usim) +{ + if (usim->enable == 1) + return; + + /* enable the clk */ + pm_runtime_get_sync(usim->dev); + + /* usim init */ + usim_configure(usim); + + usim->enable = 1; + return; +} + +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 */ + pm_runtime_put_sync_autosuspend(usim->dev); + usim->enable = 0; + return; +} + +static int usim_open(struct inode *inode, struct file *file) +{ + 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; + usim_enable(usim); + 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); */ + return 0; +} + +static int usim_resume(struct device *dev) +{ + /* struct usim *usim = dev_to_usim(dev); */ + 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; + + /* 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); + + 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; + } + + dev_set_drvdata(dev, usim); + usim_pm_init(usim); + + /* 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); + 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 + /* 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@xxxxxx>"); +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..f4b3ca8 --- /dev/null +++ b/include/linux/ti-usim.h @@ -0,0 +1,98 @@ +/* + * 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, +}; + +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.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html