2 * Driver for the NXP SAA7164 PCIe bridge
4 * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
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.
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
15 * GNU General Public License for more details.
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.
22 #include <linux/wait.h>
23 #include <linux/slab.h>
27 int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode)
31 ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
32 SAA_STATE_CONTROL, sizeof(mode), &mode);
34 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
39 int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version)
43 ret = saa7164_cmd_send(dev, 0, GET_CUR,
44 GET_FW_VERSION_CONTROL, sizeof(u32), version);
46 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
51 int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
53 u8 reg[] = { 0x0f, 0x00 };
58 /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */
59 /* TODO: Pull the details from the boards struct */
60 return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg),
65 int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
66 struct saa7164_tsport *port,
67 tmComResTSFormatDescrHeader_t *tsfmt)
69 dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
70 dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset);
71 dprintk(DBGLVL_API, " bPacketLength= 0x%x\n", tsfmt->bPacketLength);
72 dprintk(DBGLVL_API, " bStrideLength= 0x%x\n", tsfmt->bStrideLength);
73 dprintk(DBGLVL_API, " bguid = (....)\n");
75 /* Cache the hardware configuration in the port */
77 port->bufcounter = port->hwcfg.BARLocation;
78 port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
79 port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
80 port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
81 port->bufptr32l = port->hwcfg.BARLocation +
83 (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
84 port->bufptr32h = port->hwcfg.BARLocation +
86 (sizeof(u32) * port->hwcfg.buffercount);
87 port->bufptr64 = port->hwcfg.BARLocation +
89 (sizeof(u32) * port->hwcfg.buffercount);
90 dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
91 port->hwcfg.BARLocation);
93 dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n",
99 int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
101 struct saa7164_tsport *port = 0;
102 u32 idx, next_offset;
104 tmComResDescrHeader_t *hdr, *t;
105 tmComResExtDevDescrHeader_t *exthdr;
106 tmComResPathDescrHeader_t *pathhdr;
107 tmComResAntTermDescrHeader_t *anttermhdr;
108 tmComResTunerDescrHeader_t *tunerunithdr;
109 tmComResDMATermDescrHeader_t *vcoutputtermhdr;
110 tmComResTSFormatDescrHeader_t *tsfmt;
114 "%s(?,?,%d) sizeof(tmComResDescrHeader_t) = %d bytes\n",
115 __func__, len, (u32)sizeof(tmComResDescrHeader_t));
117 for (idx = 0; idx < (len - sizeof(tmComResDescrHeader_t)); ) {
119 hdr = (tmComResDescrHeader_t *)(buf + idx);
121 if (hdr->type != CS_INTERFACE)
122 return SAA_ERR_NOT_SUPPORTED;
124 dprintk(DBGLVL_API, "@ 0x%x = \n", idx);
125 switch (hdr->subtype) {
126 case GENERAL_REQUEST:
127 dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
130 dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
131 pathhdr = (tmComResPathDescrHeader_t *)(buf + idx);
132 dprintk(DBGLVL_API, " pathid = 0x%x\n",
134 currpath = pathhdr->pathid;
136 case VC_INPUT_TERMINAL:
137 dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
139 (tmComResAntTermDescrHeader_t *)(buf + idx);
140 dprintk(DBGLVL_API, " terminalid = 0x%x\n",
141 anttermhdr->terminalid);
142 dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
143 anttermhdr->terminaltype);
144 switch (anttermhdr->terminaltype) {
146 dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
149 dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
151 case SPDIF_CONNECTOR:
152 dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
154 case COMPOSITE_CONNECTOR:
156 " = COMPOSITE_CONNECTOR\n");
158 case SVIDEO_CONNECTOR:
159 dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
161 case COMPONENT_CONNECTOR:
163 " = COMPONENT_CONNECTOR\n");
166 dprintk(DBGLVL_API, " = STANDARD_DMA\n");
169 dprintk(DBGLVL_API, " = undefined (0x%x)\n",
170 anttermhdr->terminaltype);
172 dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
173 anttermhdr->assocterminal);
174 dprintk(DBGLVL_API, " iterminal = 0x%x\n",
175 anttermhdr->iterminal);
176 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
177 anttermhdr->controlsize);
179 case VC_OUTPUT_TERMINAL:
180 dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
182 (tmComResDMATermDescrHeader_t *)(buf + idx);
183 dprintk(DBGLVL_API, " unitid = 0x%x\n",
184 vcoutputtermhdr->unitid);
185 dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
186 vcoutputtermhdr->terminaltype);
187 switch (vcoutputtermhdr->terminaltype) {
189 dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
192 dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
194 case SPDIF_CONNECTOR:
195 dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
197 case COMPOSITE_CONNECTOR:
199 " = COMPOSITE_CONNECTOR\n");
201 case SVIDEO_CONNECTOR:
202 dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
204 case COMPONENT_CONNECTOR:
206 " = COMPONENT_CONNECTOR\n");
209 dprintk(DBGLVL_API, " = STANDARD_DMA\n");
212 dprintk(DBGLVL_API, " = undefined (0x%x)\n",
213 vcoutputtermhdr->terminaltype);
215 dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
216 vcoutputtermhdr->assocterminal);
217 dprintk(DBGLVL_API, " sourceid = 0x%x\n",
218 vcoutputtermhdr->sourceid);
219 dprintk(DBGLVL_API, " iterminal = 0x%x\n",
220 vcoutputtermhdr->iterminal);
221 dprintk(DBGLVL_API, " BARLocation = 0x%x\n",
222 vcoutputtermhdr->BARLocation);
223 dprintk(DBGLVL_API, " flags = 0x%x\n",
224 vcoutputtermhdr->flags);
225 dprintk(DBGLVL_API, " interruptid = 0x%x\n",
226 vcoutputtermhdr->interruptid);
227 dprintk(DBGLVL_API, " buffercount = 0x%x\n",
228 vcoutputtermhdr->buffercount);
229 dprintk(DBGLVL_API, " metadatasize = 0x%x\n",
230 vcoutputtermhdr->metadatasize);
231 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
232 vcoutputtermhdr->controlsize);
233 dprintk(DBGLVL_API, " numformats = 0x%x\n",
234 vcoutputtermhdr->numformats);
236 t = (tmComResDescrHeader_t *)
237 ((tmComResDMATermDescrHeader_t *)(buf + idx));
238 next_offset = idx + (vcoutputtermhdr->len);
239 for (i = 0; i < vcoutputtermhdr->numformats; i++) {
240 t = (tmComResDescrHeader_t *)
242 switch (t->subtype) {
243 case VS_FORMAT_MPEG2TS:
245 (tmComResTSFormatDescrHeader_t *)t;
250 memcpy(&port->hwcfg, vcoutputtermhdr,
251 sizeof(*vcoutputtermhdr));
252 saa7164_api_configure_port_mpeg2ts(dev,
255 case VS_FORMAT_MPEG2PS:
257 " = VS_FORMAT_MPEG2PS\n");
261 " = VS_FORMAT_VBI\n");
265 " = VS_FORMAT_RDS\n");
267 case VS_FORMAT_UNCOMPRESSED:
269 " = VS_FORMAT_UNCOMPRESSED\n");
273 " = VS_FORMAT_TYPE\n");
277 " = undefined (0x%x)\n",
280 next_offset += t->len;
285 dprintk(DBGLVL_API, " TUNER_UNIT\n");
287 (tmComResTunerDescrHeader_t *)(buf + idx);
288 dprintk(DBGLVL_API, " unitid = 0x%x\n",
289 tunerunithdr->unitid);
290 dprintk(DBGLVL_API, " sourceid = 0x%x\n",
291 tunerunithdr->sourceid);
292 dprintk(DBGLVL_API, " iunit = 0x%x\n",
293 tunerunithdr->iunit);
294 dprintk(DBGLVL_API, " tuningstandards = 0x%x\n",
295 tunerunithdr->tuningstandards);
296 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
297 tunerunithdr->controlsize);
298 dprintk(DBGLVL_API, " controls = 0x%x\n",
299 tunerunithdr->controls);
301 case VC_SELECTOR_UNIT:
302 dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
304 case VC_PROCESSING_UNIT:
305 dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
308 dprintk(DBGLVL_API, " FEATURE_UNIT\n");
311 dprintk(DBGLVL_API, " ENCODER_UNIT\n");
314 dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
315 exthdr = (tmComResExtDevDescrHeader_t *)(buf + idx);
316 dprintk(DBGLVL_API, " unitid = 0x%x\n",
318 dprintk(DBGLVL_API, " deviceid = 0x%x\n",
320 dprintk(DBGLVL_API, " devicetype = 0x%x\n",
322 if (exthdr->devicetype & 0x1)
323 dprintk(DBGLVL_API, " = Decoder Device\n");
324 if (exthdr->devicetype & 0x2)
325 dprintk(DBGLVL_API, " = GPIO Source\n");
326 if (exthdr->devicetype & 0x4)
327 dprintk(DBGLVL_API, " = Video Decoder\n");
328 if (exthdr->devicetype & 0x8)
329 dprintk(DBGLVL_API, " = Audio Decoder\n");
330 if (exthdr->devicetype & 0x20)
331 dprintk(DBGLVL_API, " = Crossbar\n");
332 if (exthdr->devicetype & 0x40)
333 dprintk(DBGLVL_API, " = Tuner\n");
334 if (exthdr->devicetype & 0x80)
335 dprintk(DBGLVL_API, " = IF PLL\n");
336 if (exthdr->devicetype & 0x100)
337 dprintk(DBGLVL_API, " = Demodulator\n");
338 if (exthdr->devicetype & 0x200)
339 dprintk(DBGLVL_API, " = RDS Decoder\n");
340 if (exthdr->devicetype & 0x400)
341 dprintk(DBGLVL_API, " = Encoder\n");
342 if (exthdr->devicetype & 0x800)
343 dprintk(DBGLVL_API, " = IR Decoder\n");
344 if (exthdr->devicetype & 0x1000)
345 dprintk(DBGLVL_API, " = EEPROM\n");
346 if (exthdr->devicetype & 0x2000)
349 if (exthdr->devicetype & 0x10000)
351 " = Streaming Device\n");
352 if (exthdr->devicetype & 0x20000)
355 if (exthdr->devicetype & 0x40000000)
357 " = Generic Device\n");
358 if (exthdr->devicetype & 0x80000000)
360 " = Config Space Device\n");
361 dprintk(DBGLVL_API, " numgpiopins = 0x%x\n",
362 exthdr->numgpiopins);
363 dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n",
364 exthdr->numgpiogroups);
365 dprintk(DBGLVL_API, " controlsize = 0x%x\n",
366 exthdr->controlsize);
368 case PVC_INFRARED_UNIT:
369 dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
372 dprintk(DBGLVL_API, " DRM_UNIT\n");
375 dprintk(DBGLVL_API, "default %d\n", hdr->subtype);
378 dprintk(DBGLVL_API, " 1.%x\n", hdr->len);
379 dprintk(DBGLVL_API, " 2.%x\n", hdr->type);
380 dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype);
381 dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid);
389 int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
395 dprintk(DBGLVL_API, "%s()\n", __func__);
397 /* Get the total descriptor length */
398 ret = saa7164_cmd_send(dev, 0, GET_LEN,
399 GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen);
401 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
403 dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n",
406 /* Allocate enough storage for all of the descs */
407 buf = kzalloc(buflen, GFP_KERNEL);
409 return SAA_ERR_NO_RESOURCES;
412 ret = saa7164_cmd_send(dev, 0, GET_CUR,
413 GET_DESCRIPTORS_CONTROL, buflen, buf);
415 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
419 if (saa_debug & DBGLVL_API)
420 saa7164_dumphex16(dev, buf, (buflen/16)*16);
422 saa7164_api_dump_subdevs(dev, buf, buflen);
429 int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
430 u32 datalen, u8 *data)
432 struct saa7164_dev *dev = bus->dev;
439 dprintk(DBGLVL_API, "%s()\n", __func__);
448 regval = ((*(reg) << 8) || *(reg+1));
451 regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2));
454 regval = ((*(reg) << 24) | (*(reg+1) << 16) |
455 (*(reg+2) << 8) | *(reg+3));
457 /* Prepare the send buffer */
458 /* Bytes 00-03 source register length
459 * 04-07 source bytes to read
460 * 08... register address
462 memset(buf, 0, sizeof(buf));
463 memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen);
464 *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
465 *((u32 *)(buf + 1 * sizeof(u32))) = datalen;
467 unitid = saa7164_i2caddr_to_unitid(bus, addr);
470 "%s() error, cannot translate regaddr 0x%x to unitid\n",
475 ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
476 EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
478 printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
482 dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
484 if (saa_debug & DBGLVL_I2C)
485 saa7164_dumphex16(dev, buf, 2 * 16);
487 ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR,
488 EXU_REGISTER_ACCESS_CONTROL, len, &buf);
490 printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
492 if (saa_debug & DBGLVL_I2C)
493 saa7164_dumphex16(dev, buf, sizeof(buf));
494 memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen);
497 return ret == SAA_OK ? 0 : -EIO;
500 /* For a given 8 bit i2c address device, write the buffer */
501 int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
504 struct saa7164_dev *dev = bus->dev;
511 dprintk(DBGLVL_API, "%s()\n", __func__);
513 if ((datalen == 0) || (datalen > 232))
516 memset(buf, 0, sizeof(buf));
518 unitid = saa7164_i2caddr_to_unitid(bus, addr);
521 "%s() error, cannot translate regaddr 0x%x to unitid\n",
526 reglen = saa7164_i2caddr_to_reglen(bus, addr);
529 "%s() error, cannot translate regaddr to reglen\n",
534 ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
535 EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
537 printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
541 dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
543 /* Prepare the send buffer */
544 /* Bytes 00-03 dest register length
545 * 04-07 dest bytes to write
546 * 08... register address
548 *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
549 *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen;
550 memcpy((buf + 2 * sizeof(u32)), data, datalen);
552 if (saa_debug & DBGLVL_I2C)
553 saa7164_dumphex16(dev, buf, sizeof(buf));
555 ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR,
556 EXU_REGISTER_ACCESS_CONTROL, len, &buf);
558 printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
560 return ret == SAA_OK ? 0 : -EIO;
564 int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
570 dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
571 __func__, unitid, pin, state);
573 if ((pin > 7) || (state > 2))
574 return SAA_ERR_BAD_PARAMETER;
579 ret = saa7164_cmd_send(dev, unitid, SET_CUR,
580 EXU_GPIO_CONTROL, sizeof(t), &t);
582 printk(KERN_ERR "%s() error, ret = 0x%x\n",
588 int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid,
591 return saa7164_api_modify_gpio(dev, unitid, pin, 1);
594 int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
597 return saa7164_api_modify_gpio(dev, unitid, pin, 0);