blob: cf9789ad3cfa80d20aa86b932ba8bd9da9fedb15 [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
15 for (i = 0; i < 100; i++) {
16 v = 0;
17 }
18}
19
Harald Welte226b40a2016-08-21 19:33:24 +020020void i2c_pin_init(void)
21{
22 PIO_Configure(&pin_scl, PIO_LISTSIZE(pin_scl));
23 PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
24}
25
26static void set_scl(void)
27{
28 PIO_Set(&pin_scl);
Harald Weltec6ae98c2016-09-01 11:57:09 +020029 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020030}
31
32static void set_sda(void)
33{
34 PIO_Set(&pin_sda);
Harald Weltec6ae98c2016-09-01 11:57:09 +020035 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020036}
37
38static void clear_scl(void)
39{
40 PIO_Clear(&pin_scl);
Harald Weltec6ae98c2016-09-01 11:57:09 +020041 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020042}
43
44static void clear_sda(void)
45{
46 PIO_Clear(&pin_sda);
Harald Weltec6ae98c2016-09-01 11:57:09 +020047 i2c_delay();
Harald Welte226b40a2016-08-21 19:33:24 +020048}
49
50static bool read_sda(void)
51{
52 bool ret;
53
54 PIO_Configure(&pin_sda_in, PIO_LISTSIZE(pin_sda_in));
Harald Welte0aea9ff2016-09-01 18:39:12 +020055 if (PIO_Get(&pin_sda_in))
Harald Welte226b40a2016-08-21 19:33:24 +020056 ret = true;
57 else
58 ret = false;
59 PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
60
61 return ret;
62}
63
64/* Core I2C Routines */
65
66static bool i2c_started = false;
67
Harald Welte226b40a2016-08-21 19:33:24 +020068static void i2c_start_cond(void)
69{
70 if (i2c_started) {
71 set_sda();
Harald Welte226b40a2016-08-21 19:33:24 +020072 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +020073 }
74
Harald Welte226b40a2016-08-21 19:33:24 +020075 clear_sda();
76 i2c_delay();
77 clear_scl();
78 i2c_started = true;
79}
80
81static void i2c_stop_cond(void)
82{
83 clear_sda();
Harald Welte226b40a2016-08-21 19:33:24 +020084 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +020085 set_sda();
86 i2c_delay();
87 i2c_started = false;
88}
89
90static void i2c_write_bit(bool bit)
91{
92 if (bit)
93 set_sda();
94 else
95 clear_sda();
Harald Weltec6ae98c2016-09-01 11:57:09 +020096 i2c_delay(); // ?
Harald Welte226b40a2016-08-21 19:33:24 +020097 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +020098 clear_scl();
Harald Welte226b40a2016-08-21 19:33:24 +020099}
100
101static bool i2c_read_bit(void)
102{
103 bool bit;
104
105 set_sda();
Harald Welte226b40a2016-08-21 19:33:24 +0200106 set_scl();
Harald Welte226b40a2016-08-21 19:33:24 +0200107 bit = read_sda();
108 clear_scl();
109
110 return bit;
111}
112
113bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte)
114{
115 uint8_t bit;
116 bool nack;
117
118 if (send_start)
119 i2c_start_cond();
120
121 for (bit = 0; bit < 8; bit++) {
122 i2c_write_bit((byte & 0x80) != 0);
123 byte <<= 1;
124 }
125
126 nack = i2c_read_bit();
127
128 if (send_stop)
129 i2c_stop_cond();
130
131 return nack;
132}
133
134uint8_t i2c_read_byte(bool nack, bool send_stop)
135{
136 uint8_t byte = 0;
137 uint8_t bit;
138
139 for (bit = 0; bit < 8; bit++) {
140 byte = (byte << 1) | i2c_read_bit();
141 }
142
143 i2c_write_bit(nack);
144
145 if (send_stop)
146 i2c_stop_cond();
147
148 return byte;
149}
150
151
152/* EEPROM related code */
153
154int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
155{
156 bool nack;
157
158 /* Write slave address */
159 nack = i2c_write_byte(true, false, slave << 1);
160 if (nack)
161 goto out_stop;
162 nack = i2c_write_byte(false, false, addr);
163 if (nack)
164 goto out_stop;
165 nack = i2c_write_byte(false, true, byte);
166 if (nack)
167 goto out_stop;
168
169out_stop:
170 i2c_stop_cond();
171 if (nack)
172 return -1;
173 else
174 return 0;
175}
176
177int eeprom_read_byte(uint8_t slave, uint8_t addr)
178{
179 bool nack;
180
181 /* dummy write cycle */
182 nack = i2c_write_byte(true, false, slave << 1);
183 if (nack)
184 goto out_stop;
185 nack = i2c_write_byte(false, false, addr);
186 if (nack)
187 goto out_stop;
188 /* Re-start with read */
189 nack = i2c_write_byte(true, false, (slave << 1) | 1);
190 if (nack)
191 goto out_stop;
192
193 return i2c_read_byte(true, true);
194
195out_stop:
196 i2c_stop_cond();
197 if (nack)
198 return -1;
199 else
200 return 0;
201}