Root/tools/lib/atusd.c

Source at commit ebe667197a3c09a1f9b3005efcf7729c8b12da84 created 8 years 10 months ago.
By Werner Almesberger, dirtly made the atrf tools run with the new atusd board
1/*
2 * lib/atusd.c - ATRF access functions library (uSD version)
3 *
4 * Written 2010-2011 by Werner Almesberger
5 * Copyright 2010-2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <fcntl.h>
19#include <sys/mman.h>
20
21#include "at86rf230.h"
22#include "driver.h"
23
24
25enum {
26    VDD_OFF = 1 << 2, /* VDD disable, PD02 */
27    MOSI = 1 << 8, /* CMD, PD08 */
28#ifdef OLD
29    CLK = 1 << 9, /* CLK, PD09 */
30#else
31    SLP_TR = 1 << 9, /* CLK, PD09 */
32#endif
33    MISO = 1 << 10, /* DAT0, PD10 */
34    SCLK = 1 << 11, /* DAT1, PD11 */
35    IRQ = 1 << 12, /* DAT2, PD12 */
36    nSEL = 1 << 13, /* DAT3/CD, PD13 */
37};
38
39
40#define SOC_BASE 0x10000000
41
42#define REG(n) (*(volatile uint32_t *) (dsc->mem+(n)))
43
44#define CGU(n) REG(0x00000+(n))
45#define GPIO(n) REG(0x10000+(n))
46#define MSC(n) REG(0x21000+(n))
47
48#define PDPIN GPIO(0x300) /* port D pin level */
49#define PDDATS GPIO(0x314) /* port D data set */
50#define PDDATC GPIO(0x318) /* port D data clear */
51#define PDFUNS GPIO(0x344) /* port D function set */
52#define PDFUNC GPIO(0x348) /* port D function clear */
53#define PDDIRS GPIO(0x364) /* port D direction set */
54#define PDDIRC GPIO(0x368) /* port D direction clear */
55
56#define MSC_STRPCL MSC(0x00) /* Start/stop MMC/SD clock */
57#define MSC_CLKRT MSC(0x08) /* MSC Clock Rate */
58
59#define CLKGR CGU(0x0020) /* Clock Gate */
60#define MSCCDR CGU(0x0068) /* MSC device clock divider */
61
62
63#define PAGE_SIZE 4096
64
65
66struct atusd_dsc {
67    int fd;
68    void *mem;
69};
70
71
72/* ----- Reset functions --------------------------------------------------- */
73
74
75static void wait_for_power(void)
76{
77    /*
78     * Give power time to stabilize and the chip time to reset.
79     * Power takes about 2 ms to ramp up. We wait 10 ms to be sure.
80     */
81    usleep(10*1000);
82}
83
84
85static void atusd_cycle(struct atusd_dsc *dsc)
86{
87    /* stop the MMC bus clock */
88    MSC_STRPCL = 1;
89
90    /* drive all outputs low (including the MMC bus clock) */
91#ifdef OLD
92    PDDATC = MOSI | CLK | SCLK | nSEL;
93
94    /* make the MMC bus clock a regular output */
95    PDFUNC = CLK;
96#else
97    PDDATC = MOSI | SLP_TR | SCLK | nSEL;
98    PDFUNC = SLP_TR;
99#endif
100
101    /* cut the power */
102    PDDATS = VDD_OFF;
103
104    /* Power drains within about 20 ms. Wait 100 ms to be sure. */
105    usleep(100*1000);
106
107    /* drive MOSI and nSS high */
108    PDDATS = MOSI | nSEL;
109
110    /* precharge the capacitors to avoid current surge */
111    wait_for_power();
112
113#ifdef OLD
114
115    /* return the bus clock output to the MMC controller */
116    PDFUNS = CLK;
117
118    /* start MMC clock output */
119    MSC_STRPCL = 2;
120#endif
121
122    /* supply power */
123    PDDATC = VDD_OFF;
124
125    wait_for_power();
126}
127
128
129/* ----- Low-level SPI operations ------------------------------------------ */
130
131
132static void spi_begin(struct atusd_dsc *dsc)
133{
134    PDDATC = nSEL;
135}
136
137
138static void spi_end(struct atusd_dsc *dsc)
139{
140    PDDATS = nSEL;
141}
142
143
144static void spi_send(struct atusd_dsc *dsc, uint8_t v)
145{
146    uint8_t mask;
147
148    for (mask = 0x80; mask; mask >>= 1) {
149        if (v & mask)
150            PDDATS = MOSI;
151        else
152            PDDATC = MOSI;
153        PDDATS = SCLK;
154        PDDATC = SCLK;
155    }
156}
157
158
159static uint8_t spi_recv(struct atusd_dsc *dsc)
160{
161    uint8_t res = 0;
162        uint8_t mask;
163
164    for (mask = 0x80; mask; mask >>= 1) {
165        if (PDPIN & MISO)
166            res |= mask;
167        PDDATS = SCLK;
168        PDDATC = SCLK;
169    }
170        return res;
171}
172
173
174/* ----- Driver operations ------------------------------------------------- */
175
176
177static void atusd_reset_rf(void *handle)
178{
179    struct atusd_dsc *dsc = handle;
180
181    atusd_cycle(dsc);
182    wait_for_power();
183}
184
185
186static void *atusd_open(void)
187{
188    struct atusd_dsc *dsc;
189
190    dsc = malloc(sizeof(*dsc));
191    if (!dsc) {
192        perror("malloc");
193        exit(1);
194    }
195
196    dsc->fd = open("/dev/mem", O_RDWR | O_SYNC);
197    if (dsc->fd < 0) {
198        perror("/dev/mem");
199        exit(1);
200    }
201    dsc->mem = mmap(NULL, PAGE_SIZE*3*16, PROT_READ | PROT_WRITE,
202        MAP_SHARED, dsc->fd, SOC_BASE);
203        if (dsc->mem == MAP_FAILED) {
204                perror("mmap");
205                exit(1);
206        }
207
208    /* set the output levels */
209    PDDATS = nSEL | VDD_OFF;
210    PDDATC = SCLK;
211
212    /* take the GPIOs away from the MMC controller */
213#ifdef OLD
214    PDFUNC = MOSI | MISO | SCLK | IRQ | nSEL;
215    PDFUNS = CLK;
216#else
217    PDFUNC = MOSI | MISO | SCLK | IRQ | nSEL | SLP_TR;
218#endif
219
220    /* set the pin directions */
221    PDDIRC = MISO | IRQ;
222#ifdef OLD
223    PDDIRS = MOSI | CLK | SCLK | nSEL;
224#else
225    PDDIRS = MOSI | SLP_TR | SCLK | nSEL;
226#endif
227
228    /* let capacitors precharge */
229    wait_for_power();
230
231    /* enable power */
232    PDDATC = VDD_OFF;
233
234#ifdef OLD
235    /* set the MSC clock to 316 MHz / 21 = 16 MHz */
236    MSCCDR = 20;
237    /*
238     * Enable the MSC clock. We need to do this before accessing any
239     * registers of the MSC block !
240     */
241    CLKGR &= ~(1 << 7);
242    /* bus clock = MSC clock / 1 */
243    MSC_CLKRT = 0;
244    /* start MMC clock output */
245    MSC_STRPCL = 2;
246#endif
247
248    wait_for_power();
249    atusd_reset_rf(dsc);
250
251    return dsc;
252}
253
254
255static void atusd_close(void *arg)
256{
257    struct atusd_dsc *dsc = arg;
258
259    /* stop the MMC bus clock */
260    MSC_STRPCL = 1;
261
262    /* cut the power */
263    PDDATS = VDD_OFF;
264
265    /* make all MMC pins inputs */
266#ifdef OLD
267    PDDIRC = MOSI | MISO | CLK | SCLK | IRQ | nSEL;
268#else
269    PDDIRC = MOSI | MISO | SLP_TR | SCLK | IRQ | nSEL;
270#endif
271}
272
273
274static void atusd_reg_write(void *handle, uint8_t reg, uint8_t v)
275{
276    struct atusd_dsc *dsc = handle;
277
278    spi_begin(dsc);
279    spi_send(dsc, AT86RF230_REG_WRITE | reg);
280    spi_send(dsc, v);
281    spi_end(dsc);
282}
283
284
285static uint8_t atusd_reg_read(void *handle, uint8_t reg)
286{
287    struct atusd_dsc *dsc = handle;
288    uint8_t res;
289
290    spi_begin(dsc);
291    spi_send(dsc, AT86RF230_REG_READ | reg);
292    res = spi_recv(dsc);
293    spi_end(dsc);
294    return res;
295}
296
297
298static void atusd_buf_write(void *handle, const void *buf, int size)
299{
300    struct atusd_dsc *dsc = handle;
301
302    spi_begin(dsc);
303    spi_send(dsc, AT86RF230_BUF_WRITE);
304    spi_send(dsc, size);
305    while (size--)
306        spi_send(dsc, *(uint8_t *) buf++);
307    spi_end(dsc);
308}
309
310
311static int atusd_buf_read(void *handle, void *buf, int size)
312{
313    struct atusd_dsc *dsc = handle;
314    uint8_t len, i;
315
316    spi_begin(dsc);
317    spi_send(dsc, AT86RF230_BUF_READ);
318    len = spi_recv(dsc);
319    len++; /* LQI */
320    if (len > size)
321        len = size;
322    for (i = 0; i != len; i++)
323        *(uint8_t *) buf++ = spi_recv(dsc);
324    spi_end(dsc);
325    return len;
326}
327
328
329/* ----- RF interrupt ------------------------------------------------------ */
330
331
332static int atusd_interrupt(void *handle)
333{
334        struct atusd_dsc *dsc = handle;
335
336    return !!(PDPIN & IRQ);
337}
338
339
340/* ----- Driver interface -------------------------------------------------- */
341
342
343struct atrf_driver atusd_driver = {
344    .name = "uSD",
345    .open = atusd_open,
346    .close = atusd_close,
347    .reset = NULL,
348    .reset_rf = atusd_reset_rf,
349    .test_mode = NULL,
350    .reg_write = atusd_reg_write,
351    .reg_read = atusd_reg_read,
352    .buf_write = atusd_buf_write,
353    .buf_read = atusd_buf_read,
354    .interrupt = atusd_interrupt,
355};
356

Archive Download this file



interactive