Subversion Repositories freemyipod

Rev

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 "i2c.h"
26
#include "thread.h"
27
#include "s5l8702.h"
28
 
29
 
30
static struct mutex i2cmutex;
31
 
32
 
560 theseven 33
static void i2c_on(int bus)
34
{
35
    /* enable I2C clock */
36
    clockgate_enable(CLOCKGATE_I2C(bus), true);
37
 
38
    IICCON(bus) = (1 << 7) | /* ACK_GEN */
39
                  (0 << 6) | /* CLKSEL = PCLK/16 */
40
                  (1 << 5) | /* INT_EN */
41
                  (1 << 4) | /* IRQ clear */
42
                  (7 << 0);  /* CK_REG */
43
 
44
    /* serial output on */
45
    IICSTAT(bus) = (1 << 4);
46
}
47
 
48
static void i2c_off(int bus)
49
{
50
    /* serial output off */
51
    IICSTAT(bus) = 0;
52
 
53
    /* disable I2C clock */
54
    clockgate_enable(CLOCKGATE_I2C(bus), false);
55
}
56
 
273 theseven 57
void i2c_init()
58
{
59
    mutex_init(&i2cmutex);
60
}
61
 
62
void i2c_send(uint32_t bus, uint32_t device, uint32_t address, const uint8_t* data, uint32_t length)
63
{
64
    mutex_lock(&i2cmutex, TIMEOUT_BLOCK);
560 theseven 65
	i2c_on(bus);
386 theseven 66
    while (IIC10(bus));
273 theseven 67
    IICDS(bus) = device & ~1;
386 theseven 68
    while (IIC10(bus));
273 theseven 69
    IICSTAT(bus) = 0xF0;
386 theseven 70
    while (IIC10(bus));
273 theseven 71
    IICCON(bus) = 0xB7;
72
    while ((IICCON(bus) & 0x10) == 0) yield();
73
    if (address >= 0)
74
    {
75
        /* write address */
386 theseven 76
        while (IIC10(bus));
273 theseven 77
        IICDS(bus) = address;
386 theseven 78
        while (IIC10(bus));
273 theseven 79
        IICCON(bus) = 0xB7;
80
        while ((IICCON(bus) & 0x10) == 0) yield();
81
    }
82
    /* write data */
83
    while (length--)
84
    {
386 theseven 85
        while (IIC10(bus));
273 theseven 86
        IICDS(bus) = *data++;
386 theseven 87
        while (IIC10(bus));
273 theseven 88
        IICCON(bus) = 0xB7;
89
        while ((IICCON(bus) & 0x10) == 0) yield();
90
    }
91
    /* STOP */
386 theseven 92
    while (IIC10(bus));
273 theseven 93
    IICSTAT(bus) = 0xD0;
386 theseven 94
    while (IIC10(bus));
273 theseven 95
    IICCON(bus) = 0xB7;
96
    while ((IICSTAT(bus) & (1 << 5)) != 0) yield();
560 theseven 97
	i2c_off(bus);
273 theseven 98
    mutex_unlock(&i2cmutex);
99
}
100
 
101
void i2c_recv(uint32_t bus, uint32_t device, uint32_t address, uint8_t* data, uint32_t length)
102
{
103
    mutex_lock(&i2cmutex, TIMEOUT_BLOCK);
560 theseven 104
	i2c_on(bus);
273 theseven 105
    if (address >= 0)
106
    {
107
        /* START */
386 theseven 108
        while (IIC10(bus));
273 theseven 109
        IICDS(bus) = device & ~1;
386 theseven 110
        while (IIC10(bus));
273 theseven 111
        IICSTAT(bus) = 0xF0;
386 theseven 112
        while (IIC10(bus));
273 theseven 113
        IICCON(bus) = 0xB7;
114
        while ((IICCON(bus) & 0x10) == 0) yield();
115
        /* write address */
386 theseven 116
        while (IIC10(bus));
273 theseven 117
        IICDS(bus) = address;
386 theseven 118
        while (IIC10(bus));
273 theseven 119
        IICCON(bus) = 0xB7;
120
        while ((IICCON(bus) & 0x10) == 0) yield();
121
    }
122
    /* (repeated) START */
386 theseven 123
    while (IIC10(bus));
273 theseven 124
    IICDS(bus) = device | 1;
386 theseven 125
    while (IIC10(bus));
273 theseven 126
    IICSTAT(bus) = 0xB0;
386 theseven 127
    while (IIC10(bus));
273 theseven 128
    IICCON(bus) = 0xB7;
129
    while ((IICCON(bus) & 0x10) == 0) yield();
130
    while (length--)
131
    {
386 theseven 132
        while (IIC10(bus));
273 theseven 133
        IICCON(bus) = (length == 0) ? 0x37 : 0xB7; /* NACK or ACK */
134
        while ((IICCON(bus) & 0x10) == 0) yield();
135
        *data++ = IICDS(bus);
136
    }
137
    /* STOP */
386 theseven 138
    while (IIC10(bus));
273 theseven 139
    IICSTAT(bus) = 0x90;
386 theseven 140
    while (IIC10(bus));
273 theseven 141
    IICCON(bus) = 0xB7;
142
    while ((IICSTAT(bus) & (1 << 5)) != 0) yield();
560 theseven 143
	i2c_off(bus);
273 theseven 144
    mutex_unlock(&i2cmutex);
145
}
146
 
147
void i2c_sendbyte(uint32_t bus, uint32_t device, uint32_t address, uint32_t data)
148
{
149
    uint8_t buf[1];
150
    buf[0] = data;
151
    i2c_send(bus, device, address, buf, 1);
152
}
153
 
154
uint8_t i2c_recvbyte(uint32_t bus, uint32_t device, uint32_t address)
155
{
156
    uint8_t buf[1];
157
    i2c_recv(bus, device, address, buf, 1);
158
    return buf[0];
159
}