123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include <linux/clk.h>
- #include <linux/delay.h>
- #include <linux/dsmart_card_interface.h>
- #include <asm/io.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/fs.h>
- #include <linux/interrupt.h>
- #include <linux/init.h>
- #include <linux/miscdevice.h>
- #include <linux/module.h>
- #include <linux/of_device.h>
- #include <linux/spinlock.h>
- #include <linux/types.h>
- #include <linux/uaccess.h>
- #include <asm/uaccess.h>
- #define MAX_TRY_TIME_COUNT 100000
- #define MAX_INT_TIMEOUT (msecs_to_jiffies(1000))
- #define RX_TX_FIFO 0x00
- #define CONTROL 0x04
- #define MSTATUS_MMASK 0x08 /* Each bit of the MSTATUS register is a source of a maskable interrupt. Writing logic '1' to the corresponding bit of MMASK register,
- enables pending interrupt from the given source. */
- #define CSTATUS 0x0c
- #define CONFIG 0x10
- #define MISC 0x14
- #define CCLK_DIV 0x18
- #define ETU 0x1c
- #define EGT 0x20
- #define WT0_BGT 0x24
- #define WT1_CWT 0x28
- #define WT2 0x2c
- #define WT3 0x30
- #define ERROR_MERROR 0x34
- #define LENGTH 0x38
- /* bit definition for CONFIG */
- #define MIE BIT(7) /* This bit is set to HIGH to globally enable interrupts, and cleared to LOW disables interrupts */
- #define DMA_EN BIT(6) /* HIGH state written into this bit enables the DMA mode */
- #define BLOCK_ON BIT(5) /* Active HIGH bit which is responsible for block mode activation. See 9.15 LENGTH register for details */
- #define CLOCK_STOP BIT(4) /* The value in which card clock (cclk pin) will be stopped in the power down mode. Automatically cleared when CRD_ERR is detected or STOP asserted */
- #define C BIT(3) /* These bits work as GPIO for pins c5v3 and c18. Used for class setting */
- #define AB BIT(2) /* These bits work as GPIO for pins c5v3 and c18. Used for class setting */
- #define TMOD BIT(1) /* HIGH state of this bit indicates that the T=1 protocol is used, else T=0 protocol. In the DSMART, it changes the error signaling of character repetition */
- #define CRD_DET_EN BIT(0) /* When this bit is HIGH CRD_DET bit in Card Status register will follow the state of the cdet pin */
- /* bit definition for MSTATUS/MMASK */
- #define CRD_EV_IRQ BIT(7)
- #define ERR_EV_IRQ BIT(6)
- #define TX_EV_IRQ BIT(5)
- #define RX_EV_IRQ BIT(4)
- #define TX_EM_IRQ BIT(3)
- #define BREAK_IRQ BIT(2)
- #define BLK_FIN_IRQ BIT(1)
- #define RX_AV_IRQ BIT(0)
- /* bit definition for CSTATUS */
- #define ODDP BIT(7)
- #define SES_END_CARD_STATE BIT(6)
- #define TIMEOUT_CARD_STATE BIT(5)
- #define SYNC_ERR_CARD_STATE BIT(4)
- #define CONV_CARD_STATE BIT(3)
- #define CRD_ERR_CARD_STATE BIT(2)
- #define CRD_ACT_CARD_STATE BIT(1)
- #define CRD_DET_CARD_STATE BIT(0)
- /* bit definition for MISC */
- #define TX_TR BIT(6)
- #define RX_TR BIT(4)
- #define TXFIFO_ON BIT(3)
- #define RXFIFO_ON BIT(2)
- #define CRC_MOD BIT(1)
- #define CRC_EN BIT(0)
- #define RX_TR_OFF 4
- #define TX_TR_OFF 6
- #define RX_TR_MSK 0x3
- #define TX_TR_MSK 0x3
- /* bit definition for CONTROL */
- #define TX_END BIT(7)
- #define LAST BIT(6)
- #define PWD BIT(5)
- #define RT BIT(4)
- #define STOP BIT(3)
- #define CLR_ERR BIT(2)
- #define WRST BIT(1)
- #define START BIT(0)
- /* bit definition for WT0/BGT */
- #define BIT_WT2 BIT(7)
- #define WT1 BIT(6)
- #define WT0 BIT(5)
- #define BGT4 BIT(4)
- #define BGT3 BIT(3)
- #define BGT2 BIT(2)
- #define BGT1 BIT(1)
- #define BGT0 BIT(0)
- #define WT0_OFF 5
- #define BGT_OFF 0
- #define WT0_MSK 0x7
- #define BGT_MSK 0x1f
- /* bit definition for WT1/CWT */
- #define WT6 BIT(7)
- #define WT5 BIT(6)
- #define WT4 BIT(5)
- #define BIT_WT3 BIT(4)
- #define CWT3 BIT(3)
- #define CWT2 BIT(2)
- #define CWT1 BIT(1)
- #define CWT0 BIT(0)
- #define WT3_OFF 4
- #define CWT_OFF 0
- #define WT3_MSK 0xf
- #define CWT_MSK 0xf
- /* bit definition for ERROR/MERROR */
- #define PAR_ERR_STATE BIT(0)
- #define CRC_ERR_STATE BIT(1)
- #define REP_ERR_STATE BIT(2)
- #define RX_OVER_ERR_STATE BIT(3)
- #define TX_FULL_ERR_STATE BIT(4)
- #define CWT_TIM_ERR_STATE BIT(5)
- #define RX_FULL_ERR_STATE BIT(6)
- #define MAX_DSMART_CARD_CWT 10080 /* in ETU */
- #define CVOL_CLASS_MSK 0x3
- #define DSMART_CARD_RCV_BUFFER_SIZE 400
- #define DSMART_CARD_XMT_BUFFER_SIZE 300
- #define DSMART_CARD_PRESENT_REMOVED 0
- #define DSMART_CARD_PRESENT_DETECTED 1
- #define DSMART_CARD_STATE_REMOVED 0
- #define DSMART_CARD_STATE_DETECTED 1
- #define DSMART_CARD_STATE_ACTIVATED 2
- #define DSMART_CARD_STATE_RECEIVING 3
- #define DSMART_CARD_STATE_RECEIVE_DONE 4
- #define DSMART_CARD_STATE_ATR_RECEIVING 5
- #define DSMART_CARD_STATE_ATR_RECEIVE_DONE 6
- #define DSMART_CARD_STATE_XMTING 7
- #define DSMART_CARD_FIFO_SIZE 16
- enum trans_direction {
- RECEIVER_MOD,
- TRANSMITTER_MOD,
- };
- enum card_staus {
- DEACTIVATE,
- ACTIVATING,
- PSS_TRF,
- PSS_RECV,
- ACTIVATE,
- };
- enum dsmart_card_event {
- EVENT_CARD_DETECTED,
- EVENT_READ_COMPLETE,
- EVENT_WRITE_COMPLETE,
- EVENT_READ_ERROR,
- EVENT_WRITE_ERROR,
- EVENT_ACTIVATE_SUCCESS,
- EVENT_ACTIVATE_FAILED,
- EVENT_CARD_ERROR_DEACTIVATE,
- EVENT_CARD_SESSION_CLOSED,
- EVENT_RX_FULL,
- EVENT_CWT_TIME_OUT,
- EVENT_RX_OVER,
- EVENT_CRC_ERR,
- EVENT_PARITY_ERR,
- EVENT_SLAVE_ATR_DETECTED,
- EVENT_SLAVE_ATR_DONE,
- };
- struct dsmart_card {
- struct device *dev;
- void __iomem *base;
- struct clk *clk;
- int irq;
- spinlock_t lock;
- u8 rcv_buffer[DSMART_CARD_RCV_BUFFER_SIZE];
- u8 xmt_buffer[DSMART_CARD_XMT_BUFFER_SIZE];
- struct completion xfer_done;
- enum card_staus card_sta;
- int protocol_type;
- int present;
- u32 expected_rcv_cnt;
- u32 rx_threshold;
- u32 tx_threshold;
- bool is_fixed_len;
- int rcv_head;
- int rcv_count;
- int xmt_head;
- int xmt_count;
- int xmt_remainning_count;
- int errval;
- struct dsmart_card_timing timing_data;
- int state;
- struct dsmart_card_baud baud_rate;
- };
- static inline void card_clk_div_set(void __iomem *base, u32 val)
- {
- writel(val, base + CCLK_DIV);
- }
- static inline void card_vol_class_set(void __iomem *base, u32 val)
- {
- u32 data = readl(base + CONFIG);
- data &= ~(CVOL_CLASS_MSK << AB);
- data |= val << AB;
- writel(data, base + CONFIG);
- }
- static inline void card_det_enable(void __iomem *base, bool en)
- {
- u32 data = readl(base + CONFIG);
- if (en)
- data |= CRD_DET_EN;
- else
- data &= ~CRD_DET_EN;
- writel(data, base + CONFIG);
- }
- static inline void card_event_interrupt_enable(void __iomem *base, u32 mask, bool en)
- {
- u32 data = readl(base + MSTATUS_MMASK);
- if (en)
- data |= mask;
- else
- data &= ~mask;
- writel(data, base + MSTATUS_MMASK);
- }
- static inline void card_glb_interrupt_enable(void __iomem *base, bool en)
- {
- u32 data = readl(base + CONFIG);
- if (en)
- data |= MIE;
- else
- data &= ~MIE;
- writel(data, base + CONFIG);
- }
- static inline void card_odd_parity_set(void __iomem *base, bool en)
- {
- u32 data = readl(base + CSTATUS);
- if (en)
- data |= ODDP;
- else /* EVEN Parity */
- data &= ~ODDP;
- writel(data, base + CSTATUS);
- }
- static inline void card_trans_protocol_set(void __iomem *base, int proto)
- {
- u32 data = readl(base + CONFIG);
- if (proto == CARD_PROTOCOL_T0)
- data &= ~TMOD;
- else
- data |= TMOD;
- writel(data, base + CONFIG);
- }
- static inline void card_tx_fifo_enable(void __iomem *base, bool en)
- {
- u32 data = readl(base + MISC);
- if (en)
- data |= TXFIFO_ON;
- else
- data &= ~TXFIFO_ON;
- writel(data, base + MISC);
- }
- static inline void card_rx_fifo_enable(void __iomem *base, bool en)
- {
- u32 data = readl(base + MISC);
- if (en)
- data |= RXFIFO_ON;
- else
- data &= ~RXFIFO_ON;
- writel(data, base + MISC);
- }
- static inline void card_trans_direction_set(void __iomem *base, enum trans_direction dire)
- {
- u32 data = readl(base + CONTROL);
- if (dire == RECEIVER_MOD)
- data &= ~RT;
- else
- data |= RT;
- writel(data, base + CONTROL);
- }
- static inline void card_warm_reset(void __iomem *base)
- {
- u32 data = readl(base + CONTROL);
- data |= WRST;
- writel(data, base + CONTROL);
- }
- /*
- * shall not exceed WWT={960xDxWI}x1etu, where D=TA1 interface byte, WI=TC2 interface byte.
- * WWT value should be a priori converted to current ETU value written to the WT0-WT3 register
- */
- static inline void card_wwt_time_set(void __iomem *base, u32 time)
- {
- u32 data = readl(base + WT0_BGT);
- data &= ~(WT0_MSK << WT0_OFF);
- data |= ((time >> 0) & WT0_MSK) << WT0_OFF;
- writel(data, base + WT0_BGT);
- data = readl(base + WT1_CWT);
- data &= ~(WT3_MSK << WT3_OFF);
- data |= ((time >> 3) & WT3_MSK) << WT3_OFF;
- writel(data, base + WT1_CWT);
- data = ~0xff;
- data |= (time >> 7) & 0xff;
- writel(data, base + WT2);
- data = ~0xff;
- data |= (time >> 15) & 0xff;
- writel(data, base + WT3);
- }
- static inline void card_trans_start(void __iomem *base)
- {
- writel(readl(base + CONTROL) | START, base + CONTROL);
- }
- /*
- *When set HIGH the interface begins the deactivation procedure. After card deactivation this signal is automatically cleared.
- *It can be also used to clear card detection or session end interrupt without invoking the activation procedure
- */
- static inline void card_trans_stop(void __iomem *base)
- {
- writel(readl(base + CONTROL) | STOP, base + CONTROL);
- }
- static inline void card_rx_threshold_set(void __iomem *base, u32 val)
- {
- u32 data = readl(base + MISC);
- data &= ~(RX_TR_MSK << RX_TR_OFF);
- data |= (val & RX_TR_MSK) << RX_TR_OFF;
- writel(data, base + MISC);
- }
- static inline void card_tx_threshold_set(void __iomem *base, u32 val)
- {
- u32 data = readl(base + MISC);
- data &= ~(TX_TR_MSK << TX_TR_OFF);
- data |= (val & TX_TR_MSK) << TX_TR_OFF;
- writel(data, base + MISC);
- }
- static inline u32 card_mstatus_get(void __iomem *base)
- {
- return readl(base + MSTATUS_MMASK);
- }
- static inline u32 card_status_get(void __iomem *base)
- {
- return readl(base + CSTATUS);
- }
- static inline void card_error_clear(void __iomem *base)
- {
- writel(readl(base + CONTROL) | CLR_ERR, base + CONTROL);
- }
- static inline u32 card_error_status_get(void __iomem *base)
- {
- return readl(base + ERROR_MERROR);
- }
- static inline void card_bgt_time_set(void __iomem *base, u32 time)
- {
- u32 data = readl(base + WT0_BGT);
- data &= ~0x1f;
- data |= time & 0x1f;
- writel(data, base + WT0_BGT);
- }
- static inline void card_cwt_time_set(void __iomem *base, u32 time)
- {
- u32 data = readl(base + WT1_CWT);
- data &= ~0xf;
- data |= time & 0xf;
- writel(data, base + WT1_CWT);
- }
- /* BWT={(2BWIx960)+11}x1etu. The result should be written into the WT0-WT3 registers */
- static inline void card_bwt_time_set(void __iomem *base, u32 time)
- {
- card_wwt_time_set(base, time);
- }
- /*
- * The value of 255 indicates that the minimum GUARD TIME (2 ETU for T=0 protocol and 1 ETU for T=1 protocol) should be used,
- * then the minimum character to character duration for subsequent transmissions shall be 12 ETUs if T=0 protocol is used,
- * or 11 ETUs if T=1 protocol is used. The exact value of EXTRA GUARD TIME (from 0 to 254) should be written into the guard time register.
- * Default value after reset is 1
- */
- static inline void card_egt_time_set(void __iomem *base, u32 time) /* means char guard time */
- {
- writel(time, base + EGT);
- }
- /* 1etu={1/f}x{Fi/Di} */
- static inline void card_baud_rate_set(void __iomem *base, u32 fi, u32 di)
- {
- u32 data = (fi & 0xf) << 4 | (di & 0xf);
- writel(data, base + ETU);
- }
- static inline u32 card_data_length_get(void __iomem *base)
- {
- return readl(base + LENGTH);
- }
- static inline u32 card_fifo_data_get(void __iomem *base)
- {
- return readl(base + RX_TX_FIFO);
- }
- static inline void card_fifo_data_set(void __iomem *base, u8 data)
- {
- writel(data, base + RX_TX_FIFO);
- }
- static struct miscdevice dsmart_card_dev;
- static void dsmart_card_rcv_read_fifo(struct dsmart_card *card)
- {
- u32 i, data, len = card_data_length_get(card->base);
- pr_debug("%s, %d: len = %d\n", __func__, __LINE__, len);
- if (!len)
- card_fifo_data_get(card->base); //clear the fifo
- spin_lock(&card->lock);
- for (i = 0; i < len; i++) {
- data = card_fifo_data_get(card->base);
- card->rcv_buffer[card->rcv_head + card->rcv_count] = (u8)data;
- pr_debug("data%d = 0x%x , card->rcv_buffer[%d] = 0x%x ", i, data, card->rcv_head + card->rcv_count,
- card->rcv_buffer[card->rcv_head + card->rcv_count]);
- card->rcv_count++;
- if (card->rcv_head + card->rcv_count >= DSMART_CARD_RCV_BUFFER_SIZE) {
- pr_err("the software fifo is full, head:%d, count:%d\n", card->rcv_head,
- card->rcv_count);
- break;
- }
- }
- spin_unlock(&card->lock);
- }
- static void dsmart_card_xmt_write_fifo(struct dsmart_card *card)
- {
- u32 i, data, len = card_data_length_get(card->base);
- u32 avail_size = 0;
- spin_lock(&card->lock);
- avail_size = DSMART_CARD_FIFO_SIZE - len;
- for (i = 0; i < avail_size; i++) {
- data = card->xmt_buffer[card->xmt_head + card->xmt_count];
- card_fifo_data_set(card->base, data);
- card->xmt_count++;
- if (card->xmt_head + card->xmt_count >= DSMART_CARD_XMT_BUFFER_SIZE) {
- pr_err("the software fifo is empty, head:%d, count:%d\n", card->xmt_head,
- card->xmt_count);
- break;
- }
- }
- spin_unlock(&card->lock);
- }
- static void dsmart_error_event_handle(struct dsmart_card *card)
- {
- u32 err_status = card_error_status_get(card->base);
- if (err_status & RX_FULL_ERR_STATE) {
- dsmart_card_rcv_read_fifo(card);
- card->state = DSMART_CARD_STATE_RECEIVE_DONE;
- return;
- }
- if (err_status & TX_FULL_ERR_STATE) {
- //card->errval = -DSMART_CARD_E_TX_FULL;
- card->errval = DSMART_CARD_OK;
- return;
- }
- if (err_status & PAR_ERR_STATE) {
- card->errval = -DSMART_CARD_E_PAR_ERR;
- pr_err("par error occured\n");
- } else if (err_status & CRC_ERR_STATE) {
- card->errval = -DSMART_CARD_E_CRC_ERR;
- pr_err("crc error occured\n");
- } else if (err_status & REP_ERR_STATE) {
- card->errval = -DSMART_CARD_E_REP_ERR;
- pr_err("rep error occured\n");
- } else if (err_status & CWT_TIM_ERR_STATE) {
- card->errval = -DSMART_CARD_E_CWT_TIM;
- pr_err("cwt_tim error occured\n");
- } else if (err_status & RX_OVER_ERR_STATE) {
- card->errval = -DSMART_CARD_E_RX_OVER;
- pr_err("rx_over error occured\n");
- } else {
- pr_err("invalid error event number\n");
- return;
- }
- /* clear the error to stop interrupt */
- card_error_clear(card->base);
- card_event_interrupt_enable(card->base, ERR_EV_IRQ, false);
- }
- static void dsmart_card_event_handle(struct dsmart_card *card)
- {
- u32 card_status = card_status_get(card->base);
- pr_debug("%s:%d, card event status = 0x%x\n", __func__, __LINE__, card_status);
- if (card_status & CRD_DET_CARD_STATE) {
- card->present = DSMART_CARD_PRESENT_DETECTED;
- card->state = DSMART_CARD_STATE_DETECTED;
- card->errval = DSMART_CARD_OK;
- pr_debug("%s:%d\n", __func__, __LINE__);
- card_event_interrupt_enable(card->base, CRD_EV_IRQ, false);
- complete(&card->xfer_done);
- /* just clear the card detection interrupt without invoking the activation procedure */
- //card_trans_stop(card->base);
- } else if (card_status & CRD_ACT_CARD_STATE) {
- pr_debug("%s:%d\n", __func__, __LINE__);
- complete(&card->xfer_done);
- } else if (card_status & TIMEOUT_CARD_STATE) {
- card->errval = -DSMART_CARD_E_ACT_TIMEOUT;
- card_error_clear(card->base);
- pr_debug("%s:%d\n", __func__, __LINE__);
- } else if (card_status & CRD_ERR_CARD_STATE) {
- card->errval = -DSMART_CARD_E_REMOVED;
- card_error_clear(card->base);
- pr_debug("%s:%d\n", __func__, __LINE__);
- } else if (card_status & SES_END_CARD_STATE) {
- pr_debug("the session is terminated\n");
- }
- }
- static irqreturn_t dsmart_card_handler(int irq, void *p)
- {
- struct dsmart_card *card = (struct dsmart_card *)p;
- u32 card_event = card_mstatus_get(card->base);
- pr_debug("%s:%d, irq status = 0x%x\n", __func__, __LINE__, card_event);
- if (card_event & CRD_EV_IRQ) {
- dsmart_card_event_handle(card);
- }
- if (card_event & ERR_EV_IRQ) {
- dsmart_error_event_handle(card);
- }
- if (card_event & RX_AV_IRQ) {
- dsmart_card_rcv_read_fifo(card);
- pr_debug("%s:%d\n", __func__, __LINE__);
- }
- if (card_event & TX_EM_IRQ) {
- dsmart_card_xmt_write_fifo(card);
- pr_debug("%s:%d\n", __func__, __LINE__);
- }
- if (card_event & RX_EV_IRQ) {
- dsmart_card_rcv_read_fifo(card);
- pr_debug("%s:%d\n", __func__, __LINE__);
- }
- if (card_event & TX_EV_IRQ) {
- dsmart_card_xmt_write_fifo(card);
- pr_debug("%s:%d\n", __func__, __LINE__);
- }
- //complete(&card->xfer_done);
- return IRQ_HANDLED;
- }
- static int dsmart_card_check_timing_data(struct dsmart_card_timing *timing_data)
- {
- pr_debug("wwt = 0x%d, cwt = 0x%d, bwt = 0x%d, bgt = 0x%d, egt = 0x%d\n",
- timing_data->wwt, timing_data->cwt, timing_data->bwt, timing_data->bgt, timing_data->egt);
- if (timing_data->wwt > 0x7fffff ||
- timing_data->cwt > 0xf ||
- timing_data->bwt > 0x7fffff ||
- timing_data->bgt > 0x1f ||
- timing_data->egt > 0xf) {
- pr_err("the timing value is out of scope\n");
- return -EINVAL;
- }
- return 0;
- }
- static int dsmart_card_baud_rate_check(struct dsmart_card_baud *rate)
- {
- /*
- * According to Table: The clock rate conversion Fi integer & Table: The baud rate dividion Di integer
- */
- if (rate->fi == 7 || rate->fi >= 0xe || rate->di >= 0xa)
- return -EINVAL;
- return 0;
- }
- static void dsmart_card_baud_rate_set(struct dsmart_card *card)
- {
- if (card->baud_rate.fi && card->baud_rate.di)
- card_baud_rate_set(card->base, card->baud_rate.fi, card->baud_rate.di);
- }
- static void dsmart_card_data_reset(struct dsmart_card *card)
- {
- card->errval = DSMART_CARD_OK;
- card->rcv_count = 0;
- card->rcv_head = 0;
- card->xmt_count = 0;
- card->xmt_remainning_count = 0;
- card->xmt_head = 0;
- card->protocol_type = CARD_PROTOCOL_T0;
- card_event_interrupt_enable(card->base, 0xff, false);
- card_tx_fifo_enable(card->base, false);
- card_rx_fifo_enable(card->base, false);
- card_rx_threshold_set(card->base, 2); /* set minimum threshold for receiving atr */
- card_event_interrupt_enable(card->base, CRD_EV_IRQ, true); /* enable card & error event occur first */
- card_glb_interrupt_enable(card->base, true);
- /* set card working frequency as 1M clk, clk = pclk / {(CLK_DIV + 1) * 2}*/
- #ifdef CONFIG_MAX_CCLK
- card_clk_div_set(card->base, 1); //7
- #else
- card_clk_div_set(card->base, 29);
- #endif
- memset(card->rcv_buffer, 0, DSMART_CARD_RCV_BUFFER_SIZE);
- memset(card->xmt_buffer, 0, DSMART_CARD_XMT_BUFFER_SIZE);
- memset(&card->timing_data, 0, sizeof(card->timing_data));
- memset(&card->baud_rate, 0, sizeof(card->baud_rate));
- reinit_completion(&card->xfer_done);
- }
- static int dsmart_card_detect(struct dsmart_card *card)
- {
- reinit_completion(&card->xfer_done);
- card_det_enable(card->base, true);
- /* check the card if detected */
- if (wait_for_completion_interruptible(&card->xfer_done)) {/* wait for CRD_DET bit set */
- pr_err("%s, %d: dsmart card detected timeout\n", __func__, __LINE__);
- return -ETIMEDOUT;
- }
- card->state = DSMART_CARD_STATE_DETECTED;
- pr_debug("%s:%d\n", __func__, __LINE__);
- return 0;
- }
- static int dsmart_card_start_data_rcv(struct dsmart_card *card, unsigned long arg)
- {
- dsmart_card_baud_rate_set(card);
- card_trans_protocol_set(card->base, card->protocol_type);
- card_rx_fifo_enable(card->base, true);
- card_trans_direction_set(card->base, RECEIVER_MOD);
- card->state = DSMART_CARD_STATE_RECEIVING;
- card_event_interrupt_enable(card->base, RX_EV_IRQ | RX_AV_IRQ, true);
- card_trans_start(card->base);
- #if 0
- reinit_completion(&card->xfer_done);
- pr_debug("%s:%d\n", __func__, __LINE__);
- /* wait RX_TD interrupt */
- if (wait_for_completion_interruptible(&card->xfer_done)) {
- pr_err("%s,%d: timeout in receiving normal data\n", __func__, __LINE__);
- return -DSMART_CARD_E_DATA_TIMEOUT;
- }
- #endif
- pr_debug("%s:%d\n", __func__, __LINE__);
- return 0;
- }
- static int dsmart_card_atr_rcv(struct dsmart_card *card, unsigned long arg)
- {
- int __maybe_unused i;
- u32 delay_cnt = 0;
- u32 card_status = card_status_get(card->base);
- card_tx_fifo_enable(card->base, true);
- card_trans_direction_set(card->base, RECEIVER_MOD);
- /*Set the cwt timer.Refer the setting of ATR on EMV4.3 book*/
- //card_wwt_time_set(card->base, MAX_DSMART_CARD_CWT);
- /* Set 12 ETUS */
- //card_egt_time_set(card->base, 0xff);
- card_trans_start(card->base); /* activate the secquence */
- card_fifo_data_set(card->base, 0x1);
- card_fifo_data_set(card->base, 0x2);
- card_fifo_data_set(card->base, 0x3);
- card_trans_direction_set(card->base, TRANSMITTER_MOD);
- pr_debug("%s:%d\n", __func__, __LINE__);
- #if 1
- while ((card_status & CRD_ACT_CARD_STATE) != CRD_ACT_CARD_STATE) {
- card_status = card_status_get(card->base);
- mdelay(1);
- delay_cnt++;
- }
- #else
- card_event_interrupt_enable(card->base, CRD_EV_IRQ, true);
- reinit_completion(&card->xfer_done);
- if (wait_for_completion_interruptible(&card->xfer_done)) { /* wait for successful activation */
- pr_err("%s, %d: dsmart card activate timeout\n", __func__, __LINE__);
- return -ETIMEDOUT;
- }
- #endif
- pr_debug("delay_cnt = %d ms\n", delay_cnt);
- card->state = DSMART_CARD_STATE_ACTIVATED;
- pr_debug("%s:%d\n", __func__, __LINE__);
- card_event_interrupt_enable(card->base, RX_EV_IRQ, true);
- card_rx_fifo_enable(card->base, true);
- card->state = DSMART_CARD_STATE_ATR_RECEIVING;
- pr_debug("%s:%d\n", __func__, __LINE__);
- card_trans_direction_set(card->base, RECEIVER_MOD);
- pr_debug("%s:%d\n", __func__, __LINE__);
- msleep(5000); //how to confirm the atr length ?
- card->state = DSMART_CARD_STATE_ATR_RECEIVE_DONE;
- #ifdef CONFIG_ATR_DATA_PRINT
- for (i = 0; i < card->rcv_count; i++) {
- pr_debug("0x%02x ", card->rcv_buffer[i]);
- }
- #endif
- pr_info("[%s:%d]set fcclk as 15M\n", __func__, __LINE__);
- card_clk_div_set(card->base, 1);
- return 0;
- }
- static int dsmart_card_start_data_xmt(struct dsmart_card *card, unsigned long arg)
- {
- dsmart_card_baud_rate_set(card);
- card_trans_protocol_set(card->base, card->protocol_type);
- card_tx_fifo_enable(card->base, true);
- card_trans_direction_set(card->base, TRANSMITTER_MOD);
- card->state = DSMART_CARD_STATE_XMTING;
- card_event_interrupt_enable(card->base, TX_EV_IRQ | TX_EM_IRQ, true);
- card_trans_start(card->base);
- reinit_completion(&card->xfer_done);
- pr_debug("%s:%d\n", __func__, __LINE__);
- /* wait RX_TD interrupt */
- if (wait_for_completion_interruptible(&card->xfer_done)) {
- pr_err("%s,%d: timeout in receiving normal data\n", __func__, __LINE__);
- return -DSMART_CARD_E_DATA_TIMEOUT;
- }
- pr_debug("%s:%d\n", __func__, __LINE__);
- return 0;
- }
- static void dsmart_card_deactivate(struct dsmart_card *card)
- {
- card_trans_stop(card);
- }
- static int dsmart_card_warm_reset(struct dsmart_card *card)
- {
- card_warm_reset(card->base);
- pr_info("[%s:%d]set fcclk as 1M\n", __func__, __LINE__);
- card_clk_div_set(card->base, 29);
- card->errval = DSMART_CARD_OK;
- return dsmart_card_atr_rcv(card, 0);
- }
- static void dsmart_card_timing_counter_set(struct dsmart_card *card)
- {
- if (card->timing_data.wwt && card->protocol_type == CARD_PROTOCOL_T0) {
- card->timing_data.cwt = card->timing_data.wwt;
- card->timing_data.bwt = card->timing_data.wwt;
- card_wwt_time_set(card->base, card->timing_data.cwt);
- }
- if (card->timing_data.bgt && card->protocol_type == CARD_PROTOCOL_T1)
- card_bgt_time_set(card->base, card->timing_data.bgt);
- if (card->timing_data.cwt && card->protocol_type == CARD_PROTOCOL_T1)
- card_cwt_time_set(card->base, card->timing_data.cwt);
- if (card->timing_data.egt)
- card_egt_time_set(card->base, card->timing_data.egt);
- }
- static int dsmart_card_open(struct inode *inode, struct file *filp)
- {
- struct dsmart_card *dsmart_card = dev_get_drvdata(dsmart_card_dev.parent);
- filp->private_data = dsmart_card;
- spin_lock_init(&dsmart_card->lock);
- //dsmart_card_data_reset(dsmart_card);
- return 0;
- }
- static int dsmart_card_release(struct inode *inode, struct file *filp)
- {
- /* struct dsmart_card *dsmart_card = (struct dsmart_card *)filp->private_data; */
- return 0;
- }
- static long dsmart_card_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- {
- int ret = 0;
- int __maybe_unused i;
- struct dsmart_card *card = (struct dsmart_card *)filp->private_data;
- u32 copy_cnt;
- unsigned long flags;
- u32 xmt_size = 0;
- pr_debug("%s entering, cmd = 0x%x\n", __func__, cmd);
- switch (cmd) {
- case DSMART_CARD_IOCTL_SET_PROTOCOL:
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_from_user(&card->protocol_type, (int *)arg, sizeof(int));
- if (ret)
- pr_err("protocol copy error\n");
- break;
- case DSMART_CARD_IOCTL_DEACTIVATE:
- pr_debug("%s:%d\n", __func__, __LINE__);
- dsmart_card_deactivate(card);
- break;
- case DSMART_CARD_IOCTL_COLD_RESET:
- pr_debug("%s:%d\n", __func__, __LINE__);
- card->present = DSMART_CARD_PRESENT_REMOVED;
- card->state = DSMART_CARD_STATE_REMOVED;
- dsmart_card_data_reset(card);
- ret = dsmart_card_detect(card);
- if (ret) {
- pr_err("no card found\n");
- ret = -DSMART_CARD_E_DATA_TIMEOUT;
- break;
- }
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = dsmart_card_atr_rcv(card, arg);
- break;
- case DSMART_CARD_IOCTL_WARM_RESET:
- pr_debug("%s:%d\n", __func__, __LINE__);
- card_clk_div_set(card->base, 29);
- ret = dsmart_card_warm_reset(card);
- break;
- case DSMART_CARD_IOCTL_SET_TIMING:
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_from_user(&card->timing_data, (struct dsmart_card_timing *)arg,
- sizeof(struct dsmart_card_timing));
- if (ret) {
- pr_err("timing copy error\n");
- break;
- }
- ret = dsmart_card_check_timing_data(&card->timing_data);
- break;
- case DSMART_CARD_IOCTL_SET_BAUD:
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_from_user(&card->baud_rate, (struct dsmart_card_baud *)arg,
- sizeof(struct dsmart_card_baud));
- if (ret) {
- pr_err("baud rate copy error\n");
- break;
- }
- ret = dsmart_card_baud_rate_check(&card->baud_rate);
- if (ret)
- pr_err("invalid baud rate value\n");
- break;
- case DSMART_CARD_IOCTL_SET_RX_THRESHOLD:
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_from_user(&card->rx_threshold, (int *)arg, sizeof(int));
- if (ret) {
- pr_err("threshold copy error\n");
- break;
- }
- break;
- case DSMART_CARD_IOCTL_SET_TX_THRESHOLD:
- pr_debug("%s:%d\n", __func__, __LINE__);
- break;
- case DSMART_CARD_IOCTL_ATR_RCV:
- pr_debug("%s:%d\n", __func__, __LINE__);
- if (card->state != DSMART_CARD_STATE_ATR_RECEIVE_DONE) {
- pr_err("failed to activate sequence\n");
- ret = -DSMART_CARD_E_ACTIVATE_FAILED;
- goto report_error;
- }
- ret = copy_to_user(&(((struct dsmart_card_atr *)arg)->len), &card->rcv_count,
- sizeof(card->rcv_count));
- if (ret) {
- pr_err("len copy error\n");
- ret = -DSMART_CARD_E_ACCESS;
- goto report_error;
- }
- ret = copy_to_user(((struct dsmart_card_atr __user *)arg)->atr_buffer, card->rcv_buffer, card->rcv_count);
- if (ret) {
- pr_err("failed to copy atr data to user\n");
- ret = -DSMART_CARD_E_ACCESS;
- goto report_error;
- }
- #ifdef CONFIG_ATR_DATA_PRINT
- for (i = 0; i < card->rcv_count; i++) {
- pr_info("0x%02x ", card->rcv_buffer[i]);
- }
- #endif
- pr_debug("%s:%d\n", __func__, __LINE__);
- report_error:
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_to_user(&(((struct dsmart_card_atr __user *)arg)->errval), &card->errval,
- sizeof(card->errval));
- if (ret) {
- pr_err("ATR error value copy error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- card->rcv_count = 0;
- card->rcv_head = 0;
- card->errval = 0;
- break;
- case DSMART_CARD_IOCTL_XMT:
- /*ret = dsmart_card_xmt(card);*/
- xmt_size = 0;
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_from_user(&card->xmt_remainning_count, &(((struct dsmart_card_xmt __user *)arg)->xmt_length),
- sizeof(card->xmt_remainning_count));
- if (ret) {
- pr_err("get user xmt length error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- if (card->xmt_remainning_count > DSMART_CARD_XMT_BUFFER_SIZE) {
- pr_err("the data to send is too big\n");
- ret = -EINVAL;
- break;
- }
- ret = copy_from_user(&card->xmt_buffer[card->xmt_head], ((struct dsmart_card_xmt __user *)arg)->xmt_buffer, xmt_size);
- if (ret) {
- pr_err("get user buffer data error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- if (card->state != DSMART_CARD_STATE_XMTING) {
- dsmart_card_timing_counter_set(card);
- ret = dsmart_card_start_data_xmt(card, arg);
- if (ret) {
- pr_err("failed to xmt normal data\n");
- break;
- }
- }
- spin_lock_irqsave(&card->lock, flags);
- card->xmt_head += card->xmt_count;
- card->xmt_remainning_count -= card->xmt_count;
- card->xmt_count = 0;
- card->errval = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- //dsmart_card_start_data_rcv(card, 0);
- break;
- case DSMART_CARD_IOCTL_RCV:
- pr_debug("%s:%d\n", __func__, __LINE__);
- ret = copy_from_user(&card->expected_rcv_cnt, &(((struct dsmart_card_rcv __user *)arg)->rcv_length),
- sizeof(card->expected_rcv_cnt));
- if (ret) {
- pr_err("rcv data error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- if (card->expected_rcv_cnt)
- card->is_fixed_len = true;
- if ((card->rcv_count >= card->expected_rcv_cnt) && card->rcv_count)
- goto copy_data;
- if (card->state != DSMART_CARD_STATE_RECEIVING) {
- dsmart_card_timing_counter_set(card);
- ret = dsmart_card_start_data_rcv(card, arg);
- if (ret) {
- pr_err("failed to receive normal data\n");
- break;
- }
- msleep(5000);
- }
- pr_debug("%s:%d\n", __func__, __LINE__);
- copy_data:
- pr_debug("%s:%d\n", __func__, __LINE__);
- if (card->is_fixed_len)
- copy_cnt = card->rcv_count >= card->expected_rcv_cnt ? card->expected_rcv_cnt : card->rcv_count;
- else
- copy_cnt = card->rcv_count;
- ret = copy_to_user(&(((struct dsmart_card_rcv __user *)arg)->rcv_length), ©_cnt, sizeof(copy_cnt));
- if (ret) {
- pr_err("length copy error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- ret = copy_to_user(((struct dsmart_card_rcv __user *)arg)->rcv_buffer, &card->rcv_buffer[card->rcv_head], copy_cnt);
- if (ret) {
- pr_err("buffer copy error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- ret = copy_to_user(&(((struct dsmart_card_rcv __user *)arg)->errval), &card->errval, sizeof(card->errval));
- if (ret) {
- pr_err("error value copy error\n");
- ret = -DSMART_CARD_E_ACCESS;
- break;
- }
- pr_debug("%s:%d, copy_cnt = %d, rcv_head = %d, rcv_count = %d\n", __func__, __LINE__, copy_cnt, card->rcv_head, card->rcv_count);
- #ifdef CONFIG_ATR_DATA_PRINT
- for (i = 0; i < copy_cnt; i++) {
- pr_info("%s, %d, 0x%x ", __func__, __LINE__, card->rcv_buffer[card->rcv_head + i]);
- }
- #endif
- spin_lock_irqsave(&card->lock, flags);
- card->rcv_head += copy_cnt;
- card->rcv_count -= copy_cnt;
- card->errval = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- default:
- pr_err("invalid ioctol command\n");
- return -EINVAL;
- }
- pr_debug("%s:%d\n", __func__, __LINE__);
- return ret;
- }
- static const struct file_operations dsmart_card_fops = {
- .owner = THIS_MODULE,
- .open = dsmart_card_open,
- .release = dsmart_card_release,
- .unlocked_ioctl = dsmart_card_ioctl,
- };
- static struct miscdevice dsmart_card_dev = {
- MISC_DYNAMIC_MINOR,
- "dsmart_card",
- &dsmart_card_fops,
- };
- static int dsmart_card_probe(struct platform_device *pdev)
- {
- struct resource *res;
- struct dsmart_card *priv;
- int ret;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq < 0) {
- dev_err(&pdev->dev, "failed to get irq for dsmart card\n");
- return priv->irq;
- }
- /* optional clock, default open */
- priv->clk = devm_clk_get(&pdev->dev, "dsmart_card");
- if(IS_ERR(priv->clk))
- priv->clk = NULL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(priv->base))
- return PTR_ERR(priv->base);
- platform_set_drvdata(pdev, priv);
- dsmart_card_dev.parent = &(pdev->dev);
- card_event_interrupt_enable(priv->base, 0xff, false);
- init_completion(&priv->xfer_done);
- ret = devm_request_irq(&pdev->dev, priv->irq, dsmart_card_handler, 0,
- "dsmart_card", priv);
- if (ret) {
- dev_err(&pdev->dev, "failed to register a dsmart card IRQ handler(%d)\n", ret);
- return ret;
- }
- ret = misc_register(&dsmart_card_dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to register a misc device\n");
- return ret;
- }
- dev_info(&pdev->dev, "initialized iso7816 smart card driver\n");
- return 0;
- }
- static int dsmart_card_remove(struct platform_device *pdev)
- {
- misc_deregister(&dsmart_card_dev);
- return 0;
- }
- static const struct of_device_id dsmart_card_of_match[] = {
- {.compatible = "thead,light-iso7816-card"},
- {/* sentinel */},
- };
- MODULE_DEVICE_TABLE(of, dsmart_card_of_match);
- static struct platform_driver dsmart_card_driver = {
- .driver = {
- .name = "iso7816-card-drv",
- .owner = THIS_MODULE,
- .of_match_table = dsmart_card_of_match,
- },
- .probe = dsmart_card_probe,
- .remove = dsmart_card_remove,
- };
- module_platform_driver(dsmart_card_driver);
- MODULE_AUTHOR("wei.liu <lw32886@linux.alibaba.com>");
- MODULE_DESCRIPTION("iso7816 smart card platform driver");
- MODULE_LICENSE("GPL v2");
|