summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c313
1 files changed, 298 insertions, 15 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
index 54ddaa7a46..ccd9efb321 100644
--- a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2007 by Michael Sevakis 10 * Copyright (C) 2008 by Michael Sevakis
11 * 11 *
12 * All files in this archive are subject to the GNU General Public License. 12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement. 13 * See the file COPYING in the source tree root for full license agreement.
@@ -16,38 +16,321 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include <stdlib.h>
20#include "config.h"
19#include "system.h" 21#include "system.h"
22#include "kernel.h"
23#include "avic-imx31.h"
24#include "clkctl-imx31.h"
20#include "i2c-imx31.h" 25#include "i2c-imx31.h"
21 26
22#if 0 27/* Forward interrupt handler declarations */
23static int i2c_getack(void) 28#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
29static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void);
30#endif
31#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
32static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void);
33#endif
34#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
35static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void);
36#endif
37
38static struct i2c_module_descriptor
24{ 39{
25 return 0; 40 struct i2c_map *base; /* Module base address */
41 enum IMX31_CG_LIST cg; /* Clock gating index */
42 enum IMX31_INT_LIST ints; /* Module interrupt number */
43 int enable; /* Enable count */
44 void (*handler)(void); /* Module interrupt handler */
45 struct mutex m; /* Node mutual-exclusion */
46 struct wakeup w; /* I2C done signal */
47 unsigned char *addr_data; /* Additional addressing data */
48 int addr_count; /* Addressing byte count */
49 unsigned char *data; /* TX/RX buffer (actual data) */
50 int data_count; /* TX/RX byte count */
51 unsigned char addr; /* Address + r/w bit */
52} i2c_descs[I2C_NUM_I2C] =
53{
54#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
55 {
56 .base = (struct i2c_map *)I2C1_BASE_ADDR,
57 .cg = CG_I2C1,
58 .ints = I2C1,
59 .handler = I2C1_HANDLER,
60 },
61#endif
62#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
63 {
64 .base = (struct i2c_map *)I2C2_BASE_ADDR,
65 .cg = CG_I2C2,
66 .ints = I2C2,
67 .handler = I2C2_HANDLER,
68 },
69#endif
70#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
71 {
72 .base = (struct i2c_map *)I2C3_BASE_ADDR,
73 .cg = CG_I2C3,
74 .ints = I2C3,
75 .handler = I2C3_HANDLER,
76 },
77#endif
78};
79
80static void i2c_interrupt(enum i2c_module_number i2c)
81{
82 struct i2c_module_descriptor *const desc = &i2c_descs[i2c];
83 struct i2c_map * const base = desc->base;
84 uint16_t i2sr = base->i2sr;
85
86 base->i2sr = i2sr & ~I2C_I2SR_IIF; /* Clear IIF */
87
88 if (desc->addr_count >= 0)
89 {
90 /* ADDR cycle - either done or more to send */
91 if ((i2sr & I2C_I2SR_RXAK) != 0)
92 {
93 goto i2c_stop; /* problem */
94 }
95
96 if (--desc->addr_count < 0)
97 {
98 /* Switching to data cycle */
99 if (desc->addr & 0x1)
100 {
101 base->i2cr &= ~I2C_I2CR_MTX; /* Switch to RX mode */
102 base->i2dr; /* Dummy read */
103 return;
104 }
105 /* else remaining data is TX - handle below */
106 goto i2c_transmit;
107 }
108 else
109 {
110 base->i2dr = *desc->addr_data++; /* Send next addressing byte */
111 return;
112 }
113 }
114
115 if (base->i2cr & I2C_I2CR_MTX)
116 {
117i2c_transmit:
118 /* Transmitting data */
119 if ((i2sr & I2C_I2SR_RXAK) == 0 && desc->data_count > 0)
120 {
121 /* More bytes to send, got ACK from previous byte */
122 base->i2dr = *desc->data++;
123 desc->data_count--;
124 return;
125 }
126 /* else done or no ACK received */
127 }
128 else
129 {
130 /* Receiving data */
131 if (--desc->data_count > 0)
132 {
133 if (desc->data_count == 1)
134 {
135 /* 2nd to Last byte - NACK */
136 base->i2cr |= I2C_I2CR_TXAK;
137 }
138
139 *desc->data++ = base->i2dr; /* Read data from I2DR and store */
140 return;
141 }
142 else
143 {
144 /* Generate STOP signal before reading data */
145 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
146 *desc->data++ = base->i2dr; /* Read data from I2DR and store */
147 goto i2c_done;
148 }
149 }
150
151i2c_stop:
152 /* Generate STOP signal */
153 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
154i2c_done:
155 /* Signal thread we're done */
156 wakeup_signal(&desc->w);
26} 157}
27 158
28static int i2c_start(void) 159#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
160static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void)
29{ 161{
30 return 0; 162 i2c_interrupt(I2C1_NUM);
31} 163}
164#endif
165#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
166static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void)
167{
168 i2c_interrupt(I2C2_NUM);
169}
170#endif
171#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
172static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void)
173{
174 i2c_interrupt(I2C3_NUM);
175}
176#endif
32 177
33static void i2c_stop(void) 178static int i2c_transfer(struct i2c_node * const node,
179 struct i2c_module_descriptor *const desc)
34{ 180{
181 struct i2c_map * const base = desc->base;
182 int count = desc->data_count;
183 uint16_t i2cr;
184
185 /* Set speed */
186 base->ifdr = node->ifdr;
187
188 /* Enable module */
189 base->i2cr = I2C_I2CR_IEN;
190
191 /* Enable Interrupt, Master */
192 i2cr = I2C_I2CR_IEN | I2C_I2CR_IIEN | I2C_I2CR_MTX;
193
194 if ((desc->addr & 0x1) && desc->data_count < 2)
195 {
196 /* Receiving less than two bytes - disable ACK generation */
197 i2cr |= I2C_I2CR_TXAK;
198 }
199
200 /* Set config */
201 base->i2cr = i2cr;
202
203 /* Generate START */
204 base->i2cr |= I2C_I2CR_MSTA;
205
206 /* Address slave (first byte sent) and begin session. */
207 base->i2dr = desc->addr;
208
209 /* Wait for transfer to complete */
210 count = (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) ?
211 -1 : (count - desc->data_count);
212
213 /* Disable module - generate STOP if timeout */
214 base->i2cr = 0;
215
216 return count;
35} 217}
36 218
37static int i2c_outb(unsigned char byte) 219int i2c_read(struct i2c_node *node, int reg,
220 unsigned char *data, int data_count)
38{ 221{
39 (void)byte; 222 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
40 return 0; 223 unsigned char ad[1];
224
225 mutex_lock(&desc->m);
226
227 desc->addr = (node->addr & 0xfe) | 0x1; /* Slave address/rd */
228
229 if (reg >= 0)
230 {
231 /* Sub-address */
232 desc->addr_count = 1;
233 desc->addr_data = ad;
234 ad[0] = reg;
235 }
236 /* else raw read from slave */
237
238 desc->data = data;
239 desc->data_count = data_count;
240
241 data_count = i2c_transfer(node, desc);
242
243 desc->addr_count = 0; /* To eliminate zeroing elsewhere */
244
245 mutex_unlock(&desc->m);
246
247 return data_count;
41} 248}
42#endif
43 249
44void i2c_write(int addr, const unsigned char *buf, int count) 250int i2c_write(struct i2c_node *node, const unsigned char *data, int data_count)
45{ 251{
46 (void)addr; 252 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
47 (void)buf; 253
48 (void)count; 254 mutex_lock(&desc->m);
255
256 desc->addr = node->addr & 0xfe; /* Slave address/wr */
257 desc->data = (unsigned char *)data;
258 desc->data_count = data_count;
259
260 data_count = i2c_transfer(node, desc);
261
262 mutex_unlock(&desc->m);
263
264 return data_count;
49} 265}
50 266
51void i2c_init(void) 267void i2c_init(void)
52{ 268{
269 int i;
270
271 /* Do one-time inits for each module that will be used - leave
272 * module disabled and unclocked until something wants it */
273 for (i = 0; i < I2C_NUM_I2C; i++)
274 {
275 struct i2c_module_descriptor *const desc = &i2c_descs[i];
276 imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
277 mutex_init(&desc->m);
278 wakeup_init(&desc->w);
279 desc->base->i2cr = 0;
280 imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
281 }
282
283#if 0
284 /* Pad config set up by OF bootloader doesn't agree with manual but
285 * TX works at the moment - probably would't do this here either */
286 uint32_t reg = SW_PAD_CTL_CSI_PIXCLK_I2C_CLK_I2C_DAT;
287 reg &= ~0xfffff;
288 reg |= (1 << 19) | (3 << 17) | (1 << 15) | (1 << 14) |
289 (1 << 13) | (0 << 11);
290
291 reg |= (1 << 9) | (3 << 7) | (1 << 5) | (1 << 4) |
292 (1 << 3) | (0 << 1);
293
294 SW_PAD_CTL_CSI_PIXCLK_I2C_CLK_I2C_DAT = reg;
295#endif
296}
297
298void i2c_enable_node(struct i2c_node *node, bool enable)
299{
300 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
301
302 mutex_lock(&desc->m);
303
304 if (enable)
305 {
306 if (++desc->enable == 1)
307 {
308 /* First enable */
309 imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
310 avic_enable_int(desc->ints, IRQ, 7, desc->handler);
311 }
312 }
313 else
314 {
315 if (desc->enable > 0 && --desc->enable == 0)
316 {
317 /* Last enable */
318 avic_disable_int(desc->ints);
319 imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
320 }
321 }
322
323 mutex_unlock(&desc->m);
324}
325
326void i2c_lock_node(struct i2c_node *node)
327{
328 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
329 mutex_lock(&desc->m);
330}
331
332void i2c_unlock_node(struct i2c_node *node)
333{
334 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
335 mutex_unlock(&desc->m);
53} 336}