summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-03-30 05:38:28 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-03-30 05:38:28 +0000
commit5f1590bf4a1da9f6edd11c167e67109e9e06e03a (patch)
tree3b3b819ef6c6f154c8fe5396bbc47002b5ba4386
parentbc192c953eb2fe80cac471ea4601c27e23512440 (diff)
downloadrockbox-5f1590bf4a1da9f6edd11c167e67109e9e06e03a.tar.gz
rockbox-5f1590bf4a1da9f6edd11c167e67109e9e06e03a.zip
Have meg-fx i2c driver use the wakeup functionality by making it interrupt-based (and serves as a simple usage example).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16886 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c127
1 files changed, 72 insertions, 55 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
index 45140c0f0c..7e4e608e15 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
@@ -19,79 +19,55 @@
19#include "system.h" 19#include "system.h"
20#include "i2c-meg-fx.h" 20#include "i2c-meg-fx.h"
21 21
22/* Only implements sending bytes for now. Adding receiving bytes should be 22static struct wakeup i2c_wake; /* Transfer completion signal */
23 straightforward if needed. No yielding is present since the calls only 23static struct mutex i2c_mtx; /* Mutual exclusion */
24 involve setting audio codec registers - a very rare event. */ 24static unsigned char *buf_ptr; /* Next byte to transfer */
25 25static int buf_count; /* Number of bytes remaining to transfer */
26/* Wait for a condition on the bus, optionally returning it */
27#define COND_RET _c;
28#define COND_VOID
29#define WAIT_COND(cond, ret) \
30 ({ \
31 int _t = current_tick + 2; \
32 bool _c; \
33 while (1) { \
34 _c = !!(cond); \
35 if (_c || TIME_AFTER(current_tick, _t)) \
36 break; \
37 } \
38 ret \
39 })
40
41static int i2c_getack(void)
42{
43 /* Wait for ACK: 0 = ack received, 1 = ack not received */
44 WAIT_COND(IICCON & I2C_TXRX_INTPND, COND_VOID);
45 return IICSTAT & I2C_ACK_L;
46}
47
48static int i2c_start(void)
49{
50 /* Generate START */
51 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
52 return i2c_getack();
53}
54 26
55static void i2c_stop(void) 27static void i2c_stop(void)
56{ 28{
57 /* Generate STOP */ 29 /* Generate STOP */
58 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB; 30 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
59 /* Clear pending interrupt to continue */
60 IICCON &= ~I2C_TXRX_INTPND;
61}
62 31
63static int i2c_outb(unsigned char byte) 32 /* No more interrupts, clear pending interrupt to continue */
64{ 33 IICCON &= ~(I2C_TXRX_INTPND | I2C_TXRX_INTENB);
65 /* Write byte to shift register */
66 IICDS = byte;
67 /* Clear pending interrupt to continue */
68 IICCON &= ~I2C_TXRX_INTPND;
69 return i2c_getack();
70} 34}
71 35
72void i2c_write(int addr, const unsigned char *buf, int count) 36void i2c_write(int addr, const unsigned char *buf, int count)
73{ 37{
38 if (count <= 0)
39 return;
40
41 mutex_lock(&i2c_mtx);
42
74 /* Turn on I2C clock */ 43 /* Turn on I2C clock */
75 CLKCON |= (1 << 16); 44 CLKCON |= (1 << 16);
76 45
77 /* Set mode to master transmitter and enable lines */ 46 /* Set mode to master transmitter and enable lines */
78 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB; 47 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
79 48
80 /* Wait for bus to be available */ 49 /* Set buffer start and count */
81 if (WAIT_COND(!(IICSTAT & I2C_BUSY), COND_RET)) 50 buf_ptr = (unsigned char *)buf;
82 { 51 buf_count = count;
83 /* Send slave address and then data */
84 IICCON &= ~I2C_TXRX_INTPND;
85 IICCON |= I2C_TXRX_INTENB;
86 52
87 IICDS = addr & 0xfe; 53 /* Send slave address and then data */
54 SRCPND = IIC_MASK;
55 INTPND = IIC_MASK;
88 56
89 if (i2c_start() == 0) 57 IICCON |= I2C_TXRX_INTENB;
90 while (count-- > 0 && i2c_outb(*buf++) == 0);
91 58
92 i2c_stop(); 59 /* Load slave address into shift register */
60 IICDS = addr & 0xfe;
61
62 /* Generate START */
63 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
93 64
94 IICCON &= ~I2C_TXRX_INTENB; 65 if (wakeup_wait(&i2c_wake, HZ) != WAIT_SUCCEEDED)
66 {
67 /* Something went wrong - stop transmission */
68 int oldlevel = disable_irq_save();
69 i2c_stop();
70 restore_irq(oldlevel);
95 } 71 }
96 72
97 /* Go back to slave receive mode and disable lines */ 73 /* Go back to slave receive mode and disable lines */
@@ -99,12 +75,23 @@ void i2c_write(int addr, const unsigned char *buf, int count)
99 75
100 /* Turn off I2C clock */ 76 /* Turn off I2C clock */
101 CLKCON &= ~(1 << 16); 77 CLKCON &= ~(1 << 16);
78
79 mutex_unlock(&i2c_mtx);
102} 80}
103 81
104void i2c_init(void) 82void i2c_init(void)
105{ 83{
106 /* We poll I2C interrupts */ 84 /* Init kernel objects */
107 INTMSK |= (1 << 27); 85 wakeup_init(&i2c_wake);
86 mutex_init(&i2c_mtx);
87
88 /* Clear pending source */
89 SRCPND = IIC_MASK;
90 INTPND = IIC_MASK;
91
92 /* Enable i2c interrupt in controller */
93 INTMOD &= ~IIC_MASK;
94 INTMSK &= ~IIC_MASK;
108 95
109 /* Turn on I2C clock */ 96 /* Turn on I2C clock */
110 CLKCON |= (1 << 16); 97 CLKCON |= (1 << 16);
@@ -123,3 +110,33 @@ void i2c_init(void)
123 /* Turn off I2C clock */ 110 /* Turn off I2C clock */
124 CLKCON &= ~(1 << 16); 111 CLKCON &= ~(1 << 16);
125} 112}
113
114void IIC(void)
115{
116 for (;;)
117 {
118 /* If ack was received from last byte and bytes are remaining */
119 if (--buf_count >= 0 && (IICSTAT & I2C_ACK_L) == 0)
120 {
121 /* Write next byte to shift register */
122 IICDS = *buf_ptr++;
123
124 /* Clear pending interrupt to continue */
125 IICCON &= ~I2C_TXRX_INTPND;
126 break;
127 }
128
129 /* Finished */
130
131 /* Generate STOP */
132 i2c_stop();
133
134 /* Signal thread */
135 wakeup_signal(&i2c_wake);
136 break;
137 }
138
139 /* Ack */
140 SRCPND = IIC_MASK;
141 INTPND = IIC_MASK;
142}