blob: 2e5f202307ec84b89bea6a2cfd6aa6e2f8bb36b4 [file] [log] [blame]
Linus Nielsen Feltzing2a2d3462006-02-22 14:50:57 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Linus Nielsen Feltzing
11 *
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.
Linus Nielsen Feltzing2a2d3462006-02-22 14:50:57 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "cpu.h"
23#include <stdbool.h>
24#include <stdlib.h>
25#include "debug.h"
26#include "logf.h"
27#include "generic_i2c.h"
28
29int i2c_num_ifs = 0;
30struct i2c_interface *i2c_if[5];
31
32static void i2c_start(struct i2c_interface *iface)
33{
34 iface->sda_hi();
35 iface->scl_hi();
36 iface->sda_lo();
37 iface->delay_hd_sta();
38 iface->scl_lo();
39}
40
41static void i2c_stop(struct i2c_interface *iface)
42{
43 iface->sda_lo();
44 iface->scl_hi();
45 iface->delay_su_sto();
46 iface->sda_hi();
47}
48
49static void i2c_ack(struct i2c_interface *iface, bool ack)
50{
51 iface->scl_lo();
52 if ( ack )
53 iface->sda_lo();
54 else
55 iface->sda_hi();
56
57 iface->delay_su_dat();
58 iface->scl_hi();
59 iface->delay_thigh();
60 iface->scl_lo();
61}
62
63static int i2c_getack(struct i2c_interface *iface)
64{
65 int ret = 1;
66
67 iface->sda_input();
68 iface->delay_su_dat();
69 iface->scl_hi();
70
71 if (iface->sda())
72 ret = 0; /* ack failed */
73
74 iface->delay_thigh();
75 iface->scl_lo();
76 iface->sda_hi();
77 iface->sda_output();
78 iface->delay_hd_dat();
79 return ret;
80}
81
82static unsigned char i2c_inb(struct i2c_interface *iface, bool ack)
83{
84 int i;
85 unsigned char byte = 0;
86
87 /* clock in each bit, MSB first */
88 for ( i=0x80; i; i>>=1 ) {
89 iface->sda_input();
90 iface->scl_hi();
91 iface->delay_thigh();
92 if (iface->sda())
93 byte |= i;
94 iface->scl_lo();
95 iface->delay_hd_dat();
96 iface->sda_output();
97 }
98
99 i2c_ack(iface, ack);
100
101 return byte;
102}
103
104static void i2c_outb(struct i2c_interface *iface, unsigned char byte)
105{
106 int i;
107
108 /* clock out each bit, MSB first */
109 for (i=0x80; i; i>>=1) {
110 if (i & byte)
111 iface->sda_hi();
112 else
113 iface->sda_lo();
114 iface->delay_su_dat();
115 iface->scl_hi();
116 iface->delay_thigh();
117 iface->scl_lo();
118 iface->delay_hd_dat();
119 }
120
121 iface->sda_hi();
122}
123
124static struct i2c_interface *find_if(int address)
125{
126 int i;
127
128 for(i = 0;i < i2c_num_ifs;i++) {
129 if(i2c_if[i]->address == address)
130 return i2c_if[i];
131 }
132 return NULL;
133}
134
135int i2c_write_data(int bus_address, int address,
136 const unsigned char* buf, int count)
137{
138 int i;
139 int ret = 0;
140 struct i2c_interface *iface = find_if(bus_address);
141 if(!iface)
142 return -1;
143
144 i2c_start(iface);
145 i2c_outb(iface, iface->address & 0xfe);
146 if (i2c_getack(iface)) {
147 i2c_outb(iface, address);
148 if (i2c_getack(iface)) {
149 for(i = 0;i < count;i++) {
150 i2c_outb(iface, buf[i]);
151 if (!i2c_getack(iface)) {
152 ret = -3;
153 break;
154 }
155 }
156 } else {
157 ret = -2;
158 }
159 } else {
160 logf("i2c_write_data() - no ack\n");
161 ret = -1;
162 }
163
164 i2c_stop(iface);
165 return ret;
166}
167
168int i2c_read_data(int bus_address, int address,
169 unsigned char* buf, int count)
170{
171 int i;
172 int ret = 0;
173 struct i2c_interface *iface = find_if(bus_address);
174 if(!iface)
175 return -1;
176
177 i2c_start(iface);
178 i2c_outb(iface, iface->address & 0xfe);
179 if (i2c_getack(iface)) {
180 i2c_outb(iface, address);
181 if (i2c_getack(iface)) {
182 i2c_start(iface);
183 i2c_outb(iface, iface->address | 1);
184 if (i2c_getack(iface)) {
185 for(i = 0;i < count-1;i++)
186 buf[i] = i2c_inb(iface, true);
187
188 buf[i] = i2c_inb(iface, false);
189 } else {
190 ret = -3;
191 }
192 } else {
193 ret = -2;
194 }
195 } else {
196 ret = -1;
197 }
198
199 i2c_stop(iface);
200 return ret;
201}
202
203void i2c_add_node(struct i2c_interface *iface)
204{
205 i2c_if[i2c_num_ifs++] = iface;
206}