aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char/vfc_i2c.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/sbus/char/vfc_i2c.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/sbus/char/vfc_i2c.c')
-rw-r--r--drivers/sbus/char/vfc_i2c.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
new file mode 100644
index 000000000000..95e3cebf792c
--- /dev/null
+++ b/drivers/sbus/char/vfc_i2c.c
@@ -0,0 +1,347 @@
1/*
2 * drivers/sbus/char/vfc_i2c.c
3 *
4 * Driver for the Videopix Frame Grabber.
5 *
6 * Functions that support the Phillips i2c(I squared C) bus on the vfc
7 * Documentation for the Phillips I2C bus can be found on the
8 * phillips home page
9 *
10 * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
11 *
12 */
13
14/* NOTE: It seems to me that the documentation regarding the
15pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
16Based on the information on the I2C bus itself and the remainder of
17the Phillips docs the following algorithims apper to be correct. I am
18fairly certain that the flowcharts in the phillips docs are wrong. */
19
20
21#include <linux/kernel.h>
22#include <linux/string.h>
23#include <linux/slab.h>
24#include <linux/errno.h>
25#include <linux/sched.h>
26#include <linux/wait.h>
27#include <linux/delay.h>
28#include <asm/openprom.h>
29#include <asm/oplib.h>
30#include <asm/io.h>
31#include <asm/system.h>
32#include <asm/sbus.h>
33
34#if 0
35#define VFC_I2C_DEBUG
36#endif
37
38#include "vfc.h"
39#include "vfc_i2c.h"
40
41#define WRITE_S1(__val) \
42 sbus_writel(__val, &dev->regs->i2c_s1)
43#define WRITE_REG(__val) \
44 sbus_writel(__val, &dev->regs->i2c_reg)
45
46#define VFC_I2C_READ (0x1)
47#define VFC_I2C_WRITE (0x0)
48
49/******
50 The i2c bus controller chip on the VFC is a pcd8584t, but
51 phillips claims it doesn't exist. As far as I can tell it is
52 identical to the PCF8584 so I treat it like it is the pcf8584.
53
54 NOTE: The pcf8584 only cares
55 about the msb of the word you feed it
56*****/
57
58int vfc_pcf8584_init(struct vfc_dev *dev)
59{
60 /* This will also choose register S0_OWN so we can set it. */
61 WRITE_S1(RESET);
62
63 /* The pcf8584 shifts this value left one bit and uses
64 * it as its i2c bus address.
65 */
66 WRITE_REG(0x55000000);
67
68 /* This will set the i2c bus at the same speed sun uses,
69 * and set another magic bit.
70 */
71 WRITE_S1(SELECT(S2));
72 WRITE_REG(0x14000000);
73
74 /* Enable the serial port, idle the i2c bus and set
75 * the data reg to s0.
76 */
77 WRITE_S1(CLEAR_I2C_BUS);
78 udelay(100);
79 return 0;
80}
81
82void vfc_i2c_delay_wakeup(struct vfc_dev *dev)
83{
84 /* Used to profile code and eliminate too many delays */
85 VFC_I2C_DEBUG_PRINTK(("vfc%d: Delaying\n", dev->instance));
86 wake_up(&dev->poll_wait);
87}
88
89void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs)
90{
91 init_timer(&dev->poll_timer);
92 dev->poll_timer.expires = jiffies +
93 ((unsigned long)usecs*(HZ))/1000000;
94 dev->poll_timer.data=(unsigned long)dev;
95 dev->poll_timer.function=(void *)(unsigned long)vfc_i2c_delay_wakeup;
96 add_timer(&dev->poll_timer);
97 sleep_on(&dev->poll_wait);
98 del_timer(&dev->poll_timer);
99}
100
101void inline vfc_i2c_delay(struct vfc_dev *dev)
102{
103 vfc_i2c_delay_no_busy(dev, 100);
104}
105
106int vfc_init_i2c_bus(struct vfc_dev *dev)
107{
108 WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK);
109 vfc_i2c_reset_bus(dev);
110 return 0;
111}
112
113int vfc_i2c_reset_bus(struct vfc_dev *dev)
114{
115 VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
116 dev->instance));
117 if(dev == NULL)
118 return -EINVAL;
119 if(dev->regs == NULL)
120 return -EINVAL;
121 WRITE_S1(SEND_I2C_STOP);
122 WRITE_S1(SEND_I2C_STOP | ACK);
123 vfc_i2c_delay(dev);
124 WRITE_S1(CLEAR_I2C_BUS);
125 VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
126 dev->instance,
127 sbus_readl(&dev->regs->i2c_s1)));
128 return 0;
129}
130
131int vfc_i2c_wait_for_bus(struct vfc_dev *dev)
132{
133 int timeout = 1000;
134
135 while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) {
136 if(!(timeout--))
137 return -ETIMEDOUT;
138 vfc_i2c_delay(dev);
139 }
140 return 0;
141}
142
143int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
144{
145 int timeout = 1000;
146 int s1;
147
148 while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) {
149 if (!(timeout--))
150 return -ETIMEDOUT;
151 vfc_i2c_delay(dev);
152 }
153 if (ack == VFC_I2C_ACK_CHECK) {
154 if(s1 & LRB)
155 return -EIO;
156 }
157 return 0;
158}
159
160#define SHIFT(a) ((a) << 24)
161int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode)
162{
163 int ret, raddr;
164#if 1
165 WRITE_S1(SEND_I2C_STOP | ACK);
166 WRITE_S1(SELECT(S0) | ENABLE_SERIAL);
167 vfc_i2c_delay(dev);
168#endif
169
170 switch(mode) {
171 case VFC_I2C_READ:
172 raddr = SHIFT(((unsigned int)addr | 0x1));
173 WRITE_REG(raddr);
174 VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n",
175 dev->instance, addr | 0x1));
176 break;
177 case VFC_I2C_WRITE:
178 raddr = SHIFT((unsigned int)addr & ~0x1);
179 WRITE_REG(raddr);
180 VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
181 dev->instance, addr & ~0x1));
182 break;
183 default:
184 return -EINVAL;
185 };
186
187 WRITE_S1(SEND_I2C_START);
188 vfc_i2c_delay(dev);
189 ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
190 for the
191 i2c send
192 to finish
193 here but
194 Sun
195 doesn't,
196 hmm */
197 if (ret) {
198 printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
199 dev->instance);
200 return ret;
201 } else if (mode == VFC_I2C_READ) {
202 if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) {
203 printk(KERN_WARNING
204 "vfc%d: returned slave address "
205 "mismatch(%x,%x)\n",
206 dev->instance, raddr, ret);
207 }
208 }
209 return 0;
210}
211
212int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte)
213{
214 int ret;
215 u32 val = SHIFT((unsigned int)*byte);
216
217 WRITE_REG(val);
218
219 ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK);
220 switch(ret) {
221 case -ETIMEDOUT:
222 printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
223 dev->instance);
224 break;
225 case -EIO:
226 ret = XMIT_LAST_BYTE;
227 break;
228 default:
229 break;
230 };
231
232 return ret;
233}
234
235int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, int last)
236{
237 int ret;
238
239 if (last) {
240 WRITE_REG(NEGATIVE_ACK);
241 VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
242 dev->instance));
243 } else {
244 WRITE_S1(ACK);
245 }
246
247 ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK);
248 if(ret) {
249 printk(KERN_ERR "vfc%d: "
250 "VFC recv byte timed out\n",
251 dev->instance);
252 }
253 *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24;
254 return ret;
255}
256
257int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
258 char *buf, int count)
259{
260 int ret, last;
261
262 if(!(count && buf && dev && dev->regs) )
263 return -EINVAL;
264
265 if ((ret = vfc_i2c_wait_for_bus(dev))) {
266 printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
267 return ret;
268 }
269
270 if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) {
271 WRITE_S1(SEND_I2C_STOP);
272 vfc_i2c_delay(dev);
273 return ret;
274 }
275
276 last = 0;
277 while (count--) {
278 if (!count)
279 last = 1;
280 if ((ret = vfc_i2c_recv_byte(dev, buf, last))) {
281 printk(KERN_ERR "vfc%d: "
282 "VFC error while receiving byte\n",
283 dev->instance);
284 WRITE_S1(SEND_I2C_STOP);
285 ret = -EINVAL;
286 }
287 buf++;
288 }
289 WRITE_S1(SEND_I2C_STOP | ACK);
290 vfc_i2c_delay(dev);
291 return ret;
292}
293
294int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr,
295 char *buf, int count)
296{
297 int ret;
298
299 if (!(buf && dev && dev->regs))
300 return -EINVAL;
301
302 if ((ret = vfc_i2c_wait_for_bus(dev))) {
303 printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
304 return ret;
305 }
306
307 if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) {
308 WRITE_S1(SEND_I2C_STOP);
309 vfc_i2c_delay(dev);
310 return ret;
311 }
312
313 while(count--) {
314 ret = vfc_i2c_xmit_byte(dev, buf);
315 switch(ret) {
316 case XMIT_LAST_BYTE:
317 VFC_I2C_DEBUG_PRINTK(("vfc%d: "
318 "Receiver ended transmission with "
319 " %d bytes remaining\n",
320 dev->instance, count));
321 ret = 0;
322 goto done;
323 break;
324 case 0:
325 break;
326 default:
327 printk(KERN_ERR "vfc%d: "
328 "VFC error while sending byte\n", dev->instance);
329 break;
330 };
331
332 buf++;
333 }
334done:
335 WRITE_S1(SEND_I2C_STOP | ACK);
336 vfc_i2c_delay(dev);
337 return ret;
338}
339
340
341
342
343
344
345
346
347