summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c')
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c165
1 files changed, 78 insertions, 87 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 670d6cd04c..45140c0f0c 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 by Linus Nielsen Feltzing 10 * Copyright (C) 2007 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,119 +16,110 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "config.h"
20#include "cpu.h"
21#include <stdbool.h>
22#include "kernel.h"
23#include "system.h" 19#include "system.h"
24#include "logf.h" 20#include "i2c-meg-fx.h"
25#include "debug.h" 21
26#include "string.h" 22/* Only implements sending bytes for now. Adding receiving bytes should be
27#include "generic_i2c.h" 23 straightforward if needed. No yielding is present since the calls only
28 24 involve setting audio codec registers - a very rare event. */
29static void i2c_sda_output(void) 25
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)
30{ 42{
31 GPECON |= (1 << 30); 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;
32} 46}
33 47
34static void i2c_sda_input(void) 48static int i2c_start(void)
35{ 49{
36 GPECON &= ~(3 << 30); 50 /* Generate START */
51 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
52 return i2c_getack();
37} 53}
38 54
39static void i2c_sda_lo(void) 55static void i2c_stop(void)
40{ 56{
41 GPEDAT &= ~(1 << 15); 57 /* Generate STOP */
58 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
59 /* Clear pending interrupt to continue */
60 IICCON &= ~I2C_TXRX_INTPND;
42} 61}
43 62
44static void i2c_sda_hi(void) 63static int i2c_outb(unsigned char byte)
45{ 64{
46 GPEDAT |= (1 << 15); 65 /* Write byte to shift register */
66 IICDS = byte;
67 /* Clear pending interrupt to continue */
68 IICCON &= ~I2C_TXRX_INTPND;
69 return i2c_getack();
47} 70}
48 71
49static int i2c_sda(void) 72void i2c_write(int addr, const unsigned char *buf, int count)
50{ 73{
51 return GPEDAT & (1 << 15); 74 /* Turn on I2C clock */
52} 75 CLKCON |= (1 << 16);
53 76
54static void i2c_scl_output(void) 77 /* Set mode to master transmitter and enable lines */
55{ 78 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
56 GPECON |= (1 << 28);
57}
58 79
59static void i2c_scl_input(void) 80 /* Wait for bus to be available */
60{ 81 if (WAIT_COND(!(IICSTAT & I2C_BUSY), COND_RET))
61 GPECON &= ~(3 << 28); 82 {
62} 83 /* Send slave address and then data */
84 IICCON &= ~I2C_TXRX_INTPND;
85 IICCON |= I2C_TXRX_INTENB;
63 86
64static void i2c_scl_lo(void) 87 IICDS = addr & 0xfe;
65{
66 GPEDAT &= ~(1 << 14);
67}
68 88
69static int i2c_scl(void) 89 if (i2c_start() == 0)
70{ 90 while (count-- > 0 && i2c_outb(*buf++) == 0);
71 return GPEDAT & (1 << 14);
72}
73
74static void i2c_scl_hi(void)
75{
76 i2c_scl_input();
77 while(!i2c_scl());
78 GPEDAT |= (1 << 14);
79 i2c_scl_output();
80}
81 91
92 i2c_stop();
82 93
94 IICCON &= ~I2C_TXRX_INTENB;
95 }
83 96
84static void i2c_delay(void) 97 /* Go back to slave receive mode and disable lines */
85{ 98 IICSTAT = 0;
86 unsigned _x;
87 99
88 /* The i2c can clock at 500KHz: 2uS period -> 1uS half period */ 100 /* Turn off I2C clock */
89 /* about 30 cycles overhead + X * 7 */ 101 CLKCON &= ~(1 << 16);
90 /* 300MHz: 1000nS @3.36nS/cyc = 297cyc: X = 38*/
91 /* 100MHz: 1000nS @10nS/cyc = 100cyc : X = 10 */
92 for (_x = 38; _x; _x--)
93 {
94 /* burn CPU cycles */
95 /* gcc makes it an inc loop - check with objdump for asm timing */
96 }
97} 102}
98 103
104void i2c_init(void)
105{
106 /* We poll I2C interrupts */
107 INTMSK |= (1 << 27);
99 108
109 /* Turn on I2C clock */
110 CLKCON |= (1 << 16);
100 111
101struct i2c_interface s3c2440_i2c = { 112 /* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */
102 0x34, /* Address */ 113 GPECON = (GPECON & ~((3 << 30) | (3 << 28))) |
103 114 ((2 << 30) | (2 << 28));
104 /* Bit-banged interface definitions */
105 i2c_scl_hi, /* Drive SCL high, might sleep on clk stretch */
106 i2c_scl_lo, /* Drive SCL low */
107 i2c_sda_hi, /* Drive SDA high */
108 i2c_sda_lo, /* Drive SDA low */
109 i2c_sda_input, /* Set SDA as input */
110 i2c_sda_output, /* Set SDA as output */
111 i2c_scl_input, /* Set SCL as input */
112 i2c_scl_output, /* Set SCL as output */
113 i2c_scl, /* Read SCL, returns 0 or nonzero */
114 i2c_sda, /* Read SDA, returns 0 or nonzero */
115 115
116 i2c_delay, /* START SDA hold time (tHD:SDA) */ 116 /* Bus ACK, IICCLK: fPCLK / 16, Rx/Tx Int: Disable, Tx clock: IICCLK/8 */
117 i2c_delay, /* SDA hold time (tHD:DAT) */ 117 /* OF PCLK: 49.1568MHz / 16 / 8 = 384.0375 kHz */
118 i2c_delay, /* SDA setup time (tSU:DAT) */ 118 IICCON = (7 << 0);
119 i2c_delay, /* STOP setup time (tSU:STO) */
120 i2c_delay, /* Rep. START setup time (tSU:STA) */
121 i2c_delay, /* SCL high period (tHIGH) */
122};
123 119
124void i2c_init(void) 120 /* SDA line delayed 0 PCLKs */
125{ 121 IICLC = (0 << 0);
126 /* Set GPE15 (SDA) and GPE14 (SCL) to 1 */
127 GPECON = (GPECON & ~(0xF<<28)) | 5<<28;
128 i2c_add_node(&s3c2440_i2c);
129}
130 122
131void i2c_send(int bus_address, int reg_address, const unsigned char buf) 123 /* Turn off I2C clock */
132{ 124 CLKCON &= ~(1 << 16);
133 i2c_write_data(bus_address, reg_address, &buf, 1);
134} 125}