diff options
Diffstat (limited to 'drivers/media/video/saa7134/saa7134-i2c.c')
-rw-r--r-- | drivers/media/video/saa7134/saa7134-i2c.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c new file mode 100644 index 00000000000..2d3f6d265bb --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-i2c.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * | ||
3 | * device driver for philips saa7134 based TV cards | ||
4 | * i2c interface support | ||
5 | * | ||
6 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include "saa7134-reg.h" | ||
30 | #include "saa7134.h" | ||
31 | #include <media/v4l2-common.h> | ||
32 | |||
33 | /* ----------------------------------------------------------- */ | ||
34 | |||
35 | static unsigned int i2c_debug; | ||
36 | module_param(i2c_debug, int, 0644); | ||
37 | MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); | ||
38 | |||
39 | static unsigned int i2c_scan; | ||
40 | module_param(i2c_scan, int, 0444); | ||
41 | MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); | ||
42 | |||
43 | #define d1printk if (1 == i2c_debug) printk | ||
44 | #define d2printk if (2 == i2c_debug) printk | ||
45 | |||
46 | #define I2C_WAIT_DELAY 32 | ||
47 | #define I2C_WAIT_RETRY 16 | ||
48 | |||
49 | /* ----------------------------------------------------------- */ | ||
50 | |||
51 | static char *str_i2c_status[] = { | ||
52 | "IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE", | ||
53 | "DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE", | ||
54 | "NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR" | ||
55 | }; | ||
56 | |||
57 | enum i2c_status { | ||
58 | IDLE = 0, // no I2C command pending | ||
59 | DONE_STOP = 1, // I2C command done and STOP executed | ||
60 | BUSY = 2, // executing I2C command | ||
61 | TO_SCL = 3, // executing I2C command, time out on clock stretching | ||
62 | TO_ARB = 4, // time out on arbitration trial, still trying | ||
63 | DONE_WRITE = 5, // I2C command done and awaiting next write command | ||
64 | DONE_READ = 6, // I2C command done and awaiting next read command | ||
65 | DONE_WRITE_TO = 7, // see 5, and time out on status echo | ||
66 | DONE_READ_TO = 8, // see 6, and time out on status echo | ||
67 | NO_DEVICE = 9, // no acknowledge on device slave address | ||
68 | NO_ACKN = 10, // no acknowledge after data byte transfer | ||
69 | BUS_ERR = 11, // bus error | ||
70 | ARB_LOST = 12, // arbitration lost during transfer | ||
71 | SEQ_ERR = 13, // erroneous programming sequence | ||
72 | ST_ERR = 14, // wrong status echoing | ||
73 | SW_ERR = 15 // software error | ||
74 | }; | ||
75 | |||
76 | static char *str_i2c_attr[] = { | ||
77 | "NOP", "STOP", "CONTINUE", "START" | ||
78 | }; | ||
79 | |||
80 | enum i2c_attr { | ||
81 | NOP = 0, // no operation on I2C bus | ||
82 | STOP = 1, // stop condition, no associated byte transfer | ||
83 | CONTINUE = 2, // continue with byte transfer | ||
84 | START = 3 // start condition with byte transfer | ||
85 | }; | ||
86 | |||
87 | static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) | ||
88 | { | ||
89 | enum i2c_status status; | ||
90 | |||
91 | status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; | ||
92 | d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, | ||
93 | str_i2c_status[status]); | ||
94 | return status; | ||
95 | } | ||
96 | |||
97 | static inline void i2c_set_status(struct saa7134_dev *dev, | ||
98 | enum i2c_status status) | ||
99 | { | ||
100 | d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, | ||
101 | str_i2c_status[status]); | ||
102 | saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); | ||
103 | } | ||
104 | |||
105 | static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) | ||
106 | { | ||
107 | d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, | ||
108 | str_i2c_attr[attr]); | ||
109 | saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); | ||
110 | } | ||
111 | |||
112 | static inline int i2c_is_error(enum i2c_status status) | ||
113 | { | ||
114 | switch (status) { | ||
115 | case NO_DEVICE: | ||
116 | case NO_ACKN: | ||
117 | case BUS_ERR: | ||
118 | case ARB_LOST: | ||
119 | case SEQ_ERR: | ||
120 | case ST_ERR: | ||
121 | return true; | ||
122 | default: | ||
123 | return false; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static inline int i2c_is_idle(enum i2c_status status) | ||
128 | { | ||
129 | switch (status) { | ||
130 | case IDLE: | ||
131 | case DONE_STOP: | ||
132 | return true; | ||
133 | default: | ||
134 | return false; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static inline int i2c_is_busy(enum i2c_status status) | ||
139 | { | ||
140 | switch (status) { | ||
141 | case BUSY: | ||
142 | case TO_SCL: | ||
143 | case TO_ARB: | ||
144 | return true; | ||
145 | default: | ||
146 | return false; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static int i2c_is_busy_wait(struct saa7134_dev *dev) | ||
151 | { | ||
152 | enum i2c_status status; | ||
153 | int count; | ||
154 | |||
155 | for (count = 0; count < I2C_WAIT_RETRY; count++) { | ||
156 | status = i2c_get_status(dev); | ||
157 | if (!i2c_is_busy(status)) | ||
158 | break; | ||
159 | saa_wait(I2C_WAIT_DELAY); | ||
160 | } | ||
161 | if (I2C_WAIT_RETRY == count) | ||
162 | return false; | ||
163 | return true; | ||
164 | } | ||
165 | |||
166 | static int i2c_reset(struct saa7134_dev *dev) | ||
167 | { | ||
168 | enum i2c_status status; | ||
169 | int count; | ||
170 | |||
171 | d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); | ||
172 | status = i2c_get_status(dev); | ||
173 | if (!i2c_is_error(status)) | ||
174 | return true; | ||
175 | i2c_set_status(dev,status); | ||
176 | |||
177 | for (count = 0; count < I2C_WAIT_RETRY; count++) { | ||
178 | status = i2c_get_status(dev); | ||
179 | if (!i2c_is_error(status)) | ||
180 | break; | ||
181 | udelay(I2C_WAIT_DELAY); | ||
182 | } | ||
183 | if (I2C_WAIT_RETRY == count) | ||
184 | return false; | ||
185 | |||
186 | if (!i2c_is_idle(status)) | ||
187 | return false; | ||
188 | |||
189 | i2c_set_attr(dev,NOP); | ||
190 | return true; | ||
191 | } | ||
192 | |||
193 | static inline int i2c_send_byte(struct saa7134_dev *dev, | ||
194 | enum i2c_attr attr, | ||
195 | unsigned char data) | ||
196 | { | ||
197 | enum i2c_status status; | ||
198 | __u32 dword; | ||
199 | |||
200 | /* have to write both attr + data in one 32bit word */ | ||
201 | dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); | ||
202 | dword &= 0x0f; | ||
203 | dword |= (attr << 6); | ||
204 | dword |= ((__u32)data << 8); | ||
205 | dword |= 0x00 << 16; /* 100 kHz */ | ||
206 | // dword |= 0x40 << 16; /* 400 kHz */ | ||
207 | dword |= 0xf0 << 24; | ||
208 | saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); | ||
209 | d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); | ||
210 | |||
211 | if (!i2c_is_busy_wait(dev)) | ||
212 | return -EIO; | ||
213 | status = i2c_get_status(dev); | ||
214 | if (i2c_is_error(status)) | ||
215 | return -EIO; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static inline int i2c_recv_byte(struct saa7134_dev *dev) | ||
220 | { | ||
221 | enum i2c_status status; | ||
222 | unsigned char data; | ||
223 | |||
224 | i2c_set_attr(dev,CONTINUE); | ||
225 | if (!i2c_is_busy_wait(dev)) | ||
226 | return -EIO; | ||
227 | status = i2c_get_status(dev); | ||
228 | if (i2c_is_error(status)) | ||
229 | return -EIO; | ||
230 | data = saa_readb(SAA7134_I2C_DATA); | ||
231 | d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); | ||
232 | return data; | ||
233 | } | ||
234 | |||
235 | static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
236 | struct i2c_msg *msgs, int num) | ||
237 | { | ||
238 | struct saa7134_dev *dev = i2c_adap->algo_data; | ||
239 | enum i2c_status status; | ||
240 | unsigned char data; | ||
241 | int addr,rc,i,byte; | ||
242 | |||
243 | status = i2c_get_status(dev); | ||
244 | if (!i2c_is_idle(status)) | ||
245 | if (!i2c_reset(dev)) | ||
246 | return -EIO; | ||
247 | |||
248 | d2printk("start xfer\n"); | ||
249 | d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); | ||
250 | for (i = 0; i < num; i++) { | ||
251 | if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { | ||
252 | /* send address */ | ||
253 | d2printk("send address\n"); | ||
254 | addr = msgs[i].addr << 1; | ||
255 | if (msgs[i].flags & I2C_M_RD) | ||
256 | addr |= 1; | ||
257 | if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) { | ||
258 | /* workaround for a saa7134 i2c bug | ||
259 | * needed to talk to the mt352 demux | ||
260 | * thanks to pinnacle for the hint */ | ||
261 | int quirk = 0xfe; | ||
262 | d1printk(" [%02x quirk]",quirk); | ||
263 | i2c_send_byte(dev,START,quirk); | ||
264 | i2c_recv_byte(dev); | ||
265 | } | ||
266 | d1printk(" < %02x", addr); | ||
267 | rc = i2c_send_byte(dev,START,addr); | ||
268 | if (rc < 0) | ||
269 | goto err; | ||
270 | } | ||
271 | if (msgs[i].flags & I2C_M_RD) { | ||
272 | /* read bytes */ | ||
273 | d2printk("read bytes\n"); | ||
274 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
275 | d1printk(" ="); | ||
276 | rc = i2c_recv_byte(dev); | ||
277 | if (rc < 0) | ||
278 | goto err; | ||
279 | d1printk("%02x", rc); | ||
280 | msgs[i].buf[byte] = rc; | ||
281 | } | ||
282 | } else { | ||
283 | /* write bytes */ | ||
284 | d2printk("write bytes\n"); | ||
285 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
286 | data = msgs[i].buf[byte]; | ||
287 | d1printk(" %02x", data); | ||
288 | rc = i2c_send_byte(dev,CONTINUE,data); | ||
289 | if (rc < 0) | ||
290 | goto err; | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | d2printk("xfer done\n"); | ||
295 | d1printk(" >"); | ||
296 | i2c_set_attr(dev,STOP); | ||
297 | rc = -EIO; | ||
298 | if (!i2c_is_busy_wait(dev)) | ||
299 | goto err; | ||
300 | status = i2c_get_status(dev); | ||
301 | if (i2c_is_error(status)) | ||
302 | goto err; | ||
303 | /* ensure that the bus is idle for at least one bit slot */ | ||
304 | msleep(1); | ||
305 | |||
306 | d1printk("\n"); | ||
307 | return num; | ||
308 | err: | ||
309 | if (1 == i2c_debug) { | ||
310 | status = i2c_get_status(dev); | ||
311 | printk(" ERROR: %s\n",str_i2c_status[status]); | ||
312 | } | ||
313 | return rc; | ||
314 | } | ||
315 | |||
316 | /* ----------------------------------------------------------- */ | ||
317 | |||
318 | static u32 functionality(struct i2c_adapter *adap) | ||
319 | { | ||
320 | return I2C_FUNC_SMBUS_EMUL; | ||
321 | } | ||
322 | |||
323 | static struct i2c_algorithm saa7134_algo = { | ||
324 | .master_xfer = saa7134_i2c_xfer, | ||
325 | .functionality = functionality, | ||
326 | }; | ||
327 | |||
328 | static struct i2c_adapter saa7134_adap_template = { | ||
329 | .owner = THIS_MODULE, | ||
330 | .name = "saa7134", | ||
331 | .algo = &saa7134_algo, | ||
332 | }; | ||
333 | |||
334 | static struct i2c_client saa7134_client_template = { | ||
335 | .name = "saa7134 internal", | ||
336 | }; | ||
337 | |||
338 | /* ----------------------------------------------------------- */ | ||
339 | |||
340 | static int | ||
341 | saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) | ||
342 | { | ||
343 | unsigned char buf; | ||
344 | int i,err; | ||
345 | |||
346 | dev->i2c_client.addr = 0xa0 >> 1; | ||
347 | buf = 0; | ||
348 | if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { | ||
349 | printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", | ||
350 | dev->name,err); | ||
351 | return -1; | ||
352 | } | ||
353 | if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) { | ||
354 | printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", | ||
355 | dev->name,err); | ||
356 | return -1; | ||
357 | } | ||
358 | for (i = 0; i < len; i++) { | ||
359 | if (0 == (i % 16)) | ||
360 | printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i); | ||
361 | printk(" %02x",eedata[i]); | ||
362 | if (15 == (i % 16)) | ||
363 | printk("\n"); | ||
364 | } | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static char *i2c_devs[128] = { | ||
369 | [ 0x20 ] = "mpeg encoder (saa6752hs)", | ||
370 | [ 0xa0 >> 1 ] = "eeprom", | ||
371 | [ 0xc0 >> 1 ] = "tuner (analog)", | ||
372 | [ 0x86 >> 1 ] = "tda9887", | ||
373 | [ 0x5a >> 1 ] = "remote control", | ||
374 | }; | ||
375 | |||
376 | static void do_i2c_scan(char *name, struct i2c_client *c) | ||
377 | { | ||
378 | unsigned char buf; | ||
379 | int i,rc; | ||
380 | |||
381 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { | ||
382 | c->addr = i; | ||
383 | rc = i2c_master_recv(c,&buf,0); | ||
384 | if (rc < 0) | ||
385 | continue; | ||
386 | printk("%s: i2c scan: found device @ 0x%x [%s]\n", | ||
387 | name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | int saa7134_i2c_register(struct saa7134_dev *dev) | ||
392 | { | ||
393 | dev->i2c_adap = saa7134_adap_template; | ||
394 | dev->i2c_adap.dev.parent = &dev->pci->dev; | ||
395 | strcpy(dev->i2c_adap.name,dev->name); | ||
396 | dev->i2c_adap.algo_data = dev; | ||
397 | i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); | ||
398 | i2c_add_adapter(&dev->i2c_adap); | ||
399 | |||
400 | dev->i2c_client = saa7134_client_template; | ||
401 | dev->i2c_client.adapter = &dev->i2c_adap; | ||
402 | |||
403 | saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); | ||
404 | if (i2c_scan) | ||
405 | do_i2c_scan(dev->name,&dev->i2c_client); | ||
406 | |||
407 | /* Instantiate the IR receiver device, if present */ | ||
408 | saa7134_probe_i2c_ir(dev); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | int saa7134_i2c_unregister(struct saa7134_dev *dev) | ||
413 | { | ||
414 | i2c_del_adapter(&dev->i2c_adap); | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | /* ----------------------------------------------------------- */ | ||
419 | /* | ||
420 | * Local variables: | ||
421 | * c-basic-offset: 8 | ||
422 | * End: | ||
423 | */ | ||