diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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.c | 347 |
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 | ||
15 | pcd8584t/pcf8584 does not show the correct way to address the i2c bus. | ||
16 | Based on the information on the I2C bus itself and the remainder of | ||
17 | the Phillips docs the following algorithims apper to be correct. I am | ||
18 | fairly 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 | |||
58 | int 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 | |||
82 | void 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 | |||
89 | void 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 | |||
101 | void inline vfc_i2c_delay(struct vfc_dev *dev) | ||
102 | { | ||
103 | vfc_i2c_delay_no_busy(dev, 100); | ||
104 | } | ||
105 | |||
106 | int 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 | |||
113 | int 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 | |||
131 | int 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 | |||
143 | int 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) | ||
161 | int 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 | |||
212 | int 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 | |||
235 | int 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 | |||
257 | int 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 | |||
294 | int 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 | } | ||
334 | done: | ||
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 | |||