blob: 2cd84238e8827edd459bd4f8e4fe6c915887f9e4 [file] [log] [blame]
Joachim Steigerb1a81c12019-07-26 22:13:51 +02001/* I2C EEPROM memory read and write utilities
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
16 */
17#include "board.h"
18#include <stdbool.h>
19
20/* Low-Level I2C Routines */
21
22static const Pin pin_sda = {PIO_PA30, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN };
23static const Pin pin_sda_in = {PIO_PA30, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT };
24static const Pin pin_scl = {PIO_PA31, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN };
25
26static void i2c_delay()
27{
28 volatile int v;
29 int i;
30
31 /* 100 cycles results in SCL peak length of 44us, so it's about
32 * 440ns per cycle here */
33 for (i = 0; i < 14; i++) {
34 v = 0;
35 }
36}
37
38void i2c_pin_init(void)
39{
40 PIO_Configure(&pin_scl, PIO_LISTSIZE(pin_scl));
41 PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
42}
43
44static void set_scl(void)
45{
46 PIO_Set(&pin_scl);
47 i2c_delay();
48}
49
50static void set_sda(void)
51{
52 PIO_Set(&pin_sda);
53 i2c_delay();
54}
55
56static void clear_scl(void)
57{
58 PIO_Clear(&pin_scl);
59 i2c_delay();
60}
61
62static void clear_sda(void)
63{
64 PIO_Clear(&pin_sda);
65 i2c_delay();
66}
67
68static bool read_sda(void)
69{
70 bool ret;
71
72 PIO_Configure(&pin_sda_in, PIO_LISTSIZE(pin_sda_in));
73 if (PIO_Get(&pin_sda_in))
74 ret = true;
75 else
76 ret = false;
77 PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
78
79 return ret;
80}
81
82/* Core I2C Routines */
83
84static bool i2c_started = false;
85
86static void i2c_start_cond(void)
87{
88 if (i2c_started) {
89 set_sda();
90 set_scl();
91 }
92
93 clear_sda();
94 i2c_delay();
95 clear_scl();
96 i2c_started = true;
97}
98
Joachim Steigerf7f1ea82019-10-24 18:09:05 +020099void i2c_stop_cond(void)
Joachim Steigerb1a81c12019-07-26 22:13:51 +0200100{
101 clear_sda();
102 set_scl();
103 set_sda();
104 i2c_delay();
105 i2c_started = false;
106}
107
108static void i2c_write_bit(bool bit)
109{
110 if (bit)
111 set_sda();
112 else
113 clear_sda();
114 i2c_delay(); // ?
115 set_scl();
116 clear_scl();
117}
118
119static bool i2c_read_bit(void)
120{
121 bool bit;
122
123 set_sda();
124 set_scl();
125 bit = read_sda();
126 clear_scl();
127
128 return bit;
129}
130
131bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte)
132{
133 uint8_t bit;
134 bool nack;
135
136 if (send_start)
137 i2c_start_cond();
138
139 for (bit = 0; bit < 8; bit++) {
140 i2c_write_bit((byte & 0x80) != 0);
141 byte <<= 1;
142 }
143
144 nack = i2c_read_bit();
145
146 if (send_stop)
147 i2c_stop_cond();
148
149 return nack;
150}
151
152uint8_t i2c_read_byte(bool nack, bool send_stop)
153{
154 uint8_t byte = 0;
155 uint8_t bit;
156
157 for (bit = 0; bit < 8; bit++) {
158 byte = (byte << 1) | i2c_read_bit();
159 }
160
161 i2c_write_bit(nack);
162
163 if (send_stop)
164 i2c_stop_cond();
165
166 return byte;
167}
168
169
170/* EEPROM related code */
171
172int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
173{
174 bool nack;
175
176 WDT_Restart(WDT);
177
178 /* Write slave address */
179 nack = i2c_write_byte(true, false, slave << 1);
180 if (nack)
181 goto out_stop;
182 nack = i2c_write_byte(false, false, addr);
183 if (nack)
184 goto out_stop;
185 nack = i2c_write_byte(false, true, byte);
186 if (nack)
187 goto out_stop;
188 /* Wait tWR time to ensure EEPROM is writing correctly (tWR = 5 ms for AT24C02) */
189 mdelay(5);
190
191out_stop:
192 i2c_stop_cond();
193 if (nack)
194 return -1;
195 else
196 return 0;
197}
198
199int eeprom_read_byte(uint8_t slave, uint8_t addr)
200{
201 bool nack;
202
203 WDT_Restart(WDT);
204
205 /* dummy write cycle */
206 nack = i2c_write_byte(true, false, slave << 1);
207 if (nack)
208 goto out_stop;
209 nack = i2c_write_byte(false, false, addr);
210 if (nack)
211 goto out_stop;
212 /* Re-start with read */
213 nack = i2c_write_byte(true, false, (slave << 1) | 1);
214 if (nack)
215 goto out_stop;
216
217 return i2c_read_byte(true, true);
218
219out_stop:
220 i2c_stop_cond();
221 if (nack)
222 return -1;
223 else
224 return 0;
225}