blob: e976a6e054b34938450d7300d02043f641bead43 [file] [log] [blame]
Barry Wardellc495cda2007-11-11 16:00:33 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * Physical interface of the Philips TEA5767 in iriver H10 series
10 *
11 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000013 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
Barry Wardellc495cda2007-11-11 16:00:33 +000017 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "config.h"
23#include "cpu.h"
24#include "logf.h"
25#include "system.h"
26
27/* cute little functions, atomic read-modify-write */
28
29#define SDA_OUTINIT GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x08)
30#define SDA_HI_IN GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x08)
31#define SDA_LO_OUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x08)
32#define SDA (GPIOD_INPUT_VAL & 0x08)
33
34#define SCL_INPUT GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x10)
35#define SCL_OUTPUT GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x10)
36#define SCL_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x10)
37#define SCL_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL,0x10)
38#define SCL (GPIOD_INPUT_VAL & 0x10)
39
40#define DELAY udelay(2)
41
42static void fmradio_i2c_start(void)
43{
44 SCL_HI;
45 SCL_OUTPUT;
46 SDA_HI_IN;
47 SDA_OUTINIT;
48 DELAY;
49 SDA_LO_OUT;
50 DELAY;
51 SCL_LO;
52}
53
54static void fmradio_i2c_stop(void)
55{
56 SDA_LO_OUT;
57 DELAY;
58 SCL_HI;
59 DELAY;
60 SDA_HI_IN;
61}
62
63/* Generate ACK or NACK */
64static void fmradio_i2c_ack(bool nack)
65{
66 /* Here's the deal. The slave is slow, and sometimes needs to wait
67 before it can receive the acknowledge. Therefore it forces the clock
68 low until it is ready. We need to poll the clock line until it goes
69 high before we release the ack.
70
71 In their infinite wisdom, iriver didn't pull up the SCL line, so
72 we have to drive the SCL high repeatedly to simulate a pullup. */
73
74 if (nack)
75 SDA_HI_IN;
76 else
77 SDA_LO_OUT;
78 DELAY;
79
80 SCL_HI;
81 do
82 {
83 SCL_OUTPUT; /* Set the clock to output */
84 SCL_INPUT; /* Set the clock to input */
85 DELAY;
86 }
87 while(!SCL); /* and wait for the slave to release it */
88
89 SCL_OUTPUT;
90 SCL_LO;
91}
92
93static int fmradio_i2c_getack(void)
94{
95 int ret = 1;
96
97 /* Here's the deal. The slave is slow, and sometimes needs to wait
98 before it can send the acknowledge. Therefore it forces the clock
99 low until it is ready. We need to poll the clock line until it goes
100 high before we read the ack.
101
102 In their infinite wisdom, iriver didn't pull up the SCL line, so
103 we have to drive the SCL high repeatedly to simulate a pullup. */
104
105 SDA_HI_IN;
106 DELAY;
107
108 SCL_HI; /* set clock to high */
109 do
110 {
111 SCL_OUTPUT; /* Set the clock to output */
112 SCL_INPUT; /* Set the clock to input */
113 DELAY;
114 }
115 while(!SCL); /* and wait for the slave to release it */
116
117 if (SDA)
118 ret = 0; /* ack failed */
119
120 SCL_OUTPUT;
121 SCL_LO;
122
123 return ret;
124}
125
126static void fmradio_i2c_outb(unsigned char byte)
127{
128 int i;
129
130 /* clock out each bit, MSB first */
131 for ( i=0x80; i; i>>=1 ) {
132 if ( i & byte )
133 SDA_HI_IN;
134 else
135 SDA_LO_OUT;
136 DELAY;
137 SCL_HI;
138 DELAY;
139 SCL_LO;
Michael Sevakis506d18b2008-01-25 19:17:48 +0000140
141 DELAY;
Barry Wardellc495cda2007-11-11 16:00:33 +0000142 }
143}
144
145static unsigned char fmradio_i2c_inb(void)
146{
147 int i;
148 unsigned char byte = 0;
149
150 SDA_HI_IN;
151 /* clock in each bit, MSB first */
152 for ( i=0x80; i; i>>=1 ) {
153 DELAY;
154 SCL_HI;
155 DELAY;
156 if ( SDA )
157 byte |= i;
158 SCL_LO;
159 }
160
161 return byte;
162}
163
164int fmradio_i2c_write(int address, const unsigned char* buf, int count)
165{
166 int i,x=0;
167
168 fmradio_i2c_start();
169 fmradio_i2c_outb(address & 0xfe);
170 if (fmradio_i2c_getack())
171 {
172 for (i=0; i<count; i++)
173 {
174 fmradio_i2c_outb(buf[i]);
175 if (!fmradio_i2c_getack())
176 {
177 x=-2;
178 break;
179 }
180 }
181 }
182 else
183 {
184 logf("fmradio_i2c_write() - no ack\n");
185 x=-1;
186 }
187 fmradio_i2c_stop();
188 return x;
189}
190
191int fmradio_i2c_read(int address, unsigned char* buf, int count)
192{
193 int i,x=0;
194
195 fmradio_i2c_start();
196 fmradio_i2c_outb(address | 1);
197
198 if (fmradio_i2c_getack())
199 {
200 for (i=count; i>0; i--)
201 {
202 *buf++ = fmradio_i2c_inb();
203 fmradio_i2c_ack(i == 1);
204 }
205 }
206 else
207 x=-1;
208 fmradio_i2c_stop();
209 return x;
210}