Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
273 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
427 farthen 6
//    This file is part of emCORE.
273 theseven 7
//
427 farthen 8
//    emCORE is free software: you can redistribute it and/or
273 theseven 9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
427 farthen 13
//    emCORE is distributed in the hope that it will be useful,
273 theseven 14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
427 farthen 19
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
273 theseven 20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "spi.h"
26
#include "s5l8702.h"
27
#include "thread.h"
28
#include "clockgates.h"
29
 
30
 
31
static struct mutex spimutex[3];
280 theseven 32
static struct wakeup spiwakeup[3];
273 theseven 33
 
34
 
35
void spi_prepare(int port)
36
{
37
    mutex_lock(&spimutex[port], TIMEOUT_BLOCK);
38
    clockgate_enable(SPICLKGATE(port), true);
39
    SPISTATUS(port) = 0xf;
40
    SPICTRL(port) |= 0xc;
41
    SPICLKDIV(port) = 4;
42
    SPIUNKREG1(port) = 6;
43
    SPISETUP(port) = 0x10618;
44
    SPICTRL(port) |= 0xc;
45
    SPICTRL(port) = 1;
46
}
47
 
48
void spi_release(int port)
49
{
50
    clockgate_enable(SPICLKGATE(port), false);
51
    mutex_unlock(&spimutex[port]);
52
}
53
 
54
uint32_t spi_write(int port, uint32_t data)
55
{
56
    SPIRXLIMIT(port) = 1;
57
    while ((SPISTATUS(port) & 0x1f0) == 0x100) yield();
58
    SPITXDATA(port) = data;
59
    while (!(SPISTATUS(port) & 0x3e00)) yield();
60
    return SPIRXDATA(port);
61
}
62
 
63
void spi_read(int port, uint32_t size, void* buf)
64
{
65
    uint8_t* buffer = (uint8_t*)buf;
66
    SPIRXLIMIT(port) = size;
280 theseven 67
    if (size < 0x100)
273 theseven 68
    {
280 theseven 69
        SPISETUP(port) |= 1;
70
        while (size--)
71
        {
72
            while (!(SPISTATUS(port) & 0x3e00)) yield();
73
            *buffer++ = SPIRXDATA(port);
74
        }
75
        SPISETUP(port) &= ~1;
76
        return;
273 theseven 77
    }
280 theseven 78
    SPISETUP(port) |= 0x41;
79
    void* addr = (void*)((uint32_t)buf + size);
80
    struct dma_lli* lli = (struct dma_lli*)(((uint32_t)addr - 0x10) & ~0xf);
81
    struct dma_lli* nextlli = NULL;
82
    while (addr > buf)
83
    {
84
        size = (uint32_t)addr - (uint32_t)buf;
85
        if (size > 0xfff) size = 0xfff;
86
        else lli = (struct dma_lli*)((int)&DMAC0CLLI(port + 5));
87
        addr = (void*)((uint32_t)addr - size);
88
        lli->srcaddr = (void*)((int)&SPIRXDATA(port));
89
        lli->dstaddr = addr;
90
        lli->nextlli = nextlli;
91
        lli->control = 0x78000000 | size | (nextlli == NULL ? 0x80000000 : 0);
92
        nextlli = lli;
93
        lli = &lli[-1];
94
    }
95
    clean_dcache();
96
    DMAC0CCONFIG(port + 5) = 0x9001 | (SPIDMA(port) << 1);
97
    wakeup_wait(&spiwakeup[port], TIMEOUT_BLOCK);
384 theseven 98
    invalidate_dcache();
280 theseven 99
    SPISETUP(port) &= ~0x41;
273 theseven 100
}
101
 
280 theseven 102
void INT_DMAC0C5()
103
{
104
    DMAC0INTTCCLR = 1 << 5;
105
    wakeup_signal(&spiwakeup[0]);
106
}
107
 
108
void INT_DMAC0C6()
109
{
110
    DMAC0INTTCCLR = 1 << 6;
111
    wakeup_signal(&spiwakeup[1]);
112
}
113
 
114
void INT_DMAC0C7()
115
{
116
    DMAC0INTTCCLR = 1 << 7;
117
    wakeup_signal(&spiwakeup[2]);
118
}