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
|
/* Philips CL RC632 driver (via SPI)
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
*
* */
#include "fifo.h"
#include "pio_irq.h"
static void spi_irq(void)
{
u_int32_t status = pSPI->SPI_SR;
if (status & (AT91C_SPI_OVRES|AT91C_SPI_MODF)) {
/* FIXME: print error message to debug port */
}
}
static u_int8_t spi_outbuf[64+1];
static u_int8_t spi_inbuf[64+1];
#define FIFO_ADDR (RC632_REG_FIFO_DATA << 1)
struct rc632 {
u_int16_t flags;
struct fifo fifo;
};
#define RC632_F_FIFO_TX 0x0001
/* RC632 access primitives */
void rc632_reg_write(u_int8_t addr, u_int8_t data)
{
addr = (addr << 1) & 0x7e;
}
void rc632_fifo_write(u_int8_t len, u_int8_t *data)
{
if (len > sizeof(spi_outbuf)-1)
len = sizeof(spi_outbuf)-1;
spi_outbuf[0] = FIFO_ADDR;
memcpy(spi_outbuf[1], data, len);
/* FIXME: transceive (len+1) */
return len;
}
u_int8_t rc632_reg_read(u_int8_t addr)
{
addr = (addr << 1) & 0x7e;
}
u_int8_t rc632_fifo_read(u_int8_t max_len, u_int8_t *data)
{
u_int8_t fifo_length = rc632_reg_read(RC632_REG_FIFO_LENGTH);
u_int8_t i;
if (max_len < fifo_length)
fifo_length = max_len;
for (i = 0; i < fifo_length; i++)
spi_outbuf[i] = FIFO_ADDR;
/* FIXME: transceive */
return fifo_length;
}
/* RC632 interrupt handling */
static void rc632_irq(void)
{
/* CL RC632 has interrupted us */
u_int8_t cause = rc632_reg_read(RC632_REG_INTERRUPT_RQ);
/* ACK all interrupts */
rc632_reg_write(RC632_REG_INTERRUPT_RQ, cause);
if (cause & RC632_INT_LOALERT) {
/* FIFO is getting low, refill from virtual FIFO */
if (!fifo_available(fifo))
break;
}
if (cause & RC632_INT_HIALERT) {
/* FIFO is getting full, empty into virtual FIFO */
}
if (cause & RCR632_INT_TIMER) {
/* Timer has expired, signal it to host */
}
}
void rc632_init(void)
{
AT91F_SPI_CfgPMC();
AT91F_SPI_CfgPIO(); /* check whether we really need all this */
AT91F_SPI_Enable();
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI, F,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &spi_irq);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI);
AT91F_SPI_EnableIt(pSPI, AT91C_SPI_MODF|AT91C_SPI_OVRES);
AT91F_SPI_CfgMode(AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED);
/* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10 (4.8MHz),
* DLYBS = 0, DLYBCT = 0 */
AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS8|AT91C_SPI_NCPHA|(10<<8));
AT91F_SPI_Reset();
/* Register rc632_irq */
pio_irq_register(OPENPCD_RC632_IRQ, &rc632_irq);
pio_irq_enable(OPENPCD_RC632_IRQ);
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_RC632_RESET);
};
void rc632_exit(void)
{
pio_irq_unregister(OPENPCD_RC632_IRQ);
AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SPI);
AT01F_SPI_Disable();
}
|