i.MX31: Add some enums and a couple helper functions to make dealing with pin muxing...
[kugel-rb.git] / firmware / target / arm / imx31 / i2c-imx31.c
blob1ffdce38eadcb7fb3819aecc31db9cf764ac05a9
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdlib.h>
22 #include "config.h"
23 #include "system.h"
24 #include "kernel.h"
25 #include "avic-imx31.h"
26 #include "ccm-imx31.h"
27 #include "i2c-imx31.h"
29 /* Forward interrupt handler declarations */
30 #if (I2C_MODULE_MASK & USE_I2C1_MODULE)
31 static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void);
32 #endif
33 #if (I2C_MODULE_MASK & USE_I2C2_MODULE)
34 static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void);
35 #endif
36 #if (I2C_MODULE_MASK & USE_I2C3_MODULE)
37 static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void);
38 #endif
40 static struct i2c_module_descriptor
42 struct i2c_map *base; /* Module base address */
43 enum IMX31_CG_LIST cg; /* Clock gating index */
44 enum IMX31_INT_LIST ints; /* Module interrupt number */
45 int enable; /* Enable count */
46 void (*handler)(void); /* Module interrupt handler */
47 struct mutex m; /* Node mutual-exclusion */
48 struct wakeup w; /* I2C done signal */
49 unsigned char *addr_data; /* Additional addressing data */
50 int addr_count; /* Addressing byte count */
51 unsigned char *data; /* TX/RX buffer (actual data) */
52 int data_count; /* TX/RX byte count */
53 unsigned char addr; /* Address + r/w bit */
54 } i2c_descs[I2C_NUM_I2C] =
56 #if (I2C_MODULE_MASK & USE_I2C1_MODULE)
58 .base = (struct i2c_map *)I2C1_BASE_ADDR,
59 .cg = CG_I2C1,
60 .ints = INT_I2C1,
61 .handler = I2C1_HANDLER,
63 #endif
64 #if (I2C_MODULE_MASK & USE_I2C2_MODULE)
66 .base = (struct i2c_map *)I2C2_BASE_ADDR,
67 .cg = CG_I2C2,
68 .ints = INT_I2C2,
69 .handler = I2C2_HANDLER,
71 #endif
72 #if (I2C_MODULE_MASK & USE_I2C3_MODULE)
74 .base = (struct i2c_map *)I2C3_BASE_ADDR,
75 .cg = CG_I2C3,
76 .ints = INT_I2C3,
77 .handler = I2C3_HANDLER,
79 #endif
82 static void i2c_interrupt(enum i2c_module_number i2c)
84 struct i2c_module_descriptor *const desc = &i2c_descs[i2c];
85 struct i2c_map * const base = desc->base;
86 uint16_t i2sr = base->i2sr;
88 base->i2sr = 0; /* Clear IIF */
90 if (desc->addr_count >= 0)
92 /* ADDR cycle - either done or more to send */
93 if ((i2sr & I2C_I2SR_RXAK) != 0)
95 goto i2c_stop; /* problem */
98 if (--desc->addr_count < 0)
100 /* Switching to data cycle */
101 if (desc->addr & 0x1)
103 base->i2cr &= ~I2C_I2CR_MTX; /* Switch to RX mode */
104 base->i2dr; /* Dummy read */
105 return;
107 /* else remaining data is TX - handle below */
108 goto i2c_transmit;
110 else
112 base->i2dr = *desc->addr_data++; /* Send next addressing byte */
113 return;
117 if (base->i2cr & I2C_I2CR_MTX)
119 /* Transmitting data */
120 if ((i2sr & I2C_I2SR_RXAK) == 0)
122 i2c_transmit:
123 if (desc->data_count > 0)
125 /* More bytes to send, got ACK from previous byte */
126 base->i2dr = *desc->data++;
127 desc->data_count--;
128 return;
131 /* else done or no ACK received */
133 else
135 /* Receiving data */
136 if (--desc->data_count > 0)
138 if (desc->data_count == 1)
140 /* 2nd to Last byte - NACK */
141 base->i2cr |= I2C_I2CR_TXAK;
144 *desc->data++ = base->i2dr; /* Read data from I2DR and store */
145 return;
147 else
149 /* Generate STOP signal before reading data */
150 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
151 *desc->data++ = base->i2dr; /* Read data from I2DR and store */
152 goto i2c_done;
156 i2c_stop:
157 /* Generate STOP signal */
158 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
159 i2c_done:
160 /* Signal thread we're done */
161 wakeup_signal(&desc->w);
164 #if (I2C_MODULE_MASK & USE_I2C1_MODULE)
165 static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void)
167 i2c_interrupt(I2C1_NUM);
169 #endif
170 #if (I2C_MODULE_MASK & USE_I2C2_MODULE)
171 static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void)
173 i2c_interrupt(I2C2_NUM);
175 #endif
176 #if (I2C_MODULE_MASK & USE_I2C3_MODULE)
177 static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void)
179 i2c_interrupt(I2C3_NUM);
181 #endif
183 static int i2c_transfer(struct i2c_node * const node,
184 struct i2c_module_descriptor *const desc)
186 struct i2c_map * const base = desc->base;
187 int count = desc->data_count;
188 uint16_t i2cr;
190 /* Make sure bus is idle. */
191 while (base->i2sr & I2C_I2SR_IBB);
193 /* Set speed */
194 base->ifdr = node->ifdr;
196 /* Enable module */
197 base->i2cr = I2C_I2CR_IEN;
199 /* Enable Interrupt, Master */
200 i2cr = I2C_I2CR_IEN | I2C_I2CR_IIEN | I2C_I2CR_MTX;
202 if ((desc->addr & 0x1) && desc->data_count < 2)
204 /* Receiving less than two bytes - disable ACK generation */
205 i2cr |= I2C_I2CR_TXAK;
208 /* Set config */
209 base->i2cr = i2cr;
211 /* Generate START */
212 base->i2cr = i2cr | I2C_I2CR_MSTA;
214 /* Address slave (first byte sent) and begin session. */
215 base->i2dr = desc->addr;
217 /* Wait for transfer to complete */
218 if (wakeup_wait(&desc->w, HZ) == OBJ_WAIT_SUCCEEDED)
220 count -= desc->data_count;
222 else
224 /* Generate STOP if timeout */
225 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
226 count = -1;
229 desc->addr_count = 0;
231 return count;
234 int i2c_read(struct i2c_node *node, int reg,
235 unsigned char *data, int data_count)
237 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
238 unsigned char ad[1];
240 mutex_lock(&desc->m);
242 desc->addr = (node->addr & 0xfe) | 0x1; /* Slave address/rd */
244 if (reg >= 0)
246 /* Sub-address */
247 desc->addr_count = 1;
248 desc->addr_data = ad;
249 ad[0] = reg;
251 /* else raw read from slave */
253 desc->data = data;
254 desc->data_count = data_count;
256 data_count = i2c_transfer(node, desc);
258 mutex_unlock(&desc->m);
260 return data_count;
263 int i2c_write(struct i2c_node *node, const unsigned char *data, int data_count)
265 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
267 mutex_lock(&desc->m);
269 desc->addr = node->addr & 0xfe; /* Slave address/wr */
270 desc->data = (unsigned char *)data;
271 desc->data_count = data_count;
273 data_count = i2c_transfer(node, desc);
275 mutex_unlock(&desc->m);
277 return data_count;
280 void i2c_init(void)
282 int i;
284 /* Do one-time inits for each module that will be used - leave
285 * module disabled and unclocked until something wants it */
286 for (i = 0; i < I2C_NUM_I2C; i++)
288 struct i2c_module_descriptor *const desc = &i2c_descs[i];
289 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT);
290 mutex_init(&desc->m);
291 wakeup_init(&desc->w);
292 desc->base->i2cr = 0;
293 ccm_module_clock_gating(desc->cg, CGM_OFF);
297 void i2c_enable_node(struct i2c_node *node, bool enable)
299 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
301 mutex_lock(&desc->m);
303 if (enable)
305 if (++desc->enable == 1)
307 /* First enable */
308 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT);
309 avic_enable_int(desc->ints, INT_TYPE_IRQ, INT_PRIO_DEFAULT,
310 desc->handler);
313 else
315 if (desc->enable > 0 && --desc->enable == 0)
317 /* Last enable */
318 while (desc->base->i2sr & I2C_I2SR_IBB); /* Wait for STOP */
319 desc->base->i2cr &= ~I2C_I2CR_IEN;
320 avic_disable_int(desc->ints);
321 ccm_module_clock_gating(desc->cg, CGM_OFF);
325 mutex_unlock(&desc->m);
328 void i2c_lock_node(struct i2c_node *node)
330 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
331 mutex_lock(&desc->m);
334 void i2c_unlock_node(struct i2c_node *node)
336 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
337 mutex_unlock(&desc->m);