aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/saa7164/saa7164-api.c
diff options
context:
space:
mode:
authorSteven Toth <stoth@kernellabs.com>2009-05-09 20:17:28 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:14:43 -0400
commit443c1228d50518f3c550e1fef490a2c9d9246ce7 (patch)
treecde68674e62a75b616906edcea835b2ea8b19588 /drivers/media/video/saa7164/saa7164-api.c
parent9afef394308cf63ddb67b003a1c6036615456eb9 (diff)
V4L/DVB (12923): SAA7164: Add support for the NXP SAA7164 silicon
This patch adds support for all of the known shipping Hauppauge HVR-2200 and HVR-2250 boards. Digital TV ATSC/QAM and DVB-T is enabled at this time. Both tuners are supported. Volatiles and typedefs need rework, the rest is coding style compliant. Signed-off-by: Steven Toth <stoth@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/saa7164/saa7164-api.c')
-rw-r--r--drivers/media/video/saa7164/saa7164-api.c619
1 files changed, 619 insertions, 0 deletions
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c
new file mode 100644
index 000000000000..8cef1df9b54f
--- /dev/null
+++ b/drivers/media/video/saa7164/saa7164-api.c
@@ -0,0 +1,619 @@
1/*
2 * Driver for the NXP SAA7164 PCIe bridge
3 *
4 * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/wait.h>
23
24#include "saa7164.h"
25
26int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode)
27{
28 int ret;
29
30 ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
31 SAA_STATE_CONTROL, sizeof(mode), &mode);
32 if (ret != SAA_OK)
33 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
34
35 return ret;
36}
37
38int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version)
39{
40 int ret;
41
42 ret = saa7164_cmd_send(dev, 0, GET_CUR,
43 GET_FW_VERSION_CONTROL, sizeof(u32), version);
44 if (ret != SAA_OK)
45 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
46
47 return ret;
48}
49
50int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
51{
52 u8 reg[] = { 0x0f, 0x00 };
53
54 if (buflen < 128)
55 return -ENOMEM;
56
57 /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */
58 /* TODO: Pull the details from the boards struct */
59 return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg),
60 &reg[0], 128, buf);
61}
62
63/* Exercise the i2c interface, saa7164_cmd()/bus() layers:
64 * 1. Read the identity byte from each of the demodulators.
65 * 2. Read the entire register set from the TDA18271.
66 * TODO: This function has no purpose other than to exercise i2c.
67 */
68int saa7164_api_test(struct saa7164_dev *dev)
69{
70 /* TDA10048 identities */
71 u8 reg[] = { 0x00 };
72 u8 data[256];
73 dprintk(DBGLVL_API, "%s()\n", __func__);
74 /* Read all 39 bytes from the TDA18271 tuners */
75 saa7164_api_i2c_read(&dev->i2c_bus[1], 0xc0 >> 1, 0,
76 &reg[0], 39, &data[0]);
77 saa7164_api_i2c_read(&dev->i2c_bus[2], 0xc0 >> 1, 0,
78 &reg[0], 39, &data[0]);
79
80 return 0;
81}
82
83int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
84 struct saa7164_tsport *port,
85 tmComResTSFormatDescrHeader_t *tsfmt)
86{
87 dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
88 dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset);
89 dprintk(DBGLVL_API, " bPacketLength= 0x%x\n", tsfmt->bPacketLength);
90 dprintk(DBGLVL_API, " bStrideLength= 0x%x\n", tsfmt->bStrideLength);
91 dprintk(DBGLVL_API, " bguid = (....)\n");
92
93 /* Cache the hardware configuration in the port */
94
95 port->bufcounter = port->hwcfg.BARLocation;
96 port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
97 port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
98 port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
99 port->bufptr32l = port->hwcfg.BARLocation +
100 (4 * sizeof(u32)) +
101 (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
102 port->bufptr32h = port->hwcfg.BARLocation +
103 (4 * sizeof(u32)) +
104 (sizeof(u32) * port->hwcfg.buffercount);
105 port->bufptr64 = port->hwcfg.BARLocation +
106 (4 * sizeof(u32)) +
107 (sizeof(u32) * port->hwcfg.buffercount);
108 dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
109 port->hwcfg.BARLocation);
110
111 dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n",
112 port->nr);
113
114 return 0;
115}
116
117int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
118{
119 struct saa7164_tsport *port = 0;
120 u32 idx, next_offset;
121 int i;
122 tmComResDescrHeader_t *hdr, *t;
123 tmComResExtDevDescrHeader_t *exthdr;
124 tmComResPathDescrHeader_t *pathhdr;
125 tmComResAntTermDescrHeader_t *anttermhdr;
126 tmComResTunerDescrHeader_t *tunerunithdr;
127 tmComResDMATermDescrHeader_t *vcoutputtermhdr;
128 tmComResTSFormatDescrHeader_t *tsfmt;
129 u32 currpath = 0;
130
131 dprintk(DBGLVL_API,
132 "%s(?,?,%d) sizeof(tmComResDescrHeader_t) = %lu bytes\n",
133 __func__, len, sizeof(tmComResDescrHeader_t));
134
135 for (idx = 0; idx < (len - sizeof(tmComResDescrHeader_t)); ) {
136
137 hdr = (tmComResDescrHeader_t *)(buf + idx);
138
139 if (hdr->type != CS_INTERFACE)
140 return SAA_ERR_NOT_SUPPORTED;
141
142 dprintk(DBGLVL_API, "@ 0x%x = \n", idx);
143 switch (hdr->subtype) {
144 case GENERAL_REQUEST:
145 dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
146 break;
147 case VC_TUNER_PATH:
148 dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
149 pathhdr = (tmComResPathDescrHeader_t *)(buf + idx);
150 dprintk(DBGLVL_API, " pathid = 0x%x\n",
151 pathhdr->pathid);
152 currpath = pathhdr->pathid;
153 break;
154 case VC_INPUT_TERMINAL:
155 dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
156 anttermhdr =
157 (tmComResAntTermDescrHeader_t *)(buf + idx);
158 dprintk(DBGLVL_API, " terminalid = 0x%x\n",
159 anttermhdr->terminalid);
160 dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
161 anttermhdr->terminaltype);
162 switch (anttermhdr->terminaltype) {
163 case ITT_ANTENNA:
164 dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
165 break;
166 case LINE_CONNECTOR:
167 dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
168 break;
169 case SPDIF_CONNECTOR:
170 dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
171 break;
172 case COMPOSITE_CONNECTOR:
173 dprintk(DBGLVL_API,
174 " = COMPOSITE_CONNECTOR\n");
175 break;
176 case SVIDEO_CONNECTOR:
177 dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
178 break;
179 case COMPONENT_CONNECTOR:
180 dprintk(DBGLVL_API,
181 " = COMPONENT_CONNECTOR\n");
182 break;
183 case STANDARD_DMA:
184 dprintk(DBGLVL_API, " = STANDARD_DMA\n");
185 break;
186 default:
187 dprintk(DBGLVL_API, " = undefined (0x%x)\n",
188 anttermhdr->terminaltype);
189 }
190 dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
191 anttermhdr->assocterminal);
192 dprintk(DBGLVL_API, " iterminal = 0x%x\n",
193 anttermhdr->iterminal);
194 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
195 anttermhdr->controlsize);
196 break;
197 case VC_OUTPUT_TERMINAL:
198 dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
199 vcoutputtermhdr =
200 (tmComResDMATermDescrHeader_t *)(buf + idx);
201 dprintk(DBGLVL_API, " unitid = 0x%x\n",
202 vcoutputtermhdr->unitid);
203 dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
204 vcoutputtermhdr->terminaltype);
205 switch (vcoutputtermhdr->terminaltype) {
206 case ITT_ANTENNA:
207 dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
208 break;
209 case LINE_CONNECTOR:
210 dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
211 break;
212 case SPDIF_CONNECTOR:
213 dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
214 break;
215 case COMPOSITE_CONNECTOR:
216 dprintk(DBGLVL_API,
217 " = COMPOSITE_CONNECTOR\n");
218 break;
219 case SVIDEO_CONNECTOR:
220 dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
221 break;
222 case COMPONENT_CONNECTOR:
223 dprintk(DBGLVL_API,
224 " = COMPONENT_CONNECTOR\n");
225 break;
226 case STANDARD_DMA:
227 dprintk(DBGLVL_API, " = STANDARD_DMA\n");
228 break;
229 default:
230 dprintk(DBGLVL_API, " = undefined (0x%x)\n",
231 vcoutputtermhdr->terminaltype);
232 }
233 dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
234 vcoutputtermhdr->assocterminal);
235 dprintk(DBGLVL_API, " sourceid = 0x%x\n",
236 vcoutputtermhdr->sourceid);
237 dprintk(DBGLVL_API, " iterminal = 0x%x\n",
238 vcoutputtermhdr->iterminal);
239 dprintk(DBGLVL_API, " BARLocation = 0x%x\n",
240 vcoutputtermhdr->BARLocation);
241 dprintk(DBGLVL_API, " flags = 0x%x\n",
242 vcoutputtermhdr->flags);
243 dprintk(DBGLVL_API, " interruptid = 0x%x\n",
244 vcoutputtermhdr->interruptid);
245 dprintk(DBGLVL_API, " buffercount = 0x%x\n",
246 vcoutputtermhdr->buffercount);
247 dprintk(DBGLVL_API, " metadatasize = 0x%x\n",
248 vcoutputtermhdr->metadatasize);
249 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
250 vcoutputtermhdr->controlsize);
251 dprintk(DBGLVL_API, " numformats = 0x%x\n",
252 vcoutputtermhdr->numformats);
253
254 t = (tmComResDescrHeader_t *)
255 ((tmComResDMATermDescrHeader_t *)(buf + idx));
256 next_offset = idx + (vcoutputtermhdr->len);
257 for (i = 0; i < vcoutputtermhdr->numformats; i++) {
258 t = (tmComResDescrHeader_t *)
259 (buf + next_offset);
260 switch (t->subtype) {
261 case VS_FORMAT_MPEG2TS:
262 tsfmt =
263 (tmComResTSFormatDescrHeader_t *)t;
264 if (currpath == 1)
265 port = &dev->ts1;
266 else
267 port = &dev->ts2;
268 memcpy(&port->hwcfg, vcoutputtermhdr,
269 sizeof(*vcoutputtermhdr));
270 saa7164_api_configure_port_mpeg2ts(dev,
271 port, tsfmt);
272 break;
273 case VS_FORMAT_MPEG2PS:
274 dprintk(DBGLVL_API,
275 " = VS_FORMAT_MPEG2PS\n");
276 break;
277 case VS_FORMAT_VBI:
278 dprintk(DBGLVL_API,
279 " = VS_FORMAT_VBI\n");
280 break;
281 case VS_FORMAT_RDS:
282 dprintk(DBGLVL_API,
283 " = VS_FORMAT_RDS\n");
284 break;
285 case VS_FORMAT_UNCOMPRESSED:
286 dprintk(DBGLVL_API,
287 " = VS_FORMAT_UNCOMPRESSED\n");
288 break;
289 case VS_FORMAT_TYPE:
290 dprintk(DBGLVL_API,
291 " = VS_FORMAT_TYPE\n");
292 break;
293 default:
294 dprintk(DBGLVL_API,
295 " = undefined (0x%x)\n",
296 t->subtype);
297 }
298 next_offset += t->len;
299 }
300
301 break;
302 case TUNER_UNIT:
303 dprintk(DBGLVL_API, " TUNER_UNIT\n");
304 tunerunithdr =
305 (tmComResTunerDescrHeader_t *)(buf + idx);
306 dprintk(DBGLVL_API, " unitid = 0x%x\n",
307 tunerunithdr->unitid);
308 dprintk(DBGLVL_API, " sourceid = 0x%x\n",
309 tunerunithdr->sourceid);
310 dprintk(DBGLVL_API, " iunit = 0x%x\n",
311 tunerunithdr->iunit);
312 dprintk(DBGLVL_API, " tuningstandards = 0x%x\n",
313 tunerunithdr->tuningstandards);
314 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
315 tunerunithdr->controlsize);
316 dprintk(DBGLVL_API, " controls = 0x%x\n",
317 tunerunithdr->controls);
318 break;
319 case VC_SELECTOR_UNIT:
320 dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
321 break;
322 case VC_PROCESSING_UNIT:
323 dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
324 break;
325 case FEATURE_UNIT:
326 dprintk(DBGLVL_API, " FEATURE_UNIT\n");
327 break;
328 case ENCODER_UNIT:
329 dprintk(DBGLVL_API, " ENCODER_UNIT\n");
330 break;
331 case EXTENSION_UNIT:
332 dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
333 exthdr = (tmComResExtDevDescrHeader_t *)(buf + idx);
334 dprintk(DBGLVL_API, " unitid = 0x%x\n",
335 exthdr->unitid);
336 dprintk(DBGLVL_API, " deviceid = 0x%x\n",
337 exthdr->deviceid);
338 dprintk(DBGLVL_API, " devicetype = 0x%x\n",
339 exthdr->devicetype);
340 if (exthdr->devicetype & 0x1)
341 dprintk(DBGLVL_API, " = Decoder Device\n");
342 if (exthdr->devicetype & 0x2)
343 dprintk(DBGLVL_API, " = GPIO Source\n");
344 if (exthdr->devicetype & 0x4)
345 dprintk(DBGLVL_API, " = Video Decoder\n");
346 if (exthdr->devicetype & 0x8)
347 dprintk(DBGLVL_API, " = Audio Decoder\n");
348 if (exthdr->devicetype & 0x20)
349 dprintk(DBGLVL_API, " = Crossbar\n");
350 if (exthdr->devicetype & 0x40)
351 dprintk(DBGLVL_API, " = Tuner\n");
352 if (exthdr->devicetype & 0x80)
353 dprintk(DBGLVL_API, " = IF PLL\n");
354 if (exthdr->devicetype & 0x100)
355 dprintk(DBGLVL_API, " = Demodulator\n");
356 if (exthdr->devicetype & 0x200)
357 dprintk(DBGLVL_API, " = RDS Decoder\n");
358 if (exthdr->devicetype & 0x400)
359 dprintk(DBGLVL_API, " = Encoder\n");
360 if (exthdr->devicetype & 0x800)
361 dprintk(DBGLVL_API, " = IR Decoder\n");
362 if (exthdr->devicetype & 0x1000)
363 dprintk(DBGLVL_API, " = EEPROM\n");
364 if (exthdr->devicetype & 0x2000)
365 dprintk(DBGLVL_API,
366 " = VBI Decoder\n");
367 if (exthdr->devicetype & 0x10000)
368 dprintk(DBGLVL_API,
369 " = Streaming Device\n");
370 if (exthdr->devicetype & 0x20000)
371 dprintk(DBGLVL_API,
372 " = DRM Device\n");
373 if (exthdr->devicetype & 0x40000000)
374 dprintk(DBGLVL_API,
375 " = Generic Device\n");
376 if (exthdr->devicetype & 0x80000000)
377 dprintk(DBGLVL_API,
378 " = Config Space Device\n");
379 dprintk(DBGLVL_API, " numgpiopins = 0x%x\n",
380 exthdr->numgpiopins);
381 dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n",
382 exthdr->numgpiogroups);
383 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
384 exthdr->controlsize);
385 break;
386 case PVC_INFRARED_UNIT:
387 dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
388 break;
389 case DRM_UNIT:
390 dprintk(DBGLVL_API, " DRM_UNIT\n");
391 break;
392 default:
393 dprintk(DBGLVL_API, "default %d\n", hdr->subtype);
394 }
395
396 dprintk(DBGLVL_API, " 1.%x\n", hdr->len);
397 dprintk(DBGLVL_API, " 2.%x\n", hdr->type);
398 dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype);
399 dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid);
400
401 idx += hdr->len;
402 }
403
404 return 0;
405}
406
407int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
408{
409 int ret;
410 u32 buflen = 0;
411 u8 *buf;
412
413 dprintk(DBGLVL_API, "%s()\n", __func__);
414
415 /* Get the total descriptor length */
416 ret = saa7164_cmd_send(dev, 0, GET_LEN,
417 GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen);
418 if (ret != SAA_OK)
419 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
420
421 dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n",
422 __func__, buflen);
423
424 /* Allocate enough storage for all of the descs */
425 buf = kzalloc(buflen, GFP_KERNEL);
426 if (buf == NULL)
427 return SAA_ERR_NO_RESOURCES;
428
429 /* Retrieve them */
430 ret = saa7164_cmd_send(dev, 0, GET_CUR,
431 GET_DESCRIPTORS_CONTROL, buflen, buf);
432 if (ret != SAA_OK) {
433 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
434 goto out;
435 }
436
437 if (debug & DBGLVL_API)
438 saa7164_dumphex16(dev, buf, (buflen/16)*16);
439
440 saa7164_api_dump_subdevs(dev, buf, buflen);
441
442out:
443 kfree(buf);
444 return ret;
445}
446
447int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
448 u32 datalen, u8 *data)
449{
450 struct saa7164_dev *dev = bus->dev;
451 u16 len = 0;
452 int unitid;
453 u32 regval;
454 u8 buf[256];
455 int ret;
456
457 dprintk(DBGLVL_API, "%s()\n", __func__);
458
459 if (reglen > 4)
460 return -EIO;
461
462 if (reglen == 1)
463 regval = *(reg);
464 else
465 if (reglen == 2)
466 regval = ((*(reg) << 8) || *(reg+1));
467 else
468 if (reglen == 3)
469 regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2));
470 else
471 if (reglen == 4)
472 regval = ((*(reg) << 24) | (*(reg+1) << 16) |
473 (*(reg+2) << 8) | *(reg+3));
474
475 /* Prepare the send buffer */
476 /* Bytes 00-03 source register length
477 * 04-07 source bytes to read
478 * 08... register address
479 */
480 memset(buf, 0, sizeof(buf));
481 memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen);
482 *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
483 *((u32 *)(buf + 1 * sizeof(u32))) = datalen;
484
485 unitid = saa7164_i2caddr_to_unitid(bus, addr);
486 if (unitid < 0) {
487 printk(KERN_ERR
488 "%s() error, cannot translate regaddr 0x%x to unitid\n",
489 __func__, addr);
490 return -EIO;
491 }
492
493 ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
494 EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
495 if (ret != SAA_OK) {
496 printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
497 return -EIO;
498 }
499
500 dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
501
502 if (debug & DBGLVL_I2C)
503 saa7164_dumphex16(dev, buf, 2 * 16);
504
505 ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR,
506 EXU_REGISTER_ACCESS_CONTROL, len, &buf);
507 if (ret != SAA_OK)
508 printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
509 else {
510 if (debug & DBGLVL_I2C)
511 saa7164_dumphex16(dev, buf, sizeof(buf));
512 memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen);
513 }
514
515 return ret == SAA_OK ? 0 : -EIO;
516}
517
518/* For a given 8 bit i2c address device, write the buffer */
519int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
520 u8 *data)
521{
522 struct saa7164_dev *dev = bus->dev;
523 u16 len = 0;
524 int unitid;
525 int reglen;
526 u8 buf[256];
527 int ret;
528
529 dprintk(DBGLVL_API, "%s()\n", __func__);
530
531 if ((datalen == 0) || (datalen > 232))
532 return -EIO;
533
534 memset(buf, 0, sizeof(buf));
535
536 unitid = saa7164_i2caddr_to_unitid(bus, addr);
537 if (unitid < 0) {
538 printk(KERN_ERR
539 "%s() error, cannot translate regaddr 0x%x to unitid\n",
540 __func__, addr);
541 return -EIO;
542 }
543
544 reglen = saa7164_i2caddr_to_reglen(bus, addr);
545 if (unitid < 0) {
546 printk(KERN_ERR
547 "%s() error, cannot translate regaddr to reglen\n",
548 __func__);
549 return -EIO;
550 }
551
552 ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
553 EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
554 if (ret != SAA_OK) {
555 printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
556 return -EIO;
557 }
558
559 dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
560
561 /* Prepare the send buffer */
562 /* Bytes 00-03 dest register length
563 * 04-07 dest bytes to write
564 * 08... register address
565 */
566 *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
567 *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen;
568 memcpy((buf + 2 * sizeof(u32)), data, datalen);
569
570 if (debug & DBGLVL_I2C)
571 saa7164_dumphex16(dev, buf, sizeof(buf));
572
573 ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR,
574 EXU_REGISTER_ACCESS_CONTROL, len, &buf);
575 if (ret != SAA_OK)
576 printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
577
578 return ret == SAA_OK ? 0 : -EIO;
579}
580
581
582int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
583 u8 pin, u8 state)
584{
585 int ret;
586 tmComResGPIO_t t;
587
588 dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
589 __func__, unitid, pin, state);
590
591 if ((pin > 7) || (state > 2))
592 return SAA_ERR_BAD_PARAMETER;
593
594 t.pin = pin;
595 t.state = state;
596
597 ret = saa7164_cmd_send(dev, unitid, SET_CUR,
598 EXU_GPIO_CONTROL, sizeof(t), &t);
599 if (ret != SAA_OK)
600 printk(KERN_ERR "%s() error, ret = 0x%x\n",
601 __func__, ret);
602
603 return ret;
604}
605
606int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid,
607 u8 pin)
608{
609 return saa7164_api_modify_gpio(dev, unitid, pin, 1);
610}
611
612int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
613 u8 pin)
614{
615 return saa7164_api_modify_gpio(dev, unitid, pin, 0);
616}
617
618
619