summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-04-27 10:30:54 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-04-27 10:30:54 +0000
commit27fac88548366f57c32931ed4d7c7dfc5b4f1627 (patch)
treee45132b551ce39a44a6fefa31e85971cea6df47e /firmware/target/arm/imx31/gigabeat-s
parentfec6af659f809d47f6e750975289e220908396fe (diff)
downloadrockbox-27fac88548366f57c32931ed4d7c7dfc5b4f1627.tar.gz
rockbox-27fac88548366f57c32931ed4d7c7dfc5b4f1627.zip
Gigabeat S: Implement i2c driver - transmit works but no testing of receiving which will get a chance later. Add some seeds for codec driver. Correct a few #defines.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17254 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c313
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h56
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c2
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c25
4 files changed, 377 insertions, 19 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}
diff --git a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h
index c708ebbfb4..d6de5c47e8 100644
--- a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h
+++ b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h
@@ -16,7 +16,61 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#ifndef _I2C_IMX31_H_
20#define _I2C_IMX31_H_
21
22#include <stdbool.h>
23
24/* I2C module usage masks */
25#define USE_I2C1_MODULE (1 << 0)
26#define USE_I2C2_MODULE (1 << 1)
27#define USE_I2C3_MODULE (1 << 2)
28
29enum i2c_module_number
30{
31 __I2C_NUM_START = -1,
32#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
33 I2C1_NUM,
34#endif
35#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
36 I2C2_NUM,
37#endif
38#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
39 I2C3_NUM,
40#endif
41 I2C_NUM_I2C,
42};
43
44/* Module interface map structure */
45struct i2c_map
46{
47 volatile uint16_t iadr; /* 0x00 */
48 volatile uint16_t unused1;
49 volatile uint16_t ifdr; /* 0x04 */
50 volatile uint16_t unused2;
51 volatile uint16_t i2cr; /* 0x08 */
52 volatile uint16_t unused3;
53 volatile uint16_t i2sr; /* 0x0C */
54 volatile uint16_t unused4;
55 volatile uint16_t i2dr; /* 0x10 */
56};
57
58struct i2c_node
59{
60 enum i2c_module_number num; /* Module that this node uses */
61 unsigned int ifdr; /* Maximum frequency for node */
62 unsigned char addr; /* Slave address on module */
63};
19 64
20void i2c_init(void); 65void i2c_init(void);
21void i2c_write(int addr, const unsigned char *data, int count); 66/* Enable or disable the node - modules will be switch on/off accordingly. */
67void i2c_enable_node(struct i2c_node *node, bool enable);
68/* If addr < 0, then raw read */
69int i2c_read(struct i2c_node *node, int addr, unsigned char *data, int count);
70int i2c_write(struct i2c_node *node, const unsigned char *data, int count);
71/* Gain mutually-exclusive access to the node and module to perform multiple
72 * operations atomically */
73void i2c_lock_node(struct i2c_node *node);
74void i2c_unlock_node(struct i2c_node *node);
22 75
76#endif /* _I2C_IMX31_H_ */
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
index 4d2206bd56..e37f6bfbe2 100644
--- a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
@@ -49,10 +49,12 @@ void pcm_apply_settings(void)
49 49
50void pcm_play_dma_init(void) 50void pcm_play_dma_init(void)
51{ 51{
52 audiohw_init();
52} 53}
53 54
54void pcm_postinit(void) 55void pcm_postinit(void)
55{ 56{
57 audiohw_postinit();
56} 58}
57 59
58#if 0 60#if 0
diff --git a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
index 238ee3aeb2..235ae54bad 100644
--- a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Gigabeat specific code for the Wolfson codec 10 * Gigabeat S specific code for the WM8978 codec
11 * 11 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/ 12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005 13 * Adapted for Rockbox in December 2005
@@ -28,12 +28,31 @@
28#include "sound.h" 28#include "sound.h"
29#include "i2c-imx31.h" 29#include "i2c-imx31.h"
30 30
31/* NOTE: Some port-specific bits will have to be moved away (node and GPIO
32 * writes) for cleanest implementation. */
33
34static struct i2c_node wm8978_i2c_node =
35{
36 .num = I2C1_NUM,
37 .ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */
38 /* Just hard-code for now - scaling may require
39 * updating */
40 .addr = WM8978_I2C_ADDR,
41};
42
31void audiohw_init(void) 43void audiohw_init(void)
32{ 44{
45 i2c_enable_node(&wm8978_i2c_node, true);
46 GPIO3_DR |= (1 << 21); /* Turn on analogue LDO */
47 sleep(HZ/10); /* Wait for things to stabilize */
48 audiohw_preinit();
33} 49}
34 50
35void wmcodec_write(int reg, int data) 51void wmcodec_write(int reg, int data)
36{ 52{
37 (void)reg; 53 unsigned char d[2];
38 (void)data; 54 /* |aaaaaaad|dddddddd| */
55 d[0] = (reg << 1) | ((data & 0x100) >> 8);
56 d[1] = data;
57 i2c_write(&wm8978_i2c_node, d, 2);
39} 58}