diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/generic_i2c.c | 149 | ||||
-rw-r--r-- | firmware/export/generic_i2c.h | 2 |
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 | |||
29 | int i2c_num_ifs = 0; | 30 | int i2c_num_ifs = 0; |
30 | struct i2c_interface *i2c_if[5]; | 31 | struct i2c_interface *i2c_if[MAX_I2C_INTERFACES]; |
31 | 32 | ||
32 | static void i2c_start(struct i2c_interface *iface) | 33 | static 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 | ||
41 | static void i2c_stop(struct i2c_interface *iface) | 44 | static 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 | ||
49 | static void i2c_ack(struct i2c_interface *iface, bool ack) | 54 | static 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 | ||
104 | static void i2c_outb(struct i2c_interface *iface, unsigned char byte) | 112 | static 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 | ||
182 | end: | ||
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 | |||
226 | end: | ||
199 | i2c_stop(iface); | 227 | i2c_stop(iface); |
200 | return ret; | 228 | return ret; |
201 | } | 229 | } |
202 | 230 | ||
203 | void i2c_add_node(struct i2c_interface *iface) | 231 | int 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 | ||
50 | extern void i2c_add_node(struct i2c_interface *iface); | 50 | extern int i2c_add_node(struct i2c_interface *iface); |
51 | extern int i2c_write_data(int bus_address, int address, | 51 | extern int i2c_write_data(int bus_address, int address, |
52 | const unsigned char* buf, int count); | 52 | const unsigned char* buf, int count); |
53 | extern int i2c_read_data(int bus_address, int address, | 53 | extern int i2c_read_data(int bus_address, int address, |