blob: fe4114e34df9e8a08d86185f52f54c4a98d2f6e0 [file] [log] [blame]
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "lcd.h"
Jean-Philippe Bernardy33114ca2005-01-24 14:40:10 +000020#include "cpu.h"
Linus Nielsen Feltzing250c3b62002-05-16 21:20:52 +000021#include "kernel.h"
Björn Stenbergc4d8d972003-02-14 09:44:34 +000022#include "thread.h"
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000023#include "debug.h"
Jörg Hohensohn75bab492003-11-06 01:34:50 +000024#include "system.h"
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000025
Jörg Hohensohn75bab492003-11-06 01:34:50 +000026/* cute little functions, atomic read-modify-write */
Jean-Philippe Bernardy33114ca2005-01-24 14:40:10 +000027
Jörg Hohensohn6c1afd72004-09-10 07:24:00 +000028/* SDA is PB7 */
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +000029#define SDA_LO and_b(~0x80, &PBDRL)
30#define SDA_HI or_b(0x80, &PBDRL)
31#define SDA_INPUT and_b(~0x80, &PBIORL)
32#define SDA_OUTPUT or_b(0x80, &PBIORL)
Jens Arnoldc42a1a02005-05-07 22:29:35 +000033#define SDA (PBDRL & 0x80)
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000034
Daniel Stenberg918918e2005-01-27 12:16:45 +000035#if CONFIG_I2C == I2C_ONDIO
Jörg Hohensohn6c1afd72004-09-10 07:24:00 +000036/* Ondio pinout, SCL moved to PB6 */
37#define SCL_INPUT and_b(~0x40, &PBIORL)
38#define SCL_OUTPUT or_b(0x40, &PBIORL)
39#define SCL_LO and_b(~0x40, &PBDRL)
40#define SCL_HI or_b(0x40, &PBDRL)
Jens Arnoldc42a1a02005-05-07 22:29:35 +000041#define SCL (PBDRL & 0x40)
Jörg Hohensohn6c1afd72004-09-10 07:24:00 +000042#else
43/* "classic" pinout, SCL is PB13 */
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +000044#define SCL_INPUT and_b(~0x20, &PBIORH)
45#define SCL_OUTPUT or_b(0x20, &PBIORH)
46#define SCL_LO and_b(~0x20, &PBDRH)
47#define SCL_HI or_b(0x20, &PBDRH)
Jens Arnoldc42a1a02005-05-07 22:29:35 +000048#define SCL (PBDRH & 0x20)
Jörg Hohensohn6c1afd72004-09-10 07:24:00 +000049#endif
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000050
51/* arbitrary delay loop */
52#define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0)
53
Linus Nielsen Feltzingb922a962002-06-24 10:34:24 +000054static struct mutex i2c_mtx;
55
56void i2c_begin(void)
57{
58 mutex_lock(&i2c_mtx);
59}
60
61void i2c_end(void)
62{
63 mutex_unlock(&i2c_mtx);
64}
65
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000066void i2c_start(void)
67{
68 SDA_OUTPUT;
69 SDA_HI;
70 SCL_HI;
71 SDA_LO;
72 DELAY;
73 SCL_LO;
74}
75
76void i2c_stop(void)
77{
78 SDA_LO;
79 SCL_HI;
80 DELAY;
81 SDA_HI;
82}
83
84void i2c_init(void)
85{
86 int i;
87
Jens Arnold780f79e2006-11-10 20:26:01 +000088#if CONFIG_I2C == I2C_ONDIO
Jens Arnoldc42a1a02005-05-07 22:29:35 +000089 /* make PB6 & PB7 general I/O */
90 PBCR2 &= ~0xf000;
Jens Arnold780f79e2006-11-10 20:26:01 +000091#else /* not Ondio */
Jens Arnoldc42a1a02005-05-07 22:29:35 +000092 /* make PB7 & PB13 general I/O */
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000093 PBCR1 &= ~0x0c00; /* PB13 */
Jens Arnoldc42a1a02005-05-07 22:29:35 +000094 PBCR2 &= ~0xc000; /* PB7 */
Jörg Hohensohn6c1afd72004-09-10 07:24:00 +000095#endif
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000096
Jörg Hohensohn6c1afd72004-09-10 07:24:00 +000097 SCL_OUTPUT;
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +000098 SDA_OUTPUT;
99 SDA_HI;
100 SCL_LO;
101 for (i=0;i<3;i++)
102 i2c_stop();
103}
104
105void i2c_ack(int bit)
106{
107 /* Here's the deal. The MAS is slow, and sometimes needs to wait
108 before it can receive the acknowledge. Therefore it forces the clock
109 low until it is ready. We need to poll the clock line until it goes
110 high before we release the ack. */
111
112 SCL_LO; /* Set the clock low */
113 if ( bit )
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000114 {
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000115 SDA_HI;
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000116 }
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000117 else
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000118 {
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000119 SDA_LO;
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000120 }
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000121
122 SCL_INPUT; /* Set the clock to input */
Linus Nielsen Feltzing250c3b62002-05-16 21:20:52 +0000123 while(!SCL) /* and wait for the MAS to release it */
Michael Sevakised8445f2008-03-20 15:20:06 +0000124 sleep(1);
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000125
126 DELAY;
127 SCL_OUTPUT;
128 SCL_LO;
129}
130
131int i2c_getack(void)
132{
Linus Nielsen Feltzing95a323c2002-05-28 15:07:45 +0000133 int ret = 1;
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000134
135 /* Here's the deal. The MAS is slow, and sometimes needs to wait
136 before it can send the acknowledge. Therefore it forces the clock
137 low until it is ready. We need to poll the clock line until it goes
138 high before we read the ack. */
Linus Nielsen Feltzing9d937e92002-06-19 12:00:37 +0000139
Daniel Stenbergaaa84432003-01-21 19:37:29 +0000140#ifdef HAVE_I2C_LOW_FIRST
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000141 SDA_LO; /* First, discharge the data line */
Linus Nielsen Feltzing9d937e92002-06-19 12:00:37 +0000142#endif
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000143 SDA_INPUT; /* And set to input */
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000144 SCL_INPUT; /* Set the clock to input */
Linus Nielsen Feltzing250c3b62002-05-16 21:20:52 +0000145 while(!SCL) /* and wait for the MAS to release it */
Michael Sevakised8445f2008-03-20 15:20:06 +0000146 sleep(1);
Linus Nielsen Feltzing250c3b62002-05-16 21:20:52 +0000147
Linus Nielsen Feltzing95a323c2002-05-28 15:07:45 +0000148 if (SDA)
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000149 /* ack failed */
Linus Nielsen Feltzing95a323c2002-05-28 15:07:45 +0000150 ret = 0;
151
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000152 SCL_OUTPUT;
153 SCL_LO;
154 SDA_HI;
155 SDA_OUTPUT;
Linus Nielsen Feltzing95a323c2002-05-28 15:07:45 +0000156 return ret;
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000157}
158
159void i2c_outb(unsigned char byte)
160{
161 int i;
162
163 /* clock out each bit, MSB first */
164 for ( i=0x80; i; i>>=1 ) {
165 if ( i & byte )
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000166 {
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000167 SDA_HI;
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000168 }
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000169 else
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000170 {
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000171 SDA_LO;
Jörg Hohensohn75bab492003-11-06 01:34:50 +0000172 }
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000173 SCL_HI;
174 SCL_LO;
175 }
176
177 SDA_HI;
178}
179
180unsigned char i2c_inb(int ack)
181{
182 int i;
183 unsigned char byte = 0;
184
185 /* clock in each bit, MSB first */
186 for ( i=0x80; i; i>>=1 ) {
Daniel Stenbergaaa84432003-01-21 19:37:29 +0000187#ifdef HAVE_I2C_LOW_FIRST
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000188 /* Tricky business. Here we discharge the data line by driving it low
189 and then set it to input to see if it stays low or goes high */
190 SDA_LO; /* First, discharge the data line */
Linus Nielsen Feltzing9d937e92002-06-19 12:00:37 +0000191#endif
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000192 SDA_INPUT; /* And set to input */
193 SCL_HI;
194 if ( SDA )
195 byte |= i;
196 SCL_LO;
197 SDA_OUTPUT;
198 }
199
200 i2c_ack(ack);
201
202 return byte;
203}
204
Jens Arnold0ceaa5e2004-08-17 01:45:48 +0000205int i2c_write(int address, const unsigned char* buf, int count )
Linus Nielsen Feltzingd057c072002-04-20 23:01:30 +0000206{
207 int i,x=0;
208
209 i2c_start();
210 i2c_outb(address & 0xfe);
211 if (i2c_getack())
212 {
213 for (i=0; i<count; i++)
214 {
215 i2c_outb(buf[i]);
216 if (!i2c_getack())
217 {
218 x=-2;
219 break;
220 }
221 }
222 }
223 else
224 {
225 debugf("i2c_write() - no ack\n");
226 x=-1;
227 }
228 i2c_stop();
229 return x;
230}
231
232int i2c_read(int address, unsigned char* buf, int count )
233{
234 int i,x=0;
235
236 i2c_start();
237 i2c_outb(address | 1);
238 if (i2c_getack()) {
239 for (i=0; i<count; i++) {
240 buf[i] = i2c_inb(0);
241 }
242 }
243 else
244 x=-1;
245 i2c_stop();
246 return x;
247}