diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-03-30 05:38:28 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-03-30 05:38:28 +0000 |
commit | 5f1590bf4a1da9f6edd11c167e67109e9e06e03a (patch) | |
tree | 3b3b819ef6c6f154c8fe5396bbc47002b5ba4386 /firmware/target | |
parent | bc192c953eb2fe80cac471ea4601c27e23512440 (diff) | |
download | rockbox-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
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c | 127 |
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 | 22 | static struct wakeup i2c_wake; /* Transfer completion signal */ |
23 | straightforward if needed. No yielding is present since the calls only | 23 | static struct mutex i2c_mtx; /* Mutual exclusion */ |
24 | involve setting audio codec registers - a very rare event. */ | 24 | static unsigned char *buf_ptr; /* Next byte to transfer */ |
25 | 25 | static 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 | |||
41 | static 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 | |||
48 | static 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 | ||
55 | static void i2c_stop(void) | 27 | static 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 | ||
63 | static 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 | ||
72 | void i2c_write(int addr, const unsigned char *buf, int count) | 36 | void 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 | ||
104 | void i2c_init(void) | 82 | void 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 | |||
114 | void 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 | } | ||