blob: 0549da1c794dda1e325d6d988be23830edaf735e [file] [log] [blame]
Harald Welte226b40a2016-08-21 19:33:24 +02001#include "board.h"
2#include <stdbool.h>
3
4/* Low-Level I2C Routines */
5
6static const Pin pin_sda = {PIO_PA30, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN };
7static const Pin pin_sda_in = {PIO_PA30, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT };
8static const Pin pin_scl = {PIO_PA31, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN };
9
Harald Weltec6ae98c2016-09-01 11:57:09 +020010static void i2c_delay()
11{
12 volatile int v;
13 int i;
14
Harald Welte73d697d2016-09-01 18:58:41 +020015 /* 100 cycles results in SCL peak length of 44us, so it's about
16 * 440ns per cycle here */
17 for (i = 0; i < 14; i++) {
Harald Weltec6ae98c2016-09-01 11:57:09 +020018 v = 0;
19 }
20}
21
Harald Welte226b40a2016-08-21 19:33:24 +020022void i2c_pin_init(void)
23{
24 PIO_Configure(&pin_scl, PIO_LISTSIZE(pin_scl));
25 PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
26}
27
28static void set_scl(void)
29{
30 PIO_Set(&pin_scl);
Harald Weltec6ae98c2016-09-01 11:57:09 +020031 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020032}
33
34static void set_sda(void)
35{
36 PIO_Set(&pin_sda);
Harald Weltec6ae98c2016-09-01 11:57:09 +020037 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020038}
39
40static void clear_scl(void)
41{
42 PIO_Clear(&pin_scl);
Harald Weltec6ae98c2016-09-01 11:57:09 +020043 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020044}
45
46static void clear_sda(void)
47{
48 PIO_Clear(&pin_sda);
Harald Weltec6ae98c2016-09-01 11:57:09 +020049 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020050}
51
52static bool read_sda(void)
53{
54 bool ret;
55
56 PIO_Configure(&pin_sda_in, PIO_LISTSIZE(pin_sda_in));
Harald Welte0aea9ff2016-09-01 18:39:12 +020057 if (PIO_Get(&pin_sda_in))
Harald Welte226b40a2016-08-21 19:33:24 +020058 ret = true;
59 else
60 ret = false;
61 PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
62
63 return ret;
64}
65
66/* Core I2C Routines */
67
68static bool i2c_started = false;
69
Harald Welte226b40a2016-08-21 19:33:24 +020070static void i2c_start_cond(void)
71{
72 if (i2c_started) {
73 set_sda();
Harald Welte226b40a2016-08-21 19:33:24 +020074 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +020075 }
76
Harald Welte226b40a2016-08-21 19:33:24 +020077 clear_sda();
78 i2c_delay();
79 clear_scl();
80 i2c_started = true;
81}
82
83static void i2c_stop_cond(void)
84{
85 clear_sda();
Harald Welte226b40a2016-08-21 19:33:24 +020086 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +020087 set_sda();
88 i2c_delay();
89 i2c_started = false;
90}
91
92static void i2c_write_bit(bool bit)
93{
94 if (bit)
95 set_sda();
96 else
97 clear_sda();
Harald Weltec6ae98c2016-09-01 11:57:09 +020098 i2c_delay(); // ?
Harald Welte226b40a2016-08-21 19:33:24 +020099 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +0200100 clear_scl();
Harald Welte226b40a2016-08-21 19:33:24 +0200101}
102
103static bool i2c_read_bit(void)
104{
105 bool bit;
106
107 set_sda();
Harald Welte226b40a2016-08-21 19:33:24 +0200108 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +0200109 bit = read_sda();
110 clear_scl();
111
112 return bit;
113}
114
115bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte)
116{
117 uint8_t bit;
118 bool nack;
119
120 if (send_start)
121 i2c_start_cond();
122
123 for (bit = 0; bit < 8; bit++) {
124 i2c_write_bit((byte & 0x80) != 0);
125 byte <<= 1;
126 }
127
128 nack = i2c_read_bit();
129
130 if (send_stop)
131 i2c_stop_cond();
132
133 return nack;
134}
135
136uint8_t i2c_read_byte(bool nack, bool send_stop)
137{
138 uint8_t byte = 0;
139 uint8_t bit;
140
141 for (bit = 0; bit < 8; bit++) {
142 byte = (byte << 1) | i2c_read_bit();
143 }
144
145 i2c_write_bit(nack);
146
147 if (send_stop)
148 i2c_stop_cond();
149
150 return byte;
151}
152
153
154/* EEPROM related code */
155
156int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
157{
158 bool nack;
159
160 /* Write slave address */
161 nack = i2c_write_byte(true, false, slave << 1);
162 if (nack)
163 goto out_stop;
164 nack = i2c_write_byte(false, false, addr);
165 if (nack)
166 goto out_stop;
167 nack = i2c_write_byte(false, true, byte);
168 if (nack)
169 goto out_stop;
170
171out_stop:
172 i2c_stop_cond();
173 if (nack)
174 return -1;
175 else
176 return 0;
177}
178
179int eeprom_read_byte(uint8_t slave, uint8_t addr)
180{
181 bool nack;
182
183 /* dummy write cycle */
184 nack = i2c_write_byte(true, false, slave << 1);
185 if (nack)
186 goto out_stop;
187 nack = i2c_write_byte(false, false, addr);
188 if (nack)
189 goto out_stop;
190 /* Re-start with read */
191 nack = i2c_write_byte(true, false, (slave << 1) | 1);
192 if (nack)
193 goto out_stop;
194
195 return i2c_read_byte(true, true);
196
197out_stop:
198 i2c_stop_cond();
199 if (nack)
200 return -1;
201 else
202 return 0;
203}