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/init.h> 23#include <linux/module.h> 24#include <linux/pci.h> 25#include <linux/delay.h> 26 27#include "saa7164.h" 28 29/* The Bridge API needs to understand register widths (in bytes) for the 30 * attached I2C devices, so we can simplify the virtual i2c mechansms 31 * and keep the -i2c.c implementation clean. 32 */ 33#define REGLEN_8bit 1 34#define REGLEN_16bit 2 35 36struct saa7164_board saa7164_boards[] = { 37 [SAA7164_BOARD_UNKNOWN] = { 38 /* Bridge will not load any firmware, without knowing 39 * the rev this would be fatal. */ 40 .name = "Unknown", 41 }, 42 [SAA7164_BOARD_UNKNOWN_REV2] = { 43 /* Bridge will load the v2 f/w and dump descriptors */ 44 /* Required during new board bringup */ 45 .name = "Generic Rev2", 46 .chiprev = SAA7164_CHIP_REV2, 47 }, 48 [SAA7164_BOARD_UNKNOWN_REV3] = { 49 /* Bridge will load the v2 f/w and dump descriptors */ 50 /* Required during new board bringup */ 51 .name = "Generic Rev3", 52 .chiprev = SAA7164_CHIP_REV3, 53 }, 54 [SAA7164_BOARD_HAUPPAUGE_HVR2200] = { 55 .name = "Hauppauge WinTV-HVR2200", 56 .porta = SAA7164_MPEG_DVB, 57 .portb = SAA7164_MPEG_DVB, 58 .chiprev = SAA7164_CHIP_REV3, 59 .unit = {{ 60 .id = 0x1d, 61 .type = SAA7164_UNIT_EEPROM, 62 .name = "4K EEPROM", 63 .i2c_bus_nr = SAA7164_I2C_BUS_0, 64 .i2c_bus_addr = 0xa0 >> 1, 65 .i2c_reg_len = REGLEN_8bit, 66 }, { 67 .id = 0x04, 68 .type = SAA7164_UNIT_TUNER, 69 .name = "TDA18271-1", 70 .i2c_bus_nr = SAA7164_I2C_BUS_1, 71 .i2c_bus_addr = 0xc0 >> 1, 72 .i2c_reg_len = REGLEN_8bit, 73 }, { 74 .id = 0x1b, 75 .type = SAA7164_UNIT_TUNER, 76 .name = "TDA18271-2", 77 .i2c_bus_nr = SAA7164_I2C_BUS_2, 78 .i2c_bus_addr = 0xc0 >> 1, 79 .i2c_reg_len = REGLEN_8bit, 80 }, { 81 .id = 0x1e, 82 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 83 .name = "TDA10048-1", 84 .i2c_bus_nr = SAA7164_I2C_BUS_1, 85 .i2c_bus_addr = 0x10 >> 1, 86 .i2c_reg_len = REGLEN_8bit, 87 }, { 88 .id = 0x1f, 89 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 90 .name = "TDA10048-2", 91 .i2c_bus_nr = SAA7164_I2C_BUS_2, 92 .i2c_bus_addr = 0x12 >> 1, 93 .i2c_reg_len = REGLEN_8bit, 94 } }, 95 }, 96 [SAA7164_BOARD_HAUPPAUGE_HVR2200_2] = { 97 .name = "Hauppauge WinTV-HVR2200", 98 .porta = SAA7164_MPEG_DVB, 99 .portb = SAA7164_MPEG_DVB, 100 .chiprev = SAA7164_CHIP_REV2, 101 .unit = {{ 102 .id = 0x06, 103 .type = SAA7164_UNIT_EEPROM, 104 .name = "4K EEPROM", 105 .i2c_bus_nr = SAA7164_I2C_BUS_0, 106 .i2c_bus_addr = 0xa0 >> 1, 107 .i2c_reg_len = REGLEN_8bit, 108 }, { 109 .id = 0x04, 110 .type = SAA7164_UNIT_TUNER, 111 .name = "TDA18271-1", 112 .i2c_bus_nr = SAA7164_I2C_BUS_1, 113 .i2c_bus_addr = 0xc0 >> 1, 114 .i2c_reg_len = REGLEN_8bit, 115 }, { 116 .id = 0x05, 117 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 118 .name = "TDA10048-1", 119 .i2c_bus_nr = SAA7164_I2C_BUS_1, 120 .i2c_bus_addr = 0x10 >> 1, 121 .i2c_reg_len = REGLEN_8bit, 122 }, { 123 .id = 0x1e, 124 .type = SAA7164_UNIT_TUNER, 125 .name = "TDA18271-2", 126 .i2c_bus_nr = SAA7164_I2C_BUS_2, 127 .i2c_bus_addr = 0xc0 >> 1, 128 .i2c_reg_len = REGLEN_8bit, 129 }, { 130 .id = 0x1f, 131 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 132 .name = "TDA10048-2", 133 .i2c_bus_nr = SAA7164_I2C_BUS_2, 134 .i2c_bus_addr = 0x12 >> 1, 135 .i2c_reg_len = REGLEN_8bit, 136 } }, 137 }, 138 [SAA7164_BOARD_HAUPPAUGE_HVR2200_3] = { 139 .name = "Hauppauge WinTV-HVR2200", 140 .porta = SAA7164_MPEG_DVB, 141 .portb = SAA7164_MPEG_DVB, 142 .chiprev = SAA7164_CHIP_REV2, 143 .unit = {{ 144 .id = 0x1d, 145 .type = SAA7164_UNIT_EEPROM, 146 .name = "4K EEPROM", 147 .i2c_bus_nr = SAA7164_I2C_BUS_0, 148 .i2c_bus_addr = 0xa0 >> 1, 149 .i2c_reg_len = REGLEN_8bit, 150 }, { 151 .id = 0x04, 152 .type = SAA7164_UNIT_TUNER, 153 .name = "TDA18271-1", 154 .i2c_bus_nr = SAA7164_I2C_BUS_1, 155 .i2c_bus_addr = 0xc0 >> 1, 156 .i2c_reg_len = REGLEN_8bit, 157 }, { 158 .id = 0x05, 159 .type = SAA7164_UNIT_ANALOG_DEMODULATOR, 160 .name = "TDA8290-1", 161 .i2c_bus_nr = SAA7164_I2C_BUS_1, 162 .i2c_bus_addr = 0x84 >> 1, 163 .i2c_reg_len = REGLEN_8bit, 164 }, { 165 .id = 0x1b, 166 .type = SAA7164_UNIT_TUNER, 167 .name = "TDA18271-2", 168 .i2c_bus_nr = SAA7164_I2C_BUS_2, 169 .i2c_bus_addr = 0xc0 >> 1, 170 .i2c_reg_len = REGLEN_8bit, 171 }, { 172 .id = 0x1c, 173 .type = SAA7164_UNIT_ANALOG_DEMODULATOR, 174 .name = "TDA8290-2", 175 .i2c_bus_nr = SAA7164_I2C_BUS_2, 176 .i2c_bus_addr = 0x84 >> 1, 177 .i2c_reg_len = REGLEN_8bit, 178 }, { 179 .id = 0x1e, 180 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 181 .name = "TDA10048-1", 182 .i2c_bus_nr = SAA7164_I2C_BUS_1, 183 .i2c_bus_addr = 0x10 >> 1, 184 .i2c_reg_len = REGLEN_8bit, 185 }, { 186 .id = 0x1f, 187 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 188 .name = "TDA10048-2", 189 .i2c_bus_nr = SAA7164_I2C_BUS_2, 190 .i2c_bus_addr = 0x12 >> 1, 191 .i2c_reg_len = REGLEN_8bit, 192 } }, 193 }, 194 [SAA7164_BOARD_HAUPPAUGE_HVR2250] = { 195 .name = "Hauppauge WinTV-HVR2250", 196 .porta = SAA7164_MPEG_DVB, 197 .portb = SAA7164_MPEG_DVB, 198 .chiprev = SAA7164_CHIP_REV3, 199 .unit = {{ 200 .id = 0x22, 201 .type = SAA7164_UNIT_EEPROM, 202 .name = "4K EEPROM", 203 .i2c_bus_nr = SAA7164_I2C_BUS_0, 204 .i2c_bus_addr = 0xa0 >> 1, 205 .i2c_reg_len = REGLEN_8bit, 206 }, { 207 .id = 0x04, 208 .type = SAA7164_UNIT_TUNER, 209 .name = "TDA18271-1", 210 .i2c_bus_nr = SAA7164_I2C_BUS_1, 211 .i2c_bus_addr = 0xc0 >> 1, 212 .i2c_reg_len = REGLEN_8bit, 213 }, { 214 .id = 0x07, 215 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 216 .name = "CX24228/S5H1411-1 (TOP)", 217 .i2c_bus_nr = SAA7164_I2C_BUS_1, 218 .i2c_bus_addr = 0x32 >> 1, 219 .i2c_reg_len = REGLEN_8bit, 220 }, { 221 .id = 0x08, 222 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 223 .name = "CX24228/S5H1411-1 (QAM)", 224 .i2c_bus_nr = SAA7164_I2C_BUS_1, 225 .i2c_bus_addr = 0x34 >> 1, 226 .i2c_reg_len = REGLEN_8bit, 227 }, { 228 .id = 0x1e, 229 .type = SAA7164_UNIT_TUNER, 230 .name = "TDA18271-2", 231 .i2c_bus_nr = SAA7164_I2C_BUS_2, 232 .i2c_bus_addr = 0xc0 >> 1, 233 .i2c_reg_len = REGLEN_8bit, 234 }, { 235 .id = 0x20, 236 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 237 .name = "CX24228/S5H1411-2 (TOP)", 238 .i2c_bus_nr = SAA7164_I2C_BUS_2, 239 .i2c_bus_addr = 0x32 >> 1, 240 .i2c_reg_len = REGLEN_8bit, 241 }, { 242 .id = 0x23, 243 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 244 .name = "CX24228/S5H1411-2 (QAM)", 245 .i2c_bus_nr = SAA7164_I2C_BUS_2, 246 .i2c_bus_addr = 0x34 >> 1, 247 .i2c_reg_len = REGLEN_8bit, 248 } }, 249 }, 250 [SAA7164_BOARD_HAUPPAUGE_HVR2250_2] = { 251 .name = "Hauppauge WinTV-HVR2250", 252 .porta = SAA7164_MPEG_DVB, 253 .portb = SAA7164_MPEG_DVB, 254 .chiprev = SAA7164_CHIP_REV3, 255 .unit = {{ 256 .id = 0x28, 257 .type = SAA7164_UNIT_EEPROM, 258 .name = "4K EEPROM", 259 .i2c_bus_nr = SAA7164_I2C_BUS_0, 260 .i2c_bus_addr = 0xa0 >> 1, 261 .i2c_reg_len = REGLEN_8bit, 262 }, { 263 .id = 0x04, 264 .type = SAA7164_UNIT_TUNER, 265 .name = "TDA18271-1", 266 .i2c_bus_nr = SAA7164_I2C_BUS_1, 267 .i2c_bus_addr = 0xc0 >> 1, 268 .i2c_reg_len = REGLEN_8bit, 269 }, { 270 .id = 0x07, 271 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 272 .name = "CX24228/S5H1411-1 (TOP)", 273 .i2c_bus_nr = SAA7164_I2C_BUS_1, 274 .i2c_bus_addr = 0x32 >> 1, 275 .i2c_reg_len = REGLEN_8bit, 276 }, { 277 .id = 0x08, 278 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 279 .name = "CX24228/S5H1411-1 (QAM)", 280 .i2c_bus_nr = SAA7164_I2C_BUS_1, 281 .i2c_bus_addr = 0x34 >> 1, 282 .i2c_reg_len = REGLEN_8bit, 283 }, { 284 .id = 0x24, 285 .type = SAA7164_UNIT_TUNER, 286 .name = "TDA18271-2", 287 .i2c_bus_nr = SAA7164_I2C_BUS_2, 288 .i2c_bus_addr = 0xc0 >> 1, 289 .i2c_reg_len = REGLEN_8bit, 290 }, { 291 .id = 0x26, 292 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 293 .name = "CX24228/S5H1411-2 (TOP)", 294 .i2c_bus_nr = SAA7164_I2C_BUS_2, 295 .i2c_bus_addr = 0x32 >> 1, 296 .i2c_reg_len = REGLEN_8bit, 297 }, { 298 .id = 0x29, 299 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 300 .name = "CX24228/S5H1411-2 (QAM)", 301 .i2c_bus_nr = SAA7164_I2C_BUS_2, 302 .i2c_bus_addr = 0x34 >> 1, 303 .i2c_reg_len = REGLEN_8bit, 304 } }, 305 }, 306 [SAA7164_BOARD_HAUPPAUGE_HVR2250_3] = { 307 .name = "Hauppauge WinTV-HVR2250", 308 .porta = SAA7164_MPEG_DVB, 309 .portb = SAA7164_MPEG_DVB, 310 .chiprev = SAA7164_CHIP_REV3, 311 .unit = {{ 312 .id = 0x26, 313 .type = SAA7164_UNIT_EEPROM, 314 .name = "4K EEPROM", 315 .i2c_bus_nr = SAA7164_I2C_BUS_0, 316 .i2c_bus_addr = 0xa0 >> 1, 317 .i2c_reg_len = REGLEN_8bit, 318 }, { 319 .id = 0x04, 320 .type = SAA7164_UNIT_TUNER, 321 .name = "TDA18271-1", 322 .i2c_bus_nr = SAA7164_I2C_BUS_1, 323 .i2c_bus_addr = 0xc0 >> 1, 324 .i2c_reg_len = REGLEN_8bit, 325 }, { 326 .id = 0x07, 327 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 328 .name = "CX24228/S5H1411-1 (TOP)", 329 .i2c_bus_nr = SAA7164_I2C_BUS_1, 330 .i2c_bus_addr = 0x32 >> 1, 331 .i2c_reg_len = REGLEN_8bit, 332 }, { 333 .id = 0x08, 334 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 335 .name = "CX24228/S5H1411-1 (QAM)", 336 .i2c_bus_nr = SAA7164_I2C_BUS_1, 337 .i2c_bus_addr = 0x34 >> 1, 338 .i2c_reg_len = REGLEN_8bit, 339 }, { 340 .id = 0x22, 341 .type = SAA7164_UNIT_TUNER, 342 .name = "TDA18271-2", 343 .i2c_bus_nr = SAA7164_I2C_BUS_2, 344 .i2c_bus_addr = 0xc0 >> 1, 345 .i2c_reg_len = REGLEN_8bit, 346 }, { 347 .id = 0x24, 348 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 349 .name = "CX24228/S5H1411-2 (TOP)", 350 .i2c_bus_nr = SAA7164_I2C_BUS_2, 351 .i2c_bus_addr = 0x32 >> 1, 352 .i2c_reg_len = REGLEN_8bit, 353 }, { 354 .id = 0x27, 355 .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, 356 .name = "CX24228/S5H1411-2 (QAM)", 357 .i2c_bus_nr = SAA7164_I2C_BUS_2, 358 .i2c_bus_addr = 0x34 >> 1, 359 .i2c_reg_len = REGLEN_8bit, 360 } }, 361 }, 362}; 363const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); 364 365/* ------------------------------------------------------------------ */ 366/* PCI subsystem IDs */ 367 368struct saa7164_subid saa7164_subids[] = { 369 { 370 .subvendor = 0x0070, 371 .subdevice = 0x8880, 372 .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, 373 }, { 374 .subvendor = 0x0070, 375 .subdevice = 0x8810, 376 .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, 377 }, { 378 .subvendor = 0x0070, 379 .subdevice = 0x8980, 380 .card = SAA7164_BOARD_HAUPPAUGE_HVR2200, 381 }, { 382 .subvendor = 0x0070, 383 .subdevice = 0x8900, 384 .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_2, 385 }, { 386 .subvendor = 0x0070, 387 .subdevice = 0x8901, 388 .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_3, 389 }, { 390 .subvendor = 0x0070, 391 .subdevice = 0x88A1, 392 .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_3, 393 }, { 394 .subvendor = 0x0070, 395 .subdevice = 0x8891, 396 .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, 397 }, { 398 .subvendor = 0x0070, 399 .subdevice = 0x8851, 400 .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, 401 }, 402}; 403const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); 404 405void saa7164_card_list(struct saa7164_dev *dev) 406{ 407 int i; 408 409 if (0 == dev->pci->subsystem_vendor && 410 0 == dev->pci->subsystem_device) { 411 printk(KERN_ERR 412 "%s: Board has no valid PCIe Subsystem ID and can't\n" 413 "%s: be autodetected. Pass card=<n> insmod option to\n" 414 "%s: workaround that. Send complaints to the vendor\n" 415 "%s: of the TV card. Best regards,\n" 416 "%s: -- tux\n", 417 dev->name, dev->name, dev->name, dev->name, dev->name); 418 } else { 419 printk(KERN_ERR 420 "%s: Your board isn't known (yet) to the driver.\n" 421 "%s: Try to pick one of the existing card configs via\n" 422 "%s: card=<n> insmod option. Updating to the latest\n" 423 "%s: version might help as well.\n", 424 dev->name, dev->name, dev->name, dev->name); 425 } 426 427 printk(KERN_ERR "%s: Here are valid choices for the card=<n> insmod " 428 "option:\n", dev->name); 429 430 for (i = 0; i < saa7164_bcount; i++) 431 printk(KERN_ERR "%s: card=%d -> %s\n", 432 dev->name, i, saa7164_boards[i].name); 433} 434 435/* TODO: clean this define up into the -cards.c structs */ 436#define PCIEBRIDGE_UNITID 2 437 438void saa7164_gpio_setup(struct saa7164_dev *dev) 439{ 440 441 442 switch (dev->board) { 443 case SAA7164_BOARD_HAUPPAUGE_HVR2200: 444 case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: 445 case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: 446 case SAA7164_BOARD_HAUPPAUGE_HVR2250: 447 case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: 448 case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: 449 /* 450 GPIO 2: s5h1411 / tda10048-1 demod reset 451 GPIO 3: s5h1411 / tda10048-2 demod reset 452 GPIO 7: IRBlaster Zilog reset 453 */ 454 455 /* Reset parts by going in and out of reset */ 456 saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2); 457 saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3); 458 459 msleep(10); 460 461 saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 2); 462 saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3); 463 break; 464 } 465 466} 467 468static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) 469{ 470 struct tveeprom tv; 471 472 /* TODO: Assumption: eeprom on bus 0 */ 473 tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, 474 eeprom_data); 475 476 /* Make sure we support the board model */ 477 switch (tv.model) { 478 case 88001: 479 /* Development board - Limit circulation */ 480 /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) 481 * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */ 482 case 88021: 483 /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) 484 * ATSC/QAM (TDA18271/S5H1411) and basic analog, MCE CIR, FM */ 485 break; 486 case 88041: 487 /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) 488 * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */ 489 break; 490 case 88061: 491 /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) 492 * ATSC/QAM (TDA18271/S5H1411) and basic analog, FM */ 493 break; 494 case 89519: 495 case 89609: 496 /* WinTV-HVR2200 (PCIe, Retail, full-height) 497 * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ 498 break; 499 case 89619: 500 /* WinTV-HVR2200 (PCIe, Retail, half-height) 501 * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ 502 break; 503 default: 504 printk(KERN_ERR "%s: Warning: Unknown Hauppauge model #%d\n", 505 dev->name, tv.model); 506 break; 507 } 508 509 printk(KERN_INFO "%s: Hauppauge eeprom: model=%d\n", dev->name, 510 tv.model); 511} 512 513void saa7164_card_setup(struct saa7164_dev *dev) 514{ 515 static u8 eeprom[256]; 516 517 if (dev->i2c_bus[0].i2c_rc == 0) { 518 if (saa7164_api_read_eeprom(dev, &eeprom[0], 519 sizeof(eeprom)) < 0) 520 return; 521 } 522 523 switch (dev->board) { 524 case SAA7164_BOARD_HAUPPAUGE_HVR2200: 525 case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: 526 case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: 527 case SAA7164_BOARD_HAUPPAUGE_HVR2250: 528 case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: 529 case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: 530 hauppauge_eeprom(dev, &eeprom[0]); 531 break; 532 } 533} 534 535/* With most other drivers, the kernel expects to communicate with subdrivers 536 * through i2c. This bridge does not allow that, it does not expose any direct 537 * access to I2C. Instead we have to communicate through the device f/w for 538 * register access to 'processing units'. Each unit has a unique 539 * id, regardless of how the physical implementation occurs across 540 * the three physical i2c busses. The being said if we want leverge of 541 * the existing kernel drivers for tuners and demods we have to 'speak i2c', 542 * to this bridge implements 3 virtual i2c buses. This is a helper function 543 * for those. 544 * 545 * Description: Translate the kernels notion of an i2c address and bus into 546 * the appropriate unitid. 547 */ 548int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr) 549{ 550 /* For a given bus and i2c device address, return the saa7164 unique 551 * unitid. < 0 on error */ 552 553 struct saa7164_dev *dev = bus->dev; 554 struct saa7164_unit *unit; 555 int i; 556 557 for (i = 0; i < SAA7164_MAX_UNITS; i++) { 558 unit = &saa7164_boards[dev->board].unit[i]; 559 560 if (unit->type == SAA7164_UNIT_UNDEFINED) 561 continue; 562 if ((bus->nr == unit->i2c_bus_nr) && 563 (addr == unit->i2c_bus_addr)) 564 return unit->id; 565 } 566 567 return -1; 568} 569 570/* The 7164 API needs to know the i2c register length in advance. 571 * this is a helper function. Based on a specific chip addr and bus return the 572 * reg length. 573 */ 574int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr) 575{ 576 /* For a given bus and i2c device address, return the 577 * saa7164 registry address width. < 0 on error 578 */ 579 580 struct saa7164_dev *dev = bus->dev; 581 struct saa7164_unit *unit; 582 int i; 583 584 for (i = 0; i < SAA7164_MAX_UNITS; i++) { 585 unit = &saa7164_boards[dev->board].unit[i]; 586 587 if (unit->type == SAA7164_UNIT_UNDEFINED) 588 continue; 589 590 if ((bus->nr == unit->i2c_bus_nr) && 591 (addr == unit->i2c_bus_addr)) 592 return unit->i2c_reg_len; 593 } 594 595 return -1; 596} 597/* TODO: implement a 'findeeprom' functio like the above and fix any other 598 * eeprom related todo's in -api.c. 599 */ 600 601/* Translate a unitid into a x readable device name, for display purposes. */ 602char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid) 603{ 604 char *undefed = "UNDEFINED"; 605 char *bridge = "BRIDGE"; 606 struct saa7164_unit *unit; 607 int i; 608 609 if (unitid == 0) 610 return bridge; 611 612 for (i = 0; i < SAA7164_MAX_UNITS; i++) { 613 unit = &saa7164_boards[dev->board].unit[i]; 614 615 if (unit->type == SAA7164_UNIT_UNDEFINED) 616 continue; 617 618 if (unitid == unit->id) 619 return unit->name; 620 } 621 622 return undefed; 623} 624