blob: 8300944243ffb7d8e85c47b483fed85a092f6a7f [file] [log] [blame]
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Michael Sevakis7fb0f712007-06-26 02:11:30 +000010 * Copyright (C) 2007 by Michael Sevakis
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000011 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000021#include "system.h"
Michael Sevakis7fb0f712007-06-26 02:11:30 +000022#include "i2c-meg-fx.h"
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000023
Michael Sevakis5f1590b2008-03-30 05:38:28 +000024static 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 */
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000028
Michael Sevakis7fb0f712007-06-26 02:11:30 +000029static void i2c_stop(void)
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000030{
Michael Sevakis7fb0f712007-06-26 02:11:30 +000031 /* Generate STOP */
32 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000033
Michael Sevakis5f1590b2008-03-30 05:38:28 +000034 /* No more interrupts, clear pending interrupt to continue */
35 IICCON &= ~(I2C_TXRX_INTPND | I2C_TXRX_INTENB);
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000036}
37
Michael Sevakis7fb0f712007-06-26 02:11:30 +000038void i2c_write(int addr, const unsigned char *buf, int count)
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000039{
Michael Sevakis5f1590b2008-03-30 05:38:28 +000040 if (count <= 0)
41 return;
42
43 mutex_lock(&i2c_mtx);
44
Michael Sevakis7fb0f712007-06-26 02:11:30 +000045 /* Turn on I2C clock */
Michael Sevakisa65406e2008-03-31 01:29:50 +000046 s3c_regset(&CLKCON, 1 << 16);
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000047
Michael Sevakis7fb0f712007-06-26 02:11:30 +000048 /* Set mode to master transmitter and enable lines */
49 IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000050
Michael Sevakis5f1590b2008-03-30 05:38:28 +000051 /* 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
Michael Sevakis3c8d93e2008-04-01 03:55:02 +000067 if (wakeup_wait(&i2c_wake, HZ) != OBJ_WAIT_SUCCEEDED)
Steve Gotthardt2aa3e3f2007-01-04 03:31:03 +000068 {
Michael Sevakis5f1590b2008-03-30 05:38:28 +000069 /* Something went wrong - stop transmission */
70 int oldlevel = disable_irq_save();
Michael Sevakis7fb0f712007-06-26 02:11:30 +000071 i2c_stop();
Michael Sevakis5f1590b2008-03-30 05:38:28 +000072 restore_irq(oldlevel);
Steve Gotthardt2aa3e3f2007-01-04 03:31:03 +000073 }
Michael Sevakis7fb0f712007-06-26 02:11:30 +000074
75 /* Go back to slave receive mode and disable lines */
76 IICSTAT = 0;
77
78 /* Turn off I2C clock */
Michael Sevakisa65406e2008-03-31 01:29:50 +000079 s3c_regclr(&CLKCON, 1 << 16);
Michael Sevakis5f1590b2008-03-30 05:38:28 +000080
81 mutex_unlock(&i2c_mtx);
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000082}
83
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000084void i2c_init(void)
85{
Michael Sevakis5f1590b2008-03-30 05:38:28 +000086 /* 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 */
Michael Sevakisa65406e2008-03-31 01:29:50 +000095 s3c_regclr(&INTMOD, IIC_MASK);
96 s3c_regclr(&INTMSK, IIC_MASK);
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +000097
Michael Sevakis7fb0f712007-06-26 02:11:30 +000098 /* Turn on I2C clock */
Michael Sevakisa65406e2008-03-31 01:29:50 +000099 s3c_regset(&CLKCON, 1 << 16);
Michael Sevakis7fb0f712007-06-26 02:11:30 +0000100
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 */
Michael Sevakisa65406e2008-03-31 01:29:50 +0000113 s3c_regclr(&CLKCON, 1 << 16);
Marcoen Hirschberg8e1e6f92006-09-29 10:54:01 +0000114}
Michael Sevakis5f1590b2008-03-30 05:38:28 +0000115
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}