summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s3c2440/i2c-s3c2440.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s3c2440/i2c-s3c2440.c')
-rw-r--r--firmware/target/arm/s3c2440/i2c-s3c2440.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/firmware/target/arm/s3c2440/i2c-s3c2440.c b/firmware/target/arm/s3c2440/i2c-s3c2440.c
new file mode 100644
index 0000000000..4669186a4c
--- /dev/null
+++ b/firmware/target/arm/s3c2440/i2c-s3c2440.c
@@ -0,0 +1,144 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "system.h"
22#include "i2c-s3c2440.h"
23
24static struct wakeup i2c_wake; /* Transfer completion signal */
25static struct mutex i2c_mtx; /* Mutual exclusion */
26static unsigned char *buf_ptr; /* Next byte to transfer */
27static int buf_count; /* Number of bytes remaining to transfer */
28
29static void i2c_stop(void)
30{
31 /* Generate STOP */
32 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
33
34 /* No more interrupts, clear pending interrupt to continue */
35 IICCON &= ~(I2C_TXRX_INTPND | I2C_TXRX_INTENB);
36}
37
38void i2c_write(int addr, const unsigned char *buf, int count)
39{
40 if (count <= 0)
41 return;
42
43 mutex_lock(&i2c_mtx);
44
45 /* Turn on I2C clock */
46 s3c_regset32(&CLKCON, 1 << 16);
47
48 /* Set mode to master transmitter and enable lines */
49 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
50
51 /* Set buffer start and count */
52 buf_ptr = (unsigned char *)buf;
53 buf_count = count;
54
55 /* Send slave address and then data */
56 SRCPND = IIC_MASK;
57 INTPND = IIC_MASK;
58
59 IICCON |= I2C_TXRX_INTENB;
60
61 /* Load slave address into shift register */
62 IICDS = addr & 0xfe;
63
64 /* Generate START */
65 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
66
67 if (wakeup_wait(&i2c_wake, HZ) != OBJ_WAIT_SUCCEEDED)
68 {
69 /* Something went wrong - stop transmission */
70 int oldlevel = disable_irq_save();
71 i2c_stop();
72 restore_irq(oldlevel);
73 }
74
75 /* Go back to slave receive mode and disable lines */
76 IICSTAT = 0;
77
78 /* Turn off I2C clock */
79 s3c_regclr32(&CLKCON, 1 << 16);
80
81 mutex_unlock(&i2c_mtx);
82}
83
84void i2c_init(void)
85{
86 /* Init kernel objects */
87 wakeup_init(&i2c_wake);
88 mutex_init(&i2c_mtx);
89
90 /* Clear pending source */
91 SRCPND = IIC_MASK;
92 INTPND = IIC_MASK;
93
94 /* Enable i2c interrupt in controller */
95 s3c_regclr32(&INTMOD, IIC_MASK);
96 s3c_regclr32(&INTMSK, IIC_MASK);
97
98 /* Turn on I2C clock */
99 s3c_regset32(&CLKCON, 1 << 16);
100
101 /* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */
102 GPECON = (GPECON & ~((3 << 30) | (3 << 28))) |
103 ((2 << 30) | (2 << 28));
104
105 /* Bus ACK, IICCLK: fPCLK / 16, Rx/Tx Int: Disable, Tx clock: IICCLK/8 */
106 /* OF PCLK: 49.1568MHz / 16 / 8 = 384.0375 kHz */
107 IICCON = (7 << 0);
108
109 /* SDA line delayed 0 PCLKs */
110 IICLC = (0 << 0);
111
112 /* Turn off I2C clock */
113 s3c_regclr32(&CLKCON, 1 << 16);
114}
115
116void IIC(void)
117{
118 for (;;)
119 {
120 /* If ack was received from last byte and bytes are remaining */
121 if (--buf_count >= 0 && (IICSTAT & I2C_ACK_L) == 0)
122 {
123 /* Write next byte to shift register */
124 IICDS = *buf_ptr++;
125
126 /* Clear pending interrupt to continue */
127 IICCON &= ~I2C_TXRX_INTPND;
128 break;
129 }
130
131 /* Finished */
132
133 /* Generate STOP */
134 i2c_stop();
135
136 /* Signal thread */
137 wakeup_signal(&i2c_wake);
138 break;
139 }
140
141 /* Ack */
142 SRCPND = IIC_MASK;
143 INTPND = IIC_MASK;
144}