1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include <stdint.h>
#include <memory.h>
#include <errno.h>
#include "cc32_irq.h"
enum iso_slave_reg {
ISOCON = 0x00,
ISOCON1 = 0x04,
ISOCON2 = 0x08,
ISOSTS = 0x0c,
ISOBRC = 0x10,
ISOBUF = 0x14,
ISODIO = 0x18,
ISOMSK = 0x1c,
ISODMACON = 0x30,
ISODMASTS = 0x34,
ISODMABFAD = 0x38,
ISODMABFLEN = 0x3c,
ISODMABFPT = 0x40,
ISODMAMSK = 0x44,
ISOTCON = 0x50,
ISOTDAT = 0x54,
ISOTRLD = 0x58,
ISOTMSK = 0x5c,
ISONULL = 0x60,
};
#define CC32_BASE_UART 0x0F8800
#define UART_REG(n) (CC32_BASE_UART+(n))
#define ISOCON_TR (1 << 5)
#define ISOCON_TACT (1 << 4)
#define ISOSTS_TBE (1 << 0)
#define ISOSTS_RBF (1 << 1)
#define ISOSTS_PE (1 << 2)
#define ISOSTS_OE (1 << 3)
#define ISOCON2_SBIT (1 << 7)
#define ISOBRC_DI(x) ((x) & 0xf)
#define ISOBRC_FI(x) (((x) & 0xf) << 4)
struct iso_slave_state {
uint8_t fi;
uint8_t di;
};
static struct iso_slave_state iss;
/* will be called from FIQ mode */
static void slave_irq(uint8_t irq)
{
//FIXME
}
int iso7816_slave_fi_di(uint8_t fi, uint8_t di)
{
writel(ISOBRC_DI(di) | ISOBRC_FI(fi), UART_REG(ISOBRC));
iss.fi = fi;
iss.di = di;
return 0;
}
int iso7816_slave_tx_ch(uint8_t ch)
{
writel(ISOCON_TR, UART_REG(ISOCON));
writel(ch, UART_REG(ISOBUF));
if (readl(UART_REG(ISOSTS)) & ISOSTS_PE) {
writel(ISOSTS_PE, UART_REG(ISOSTS));
return -EIO;
}
while (readl(UART_REG(ISOCON)) & ISOCON_TACT) { }
return 0;
}
int iso7816_slave_tx5(const uint8_t *data)
{
iso7816_slave_tx_ch(data[0]);
iso7816_slave_tx_ch(data[1]);
iso7816_slave_tx_ch(data[2]);
iso7816_slave_tx_ch(data[3]);
iso7816_slave_tx_ch(data[4]);
return 0;
}
int iso7816_slave_tx(const uint8_t *data, uint8_t len)
{
int i;
/* FIXME: fiq/dma ? */
writel(ISOCON_TR, UART_REG(ISOCON));
for (i = 0; i < len; i++) {
if (iso7816_slave_tx_ch(data[i]) < 0)
return -EIO;
}
return i;
}
int iso7816_slave_init(void)
{
/* receive mode */
writel(0, UART_REG(ISOCON));
/* up to 6 times re-transmission */
writel(6 | ISOCON2_SBIT, UART_REG(ISOCON1));
/* T=0 mode */
writel(0, UART_REG(ISOCON2));
/* clear status bits, if any */
writel(ISOSTS_PE|ISOSTS_OE, UART_REG(ISOSTS));
/* disable SBIT interrupt */
writel(ISOCON2_SBIT, UART_REG(ISOMSK));
/* Initial Fi/Di setting */
iso7816_slave_fi_di(1, 1);
cc32_irq_register(IRQ_UART, &slave_irq);
//cc32_irq_enable(IRQ_UART);
return 0;
}
|