altos: Add STM I2C recv and stop funcs
[fw/altos] / src / stm / ao_i2c_stm.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19
20 struct ao_i2c_stm_info {
21         uint8_t tx_dma_index;
22         uint8_t rx_dma_index;
23         struct stm_i2c  *stm_i2c;
24 };
25
26 #define I2C_IDLE        0
27 #define I2C_RUNNING     1
28 #define I2C_ERROR       2
29
30 static uint8_t  ao_i2c_state[STM_NUM_I2C];
31 static uint16_t ao_i2c_addr[STM_NUM_I2C];
32 uint8_t         ao_i2c_mutex[STM_NUM_I2C];
33
34 #define AO_STM_I2C_CR1 ((0 << STM_I2C_CR1_SWRST) |      \
35                         (0 << STM_I2C_CR1_ALERT) |      \
36                         (0 << STM_I2C_CR1_PEC) |        \
37                         (0 << STM_I2C_CR1_POS) |        \
38                         (0 << STM_I2C_CR1_ACK) |        \
39                         (0 << STM_I2C_CR1_STOP) |       \
40                         (0 << STM_I2C_CR1_START) |      \
41                         (0 << STM_I2C_CR1_NOSTRETCH) |  \
42                         (0 << STM_I2C_CR1_ENGC) |       \
43                         (0 << STM_I2C_CR1_ENPEC) |      \
44                         (0 << STM_I2C_CR1_ENARP) |      \
45                         (0 << STM_I2C_CR1_SMBTYPE) |    \
46                         (0 << STM_I2C_CR1_SMBUS) |      \
47                         (1 << STM_I2C_CR1_PE))
48
49 #define AO_STM_I2C_CR2  ((0 << STM_I2C_CR2_LAST) |                      \
50                          (1 << STM_I2C_CR2_DMAEN) |                     \
51                          (0 << STM_I2C_CR2_ITBUFEN) |                   \
52                          (0 << STM_I2C_CR2_ITEVTEN) |                   \
53                          (0 << STM_I2C_CR2_ITERREN) |                   \
54                          (STM_I2C_CR2_FREQ_16_MHZ << STM_I2C_CR2_FREQ))
55
56 static const struct ao_i2c_stm_info     ao_i2c_stm_info[STM_NUM_I2C] = {
57         {
58                 .tx_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_I2C1_TX),
59                 .rx_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_I2C1_RX),
60                 .stm_i2c = &stm_i2c1
61         },
62         {
63                 .tx_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_I2C2_TX),
64                 .rx_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_I2C2_RX),
65                 .stm_i2c = &stm_i2c2
66         },
67 };
68
69 static void
70 ao_i2c_ev_isr(uint8_t index)
71 {
72         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
73         uint32_t        sr1;
74
75         sr1 = stm_i2c->sr1;
76         if (sr1 & (1 << STM_I2C_SR1_SB))
77                 stm_i2c->dr = ao_i2c_addr[index];
78         if (sr1 & (1 << STM_I2C_SR1_ADDR)) {
79                 (void) stm_i2c->sr2;
80                 ao_i2c_state[index] = I2C_RUNNING;
81                 ao_wakeup(&ao_i2c_state[index]);
82         }
83 }
84
85 void stm_i2c1_ev_isr(void) { ao_i2c_ev_isr(0); }
86 void stm_i2c2_ev_isr(void) { ao_i2c_ev_isr(1); }
87
88 static void
89 ao_i2c_er_isr(uint8_t index)
90 {
91         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
92         uint32_t        sr1;
93
94         sr1 = stm_i2c->sr1;
95         if (sr1 & (1 << STM_I2C_SR1_AF)) {
96                 ao_i2c_state[index] = I2C_ERROR;
97                 stm_i2c->sr1 = sr1 & ~(1 << STM_I2C_SR1_AF);
98                 ao_wakeup(&ao_i2c_state[index]);
99         }
100 }
101
102 void stm_i2c1_er_isr(void) { ao_i2c_er_isr(0); }
103 void stm_i2c2_er_isr(void) { ao_i2c_er_isr(1); }
104
105 void
106 ao_i2c_get(uint8_t index)
107 {
108         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
109         ao_mutex_get(&ao_i2c_mutex[index]);
110
111         stm_i2c->sr1 = 0;
112         stm_i2c->sr2 = 0;
113 }
114
115 void
116 ao_i2c_put(uint8_t index)
117 {
118         ao_mutex_put(&ao_i2c_mutex[index]);
119 }
120
121 uint8_t
122 ao_i2c_start(uint8_t index, uint16_t addr)
123 {
124         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
125         
126         ao_i2c_state[index] = I2C_IDLE;
127         ao_i2c_addr[index] = addr;
128         stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN);
129         stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_START);
130         ao_arch_critical(
131                 while (ao_i2c_state[index] == I2C_IDLE)
132                         ao_sleep(&ao_i2c_state[index]);
133                 );
134         return ao_i2c_state[index] == I2C_RUNNING;
135 }
136
137 void
138 ao_i2c_stop(uint8_t index)
139 {
140         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
141         
142         ao_i2c_state[index] = I2C_IDLE;
143         stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP);
144 }
145
146 void
147 ao_i2c_send(void *block, uint16_t len, uint8_t index)
148 {
149         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
150         uint8_t         tx_dma_index = ao_i2c_stm_info[index].tx_dma_index;
151
152         stm_i2c->cr2 &= ~(1 << STM_I2C_CR2_LAST);
153         ao_dma_set_transfer(tx_dma_index,
154                             &stm_i2c->dr,
155                             block,
156                             len,
157                             (0 << STM_DMA_CCR_MEM2MEM) |
158                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
159                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
160                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
161                             (1 << STM_DMA_CCR_MINC) |
162                             (0 << STM_DMA_CCR_PINC) |
163                             (0 << STM_DMA_CCR_CIRC) |
164                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
165                            
166         ao_dma_start(tx_dma_index);
167         ao_arch_critical(
168                 while (!ao_dma_done[tx_dma_index])
169                         ao_sleep(&ao_dma_done[tx_dma_index]);
170                 );
171         ao_dma_done_transfer(tx_dma_index);
172 }
173
174 void
175 ao_i2c_recv(void *block, uint16_t len, uint8_t index)
176 {
177         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
178         uint8_t         rx_dma_index = ao_i2c_stm_info[index].rx_dma_index;
179
180         stm_i2c->cr2 |= (1 << STM_I2C_CR2_LAST);
181         ao_dma_set_transfer(rx_dma_index,
182                             &stm_i2c->dr,
183                             block,
184                             len,
185                             (0 << STM_DMA_CCR_MEM2MEM) |
186                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
187                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
188                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
189                             (1 << STM_DMA_CCR_MINC) |
190                             (0 << STM_DMA_CCR_PINC) |
191                             (0 << STM_DMA_CCR_CIRC) |
192                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
193                            
194         ao_dma_start(rx_dma_index);
195         cli();
196         while (!ao_dma_done[rx_dma_index])
197                 ao_sleep(&ao_dma_done[rx_dma_index]);
198         sei();
199         ao_dma_done_transfer(rx_dma_index);
200 }
201
202 void
203 ao_i2c_channel_init(uint8_t index)
204 {
205         struct stm_i2c  *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
206
207         /* Turn I2C off while configuring */
208         stm_i2c->cr1 = 0;
209         stm_i2c->cr2 = AO_STM_I2C_CR2;
210
211         (void) stm_i2c->sr1;
212         (void) stm_i2c->sr2;
213         (void) stm_i2c->dr;
214
215         stm_i2c->sr1 = 0;
216         stm_i2c->sr2 = 0;
217
218         stm_i2c->ccr = ((1 << STM_I2C_CCR_FS) |
219                         (0 << STM_I2C_CCR_DUTY) |
220                         (20 << STM_I2C_CCR_CCR));
221         
222         stm_i2c->cr1 = AO_STM_I2C_CR1;
223 }
224
225 void
226 ao_i2c_init(void)
227 {
228         /* All of the I2C configurations are on port B */
229         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
230 #if HAS_I2C_1
231 # if I2C_1_PB6_PB7
232         stm_afr_set(&stm_gpiob, 6, STM_AFR_AF4);
233         stm_afr_set(&stm_gpiob, 7, STM_AFR_AF4);
234 # else
235 #  if I2C_1_PB8_PB9
236         stm_afr_set(&stm_gpiob, 8, STM_AFR_AF4);
237         stm_afr_set(&stm_gpiob, 9, STM_AFR_AF4);
238 #  else
239 #   error "No I2C_1 port configuration specified"
240 #  endif
241 # endif
242
243         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_I2C1EN);
244         ao_i2c_channel_init(0);
245
246         stm_nvic_set_enable(STM_ISR_I2C1_EV_POS);
247         stm_nvic_set_priority(STM_ISR_I2C1_EV_POS, 3);
248         stm_nvic_set_enable(STM_ISR_I2C1_ER_POS);
249         stm_nvic_set_priority(STM_ISR_I2C1_ER_POS, 3);
250 #endif
251
252 #if HAS_I2C_2
253 # if I2C_2_PB10_PB11
254         stm_afr_set(&stm_gpiob, 10, STM_AFR_AF4);
255         stm_afr_set(&stm_gpiob, 11, STM_AFR_AF4);
256 # else
257 #  error "No I2C_2 port configuration specified"
258 # endif
259         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_I2C2EN);
260         ao_i2c_channel_init(1);
261
262         stm_nvic_set_enable(STM_ISR_I2C2_EV_POS);
263         stm_nvic_set_priority(STM_ISR_I2C2_EV_POS, 3);
264         stm_nvic_set_enable(STM_ISR_I2C2_ER_POS);
265         stm_nvic_set_priority(STM_ISR_I2C2_ER_POS, 3);
266 #endif
267 }
268