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"
560 theseven 29
#include "clockgates-target.h"
273 theseven 30
 
31
 
32
static struct mutex spimutex[3];
280 theseven 33
static struct wakeup spiwakeup[3];
273 theseven 34
 
35
 
36
void spi_prepare(int port)
37
{
38
    mutex_lock(&spimutex[port], TIMEOUT_BLOCK);
39
    clockgate_enable(SPICLKGATE(port), true);
40
    SPISTATUS(port) = 0xf;
41
    SPICTRL(port) |= 0xc;
42
    SPICLKDIV(port) = 4;
43
    SPIUNKREG1(port) = 6;
44
    SPISETUP(port) = 0x10618;
45
    SPICTRL(port) |= 0xc;
46
    SPICTRL(port) = 1;
47
}
48
 
49
void spi_release(int port)
50
{
51
    clockgate_enable(SPICLKGATE(port), false);
52
    mutex_unlock(&spimutex[port]);
53
}
54
 
55
uint32_t spi_write(int port, uint32_t data)
56
{
57
    SPIRXLIMIT(port) = 1;
58
    while ((SPISTATUS(port) & 0x1f0) == 0x100) yield();
59
    SPITXDATA(port) = data;
60
    while (!(SPISTATUS(port) & 0x3e00)) yield();
61
    return SPIRXDATA(port);
62
}
63
 
64
void spi_read(int port, uint32_t size, void* buf)
65
{
66
    uint8_t* buffer = (uint8_t*)buf;
67
    SPIRXLIMIT(port) = size;
280 theseven 68
    if (size < 0x100)
273 theseven 69
    {
280 theseven 70
        SPISETUP(port) |= 1;
71
        while (size--)
72
        {
73
            while (!(SPISTATUS(port) & 0x3e00)) yield();
74
            *buffer++ = SPIRXDATA(port);
75
        }
76
        SPISETUP(port) &= ~1;
77
        return;
273 theseven 78
    }
280 theseven 79
    SPISETUP(port) |= 0x41;
80
    void* addr = (void*)((uint32_t)buf + size);
81
    struct dma_lli* lli = (struct dma_lli*)(((uint32_t)addr - 0x10) & ~0xf);
82
    struct dma_lli* nextlli = NULL;
560 theseven 83
    clockgate_dma(0, port + 5, true);
280 theseven 84
    while (addr > buf)
85
    {
86
        size = (uint32_t)addr - (uint32_t)buf;
87
        if (size > 0xfff) size = 0xfff;
88
        else lli = (struct dma_lli*)((int)&DMAC0CLLI(port + 5));
89
        addr = (void*)((uint32_t)addr - size);
90
        lli->srcaddr = (void*)((int)&SPIRXDATA(port));
91
        lli->dstaddr = addr;
92
        lli->nextlli = nextlli;
93
        lli->control = 0x78000000 | size | (nextlli == NULL ? 0x80000000 : 0);
94
        nextlli = lli;
95
        lli = &lli[-1];
96
    }
636 theseven 97
    invalidate_dcache();
280 theseven 98
    DMAC0CCONFIG(port + 5) = 0x9001 | (SPIDMA(port) << 1);
99
    wakeup_wait(&spiwakeup[port], TIMEOUT_BLOCK);
560 theseven 100
    clockgate_dma(0, port + 5, false);
280 theseven 101
    SPISETUP(port) &= ~0x41;
273 theseven 102
}
103
 
280 theseven 104
void INT_DMAC0C5()
105
{
106
    DMAC0INTTCCLR = 1 << 5;
107
    wakeup_signal(&spiwakeup[0]);
108
}
109
 
110
void INT_DMAC0C6()
111
{
112
    DMAC0INTTCCLR = 1 << 6;
113
    wakeup_signal(&spiwakeup[1]);
114
}
115
 
116
void INT_DMAC0C7()
117
{
118
    DMAC0INTTCCLR = 1 << 7;
119
    wakeup_signal(&spiwakeup[2]);
120
}