summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/generic_i2c.c149
-rw-r--r--firmware/export/generic_i2c.h2
2 files changed, 93 insertions, 58 deletions
diff --git a/firmware/drivers/generic_i2c.c b/firmware/drivers/generic_i2c.c
index 2e5f202307..0dcc957260 100644
--- a/firmware/drivers/generic_i2c.c
+++ b/firmware/drivers/generic_i2c.c
@@ -23,14 +23,17 @@
23#include <stdbool.h> 23#include <stdbool.h>
24#include <stdlib.h> 24#include <stdlib.h>
25#include "debug.h" 25#include "debug.h"
26#include "logf.h"
27#include "generic_i2c.h" 26#include "generic_i2c.h"
28 27
28#define MAX_I2C_INTERFACES 5
29
29int i2c_num_ifs = 0; 30int i2c_num_ifs = 0;
30struct i2c_interface *i2c_if[5]; 31struct i2c_interface *i2c_if[MAX_I2C_INTERFACES];
31 32
32static void i2c_start(struct i2c_interface *iface) 33static void i2c_start(struct i2c_interface *iface)
33{ 34{
35 iface->sda_output();
36
34 iface->sda_hi(); 37 iface->sda_hi();
35 iface->scl_hi(); 38 iface->scl_hi();
36 iface->sda_lo(); 39 iface->sda_lo();
@@ -40,6 +43,8 @@ static void i2c_start(struct i2c_interface *iface)
40 43
41static void i2c_stop(struct i2c_interface *iface) 44static void i2c_stop(struct i2c_interface *iface)
42{ 45{
46 iface->sda_output();
47
43 iface->sda_lo(); 48 iface->sda_lo();
44 iface->scl_hi(); 49 iface->scl_hi();
45 iface->delay_su_sto(); 50 iface->delay_su_sto();
@@ -48,6 +53,7 @@ static void i2c_stop(struct i2c_interface *iface)
48 53
49static void i2c_ack(struct i2c_interface *iface, bool ack) 54static void i2c_ack(struct i2c_interface *iface, bool ack)
50{ 55{
56 iface->sda_output();
51 iface->scl_lo(); 57 iface->scl_lo();
52 if ( ack ) 58 if ( ack )
53 iface->sda_lo(); 59 iface->sda_lo();
@@ -67,10 +73,10 @@ static int i2c_getack(struct i2c_interface *iface)
67 iface->sda_input(); 73 iface->sda_input();
68 iface->delay_su_dat(); 74 iface->delay_su_dat();
69 iface->scl_hi(); 75 iface->scl_hi();
70 76
71 if (iface->sda()) 77 if (iface->sda())
72 ret = 0; /* ack failed */ 78 ret = 0; /* ack failed */
73 79
74 iface->delay_thigh(); 80 iface->delay_thigh();
75 iface->scl_lo(); 81 iface->scl_lo();
76 iface->sda_hi(); 82 iface->sda_hi();
@@ -83,7 +89,9 @@ static unsigned char i2c_inb(struct i2c_interface *iface, bool ack)
83{ 89{
84 int i; 90 int i;
85 unsigned char byte = 0; 91 unsigned char byte = 0;
86 92
93 iface->sda_input();
94
87 /* clock in each bit, MSB first */ 95 /* clock in each bit, MSB first */
88 for ( i=0x80; i; i>>=1 ) { 96 for ( i=0x80; i; i>>=1 ) {
89 iface->sda_input(); 97 iface->sda_input();
@@ -95,27 +103,29 @@ static unsigned char i2c_inb(struct i2c_interface *iface, bool ack)
95 iface->delay_hd_dat(); 103 iface->delay_hd_dat();
96 iface->sda_output(); 104 iface->sda_output();
97 } 105 }
98 106
99 i2c_ack(iface, ack); 107 i2c_ack(iface, ack);
100 108
101 return byte; 109 return byte;
102} 110}
103 111
104static void i2c_outb(struct i2c_interface *iface, unsigned char byte) 112static void i2c_outb(struct i2c_interface *iface, unsigned char byte)
105{ 113{
106 int i; 114 int i;
107 115
108 /* clock out each bit, MSB first */ 116 iface->sda_output();
109 for (i=0x80; i; i>>=1) { 117
110 if (i & byte) 118 /* clock out each bit, MSB first */
111 iface->sda_hi(); 119 for (i=0x80; i; i>>=1) {
112 else 120 if (i & byte)
113 iface->sda_lo(); 121 iface->sda_hi();
114 iface->delay_su_dat(); 122 else
115 iface->scl_hi(); 123 iface->sda_lo();
116 iface->delay_thigh(); 124 iface->delay_su_dat();
117 iface->scl_lo(); 125 iface->scl_hi();
118 iface->delay_hd_dat(); 126 iface->delay_thigh();
127 iface->scl_lo();
128 iface->delay_hd_dat();
119 } 129 }
120 130
121 iface->sda_hi(); 131 iface->sda_hi();
@@ -140,27 +150,36 @@ int i2c_write_data(int bus_address, int address,
140 struct i2c_interface *iface = find_if(bus_address); 150 struct i2c_interface *iface = find_if(bus_address);
141 if(!iface) 151 if(!iface)
142 return -1; 152 return -1;
143 153
144 i2c_start(iface); 154 i2c_start(iface);
145 i2c_outb(iface, iface->address & 0xfe); 155 i2c_outb(iface, iface->address & 0xfe);
146 if (i2c_getack(iface)) { 156 if (!i2c_getack(iface))
157 {
158 ret = -2;
159 goto end;
160 }
161
162 if (address != -1)
163 {
147 i2c_outb(iface, address); 164 i2c_outb(iface, address);
148 if (i2c_getack(iface)) { 165 if (!i2c_getack(iface))
149 for(i = 0;i < count;i++) { 166 {
150 i2c_outb(iface, buf[i]); 167 ret = -3;
151 if (!i2c_getack(iface)) { 168 goto end;
152 ret = -3; 169 }
153 break; 170 }
154 } 171
155 } 172 for(i = 0;i < count;i++)
156 } else { 173 {
157 ret = -2; 174 i2c_outb(iface, buf[i]);
175 if (!i2c_getack(iface))
176 {
177 ret = -4;
178 break;
158 } 179 }
159 } else {
160 logf("i2c_write_data() - no ack\n");
161 ret = -1;
162 } 180 }
163 181
182end:
164 i2c_stop(iface); 183 i2c_stop(iface);
165 return ret; 184 return ret;
166} 185}
@@ -173,34 +192,50 @@ int i2c_read_data(int bus_address, int address,
173 struct i2c_interface *iface = find_if(bus_address); 192 struct i2c_interface *iface = find_if(bus_address);
174 if(!iface) 193 if(!iface)
175 return -1; 194 return -1;
176 195
177 i2c_start(iface); 196 if (address != -1)
178 i2c_outb(iface, iface->address & 0xfe); 197 {
179 if (i2c_getack(iface)) { 198 i2c_start(iface);
180 i2c_outb(iface, address); 199 i2c_outb(iface, iface->address & 0xfe);
181 if (i2c_getack(iface)) { 200 if (!i2c_getack(iface))
182 i2c_start(iface); 201 {
183 i2c_outb(iface, iface->address | 1);
184 if (i2c_getack(iface)) {
185 for(i = 0;i < count-1;i++)
186 buf[i] = i2c_inb(iface, true);
187
188 buf[i] = i2c_inb(iface, false);
189 } else {
190 ret = -3;
191 }
192 } else {
193 ret = -2; 202 ret = -2;
203 goto end;
204 }
205 i2c_outb(iface, address);
206 if (!i2c_getack(iface))
207 {
208 ret = -3;
209 goto end;
194 } 210 }
195 } else {
196 ret = -1;
197 } 211 }
198 212
213 i2c_start(iface);
214 i2c_outb(iface, iface->address | 1);
215 if (!i2c_getack(iface))
216 {
217 ret = -4;
218 goto end;
219 }
220
221 for(i = 0;i < count-1;i++)
222 buf[i] = i2c_inb(iface, true);
223
224 buf[i] = i2c_inb(iface, false);
225
226end:
199 i2c_stop(iface); 227 i2c_stop(iface);
200 return ret; 228 return ret;
201} 229}
202 230
203void i2c_add_node(struct i2c_interface *iface) 231int i2c_add_node(struct i2c_interface *iface)
204{ 232{
233 if (i2c_num_ifs == MAX_I2C_INTERFACES)
234 return -1;
235
205 i2c_if[i2c_num_ifs++] = iface; 236 i2c_if[i2c_num_ifs++] = iface;
237
238 iface->scl_output();
239
240 return 0;
206} 241}
diff --git a/firmware/export/generic_i2c.h b/firmware/export/generic_i2c.h
index 7b598039fa..f38728589d 100644
--- a/firmware/export/generic_i2c.h
+++ b/firmware/export/generic_i2c.h
@@ -47,7 +47,7 @@ struct i2c_interface
47 void (*delay_thigh)(void); /* SCL high period (tHIGH) 4.0us/0.6us */ 47 void (*delay_thigh)(void); /* SCL high period (tHIGH) 4.0us/0.6us */
48}; 48};
49 49
50extern void i2c_add_node(struct i2c_interface *iface); 50extern int i2c_add_node(struct i2c_interface *iface);
51extern int i2c_write_data(int bus_address, int address, 51extern int i2c_write_data(int bus_address, int address,
52 const unsigned char* buf, int count); 52 const unsigned char* buf, int count);
53extern int i2c_read_data(int bus_address, int address, 53extern int i2c_read_data(int bus_address, int address,