Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 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 Bernardy | 33114ca | 2005-01-24 14:40:10 +0000 | [diff] [blame] | 20 | #include "cpu.h" |
Linus Nielsen Feltzing | 250c3b6 | 2002-05-16 21:20:52 +0000 | [diff] [blame] | 21 | #include "kernel.h" |
Björn Stenberg | c4d8d97 | 2003-02-14 09:44:34 +0000 | [diff] [blame] | 22 | #include "thread.h" |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 23 | #include "debug.h" |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 24 | #include "system.h" |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 25 | |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 26 | /* cute little functions, atomic read-modify-write */ |
Jean-Philippe Bernardy | 33114ca | 2005-01-24 14:40:10 +0000 | [diff] [blame] | 27 | |
Jörg Hohensohn | 6c1afd7 | 2004-09-10 07:24:00 +0000 | [diff] [blame] | 28 | /* SDA is PB7 */ |
Linus Nielsen Feltzing | bef7ab0 | 2003-11-07 12:15:24 +0000 | [diff] [blame] | 29 | #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 Arnold | c42a1a0 | 2005-05-07 22:29:35 +0000 | [diff] [blame] | 33 | #define SDA (PBDRL & 0x80) |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 34 | |
Daniel Stenberg | 918918e | 2005-01-27 12:16:45 +0000 | [diff] [blame] | 35 | #if CONFIG_I2C == I2C_ONDIO |
Jörg Hohensohn | 6c1afd7 | 2004-09-10 07:24:00 +0000 | [diff] [blame] | 36 | /* 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 Arnold | c42a1a0 | 2005-05-07 22:29:35 +0000 | [diff] [blame] | 41 | #define SCL (PBDRL & 0x40) |
Jörg Hohensohn | 6c1afd7 | 2004-09-10 07:24:00 +0000 | [diff] [blame] | 42 | #else |
| 43 | /* "classic" pinout, SCL is PB13 */ |
Linus Nielsen Feltzing | bef7ab0 | 2003-11-07 12:15:24 +0000 | [diff] [blame] | 44 | #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 Arnold | c42a1a0 | 2005-05-07 22:29:35 +0000 | [diff] [blame] | 48 | #define SCL (PBDRH & 0x20) |
Jörg Hohensohn | 6c1afd7 | 2004-09-10 07:24:00 +0000 | [diff] [blame] | 49 | #endif |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 50 | |
| 51 | /* arbitrary delay loop */ |
| 52 | #define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0) |
| 53 | |
Linus Nielsen Feltzing | b922a96 | 2002-06-24 10:34:24 +0000 | [diff] [blame] | 54 | static struct mutex i2c_mtx; |
| 55 | |
| 56 | void i2c_begin(void) |
| 57 | { |
| 58 | mutex_lock(&i2c_mtx); |
| 59 | } |
| 60 | |
| 61 | void i2c_end(void) |
| 62 | { |
| 63 | mutex_unlock(&i2c_mtx); |
| 64 | } |
| 65 | |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 66 | void i2c_start(void) |
| 67 | { |
| 68 | SDA_OUTPUT; |
| 69 | SDA_HI; |
| 70 | SCL_HI; |
| 71 | SDA_LO; |
| 72 | DELAY; |
| 73 | SCL_LO; |
| 74 | } |
| 75 | |
| 76 | void i2c_stop(void) |
| 77 | { |
| 78 | SDA_LO; |
| 79 | SCL_HI; |
| 80 | DELAY; |
| 81 | SDA_HI; |
| 82 | } |
| 83 | |
| 84 | void i2c_init(void) |
| 85 | { |
| 86 | int i; |
| 87 | |
Jens Arnold | 780f79e | 2006-11-10 20:26:01 +0000 | [diff] [blame] | 88 | #if CONFIG_I2C == I2C_ONDIO |
Jens Arnold | c42a1a0 | 2005-05-07 22:29:35 +0000 | [diff] [blame] | 89 | /* make PB6 & PB7 general I/O */ |
| 90 | PBCR2 &= ~0xf000; |
Jens Arnold | 780f79e | 2006-11-10 20:26:01 +0000 | [diff] [blame] | 91 | #else /* not Ondio */ |
Jens Arnold | c42a1a0 | 2005-05-07 22:29:35 +0000 | [diff] [blame] | 92 | /* make PB7 & PB13 general I/O */ |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 93 | PBCR1 &= ~0x0c00; /* PB13 */ |
Jens Arnold | c42a1a0 | 2005-05-07 22:29:35 +0000 | [diff] [blame] | 94 | PBCR2 &= ~0xc000; /* PB7 */ |
Jörg Hohensohn | 6c1afd7 | 2004-09-10 07:24:00 +0000 | [diff] [blame] | 95 | #endif |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 96 | |
Jörg Hohensohn | 6c1afd7 | 2004-09-10 07:24:00 +0000 | [diff] [blame] | 97 | SCL_OUTPUT; |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 98 | SDA_OUTPUT; |
| 99 | SDA_HI; |
| 100 | SCL_LO; |
| 101 | for (i=0;i<3;i++) |
| 102 | i2c_stop(); |
| 103 | } |
| 104 | |
| 105 | void 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 Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 114 | { |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 115 | SDA_HI; |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 116 | } |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 117 | else |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 118 | { |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 119 | SDA_LO; |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 120 | } |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 121 | |
| 122 | SCL_INPUT; /* Set the clock to input */ |
Linus Nielsen Feltzing | 250c3b6 | 2002-05-16 21:20:52 +0000 | [diff] [blame] | 123 | while(!SCL) /* and wait for the MAS to release it */ |
Michael Sevakis | ed8445f | 2008-03-20 15:20:06 +0000 | [diff] [blame^] | 124 | sleep(1); |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 125 | |
| 126 | DELAY; |
| 127 | SCL_OUTPUT; |
| 128 | SCL_LO; |
| 129 | } |
| 130 | |
| 131 | int i2c_getack(void) |
| 132 | { |
Linus Nielsen Feltzing | 95a323c | 2002-05-28 15:07:45 +0000 | [diff] [blame] | 133 | int ret = 1; |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 134 | |
| 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 Feltzing | 9d937e9 | 2002-06-19 12:00:37 +0000 | [diff] [blame] | 139 | |
Daniel Stenberg | aaa8443 | 2003-01-21 19:37:29 +0000 | [diff] [blame] | 140 | #ifdef HAVE_I2C_LOW_FIRST |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 141 | SDA_LO; /* First, discharge the data line */ |
Linus Nielsen Feltzing | 9d937e9 | 2002-06-19 12:00:37 +0000 | [diff] [blame] | 142 | #endif |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 143 | SDA_INPUT; /* And set to input */ |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 144 | SCL_INPUT; /* Set the clock to input */ |
Linus Nielsen Feltzing | 250c3b6 | 2002-05-16 21:20:52 +0000 | [diff] [blame] | 145 | while(!SCL) /* and wait for the MAS to release it */ |
Michael Sevakis | ed8445f | 2008-03-20 15:20:06 +0000 | [diff] [blame^] | 146 | sleep(1); |
Linus Nielsen Feltzing | 250c3b6 | 2002-05-16 21:20:52 +0000 | [diff] [blame] | 147 | |
Linus Nielsen Feltzing | 95a323c | 2002-05-28 15:07:45 +0000 | [diff] [blame] | 148 | if (SDA) |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 149 | /* ack failed */ |
Linus Nielsen Feltzing | 95a323c | 2002-05-28 15:07:45 +0000 | [diff] [blame] | 150 | ret = 0; |
| 151 | |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 152 | SCL_OUTPUT; |
| 153 | SCL_LO; |
| 154 | SDA_HI; |
| 155 | SDA_OUTPUT; |
Linus Nielsen Feltzing | 95a323c | 2002-05-28 15:07:45 +0000 | [diff] [blame] | 156 | return ret; |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | void 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 Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 166 | { |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 167 | SDA_HI; |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 168 | } |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 169 | else |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 170 | { |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 171 | SDA_LO; |
Jörg Hohensohn | 75bab49 | 2003-11-06 01:34:50 +0000 | [diff] [blame] | 172 | } |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 173 | SCL_HI; |
| 174 | SCL_LO; |
| 175 | } |
| 176 | |
| 177 | SDA_HI; |
| 178 | } |
| 179 | |
| 180 | unsigned 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 Stenberg | aaa8443 | 2003-01-21 19:37:29 +0000 | [diff] [blame] | 187 | #ifdef HAVE_I2C_LOW_FIRST |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 188 | /* 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 Feltzing | 9d937e9 | 2002-06-19 12:00:37 +0000 | [diff] [blame] | 191 | #endif |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 192 | 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 Arnold | 0ceaa5e | 2004-08-17 01:45:48 +0000 | [diff] [blame] | 205 | int i2c_write(int address, const unsigned char* buf, int count ) |
Linus Nielsen Feltzing | d057c07 | 2002-04-20 23:01:30 +0000 | [diff] [blame] | 206 | { |
| 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 | |
| 232 | int 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 | } |