summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8702/i2c-s5l8702.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s5l8702/i2c-s5l8702.c')
-rw-r--r--firmware/target/arm/s5l8702/i2c-s5l8702.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/firmware/target/arm/s5l8702/i2c-s5l8702.c b/firmware/target/arm/s5l8702/i2c-s5l8702.c
new file mode 100644
index 0000000000..be286b34b7
--- /dev/null
+++ b/firmware/target/arm/s5l8702/i2c-s5l8702.c
@@ -0,0 +1,186 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: i2c-s5l8700.c 28589 2010-11-14 15:19:30Z theseven $
9 *
10 * Copyright (C) 2009 by Bertrik Sikken
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "system.h"
24#include "kernel.h"
25#include "i2c-s5l8702.h"
26
27/* Driver for the s5l8700 built-in I2C controller in master mode
28
29 Both the i2c_read and i2c_write function take the following arguments:
30 * slave, the address of the i2c slave device to read from / write to
31 * address, optional sub-address in the i2c slave (unused if -1)
32 * len, number of bytes to be transfered
33 * data, pointer to data to be transfered
34 A return value < 0 indicates an error.
35
36 Note:
37 * blocks the calling thread for the entire duraton of the i2c transfer but
38 uses wakeup_wait/wakeup_signal to allow other threads to run.
39 * ACK from slave is not checked, so functions never return an error
40*/
41
42static struct mutex i2c_mtx[2];
43
44void i2c_init(void)
45{
46 mutex_init(&i2c_mtx[0]);
47 mutex_init(&i2c_mtx[1]);
48
49 /* initial config */
50 IICADD(0) = 0;
51 IICADD(1) = 0;
52 IICCON(0) = (1 << 7) | /* ACK_GEN */
53 (0 << 6) | /* CLKSEL = PCLK/16 */
54 (1 << 5) | /* INT_EN */
55 (1 << 4) | /* IRQ clear */
56 (3 << 0); /* CK_REG */
57 IICCON(1) = (1 << 7) | /* ACK_GEN */
58 (0 << 6) | /* CLKSEL = PCLK/16 */
59 (1 << 5) | /* INT_EN */
60 (1 << 4) | /* IRQ clear */
61 (3 << 0); /* CK_REG */
62
63 /* serial output on */
64 IICSTAT(0) = (1 << 4);
65 IICSTAT(1) = (1 << 4);
66}
67
68int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data)
69{
70 mutex_lock(&i2c_mtx[bus]);
71 long timeout = current_tick + HZ / 50;
72
73 /* START */
74 IICDS(bus) = slave & ~1;
75 IICSTAT(bus) = 0xF0;
76 IICCON(bus) = 0xB3;
77 while ((IICCON(bus) & 0x10) == 0)
78 if (TIME_AFTER(current_tick, timeout))
79 {
80 mutex_unlock(&i2c_mtx[bus]);
81 return 1;
82 }
83
84
85 if (address >= 0) {
86 /* write address */
87 IICDS(bus) = address;
88 IICCON(bus) = 0xB3;
89 while ((IICCON(bus) & 0x10) == 0)
90 if (TIME_AFTER(current_tick, timeout))
91 {
92 mutex_unlock(&i2c_mtx[bus]);
93 return 2;
94 }
95 }
96
97 /* write data */
98 while (len--) {
99 IICDS(bus) = *data++;
100 IICCON(bus) = 0xB3;
101 while ((IICCON(bus) & 0x10) == 0)
102 if (TIME_AFTER(current_tick, timeout))
103 {
104 mutex_unlock(&i2c_mtx[bus]);
105 return 4;
106 }
107 }
108
109 /* STOP */
110 IICSTAT(bus) = 0xD0;
111 IICCON(bus) = 0xB3;
112 while ((IICSTAT(bus) & (1 << 5)) != 0)
113 if (TIME_AFTER(current_tick, timeout))
114 {
115 mutex_unlock(&i2c_mtx[bus]);
116 return 5;
117 }
118
119 mutex_unlock(&i2c_mtx[bus]);
120 return 0;
121}
122
123int i2c_read(int bus, unsigned char slave, int address, int len, unsigned char *data)
124{
125 mutex_lock(&i2c_mtx[bus]);
126 long timeout = current_tick + HZ / 50;
127
128 if (address >= 0) {
129 /* START */
130 IICDS(bus) = slave & ~1;
131 IICSTAT(bus) = 0xF0;
132 IICCON(bus) = 0xB3;
133 while ((IICCON(bus) & 0x10) == 0)
134 if (TIME_AFTER(current_tick, timeout))
135 {
136 mutex_unlock(&i2c_mtx[bus]);
137 return 1;
138 }
139
140 /* write address */
141 IICDS(bus) = address;
142 IICCON(bus) = 0xB3;
143 while ((IICCON(bus) & 0x10) == 0)
144 if (TIME_AFTER(current_tick, timeout))
145 {
146 mutex_unlock(&i2c_mtx[bus]);
147 return 2;
148 }
149 }
150
151 /* (repeated) START */
152 IICDS(bus) = slave | 1;
153 IICSTAT(bus) = 0xB0;
154 IICCON(bus) = 0xB3;
155 while ((IICCON(bus) & 0x10) == 0)
156 if (TIME_AFTER(current_tick, timeout))
157 {
158 mutex_unlock(&i2c_mtx[bus]);
159 return 3;
160 }
161
162 while (len--) {
163 IICCON(bus) = (len == 0) ? 0x33 : 0xB3; /* NAK or ACK */
164 while ((IICCON(bus) & 0x10) == 0)
165 if (TIME_AFTER(current_tick, timeout))
166 {
167 mutex_unlock(&i2c_mtx[bus]);
168 return 4;
169 }
170 *data++ = IICDS(bus);
171 }
172
173 /* STOP */
174 IICSTAT(bus) = 0x90;
175 IICCON(bus) = 0xB3;
176 while ((IICSTAT(bus) & (1 << 5)) != 0)
177 if (TIME_AFTER(current_tick, timeout))
178 {
179 mutex_unlock(&i2c_mtx[bus]);
180 return 5;
181 }
182
183 mutex_unlock(&i2c_mtx[bus]);
184 return 0;
185}
186