diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
| commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
| tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/common | |
| parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) | |
Diffstat (limited to 'drivers/media/common')
63 files changed, 29896 insertions, 0 deletions
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c new file mode 100644 index 00000000000..9af2140b57a --- /dev/null +++ b/drivers/media/common/saa7146_core.c | |||
| @@ -0,0 +1,595 @@ | |||
| 1 | /* | ||
| 2 | saa7146.o - driver for generic saa7146-based hardware | ||
| 3 | |||
| 4 | Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <media/saa7146.h> | ||
| 22 | |||
| 23 | LIST_HEAD(saa7146_devices); | ||
| 24 | DEFINE_MUTEX(saa7146_devices_lock); | ||
| 25 | |||
| 26 | static int saa7146_num; | ||
| 27 | |||
| 28 | unsigned int saa7146_debug; | ||
| 29 | |||
| 30 | module_param(saa7146_debug, uint, 0644); | ||
| 31 | MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); | ||
| 32 | |||
| 33 | #if 0 | ||
| 34 | static void dump_registers(struct saa7146_dev* dev) | ||
| 35 | { | ||
| 36 | int i = 0; | ||
| 37 | |||
| 38 | INFO((" @ %li jiffies:\n",jiffies)); | ||
| 39 | for(i = 0; i <= 0x148; i+=4) { | ||
| 40 | printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i)); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | #endif | ||
| 44 | |||
| 45 | /**************************************************************************** | ||
| 46 | * gpio and debi helper functions | ||
| 47 | ****************************************************************************/ | ||
| 48 | |||
| 49 | void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) | ||
| 50 | { | ||
| 51 | u32 value = 0; | ||
| 52 | |||
| 53 | BUG_ON(port > 3); | ||
| 54 | |||
| 55 | value = saa7146_read(dev, GPIO_CTRL); | ||
| 56 | value &= ~(0xff << (8*port)); | ||
| 57 | value |= (data << (8*port)); | ||
| 58 | saa7146_write(dev, GPIO_CTRL, value); | ||
| 59 | } | ||
| 60 | |||
| 61 | /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ | ||
| 62 | static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, | ||
| 63 | unsigned long us1, unsigned long us2) | ||
| 64 | { | ||
| 65 | unsigned long timeout; | ||
| 66 | int err; | ||
| 67 | |||
| 68 | /* wait for registers to be programmed */ | ||
| 69 | timeout = jiffies + usecs_to_jiffies(us1); | ||
| 70 | while (1) { | ||
| 71 | err = time_after(jiffies, timeout); | ||
| 72 | if (saa7146_read(dev, MC2) & 2) | ||
| 73 | break; | ||
| 74 | if (err) { | ||
| 75 | printk(KERN_ERR "%s: %s timed out while waiting for " | ||
| 76 | "registers getting programmed\n", | ||
| 77 | dev->name, __func__); | ||
| 78 | return -ETIMEDOUT; | ||
| 79 | } | ||
| 80 | msleep(1); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* wait for transfer to complete */ | ||
| 84 | timeout = jiffies + usecs_to_jiffies(us2); | ||
| 85 | while (1) { | ||
| 86 | err = time_after(jiffies, timeout); | ||
| 87 | if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) | ||
| 88 | break; | ||
| 89 | saa7146_read(dev, MC2); | ||
| 90 | if (err) { | ||
| 91 | DEB_S(("%s: %s timed out while waiting for transfer " | ||
| 92 | "completion\n", dev->name, __func__)); | ||
| 93 | return -ETIMEDOUT; | ||
| 94 | } | ||
| 95 | msleep(1); | ||
| 96 | } | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, | ||
| 102 | unsigned long us1, unsigned long us2) | ||
| 103 | { | ||
| 104 | unsigned long loops; | ||
| 105 | |||
| 106 | /* wait for registers to be programmed */ | ||
| 107 | loops = us1; | ||
| 108 | while (1) { | ||
| 109 | if (saa7146_read(dev, MC2) & 2) | ||
| 110 | break; | ||
| 111 | if (!loops--) { | ||
| 112 | printk(KERN_ERR "%s: %s timed out while waiting for " | ||
| 113 | "registers getting programmed\n", | ||
| 114 | dev->name, __func__); | ||
| 115 | return -ETIMEDOUT; | ||
| 116 | } | ||
| 117 | udelay(1); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* wait for transfer to complete */ | ||
| 121 | loops = us2 / 5; | ||
| 122 | while (1) { | ||
| 123 | if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) | ||
| 124 | break; | ||
| 125 | saa7146_read(dev, MC2); | ||
| 126 | if (!loops--) { | ||
| 127 | DEB_S(("%s: %s timed out while waiting for transfer " | ||
| 128 | "completion\n", dev->name, __func__)); | ||
| 129 | return -ETIMEDOUT; | ||
| 130 | } | ||
| 131 | udelay(5); | ||
| 132 | } | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) | ||
| 138 | { | ||
| 139 | if (nobusyloop) | ||
| 140 | return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000); | ||
| 141 | else | ||
| 142 | return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000); | ||
| 143 | } | ||
| 144 | |||
| 145 | /**************************************************************************** | ||
| 146 | * general helper functions | ||
| 147 | ****************************************************************************/ | ||
| 148 | |||
| 149 | /* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c | ||
| 150 | make sure virt has been allocated with vmalloc_32(), otherwise the BUG() | ||
| 151 | may be triggered on highmem machines */ | ||
| 152 | static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) | ||
| 153 | { | ||
| 154 | struct scatterlist *sglist; | ||
| 155 | struct page *pg; | ||
| 156 | int i; | ||
| 157 | |||
| 158 | sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); | ||
| 159 | if (NULL == sglist) | ||
| 160 | return NULL; | ||
| 161 | sg_init_table(sglist, nr_pages); | ||
| 162 | for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { | ||
| 163 | pg = vmalloc_to_page(virt); | ||
| 164 | if (NULL == pg) | ||
| 165 | goto err; | ||
| 166 | BUG_ON(PageHighMem(pg)); | ||
| 167 | sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); | ||
| 168 | } | ||
| 169 | return sglist; | ||
| 170 | |||
| 171 | err: | ||
| 172 | kfree(sglist); | ||
| 173 | return NULL; | ||
| 174 | } | ||
| 175 | |||
| 176 | /********************************************************************************/ | ||
| 177 | /* common page table functions */ | ||
| 178 | |||
| 179 | void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) | ||
| 180 | { | ||
| 181 | int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; | ||
| 182 | void *mem = vmalloc_32(length); | ||
| 183 | int slen = 0; | ||
| 184 | |||
| 185 | if (NULL == mem) | ||
| 186 | goto err_null; | ||
| 187 | |||
| 188 | if (!(pt->slist = vmalloc_to_sg(mem, pages))) | ||
| 189 | goto err_free_mem; | ||
| 190 | |||
| 191 | if (saa7146_pgtable_alloc(pci, pt)) | ||
| 192 | goto err_free_slist; | ||
| 193 | |||
| 194 | pt->nents = pages; | ||
| 195 | slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); | ||
| 196 | if (0 == slen) | ||
| 197 | goto err_free_pgtable; | ||
| 198 | |||
| 199 | if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) | ||
| 200 | goto err_unmap_sg; | ||
| 201 | |||
| 202 | return mem; | ||
| 203 | |||
| 204 | err_unmap_sg: | ||
| 205 | pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); | ||
| 206 | err_free_pgtable: | ||
| 207 | saa7146_pgtable_free(pci, pt); | ||
| 208 | err_free_slist: | ||
| 209 | kfree(pt->slist); | ||
| 210 | pt->slist = NULL; | ||
| 211 | err_free_mem: | ||
| 212 | vfree(mem); | ||
| 213 | err_null: | ||
| 214 | return NULL; | ||
| 215 | } | ||
| 216 | |||
| 217 | void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) | ||
| 218 | { | ||
| 219 | pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); | ||
| 220 | saa7146_pgtable_free(pci, pt); | ||
| 221 | kfree(pt->slist); | ||
| 222 | pt->slist = NULL; | ||
| 223 | vfree(mem); | ||
| 224 | } | ||
| 225 | |||
| 226 | void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) | ||
| 227 | { | ||
| 228 | if (NULL == pt->cpu) | ||
| 229 | return; | ||
| 230 | pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); | ||
| 231 | pt->cpu = NULL; | ||
| 232 | } | ||
| 233 | |||
| 234 | int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) | ||
| 235 | { | ||
| 236 | __le32 *cpu; | ||
| 237 | dma_addr_t dma_addr = 0; | ||
| 238 | |||
| 239 | cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr); | ||
| 240 | if (NULL == cpu) { | ||
| 241 | return -ENOMEM; | ||
| 242 | } | ||
| 243 | pt->size = PAGE_SIZE; | ||
| 244 | pt->cpu = cpu; | ||
| 245 | pt->dma = dma_addr; | ||
| 246 | |||
| 247 | return 0; | ||
| 248 | } | ||
| 249 | |||
| 250 | int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, | ||
| 251 | struct scatterlist *list, int sglen ) | ||
| 252 | { | ||
| 253 | __le32 *ptr, fill; | ||
| 254 | int nr_pages = 0; | ||
| 255 | int i,p; | ||
| 256 | |||
| 257 | BUG_ON(0 == sglen); | ||
| 258 | BUG_ON(list->offset > PAGE_SIZE); | ||
| 259 | |||
| 260 | /* if we have a user buffer, the first page may not be | ||
| 261 | aligned to a page boundary. */ | ||
| 262 | pt->offset = list->offset; | ||
| 263 | |||
| 264 | ptr = pt->cpu; | ||
| 265 | for (i = 0; i < sglen; i++, list++) { | ||
| 266 | /* | ||
| 267 | printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset); | ||
| 268 | */ | ||
| 269 | for (p = 0; p * 4096 < list->length; p++, ptr++) { | ||
| 270 | *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); | ||
| 271 | nr_pages++; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | |||
| 276 | /* safety; fill the page table up with the last valid page */ | ||
| 277 | fill = *(ptr-1); | ||
| 278 | for(i=nr_pages;i<1024;i++) { | ||
| 279 | *ptr++ = fill; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* | ||
| 283 | ptr = pt->cpu; | ||
| 284 | printk("offset: %d\n",pt->offset); | ||
| 285 | for(i=0;i<5;i++) { | ||
| 286 | printk("ptr1 %d: 0x%08x\n",i,ptr[i]); | ||
| 287 | } | ||
| 288 | */ | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | /********************************************************************************/ | ||
| 293 | /* interrupt handler */ | ||
| 294 | static irqreturn_t interrupt_hw(int irq, void *dev_id) | ||
| 295 | { | ||
| 296 | struct saa7146_dev *dev = dev_id; | ||
| 297 | u32 isr; | ||
| 298 | u32 ack_isr; | ||
| 299 | |||
| 300 | /* read out the interrupt status register */ | ||
| 301 | ack_isr = isr = saa7146_read(dev, ISR); | ||
| 302 | |||
| 303 | /* is this our interrupt? */ | ||
| 304 | if ( 0 == isr ) { | ||
| 305 | /* nope, some other device */ | ||
| 306 | return IRQ_NONE; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (dev->ext) { | ||
| 310 | if (dev->ext->irq_mask & isr) { | ||
| 311 | if (dev->ext->irq_func) | ||
| 312 | dev->ext->irq_func(dev, &isr); | ||
| 313 | isr &= ~dev->ext->irq_mask; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | if (0 != (isr & (MASK_27))) { | ||
| 317 | DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); | ||
| 318 | if (dev->vv_data && dev->vv_callback) | ||
| 319 | dev->vv_callback(dev,isr); | ||
| 320 | isr &= ~MASK_27; | ||
| 321 | } | ||
| 322 | if (0 != (isr & (MASK_28))) { | ||
| 323 | if (dev->vv_data && dev->vv_callback) | ||
| 324 | dev->vv_callback(dev,isr); | ||
| 325 | isr &= ~MASK_28; | ||
| 326 | } | ||
| 327 | if (0 != (isr & (MASK_16|MASK_17))) { | ||
| 328 | SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); | ||
| 329 | /* only wake up if we expect something */ | ||
| 330 | if (0 != dev->i2c_op) { | ||
| 331 | dev->i2c_op = 0; | ||
| 332 | wake_up(&dev->i2c_wq); | ||
| 333 | } else { | ||
| 334 | u32 psr = saa7146_read(dev, PSR); | ||
| 335 | u32 ssr = saa7146_read(dev, SSR); | ||
| 336 | printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", | ||
| 337 | dev->name, isr, psr, ssr); | ||
| 338 | } | ||
| 339 | isr &= ~(MASK_16|MASK_17); | ||
| 340 | } | ||
| 341 | if( 0 != isr ) { | ||
| 342 | ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr)); | ||
| 343 | ERR(("disabling interrupt source(s)!\n")); | ||
| 344 | SAA7146_IER_DISABLE(dev,isr); | ||
| 345 | } | ||
| 346 | saa7146_write(dev, ISR, ack_isr); | ||
| 347 | return IRQ_HANDLED; | ||
| 348 | } | ||
| 349 | |||
| 350 | /*********************************************************************************/ | ||
| 351 | /* configuration-functions */ | ||
| 352 | |||
| 353 | static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) | ||
| 354 | { | ||
| 355 | struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; | ||
| 356 | struct saa7146_extension *ext = pci_ext->ext; | ||
| 357 | struct saa7146_dev *dev; | ||
| 358 | int err = -ENOMEM; | ||
| 359 | |||
| 360 | /* clear out mem for sure */ | ||
| 361 | dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL); | ||
| 362 | if (!dev) { | ||
| 363 | ERR(("out of memory.\n")); | ||
| 364 | goto out; | ||
| 365 | } | ||
| 366 | |||
| 367 | DEB_EE(("pci:%p\n",pci)); | ||
| 368 | |||
| 369 | err = pci_enable_device(pci); | ||
| 370 | if (err < 0) { | ||
| 371 | ERR(("pci_enable_device() failed.\n")); | ||
| 372 | goto err_free; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* enable bus-mastering */ | ||
| 376 | pci_set_master(pci); | ||
| 377 | |||
| 378 | dev->pci = pci; | ||
| 379 | |||
| 380 | /* get chip-revision; this is needed to enable bug-fixes */ | ||
| 381 | dev->revision = pci->revision; | ||
| 382 | |||
| 383 | /* remap the memory from virtual to physical address */ | ||
| 384 | |||
| 385 | err = pci_request_region(pci, 0, "saa7146"); | ||
| 386 | if (err < 0) | ||
| 387 | goto err_disable; | ||
| 388 | |||
| 389 | dev->mem = ioremap(pci_resource_start(pci, 0), | ||
| 390 | pci_resource_len(pci, 0)); | ||
| 391 | if (!dev->mem) { | ||
| 392 | ERR(("ioremap() failed.\n")); | ||
| 393 | err = -ENODEV; | ||
| 394 | goto err_release; | ||
| 395 | } | ||
| 396 | |||
| 397 | /* we don't do a master reset here anymore, it screws up | ||
| 398 | some boards that don't have an i2c-eeprom for configuration | ||
| 399 | values */ | ||
| 400 | /* | ||
| 401 | saa7146_write(dev, MC1, MASK_31); | ||
| 402 | */ | ||
| 403 | |||
| 404 | /* disable all irqs */ | ||
| 405 | saa7146_write(dev, IER, 0); | ||
| 406 | |||
| 407 | /* shut down all dma transfers and rps tasks */ | ||
| 408 | saa7146_write(dev, MC1, 0x30ff0000); | ||
| 409 | |||
| 410 | /* clear out any rps-signals pending */ | ||
| 411 | saa7146_write(dev, MC2, 0xf8000000); | ||
| 412 | |||
| 413 | /* request an interrupt for the saa7146 */ | ||
| 414 | err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED, | ||
| 415 | dev->name, dev); | ||
| 416 | if (err < 0) { | ||
| 417 | ERR(("request_irq() failed.\n")); | ||
| 418 | goto err_unmap; | ||
| 419 | } | ||
| 420 | |||
| 421 | err = -ENOMEM; | ||
| 422 | |||
| 423 | /* get memory for various stuff */ | ||
| 424 | dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, | ||
| 425 | &dev->d_rps0.dma_handle); | ||
| 426 | if (!dev->d_rps0.cpu_addr) | ||
| 427 | goto err_free_irq; | ||
| 428 | memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM); | ||
| 429 | |||
| 430 | dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, | ||
| 431 | &dev->d_rps1.dma_handle); | ||
| 432 | if (!dev->d_rps1.cpu_addr) | ||
| 433 | goto err_free_rps0; | ||
| 434 | memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM); | ||
| 435 | |||
| 436 | dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, | ||
| 437 | &dev->d_i2c.dma_handle); | ||
| 438 | if (!dev->d_i2c.cpu_addr) | ||
| 439 | goto err_free_rps1; | ||
| 440 | memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM); | ||
| 441 | |||
| 442 | /* the rest + print status message */ | ||
| 443 | |||
| 444 | /* create a nice device name */ | ||
| 445 | sprintf(dev->name, "saa7146 (%d)", saa7146_num); | ||
| 446 | |||
| 447 | INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device)); | ||
| 448 | dev->ext = ext; | ||
| 449 | |||
| 450 | mutex_init(&dev->v4l2_lock); | ||
| 451 | spin_lock_init(&dev->int_slock); | ||
| 452 | spin_lock_init(&dev->slock); | ||
| 453 | |||
| 454 | mutex_init(&dev->i2c_lock); | ||
| 455 | |||
| 456 | dev->module = THIS_MODULE; | ||
| 457 | init_waitqueue_head(&dev->i2c_wq); | ||
| 458 | |||
| 459 | /* set some sane pci arbitrition values */ | ||
| 460 | saa7146_write(dev, PCI_BT_V1, 0x1c00101f); | ||
| 461 | |||
| 462 | /* TODO: use the status code of the callback */ | ||
| 463 | |||
| 464 | err = -ENODEV; | ||
| 465 | |||
| 466 | if (ext->probe && ext->probe(dev)) { | ||
| 467 | DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); | ||
| 468 | goto err_free_i2c; | ||
| 469 | } | ||
| 470 | |||
| 471 | if (ext->attach(dev, pci_ext)) { | ||
| 472 | DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); | ||
| 473 | goto err_free_i2c; | ||
| 474 | } | ||
| 475 | /* V4L extensions will set the pci drvdata to the v4l2_device in the | ||
| 476 | attach() above. So for those cards that do not use V4L we have to | ||
| 477 | set it explicitly. */ | ||
| 478 | pci_set_drvdata(pci, &dev->v4l2_dev); | ||
| 479 | |||
| 480 | INIT_LIST_HEAD(&dev->item); | ||
| 481 | list_add_tail(&dev->item,&saa7146_devices); | ||
| 482 | saa7146_num++; | ||
| 483 | |||
| 484 | err = 0; | ||
| 485 | out: | ||
| 486 | return err; | ||
| 487 | |||
| 488 | err_free_i2c: | ||
| 489 | pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, | ||
| 490 | dev->d_i2c.dma_handle); | ||
| 491 | err_free_rps1: | ||
| 492 | pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, | ||
| 493 | dev->d_rps1.dma_handle); | ||
| 494 | err_free_rps0: | ||
| 495 | pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, | ||
| 496 | dev->d_rps0.dma_handle); | ||
| 497 | err_free_irq: | ||
| 498 | free_irq(pci->irq, (void *)dev); | ||
| 499 | err_unmap: | ||
| 500 | iounmap(dev->mem); | ||
| 501 | err_release: | ||
| 502 | pci_release_region(pci, 0); | ||
| 503 | err_disable: | ||
| 504 | pci_disable_device(pci); | ||
| 505 | err_free: | ||
| 506 | kfree(dev); | ||
| 507 | goto out; | ||
| 508 | } | ||
| 509 | |||
| 510 | static void saa7146_remove_one(struct pci_dev *pdev) | ||
| 511 | { | ||
| 512 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); | ||
| 513 | struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); | ||
| 514 | struct { | ||
| 515 | void *addr; | ||
| 516 | dma_addr_t dma; | ||
| 517 | } dev_map[] = { | ||
| 518 | { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle }, | ||
| 519 | { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle }, | ||
| 520 | { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle }, | ||
| 521 | { NULL, 0 } | ||
| 522 | }, *p; | ||
| 523 | |||
| 524 | DEB_EE(("dev:%p\n",dev)); | ||
| 525 | |||
| 526 | dev->ext->detach(dev); | ||
| 527 | /* Zero the PCI drvdata after use. */ | ||
| 528 | pci_set_drvdata(pdev, NULL); | ||
| 529 | |||
| 530 | /* shut down all video dma transfers */ | ||
| 531 | saa7146_write(dev, MC1, 0x00ff0000); | ||
| 532 | |||
| 533 | /* disable all irqs, release irq-routine */ | ||
| 534 | saa7146_write(dev, IER, 0); | ||
| 535 | |||
| 536 | free_irq(pdev->irq, dev); | ||
| 537 | |||
| 538 | for (p = dev_map; p->addr; p++) | ||
| 539 | pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma); | ||
| 540 | |||
| 541 | iounmap(dev->mem); | ||
| 542 | pci_release_region(pdev, 0); | ||
| 543 | list_del(&dev->item); | ||
| 544 | pci_disable_device(pdev); | ||
| 545 | kfree(dev); | ||
| 546 | |||
| 547 | saa7146_num--; | ||
| 548 | } | ||
| 549 | |||
| 550 | /*********************************************************************************/ | ||
| 551 | /* extension handling functions */ | ||
| 552 | |||
| 553 | int saa7146_register_extension(struct saa7146_extension* ext) | ||
| 554 | { | ||
| 555 | DEB_EE(("ext:%p\n",ext)); | ||
| 556 | |||
| 557 | ext->driver.name = ext->name; | ||
| 558 | ext->driver.id_table = ext->pci_tbl; | ||
| 559 | ext->driver.probe = saa7146_init_one; | ||
| 560 | ext->driver.remove = saa7146_remove_one; | ||
| 561 | |||
| 562 | printk("saa7146: register extension '%s'.\n",ext->name); | ||
| 563 | return pci_register_driver(&ext->driver); | ||
| 564 | } | ||
| 565 | |||
| 566 | int saa7146_unregister_extension(struct saa7146_extension* ext) | ||
| 567 | { | ||
| 568 | DEB_EE(("ext:%p\n",ext)); | ||
| 569 | printk("saa7146: unregister extension '%s'.\n",ext->name); | ||
| 570 | pci_unregister_driver(&ext->driver); | ||
| 571 | return 0; | ||
| 572 | } | ||
| 573 | |||
| 574 | EXPORT_SYMBOL_GPL(saa7146_register_extension); | ||
| 575 | EXPORT_SYMBOL_GPL(saa7146_unregister_extension); | ||
| 576 | |||
| 577 | /* misc functions used by extension modules */ | ||
| 578 | EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); | ||
| 579 | EXPORT_SYMBOL_GPL(saa7146_pgtable_free); | ||
| 580 | EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); | ||
| 581 | EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); | ||
| 582 | EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable); | ||
| 583 | EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); | ||
| 584 | |||
| 585 | EXPORT_SYMBOL_GPL(saa7146_setgpio); | ||
| 586 | |||
| 587 | EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); | ||
| 588 | |||
| 589 | EXPORT_SYMBOL_GPL(saa7146_debug); | ||
| 590 | EXPORT_SYMBOL_GPL(saa7146_devices); | ||
| 591 | EXPORT_SYMBOL_GPL(saa7146_devices_lock); | ||
| 592 | |||
| 593 | MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); | ||
| 594 | MODULE_DESCRIPTION("driver for generic saa7146-based hardware"); | ||
| 595 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c new file mode 100644 index 00000000000..1bd3dd762c6 --- /dev/null +++ b/drivers/media/common/saa7146_fops.c | |||
| @@ -0,0 +1,551 @@ | |||
| 1 | #include <media/saa7146_vv.h> | ||
| 2 | |||
| 3 | /****************************************************************************/ | ||
| 4 | /* resource management functions, shamelessly stolen from saa7134 driver */ | ||
| 5 | |||
| 6 | int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) | ||
| 7 | { | ||
| 8 | struct saa7146_dev *dev = fh->dev; | ||
| 9 | struct saa7146_vv *vv = dev->vv_data; | ||
| 10 | |||
| 11 | if (fh->resources & bit) { | ||
| 12 | DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources)); | ||
| 13 | /* have it already allocated */ | ||
| 14 | return 1; | ||
| 15 | } | ||
| 16 | |||
| 17 | /* is it free? */ | ||
| 18 | if (vv->resources & bit) { | ||
| 19 | DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); | ||
| 20 | /* no, someone else uses it */ | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | /* it's free, grab it */ | ||
| 24 | fh->resources |= bit; | ||
| 25 | vv->resources |= bit; | ||
| 26 | DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); | ||
| 27 | return 1; | ||
| 28 | } | ||
| 29 | |||
| 30 | void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) | ||
| 31 | { | ||
| 32 | struct saa7146_dev *dev = fh->dev; | ||
| 33 | struct saa7146_vv *vv = dev->vv_data; | ||
| 34 | |||
| 35 | BUG_ON((fh->resources & bits) != bits); | ||
| 36 | |||
| 37 | fh->resources &= ~bits; | ||
| 38 | vv->resources &= ~bits; | ||
| 39 | DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources)); | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 43 | /********************************************************************************/ | ||
| 44 | /* common dma functions */ | ||
| 45 | |||
| 46 | void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, | ||
| 47 | struct saa7146_buf *buf) | ||
| 48 | { | ||
| 49 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | ||
| 50 | DEB_EE(("dev:%p, buf:%p\n",dev,buf)); | ||
| 51 | |||
| 52 | BUG_ON(in_interrupt()); | ||
| 53 | |||
| 54 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
| 55 | videobuf_dma_unmap(q->dev, dma); | ||
| 56 | videobuf_dma_free(dma); | ||
| 57 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
| 58 | } | ||
| 59 | |||
| 60 | |||
| 61 | /********************************************************************************/ | ||
| 62 | /* common buffer functions */ | ||
| 63 | |||
| 64 | int saa7146_buffer_queue(struct saa7146_dev *dev, | ||
| 65 | struct saa7146_dmaqueue *q, | ||
| 66 | struct saa7146_buf *buf) | ||
| 67 | { | ||
| 68 | assert_spin_locked(&dev->slock); | ||
| 69 | DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf)); | ||
| 70 | |||
| 71 | BUG_ON(!q); | ||
| 72 | |||
| 73 | if (NULL == q->curr) { | ||
| 74 | q->curr = buf; | ||
| 75 | DEB_D(("immediately activating buffer %p\n", buf)); | ||
| 76 | buf->activate(dev,buf,NULL); | ||
| 77 | } else { | ||
| 78 | list_add_tail(&buf->vb.queue,&q->queue); | ||
| 79 | buf->vb.state = VIDEOBUF_QUEUED; | ||
| 80 | DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); | ||
| 81 | } | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | void saa7146_buffer_finish(struct saa7146_dev *dev, | ||
| 86 | struct saa7146_dmaqueue *q, | ||
| 87 | int state) | ||
| 88 | { | ||
| 89 | assert_spin_locked(&dev->slock); | ||
| 90 | DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state)); | ||
| 91 | DEB_EE(("q->curr:%p\n",q->curr)); | ||
| 92 | |||
| 93 | BUG_ON(!q->curr); | ||
| 94 | |||
| 95 | /* finish current buffer */ | ||
| 96 | if (NULL == q->curr) { | ||
| 97 | DEB_D(("aiii. no current buffer\n")); | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | |||
| 101 | q->curr->vb.state = state; | ||
| 102 | do_gettimeofday(&q->curr->vb.ts); | ||
| 103 | wake_up(&q->curr->vb.done); | ||
| 104 | |||
| 105 | q->curr = NULL; | ||
| 106 | } | ||
| 107 | |||
| 108 | void saa7146_buffer_next(struct saa7146_dev *dev, | ||
| 109 | struct saa7146_dmaqueue *q, int vbi) | ||
| 110 | { | ||
| 111 | struct saa7146_buf *buf,*next = NULL; | ||
| 112 | |||
| 113 | BUG_ON(!q); | ||
| 114 | |||
| 115 | DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi)); | ||
| 116 | |||
| 117 | assert_spin_locked(&dev->slock); | ||
| 118 | if (!list_empty(&q->queue)) { | ||
| 119 | /* activate next one from queue */ | ||
| 120 | buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); | ||
| 121 | list_del(&buf->vb.queue); | ||
| 122 | if (!list_empty(&q->queue)) | ||
| 123 | next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); | ||
| 124 | q->curr = buf; | ||
| 125 | DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next)); | ||
| 126 | buf->activate(dev,buf,next); | ||
| 127 | } else { | ||
| 128 | DEB_INT(("no next buffer. stopping.\n")); | ||
| 129 | if( 0 != vbi ) { | ||
| 130 | /* turn off video-dma3 */ | ||
| 131 | saa7146_write(dev,MC1, MASK_20); | ||
| 132 | } else { | ||
| 133 | /* nothing to do -- just prevent next video-dma1 transfer | ||
| 134 | by lowering the protection address */ | ||
| 135 | |||
| 136 | // fixme: fix this for vflip != 0 | ||
| 137 | |||
| 138 | saa7146_write(dev, PROT_ADDR1, 0); | ||
| 139 | saa7146_write(dev, MC2, (MASK_02|MASK_18)); | ||
| 140 | |||
| 141 | /* write the address of the rps-program */ | ||
| 142 | saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); | ||
| 143 | /* turn on rps */ | ||
| 144 | saa7146_write(dev, MC1, (MASK_12 | MASK_28)); | ||
| 145 | |||
| 146 | /* | ||
| 147 | printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); | ||
| 148 | printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); | ||
| 149 | printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); | ||
| 150 | printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); | ||
| 151 | printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); | ||
| 152 | printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); | ||
| 153 | */ | ||
| 154 | } | ||
| 155 | del_timer(&q->timeout); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | void saa7146_buffer_timeout(unsigned long data) | ||
| 160 | { | ||
| 161 | struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data; | ||
| 162 | struct saa7146_dev *dev = q->dev; | ||
| 163 | unsigned long flags; | ||
| 164 | |||
| 165 | DEB_EE(("dev:%p, dmaq:%p\n", dev, q)); | ||
| 166 | |||
| 167 | spin_lock_irqsave(&dev->slock,flags); | ||
| 168 | if (q->curr) { | ||
| 169 | DEB_D(("timeout on %p\n", q->curr)); | ||
| 170 | saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* we don't restart the transfer here like other drivers do. when | ||
| 174 | a streaming capture is disabled, the timeout function will be | ||
| 175 | called for the current buffer. if we activate the next buffer now, | ||
| 176 | we mess up our capture logic. if a timeout occurs on another buffer, | ||
| 177 | then something is seriously broken before, so no need to buffer the | ||
| 178 | next capture IMHO... */ | ||
| 179 | /* | ||
| 180 | saa7146_buffer_next(dev,q); | ||
| 181 | */ | ||
| 182 | spin_unlock_irqrestore(&dev->slock,flags); | ||
| 183 | } | ||
| 184 | |||
| 185 | /********************************************************************************/ | ||
| 186 | /* file operations */ | ||
| 187 | |||
| 188 | static int fops_open(struct file *file) | ||
| 189 | { | ||
| 190 | struct video_device *vdev = video_devdata(file); | ||
| 191 | struct saa7146_dev *dev = video_drvdata(file); | ||
| 192 | struct saa7146_fh *fh = NULL; | ||
| 193 | int result = 0; | ||
| 194 | |||
| 195 | enum v4l2_buf_type type; | ||
| 196 | |||
| 197 | DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev))); | ||
| 198 | |||
| 199 | if (mutex_lock_interruptible(&saa7146_devices_lock)) | ||
| 200 | return -ERESTARTSYS; | ||
| 201 | |||
| 202 | DEB_D(("using: %p\n",dev)); | ||
| 203 | |||
| 204 | type = vdev->vfl_type == VFL_TYPE_GRABBER | ||
| 205 | ? V4L2_BUF_TYPE_VIDEO_CAPTURE | ||
| 206 | : V4L2_BUF_TYPE_VBI_CAPTURE; | ||
| 207 | |||
| 208 | /* check if an extension is registered */ | ||
| 209 | if( NULL == dev->ext ) { | ||
| 210 | DEB_S(("no extension registered for this device.\n")); | ||
| 211 | result = -ENODEV; | ||
| 212 | goto out; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* allocate per open data */ | ||
| 216 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | ||
| 217 | if (NULL == fh) { | ||
| 218 | DEB_S(("cannot allocate memory for per open data.\n")); | ||
| 219 | result = -ENOMEM; | ||
| 220 | goto out; | ||
| 221 | } | ||
| 222 | |||
| 223 | file->private_data = fh; | ||
| 224 | fh->dev = dev; | ||
| 225 | fh->type = type; | ||
| 226 | |||
| 227 | if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
| 228 | DEB_S(("initializing vbi...\n")); | ||
| 229 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
| 230 | result = saa7146_vbi_uops.open(dev,file); | ||
| 231 | if (dev->ext_vv_data->vbi_fops.open) | ||
| 232 | dev->ext_vv_data->vbi_fops.open(file); | ||
| 233 | } else { | ||
| 234 | DEB_S(("initializing video...\n")); | ||
| 235 | result = saa7146_video_uops.open(dev,file); | ||
| 236 | } | ||
| 237 | |||
| 238 | if (0 != result) { | ||
| 239 | goto out; | ||
| 240 | } | ||
| 241 | |||
| 242 | if( 0 == try_module_get(dev->ext->module)) { | ||
| 243 | result = -EINVAL; | ||
| 244 | goto out; | ||
| 245 | } | ||
| 246 | |||
| 247 | result = 0; | ||
| 248 | out: | ||
| 249 | if (fh && result != 0) { | ||
| 250 | kfree(fh); | ||
| 251 | file->private_data = NULL; | ||
| 252 | } | ||
| 253 | mutex_unlock(&saa7146_devices_lock); | ||
| 254 | return result; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int fops_release(struct file *file) | ||
| 258 | { | ||
| 259 | struct saa7146_fh *fh = file->private_data; | ||
| 260 | struct saa7146_dev *dev = fh->dev; | ||
| 261 | |||
| 262 | DEB_EE(("file:%p\n", file)); | ||
| 263 | |||
| 264 | if (mutex_lock_interruptible(&saa7146_devices_lock)) | ||
| 265 | return -ERESTARTSYS; | ||
| 266 | |||
| 267 | if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
| 268 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
| 269 | saa7146_vbi_uops.release(dev,file); | ||
| 270 | if (dev->ext_vv_data->vbi_fops.release) | ||
| 271 | dev->ext_vv_data->vbi_fops.release(file); | ||
| 272 | } else { | ||
| 273 | saa7146_video_uops.release(dev,file); | ||
| 274 | } | ||
| 275 | |||
| 276 | module_put(dev->ext->module); | ||
| 277 | file->private_data = NULL; | ||
| 278 | kfree(fh); | ||
| 279 | |||
| 280 | mutex_unlock(&saa7146_devices_lock); | ||
| 281 | |||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int fops_mmap(struct file *file, struct vm_area_struct * vma) | ||
| 286 | { | ||
| 287 | struct saa7146_fh *fh = file->private_data; | ||
| 288 | struct videobuf_queue *q; | ||
| 289 | |||
| 290 | switch (fh->type) { | ||
| 291 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { | ||
| 292 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma)); | ||
| 293 | q = &fh->video_q; | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | case V4L2_BUF_TYPE_VBI_CAPTURE: { | ||
| 297 | DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma)); | ||
| 298 | q = &fh->vbi_q; | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | default: | ||
| 302 | BUG(); | ||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | return videobuf_mmap_mapper(q,vma); | ||
| 307 | } | ||
| 308 | |||
| 309 | static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) | ||
| 310 | { | ||
| 311 | struct saa7146_fh *fh = file->private_data; | ||
| 312 | struct videobuf_buffer *buf = NULL; | ||
| 313 | struct videobuf_queue *q; | ||
| 314 | |||
| 315 | DEB_EE(("file:%p, poll:%p\n",file, wait)); | ||
| 316 | |||
| 317 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { | ||
| 318 | if( 0 == fh->vbi_q.streaming ) | ||
| 319 | return videobuf_poll_stream(file, &fh->vbi_q, wait); | ||
| 320 | q = &fh->vbi_q; | ||
| 321 | } else { | ||
| 322 | DEB_D(("using video queue.\n")); | ||
| 323 | q = &fh->video_q; | ||
| 324 | } | ||
| 325 | |||
| 326 | if (!list_empty(&q->stream)) | ||
| 327 | buf = list_entry(q->stream.next, struct videobuf_buffer, stream); | ||
| 328 | |||
| 329 | if (!buf) { | ||
| 330 | DEB_D(("buf == NULL!\n")); | ||
| 331 | return POLLERR; | ||
| 332 | } | ||
| 333 | |||
| 334 | poll_wait(file, &buf->done, wait); | ||
| 335 | if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { | ||
| 336 | DEB_D(("poll succeeded!\n")); | ||
| 337 | return POLLIN|POLLRDNORM; | ||
| 338 | } | ||
| 339 | |||
| 340 | DEB_D(("nothing to poll for, buf->state:%d\n",buf->state)); | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
| 345 | { | ||
| 346 | struct saa7146_fh *fh = file->private_data; | ||
| 347 | |||
| 348 | switch (fh->type) { | ||
| 349 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { | ||
| 350 | // DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count)); | ||
| 351 | return saa7146_video_uops.read(file,data,count,ppos); | ||
| 352 | } | ||
| 353 | case V4L2_BUF_TYPE_VBI_CAPTURE: { | ||
| 354 | // DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count)); | ||
| 355 | if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
| 356 | return saa7146_vbi_uops.read(file,data,count,ppos); | ||
| 357 | else | ||
| 358 | return -EINVAL; | ||
| 359 | } | ||
| 360 | break; | ||
| 361 | default: | ||
| 362 | BUG(); | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) | ||
| 368 | { | ||
| 369 | struct saa7146_fh *fh = file->private_data; | ||
| 370 | |||
| 371 | switch (fh->type) { | ||
| 372 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
| 373 | return -EINVAL; | ||
| 374 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
| 375 | if (fh->dev->ext_vv_data->vbi_fops.write) | ||
| 376 | return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); | ||
| 377 | else | ||
| 378 | return -EINVAL; | ||
| 379 | default: | ||
| 380 | BUG(); | ||
| 381 | return -EINVAL; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | static const struct v4l2_file_operations video_fops = | ||
| 386 | { | ||
| 387 | .owner = THIS_MODULE, | ||
| 388 | .open = fops_open, | ||
| 389 | .release = fops_release, | ||
| 390 | .read = fops_read, | ||
| 391 | .write = fops_write, | ||
| 392 | .poll = fops_poll, | ||
| 393 | .mmap = fops_mmap, | ||
| 394 | .unlocked_ioctl = video_ioctl2, | ||
| 395 | }; | ||
| 396 | |||
| 397 | static void vv_callback(struct saa7146_dev *dev, unsigned long status) | ||
| 398 | { | ||
| 399 | u32 isr = status; | ||
| 400 | |||
| 401 | DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status)); | ||
| 402 | |||
| 403 | if (0 != (isr & (MASK_27))) { | ||
| 404 | DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); | ||
| 405 | saa7146_video_uops.irq_done(dev,isr); | ||
| 406 | } | ||
| 407 | |||
| 408 | if (0 != (isr & (MASK_28))) { | ||
| 409 | u32 mc2 = saa7146_read(dev, MC2); | ||
| 410 | if( 0 != (mc2 & MASK_15)) { | ||
| 411 | DEB_INT(("irq: RPS1 vbi workaround (0x%08x).\n",isr)); | ||
| 412 | wake_up(&dev->vv_data->vbi_wq); | ||
| 413 | saa7146_write(dev,MC2, MASK_31); | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | DEB_INT(("irq: RPS1 (0x%08x).\n",isr)); | ||
| 417 | saa7146_vbi_uops.irq_done(dev,isr); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) | ||
| 422 | { | ||
| 423 | struct saa7146_vv *vv; | ||
| 424 | int err; | ||
| 425 | |||
| 426 | err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev); | ||
| 427 | if (err) | ||
| 428 | return err; | ||
| 429 | |||
| 430 | vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); | ||
| 431 | if (vv == NULL) { | ||
| 432 | ERR(("out of memory. aborting.\n")); | ||
| 433 | return -ENOMEM; | ||
| 434 | } | ||
| 435 | ext_vv->ops = saa7146_video_ioctl_ops; | ||
| 436 | ext_vv->core_ops = &saa7146_video_ioctl_ops; | ||
| 437 | |||
| 438 | DEB_EE(("dev:%p\n",dev)); | ||
| 439 | |||
| 440 | /* set default values for video parts of the saa7146 */ | ||
| 441 | saa7146_write(dev, BCS_CTRL, 0x80400040); | ||
| 442 | |||
| 443 | /* enable video-port pins */ | ||
| 444 | saa7146_write(dev, MC1, (MASK_10 | MASK_26)); | ||
| 445 | |||
| 446 | /* save per-device extension data (one extension can | ||
| 447 | handle different devices that might need different | ||
| 448 | configuration data) */ | ||
| 449 | dev->ext_vv_data = ext_vv; | ||
| 450 | |||
| 451 | vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); | ||
| 452 | if( NULL == vv->d_clipping.cpu_addr ) { | ||
| 453 | ERR(("out of memory. aborting.\n")); | ||
| 454 | kfree(vv); | ||
| 455 | return -1; | ||
| 456 | } | ||
| 457 | memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM); | ||
| 458 | |||
| 459 | saa7146_video_uops.init(dev,vv); | ||
| 460 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
| 461 | saa7146_vbi_uops.init(dev,vv); | ||
| 462 | |||
| 463 | dev->vv_data = vv; | ||
| 464 | dev->vv_callback = &vv_callback; | ||
| 465 | |||
| 466 | return 0; | ||
| 467 | } | ||
| 468 | EXPORT_SYMBOL_GPL(saa7146_vv_init); | ||
| 469 | |||
| 470 | int saa7146_vv_release(struct saa7146_dev* dev) | ||
| 471 | { | ||
| 472 | struct saa7146_vv *vv = dev->vv_data; | ||
| 473 | |||
| 474 | DEB_EE(("dev:%p\n",dev)); | ||
| 475 | |||
| 476 | v4l2_device_unregister(&dev->v4l2_dev); | ||
| 477 | pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); | ||
| 478 | kfree(vv); | ||
| 479 | dev->vv_data = NULL; | ||
| 480 | dev->vv_callback = NULL; | ||
| 481 | |||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | EXPORT_SYMBOL_GPL(saa7146_vv_release); | ||
| 485 | |||
| 486 | int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, | ||
| 487 | char *name, int type) | ||
| 488 | { | ||
| 489 | struct video_device *vfd; | ||
| 490 | int err; | ||
| 491 | int i; | ||
| 492 | |||
| 493 | DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); | ||
| 494 | |||
| 495 | // released by vfd->release | ||
| 496 | vfd = video_device_alloc(); | ||
| 497 | if (vfd == NULL) | ||
| 498 | return -ENOMEM; | ||
| 499 | |||
| 500 | vfd->fops = &video_fops; | ||
| 501 | vfd->ioctl_ops = &dev->ext_vv_data->ops; | ||
| 502 | vfd->release = video_device_release; | ||
| 503 | vfd->lock = &dev->v4l2_lock; | ||
| 504 | vfd->tvnorms = 0; | ||
| 505 | for (i = 0; i < dev->ext_vv_data->num_stds; i++) | ||
| 506 | vfd->tvnorms |= dev->ext_vv_data->stds[i].id; | ||
| 507 | strlcpy(vfd->name, name, sizeof(vfd->name)); | ||
| 508 | video_set_drvdata(vfd, dev); | ||
| 509 | |||
| 510 | err = video_register_device(vfd, type, -1); | ||
| 511 | if (err < 0) { | ||
| 512 | ERR(("cannot register v4l2 device. skipping.\n")); | ||
| 513 | video_device_release(vfd); | ||
| 514 | return err; | ||
| 515 | } | ||
| 516 | |||
| 517 | INFO(("%s: registered device %s [v4l2]\n", | ||
| 518 | dev->name, video_device_node_name(vfd))); | ||
| 519 | |||
| 520 | *vid = vfd; | ||
| 521 | return 0; | ||
| 522 | } | ||
| 523 | EXPORT_SYMBOL_GPL(saa7146_register_device); | ||
| 524 | |||
| 525 | int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) | ||
| 526 | { | ||
| 527 | DEB_EE(("dev:%p\n",dev)); | ||
| 528 | |||
| 529 | video_unregister_device(*vid); | ||
| 530 | *vid = NULL; | ||
| 531 | |||
| 532 | return 0; | ||
| 533 | } | ||
| 534 | EXPORT_SYMBOL_GPL(saa7146_unregister_device); | ||
| 535 | |||
| 536 | static int __init saa7146_vv_init_module(void) | ||
| 537 | { | ||
| 538 | return 0; | ||
| 539 | } | ||
| 540 | |||
| 541 | |||
| 542 | static void __exit saa7146_vv_cleanup_module(void) | ||
| 543 | { | ||
| 544 | } | ||
| 545 | |||
| 546 | module_init(saa7146_vv_init_module); | ||
| 547 | module_exit(saa7146_vv_cleanup_module); | ||
| 548 | |||
| 549 | MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); | ||
| 550 | MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware"); | ||
| 551 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c new file mode 100644 index 00000000000..1d1d8d20075 --- /dev/null +++ b/drivers/media/common/saa7146_hlp.c | |||
| @@ -0,0 +1,1044 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <media/saa7146_vv.h> | ||
| 3 | |||
| 4 | static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) | ||
| 5 | { | ||
| 6 | /* clear out the necessary bits */ | ||
| 7 | *clip_format &= 0x0000ffff; | ||
| 8 | /* set these bits new */ | ||
| 9 | *clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16)); | ||
| 10 | } | ||
| 11 | |||
| 12 | static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl) | ||
| 13 | { | ||
| 14 | *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28); | ||
| 15 | *hps_ctrl |= (source << 30) | (sync << 28); | ||
| 16 | } | ||
| 17 | |||
| 18 | static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl) | ||
| 19 | { | ||
| 20 | int hyo = 0, hxo = 0; | ||
| 21 | |||
| 22 | hyo = vv->standard->v_offset; | ||
| 23 | hxo = vv->standard->h_offset; | ||
| 24 | |||
| 25 | *hps_h_scale &= ~(MASK_B0 | 0xf00); | ||
| 26 | *hps_h_scale |= (hxo << 0); | ||
| 27 | |||
| 28 | *hps_ctrl &= ~(MASK_W0 | MASK_B2); | ||
| 29 | *hps_ctrl |= (hyo << 12); | ||
| 30 | } | ||
| 31 | |||
| 32 | /* helper functions for the calculation of the horizontal- and vertical | ||
| 33 | scaling registers, clip-format-register etc ... | ||
| 34 | these functions take pointers to the (most-likely read-out | ||
| 35 | original-values) and manipulate them according to the requested | ||
| 36 | changes. | ||
| 37 | */ | ||
| 38 | |||
| 39 | /* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */ | ||
| 40 | static struct { | ||
| 41 | u16 hps_coeff; | ||
| 42 | u16 weight_sum; | ||
| 43 | } hps_h_coeff_tab [] = { | ||
| 44 | {0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8}, | ||
| 45 | {0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8}, | ||
| 46 | {0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8}, | ||
| 47 | {0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8}, | ||
| 48 | {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8}, | ||
| 49 | {0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8}, | ||
| 50 | {0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, | ||
| 51 | {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, | ||
| 52 | {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, | ||
| 53 | {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8}, | ||
| 54 | {0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, | ||
| 55 | {0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8}, | ||
| 56 | {0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16} | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* table of attenuation values for horizontal scaling */ | ||
| 60 | static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0}; | ||
| 61 | |||
| 62 | /* calculate horizontal scale registers */ | ||
| 63 | static int calculate_h_scale_registers(struct saa7146_dev *dev, | ||
| 64 | int in_x, int out_x, int flip_lr, | ||
| 65 | u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale) | ||
| 66 | { | ||
| 67 | /* horizontal prescaler */ | ||
| 68 | u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0; | ||
| 69 | /* horizontal scaler */ | ||
| 70 | u32 xim = 0, xp = 0, xsci =0; | ||
| 71 | /* vertical scale & gain */ | ||
| 72 | u32 pfuv = 0; | ||
| 73 | |||
| 74 | /* helper variables */ | ||
| 75 | u32 h_atten = 0, i = 0; | ||
| 76 | |||
| 77 | if ( 0 == out_x ) { | ||
| 78 | return -EINVAL; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* mask out vanity-bit */ | ||
| 82 | *hps_ctrl &= ~MASK_29; | ||
| 83 | |||
| 84 | /* calculate prescale-(xspc)-value: [n .. 1/2) : 1 | ||
| 85 | [1/2 .. 1/3) : 2 | ||
| 86 | [1/3 .. 1/4) : 3 | ||
| 87 | ... */ | ||
| 88 | if (in_x > out_x) { | ||
| 89 | xpsc = in_x / out_x; | ||
| 90 | } | ||
| 91 | else { | ||
| 92 | /* zooming */ | ||
| 93 | xpsc = 1; | ||
| 94 | } | ||
| 95 | |||
| 96 | /* if flip_lr-bit is set, number of pixels after | ||
| 97 | horizontal prescaling must be < 384 */ | ||
| 98 | if ( 0 != flip_lr ) { | ||
| 99 | |||
| 100 | /* set vanity bit */ | ||
| 101 | *hps_ctrl |= MASK_29; | ||
| 102 | |||
| 103 | while (in_x / xpsc >= 384 ) | ||
| 104 | xpsc++; | ||
| 105 | } | ||
| 106 | /* if zooming is wanted, number of pixels after | ||
| 107 | horizontal prescaling must be < 768 */ | ||
| 108 | else { | ||
| 109 | while ( in_x / xpsc >= 768 ) | ||
| 110 | xpsc++; | ||
| 111 | } | ||
| 112 | |||
| 113 | /* maximum prescale is 64 (p.69) */ | ||
| 114 | if ( xpsc > 64 ) | ||
| 115 | xpsc = 64; | ||
| 116 | |||
| 117 | /* keep xacm clear*/ | ||
| 118 | xacm = 0; | ||
| 119 | |||
| 120 | /* set horizontal filter parameters (CXY = CXUV) */ | ||
| 121 | cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff; | ||
| 122 | cxuv = cxy; | ||
| 123 | |||
| 124 | /* calculate and set horizontal fine scale (xsci) */ | ||
| 125 | |||
| 126 | /* bypass the horizontal scaler ? */ | ||
| 127 | if ( (in_x == out_x) && ( 1 == xpsc ) ) | ||
| 128 | xsci = 0x400; | ||
| 129 | else | ||
| 130 | xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc; | ||
| 131 | |||
| 132 | /* set start phase for horizontal fine scale (xp) to 0 */ | ||
| 133 | xp = 0; | ||
| 134 | |||
| 135 | /* set xim, if we bypass the horizontal scaler */ | ||
| 136 | if ( 0x400 == xsci ) | ||
| 137 | xim = 1; | ||
| 138 | else | ||
| 139 | xim = 0; | ||
| 140 | |||
| 141 | /* if the prescaler is bypassed, enable horizontal | ||
| 142 | accumulation mode (xacm) and clear dcgx */ | ||
| 143 | if( 1 == xpsc ) { | ||
| 144 | xacm = 1; | ||
| 145 | dcgx = 0; | ||
| 146 | } else { | ||
| 147 | xacm = 0; | ||
| 148 | /* get best match in the table of attenuations | ||
| 149 | for horizontal scaling */ | ||
| 150 | h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum; | ||
| 151 | |||
| 152 | for (i = 0; h_attenuation[i] != 0; i++) { | ||
| 153 | if (h_attenuation[i] >= h_atten) | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | |||
| 157 | dcgx = i; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* the horizontal scaling increment controls the UV filter | ||
| 161 | to reduce the bandwidth to improve the display quality, | ||
| 162 | so set it ... */ | ||
| 163 | if ( xsci == 0x400) | ||
| 164 | pfuv = 0x00; | ||
| 165 | else if ( xsci < 0x600) | ||
| 166 | pfuv = 0x01; | ||
| 167 | else if ( xsci < 0x680) | ||
| 168 | pfuv = 0x11; | ||
| 169 | else if ( xsci < 0x700) | ||
| 170 | pfuv = 0x22; | ||
| 171 | else | ||
| 172 | pfuv = 0x33; | ||
| 173 | |||
| 174 | |||
| 175 | *hps_v_gain &= MASK_W0|MASK_B2; | ||
| 176 | *hps_v_gain |= (pfuv << 24); | ||
| 177 | |||
| 178 | *hps_h_scale &= ~(MASK_W1 | 0xf000); | ||
| 179 | *hps_h_scale |= (xim << 31) | (xp << 24) | (xsci << 12); | ||
| 180 | |||
| 181 | *hps_h_prescale |= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | static struct { | ||
| 187 | u16 hps_coeff; | ||
| 188 | u16 weight_sum; | ||
| 189 | } hps_v_coeff_tab [] = { | ||
| 190 | {0x0100, 2}, {0x0102, 4}, {0x0300, 4}, {0x0106, 8}, {0x0502, 8}, | ||
| 191 | {0x0708, 8}, {0x0F00, 8}, {0x011E, 16}, {0x110E, 16}, {0x1926, 16}, | ||
| 192 | {0x3906, 16}, {0x3D42, 16}, {0x7D02, 16}, {0x7F80, 16}, {0xFF00, 16}, | ||
| 193 | {0x01FE, 32}, {0x01FE, 32}, {0x817E, 32}, {0x817E, 32}, {0xC13E, 32}, | ||
| 194 | {0xC13E, 32}, {0xE11E, 32}, {0xE11E, 32}, {0xF10E, 32}, {0xF10E, 32}, | ||
| 195 | {0xF906, 32}, {0xF906, 32}, {0xFD02, 32}, {0xFD02, 32}, {0xFF00, 32}, | ||
| 196 | {0xFF00, 32}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, | ||
| 197 | {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, | ||
| 198 | {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, | ||
| 199 | {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x817E, 64}, | ||
| 200 | {0x817E, 64}, {0xC13E, 64}, {0xC13E, 64}, {0xE11E, 64}, {0xE11E, 64}, | ||
| 201 | {0xF10E, 64}, {0xF10E, 64}, {0xF906, 64}, {0xF906, 64}, {0xFD02, 64}, | ||
| 202 | {0xFD02, 64}, {0xFF00, 64}, {0xFF00, 64}, {0x01FE, 128} | ||
| 203 | }; | ||
| 204 | |||
| 205 | /* table of attenuation values for vertical scaling */ | ||
| 206 | static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0}; | ||
| 207 | |||
| 208 | /* calculate vertical scale registers */ | ||
| 209 | static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field, | ||
| 210 | int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain) | ||
| 211 | { | ||
| 212 | int lpi = 0; | ||
| 213 | |||
| 214 | /* vertical scaling */ | ||
| 215 | u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0; | ||
| 216 | /* vertical scale & gain */ | ||
| 217 | u32 dcgy = 0, cya_cyb = 0; | ||
| 218 | |||
| 219 | /* helper variables */ | ||
| 220 | u32 v_atten = 0, i = 0; | ||
| 221 | |||
| 222 | /* error, if vertical zooming */ | ||
| 223 | if ( in_y < out_y ) { | ||
| 224 | return -EINVAL; | ||
| 225 | } | ||
| 226 | |||
| 227 | /* linear phase interpolation may be used | ||
| 228 | if scaling is between 1 and 1/2 (both fields used) | ||
| 229 | or scaling is between 1/2 and 1/4 (if only one field is used) */ | ||
| 230 | |||
| 231 | if (V4L2_FIELD_HAS_BOTH(field)) { | ||
| 232 | if( 2*out_y >= in_y) { | ||
| 233 | lpi = 1; | ||
| 234 | } | ||
| 235 | } else if (field == V4L2_FIELD_TOP | ||
| 236 | || field == V4L2_FIELD_ALTERNATE | ||
| 237 | || field == V4L2_FIELD_BOTTOM) { | ||
| 238 | if( 4*out_y >= in_y ) { | ||
| 239 | lpi = 1; | ||
| 240 | } | ||
| 241 | out_y *= 2; | ||
| 242 | } | ||
| 243 | if( 0 != lpi ) { | ||
| 244 | |||
| 245 | yacm = 0; | ||
| 246 | yacl = 0; | ||
| 247 | cya_cyb = 0x00ff; | ||
| 248 | |||
| 249 | /* calculate scaling increment */ | ||
| 250 | if ( in_y > out_y ) | ||
| 251 | ysci = ((1024 * in_y) / (out_y + 1)) - 1024; | ||
| 252 | else | ||
| 253 | ysci = 0; | ||
| 254 | |||
| 255 | dcgy = 0; | ||
| 256 | |||
| 257 | /* calculate ype and ypo */ | ||
| 258 | ype = ysci / 16; | ||
| 259 | ypo = ype + (ysci / 64); | ||
| 260 | |||
| 261 | } else { | ||
| 262 | yacm = 1; | ||
| 263 | |||
| 264 | /* calculate scaling increment */ | ||
| 265 | ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10; | ||
| 266 | |||
| 267 | /* calculate ype and ypo */ | ||
| 268 | ypo = ype = ((ysci + 15) / 16); | ||
| 269 | |||
| 270 | /* the sequence length interval (yacl) has to be set according | ||
| 271 | to the prescale value, e.g. [n .. 1/2) : 0 | ||
| 272 | [1/2 .. 1/3) : 1 | ||
| 273 | [1/3 .. 1/4) : 2 | ||
| 274 | ... */ | ||
| 275 | if ( ysci < 512) { | ||
| 276 | yacl = 0; | ||
| 277 | } else { | ||
| 278 | yacl = ( ysci / (1024 - ysci) ); | ||
| 279 | } | ||
| 280 | |||
| 281 | /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */ | ||
| 282 | cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff; | ||
| 283 | |||
| 284 | /* get best match in the table of attenuations for vertical scaling */ | ||
| 285 | v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum; | ||
| 286 | |||
| 287 | for (i = 0; v_attenuation[i] != 0; i++) { | ||
| 288 | if (v_attenuation[i] >= v_atten) | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | |||
| 292 | dcgy = i; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* ypo and ype swapped in spec ? */ | ||
| 296 | *hps_v_scale |= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1); | ||
| 297 | |||
| 298 | *hps_v_gain &= ~(MASK_W0|MASK_B2); | ||
| 299 | *hps_v_gain |= (dcgy << 16) | (cya_cyb << 0); | ||
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* simple bubble-sort algorithm with duplicate elimination */ | ||
| 305 | static int sort_and_eliminate(u32* values, int* count) | ||
| 306 | { | ||
| 307 | int low = 0, high = 0, top = 0, temp = 0; | ||
| 308 | int cur = 0, next = 0; | ||
| 309 | |||
| 310 | /* sanity checks */ | ||
| 311 | if( (0 > *count) || (NULL == values) ) { | ||
| 312 | return -EINVAL; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* bubble sort the first @count items of the array @values */ | ||
| 316 | for( top = *count; top > 0; top--) { | ||
| 317 | for( low = 0, high = 1; high < top; low++, high++) { | ||
| 318 | if( values[low] > values[high] ) { | ||
| 319 | temp = values[low]; | ||
| 320 | values[low] = values[high]; | ||
| 321 | values[high] = temp; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | /* remove duplicate items */ | ||
| 327 | for( cur = 0, next = 1; next < *count; next++) { | ||
| 328 | if( values[cur] != values[next]) | ||
| 329 | values[++cur] = values[next]; | ||
| 330 | } | ||
| 331 | |||
| 332 | *count = cur + 1; | ||
| 333 | |||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 337 | static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh, | ||
| 338 | struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field) | ||
| 339 | { | ||
| 340 | struct saa7146_vv *vv = dev->vv_data; | ||
| 341 | __le32 *clipping = vv->d_clipping.cpu_addr; | ||
| 342 | |||
| 343 | int width = fh->ov.win.w.width; | ||
| 344 | int height = fh->ov.win.w.height; | ||
| 345 | int clipcount = fh->ov.nclips; | ||
| 346 | |||
| 347 | u32 line_list[32]; | ||
| 348 | u32 pixel_list[32]; | ||
| 349 | int numdwords = 0; | ||
| 350 | |||
| 351 | int i = 0, j = 0; | ||
| 352 | int cnt_line = 0, cnt_pixel = 0; | ||
| 353 | |||
| 354 | int x[32], y[32], w[32], h[32]; | ||
| 355 | |||
| 356 | /* clear out memory */ | ||
| 357 | memset(&line_list[0], 0x00, sizeof(u32)*32); | ||
| 358 | memset(&pixel_list[0], 0x00, sizeof(u32)*32); | ||
| 359 | memset(clipping, 0x00, SAA7146_CLIPPING_MEM); | ||
| 360 | |||
| 361 | /* fill the line and pixel-lists */ | ||
| 362 | for(i = 0; i < clipcount; i++) { | ||
| 363 | int l = 0, r = 0, t = 0, b = 0; | ||
| 364 | |||
| 365 | x[i] = fh->ov.clips[i].c.left; | ||
| 366 | y[i] = fh->ov.clips[i].c.top; | ||
| 367 | w[i] = fh->ov.clips[i].c.width; | ||
| 368 | h[i] = fh->ov.clips[i].c.height; | ||
| 369 | |||
| 370 | if( w[i] < 0) { | ||
| 371 | x[i] += w[i]; w[i] = -w[i]; | ||
| 372 | } | ||
| 373 | if( h[i] < 0) { | ||
| 374 | y[i] += h[i]; h[i] = -h[i]; | ||
| 375 | } | ||
| 376 | if( x[i] < 0) { | ||
| 377 | w[i] += x[i]; x[i] = 0; | ||
| 378 | } | ||
| 379 | if( y[i] < 0) { | ||
| 380 | h[i] += y[i]; y[i] = 0; | ||
| 381 | } | ||
| 382 | if( 0 != vv->vflip ) { | ||
| 383 | y[i] = height - y[i] - h[i]; | ||
| 384 | } | ||
| 385 | |||
| 386 | l = x[i]; | ||
| 387 | r = x[i]+w[i]; | ||
| 388 | t = y[i]; | ||
| 389 | b = y[i]+h[i]; | ||
| 390 | |||
| 391 | /* insert left/right coordinates */ | ||
| 392 | pixel_list[ 2*i ] = min_t(int, l, width); | ||
| 393 | pixel_list[(2*i)+1] = min_t(int, r, width); | ||
| 394 | /* insert top/bottom coordinates */ | ||
| 395 | line_list[ 2*i ] = min_t(int, t, height); | ||
| 396 | line_list[(2*i)+1] = min_t(int, b, height); | ||
| 397 | } | ||
| 398 | |||
| 399 | /* sort and eliminate lists */ | ||
| 400 | cnt_line = cnt_pixel = 2*clipcount; | ||
| 401 | sort_and_eliminate( &pixel_list[0], &cnt_pixel ); | ||
| 402 | sort_and_eliminate( &line_list[0], &cnt_line ); | ||
| 403 | |||
| 404 | /* calculate the number of used u32s */ | ||
| 405 | numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2; | ||
| 406 | numdwords = max_t(int, 4, numdwords); | ||
| 407 | numdwords = min_t(int, 64, numdwords); | ||
| 408 | |||
| 409 | /* fill up cliptable */ | ||
| 410 | for(i = 0; i < cnt_pixel; i++) { | ||
| 411 | clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16); | ||
| 412 | } | ||
| 413 | for(i = 0; i < cnt_line; i++) { | ||
| 414 | clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16); | ||
| 415 | } | ||
| 416 | |||
| 417 | /* fill up cliptable with the display infos */ | ||
| 418 | for(j = 0; j < clipcount; j++) { | ||
| 419 | |||
| 420 | for(i = 0; i < cnt_pixel; i++) { | ||
| 421 | |||
| 422 | if( x[j] < 0) | ||
| 423 | x[j] = 0; | ||
| 424 | |||
| 425 | if( pixel_list[i] < (x[j] + w[j])) { | ||
| 426 | |||
| 427 | if ( pixel_list[i] >= x[j] ) { | ||
| 428 | clipping[2*i] |= cpu_to_le32(1 << j); | ||
| 429 | } | ||
| 430 | } | ||
| 431 | } | ||
| 432 | for(i = 0; i < cnt_line; i++) { | ||
| 433 | |||
| 434 | if( y[j] < 0) | ||
| 435 | y[j] = 0; | ||
| 436 | |||
| 437 | if( line_list[i] < (y[j] + h[j]) ) { | ||
| 438 | |||
| 439 | if( line_list[i] >= y[j] ) { | ||
| 440 | clipping[(2*i)+1] |= cpu_to_le32(1 << j); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | /* adjust arbitration control register */ | ||
| 447 | *arbtr_ctrl &= 0xffff00ff; | ||
| 448 | *arbtr_ctrl |= 0x00001c00; | ||
| 449 | |||
| 450 | vdma2->base_even = vv->d_clipping.dma_handle; | ||
| 451 | vdma2->base_odd = vv->d_clipping.dma_handle; | ||
| 452 | vdma2->prot_addr = vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords)); | ||
| 453 | vdma2->base_page = 0x04; | ||
| 454 | vdma2->pitch = 0x00; | ||
| 455 | vdma2->num_line_byte = (0 << 16 | (sizeof(u32))*(numdwords-1) ); | ||
| 456 | |||
| 457 | /* set clipping-mode. this depends on the field(s) used */ | ||
| 458 | *clip_format &= 0xfffffff7; | ||
| 459 | if (V4L2_FIELD_HAS_BOTH(field)) { | ||
| 460 | *clip_format |= 0x00000008; | ||
| 461 | } else { | ||
| 462 | *clip_format |= 0x00000000; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | /* disable clipping */ | ||
| 467 | static void saa7146_disable_clipping(struct saa7146_dev *dev) | ||
| 468 | { | ||
| 469 | u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); | ||
| 470 | |||
| 471 | /* mask out relevant bits (=lower word)*/ | ||
| 472 | clip_format &= MASK_W1; | ||
| 473 | |||
| 474 | /* upload clipping-registers*/ | ||
| 475 | saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); | ||
| 476 | saa7146_write(dev, MC2, (MASK_05 | MASK_21)); | ||
| 477 | |||
| 478 | /* disable video dma2 */ | ||
| 479 | saa7146_write(dev, MC1, MASK_21); | ||
| 480 | } | ||
| 481 | |||
| 482 | static void saa7146_set_clipping_rect(struct saa7146_fh *fh) | ||
| 483 | { | ||
| 484 | struct saa7146_dev *dev = fh->dev; | ||
| 485 | enum v4l2_field field = fh->ov.win.field; | ||
| 486 | struct saa7146_video_dma vdma2; | ||
| 487 | u32 clip_format; | ||
| 488 | u32 arbtr_ctrl; | ||
| 489 | |||
| 490 | /* check clipcount, disable clipping if clipcount == 0*/ | ||
| 491 | if( fh->ov.nclips == 0 ) { | ||
| 492 | saa7146_disable_clipping(dev); | ||
| 493 | return; | ||
| 494 | } | ||
| 495 | |||
| 496 | clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); | ||
| 497 | arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); | ||
| 498 | |||
| 499 | calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field); | ||
| 500 | |||
| 501 | /* set clipping format */ | ||
| 502 | clip_format &= 0xffff0008; | ||
| 503 | clip_format |= (SAA7146_CLIPPING_RECT << 4); | ||
| 504 | |||
| 505 | /* prepare video dma2 */ | ||
| 506 | saa7146_write(dev, BASE_EVEN2, vdma2.base_even); | ||
| 507 | saa7146_write(dev, BASE_ODD2, vdma2.base_odd); | ||
| 508 | saa7146_write(dev, PROT_ADDR2, vdma2.prot_addr); | ||
| 509 | saa7146_write(dev, BASE_PAGE2, vdma2.base_page); | ||
| 510 | saa7146_write(dev, PITCH2, vdma2.pitch); | ||
| 511 | saa7146_write(dev, NUM_LINE_BYTE2, vdma2.num_line_byte); | ||
| 512 | |||
| 513 | /* prepare the rest */ | ||
| 514 | saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); | ||
| 515 | saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); | ||
| 516 | |||
| 517 | /* upload clip_control-register, clipping-registers, enable video dma2 */ | ||
| 518 | saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19)); | ||
| 519 | saa7146_write(dev, MC1, (MASK_05 | MASK_21)); | ||
| 520 | } | ||
| 521 | |||
| 522 | static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field) | ||
| 523 | { | ||
| 524 | struct saa7146_vv *vv = dev->vv_data; | ||
| 525 | |||
| 526 | int source = vv->current_hps_source; | ||
| 527 | int sync = vv->current_hps_sync; | ||
| 528 | |||
| 529 | u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0; | ||
| 530 | |||
| 531 | /* set vertical scale */ | ||
| 532 | hps_v_scale = 0; /* all bits get set by the function-call */ | ||
| 533 | hps_v_gain = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ | ||
| 534 | calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain); | ||
| 535 | |||
| 536 | /* set horizontal scale */ | ||
| 537 | hps_ctrl = 0; | ||
| 538 | hps_h_prescale = 0; /* all bits get set in the function */ | ||
| 539 | hps_h_scale = 0; | ||
| 540 | calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale); | ||
| 541 | |||
| 542 | /* set hyo and hxo */ | ||
| 543 | calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl); | ||
| 544 | calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl); | ||
| 545 | |||
| 546 | /* write out new register contents */ | ||
| 547 | saa7146_write(dev, HPS_V_SCALE, hps_v_scale); | ||
| 548 | saa7146_write(dev, HPS_V_GAIN, hps_v_gain); | ||
| 549 | saa7146_write(dev, HPS_CTRL, hps_ctrl); | ||
| 550 | saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale); | ||
| 551 | saa7146_write(dev, HPS_H_SCALE, hps_h_scale); | ||
| 552 | |||
| 553 | /* upload shadow-ram registers */ | ||
| 554 | saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) ); | ||
| 555 | } | ||
| 556 | |||
| 557 | /* calculate the new memory offsets for a desired position */ | ||
| 558 | static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat) | ||
| 559 | { | ||
| 560 | struct saa7146_vv *vv = dev->vv_data; | ||
| 561 | struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat); | ||
| 562 | |||
| 563 | int b_depth = vv->ov_fmt->depth; | ||
| 564 | int b_bpl = vv->ov_fb.fmt.bytesperline; | ||
| 565 | /* The unsigned long cast is to remove a 64-bit compile warning since | ||
| 566 | it looks like a 64-bit address is cast to a 32-bit value, even | ||
| 567 | though the base pointer is really a 32-bit physical address that | ||
| 568 | goes into a 32-bit DMA register. | ||
| 569 | FIXME: might not work on some 64-bit platforms, but see the FIXME | ||
| 570 | in struct v4l2_framebuffer (videodev2.h) for that. | ||
| 571 | */ | ||
| 572 | u32 base = (u32)(unsigned long)vv->ov_fb.base; | ||
| 573 | |||
| 574 | struct saa7146_video_dma vdma1; | ||
| 575 | |||
| 576 | /* calculate memory offsets for picture, look if we shall top-down-flip */ | ||
| 577 | vdma1.pitch = 2*b_bpl; | ||
| 578 | if ( 0 == vv->vflip ) { | ||
| 579 | vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); | ||
| 580 | vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2); | ||
| 581 | vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2)); | ||
| 582 | } | ||
| 583 | else { | ||
| 584 | vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); | ||
| 585 | vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2); | ||
| 586 | vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2)); | ||
| 587 | } | ||
| 588 | |||
| 589 | if (V4L2_FIELD_HAS_BOTH(field)) { | ||
| 590 | } else if (field == V4L2_FIELD_ALTERNATE) { | ||
| 591 | /* fixme */ | ||
| 592 | vdma1.base_odd = vdma1.prot_addr; | ||
| 593 | vdma1.pitch /= 2; | ||
| 594 | } else if (field == V4L2_FIELD_TOP) { | ||
| 595 | vdma1.base_odd = vdma1.prot_addr; | ||
| 596 | vdma1.pitch /= 2; | ||
| 597 | } else if (field == V4L2_FIELD_BOTTOM) { | ||
| 598 | vdma1.base_odd = vdma1.base_even; | ||
| 599 | vdma1.base_even = vdma1.prot_addr; | ||
| 600 | vdma1.pitch /= 2; | ||
| 601 | } | ||
| 602 | |||
| 603 | if ( 0 != vv->vflip ) { | ||
| 604 | vdma1.pitch *= -1; | ||
| 605 | } | ||
| 606 | |||
| 607 | vdma1.base_page = sfmt->swap; | ||
| 608 | vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels; | ||
| 609 | |||
| 610 | saa7146_write_out_dma(dev, 1, &vdma1); | ||
| 611 | } | ||
| 612 | |||
| 613 | static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette) | ||
| 614 | { | ||
| 615 | u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); | ||
| 616 | |||
| 617 | /* call helper function */ | ||
| 618 | calculate_output_format_register(dev,palette,&clip_format); | ||
| 619 | |||
| 620 | /* update the hps registers */ | ||
| 621 | saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); | ||
| 622 | saa7146_write(dev, MC2, (MASK_05 | MASK_21)); | ||
| 623 | } | ||
| 624 | |||
| 625 | /* select input-source */ | ||
| 626 | void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync) | ||
| 627 | { | ||
| 628 | struct saa7146_vv *vv = dev->vv_data; | ||
| 629 | u32 hps_ctrl = 0; | ||
| 630 | |||
| 631 | /* read old state */ | ||
| 632 | hps_ctrl = saa7146_read(dev, HPS_CTRL); | ||
| 633 | |||
| 634 | hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 ); | ||
| 635 | hps_ctrl |= (source << 30) | (sync << 28); | ||
| 636 | |||
| 637 | /* write back & upload register */ | ||
| 638 | saa7146_write(dev, HPS_CTRL, hps_ctrl); | ||
| 639 | saa7146_write(dev, MC2, (MASK_05 | MASK_21)); | ||
| 640 | |||
| 641 | vv->current_hps_source = source; | ||
| 642 | vv->current_hps_sync = sync; | ||
| 643 | } | ||
| 644 | EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); | ||
| 645 | |||
| 646 | int saa7146_enable_overlay(struct saa7146_fh *fh) | ||
| 647 | { | ||
| 648 | struct saa7146_dev *dev = fh->dev; | ||
| 649 | struct saa7146_vv *vv = dev->vv_data; | ||
| 650 | |||
| 651 | saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field); | ||
| 652 | saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat); | ||
| 653 | saa7146_set_output_format(dev, vv->ov_fmt->trans); | ||
| 654 | saa7146_set_clipping_rect(fh); | ||
| 655 | |||
| 656 | /* enable video dma1 */ | ||
| 657 | saa7146_write(dev, MC1, (MASK_06 | MASK_22)); | ||
| 658 | return 0; | ||
| 659 | } | ||
| 660 | |||
| 661 | void saa7146_disable_overlay(struct saa7146_fh *fh) | ||
| 662 | { | ||
| 663 | struct saa7146_dev *dev = fh->dev; | ||
| 664 | |||
| 665 | /* disable clipping + video dma1 */ | ||
| 666 | saa7146_disable_clipping(dev); | ||
| 667 | saa7146_write(dev, MC1, MASK_22); | ||
| 668 | } | ||
| 669 | |||
| 670 | void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) | ||
| 671 | { | ||
| 672 | int where = 0; | ||
| 673 | |||
| 674 | if( which < 1 || which > 3) { | ||
| 675 | return; | ||
| 676 | } | ||
| 677 | |||
| 678 | /* calculate starting address */ | ||
| 679 | where = (which-1)*0x18; | ||
| 680 | |||
| 681 | saa7146_write(dev, where, vdma->base_odd); | ||
| 682 | saa7146_write(dev, where+0x04, vdma->base_even); | ||
| 683 | saa7146_write(dev, where+0x08, vdma->prot_addr); | ||
| 684 | saa7146_write(dev, where+0x0c, vdma->pitch); | ||
| 685 | saa7146_write(dev, where+0x10, vdma->base_page); | ||
| 686 | saa7146_write(dev, where+0x14, vdma->num_line_byte); | ||
| 687 | |||
| 688 | /* upload */ | ||
| 689 | saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1))); | ||
| 690 | /* | ||
| 691 | printk("vdma%d.base_even: 0x%08x\n", which,vdma->base_even); | ||
| 692 | printk("vdma%d.base_odd: 0x%08x\n", which,vdma->base_odd); | ||
| 693 | printk("vdma%d.prot_addr: 0x%08x\n", which,vdma->prot_addr); | ||
| 694 | printk("vdma%d.base_page: 0x%08x\n", which,vdma->base_page); | ||
| 695 | printk("vdma%d.pitch: 0x%08x\n", which,vdma->pitch); | ||
| 696 | printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte); | ||
| 697 | */ | ||
| 698 | } | ||
| 699 | |||
| 700 | static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf) | ||
| 701 | { | ||
| 702 | struct saa7146_vv *vv = dev->vv_data; | ||
| 703 | struct saa7146_video_dma vdma1; | ||
| 704 | |||
| 705 | struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | ||
| 706 | |||
| 707 | int width = buf->fmt->width; | ||
| 708 | int height = buf->fmt->height; | ||
| 709 | int bytesperline = buf->fmt->bytesperline; | ||
| 710 | enum v4l2_field field = buf->fmt->field; | ||
| 711 | |||
| 712 | int depth = sfmt->depth; | ||
| 713 | |||
| 714 | DEB_CAP(("[size=%dx%d,fields=%s]\n", | ||
| 715 | width,height,v4l2_field_names[field])); | ||
| 716 | |||
| 717 | if( bytesperline != 0) { | ||
| 718 | vdma1.pitch = bytesperline*2; | ||
| 719 | } else { | ||
| 720 | vdma1.pitch = (width*depth*2)/8; | ||
| 721 | } | ||
| 722 | vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); | ||
| 723 | vdma1.base_page = buf->pt[0].dma | ME1 | sfmt->swap; | ||
| 724 | |||
| 725 | if( 0 != vv->vflip ) { | ||
| 726 | vdma1.prot_addr = buf->pt[0].offset; | ||
| 727 | vdma1.base_even = buf->pt[0].offset+(vdma1.pitch/2)*height; | ||
| 728 | vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); | ||
| 729 | } else { | ||
| 730 | vdma1.base_even = buf->pt[0].offset; | ||
| 731 | vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); | ||
| 732 | vdma1.prot_addr = buf->pt[0].offset+(vdma1.pitch/2)*height; | ||
| 733 | } | ||
| 734 | |||
| 735 | if (V4L2_FIELD_HAS_BOTH(field)) { | ||
| 736 | } else if (field == V4L2_FIELD_ALTERNATE) { | ||
| 737 | /* fixme */ | ||
| 738 | if ( vv->last_field == V4L2_FIELD_TOP ) { | ||
| 739 | vdma1.base_odd = vdma1.prot_addr; | ||
| 740 | vdma1.pitch /= 2; | ||
| 741 | } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { | ||
| 742 | vdma1.base_odd = vdma1.base_even; | ||
| 743 | vdma1.base_even = vdma1.prot_addr; | ||
| 744 | vdma1.pitch /= 2; | ||
| 745 | } | ||
| 746 | } else if (field == V4L2_FIELD_TOP) { | ||
| 747 | vdma1.base_odd = vdma1.prot_addr; | ||
| 748 | vdma1.pitch /= 2; | ||
| 749 | } else if (field == V4L2_FIELD_BOTTOM) { | ||
| 750 | vdma1.base_odd = vdma1.base_even; | ||
| 751 | vdma1.base_even = vdma1.prot_addr; | ||
| 752 | vdma1.pitch /= 2; | ||
| 753 | } | ||
| 754 | |||
| 755 | if( 0 != vv->vflip ) { | ||
| 756 | vdma1.pitch *= -1; | ||
| 757 | } | ||
| 758 | |||
| 759 | saa7146_write_out_dma(dev, 1, &vdma1); | ||
| 760 | return 0; | ||
| 761 | } | ||
| 762 | |||
| 763 | static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) | ||
| 764 | { | ||
| 765 | int height = buf->fmt->height; | ||
| 766 | int width = buf->fmt->width; | ||
| 767 | |||
| 768 | vdma2->pitch = width; | ||
| 769 | vdma3->pitch = width; | ||
| 770 | |||
| 771 | /* fixme: look at bytesperline! */ | ||
| 772 | |||
| 773 | if( 0 != vv->vflip ) { | ||
| 774 | vdma2->prot_addr = buf->pt[1].offset; | ||
| 775 | vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[1].offset; | ||
| 776 | vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); | ||
| 777 | |||
| 778 | vdma3->prot_addr = buf->pt[2].offset; | ||
| 779 | vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[2].offset; | ||
| 780 | vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); | ||
| 781 | } else { | ||
| 782 | vdma3->base_even = buf->pt[2].offset; | ||
| 783 | vdma3->base_odd = vdma3->base_even + (vdma3->pitch/2); | ||
| 784 | vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; | ||
| 785 | |||
| 786 | vdma2->base_even = buf->pt[1].offset; | ||
| 787 | vdma2->base_odd = vdma2->base_even + (vdma2->pitch/2); | ||
| 788 | vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; | ||
| 789 | } | ||
| 790 | |||
| 791 | return 0; | ||
| 792 | } | ||
| 793 | |||
| 794 | static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) | ||
| 795 | { | ||
| 796 | int height = buf->fmt->height; | ||
| 797 | int width = buf->fmt->width; | ||
| 798 | |||
| 799 | vdma2->pitch = width/2; | ||
| 800 | vdma3->pitch = width/2; | ||
| 801 | |||
| 802 | if( 0 != vv->vflip ) { | ||
| 803 | vdma2->prot_addr = buf->pt[2].offset; | ||
| 804 | vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[2].offset; | ||
| 805 | vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); | ||
| 806 | |||
| 807 | vdma3->prot_addr = buf->pt[1].offset; | ||
| 808 | vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[1].offset; | ||
| 809 | vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); | ||
| 810 | |||
| 811 | } else { | ||
| 812 | vdma3->base_even = buf->pt[2].offset; | ||
| 813 | vdma3->base_odd = vdma3->base_even + (vdma3->pitch); | ||
| 814 | vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; | ||
| 815 | |||
| 816 | vdma2->base_even = buf->pt[1].offset; | ||
| 817 | vdma2->base_odd = vdma2->base_even + (vdma2->pitch); | ||
| 818 | vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; | ||
| 819 | } | ||
| 820 | return 0; | ||
| 821 | } | ||
| 822 | |||
| 823 | static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf) | ||
| 824 | { | ||
| 825 | struct saa7146_vv *vv = dev->vv_data; | ||
| 826 | struct saa7146_video_dma vdma1; | ||
| 827 | struct saa7146_video_dma vdma2; | ||
| 828 | struct saa7146_video_dma vdma3; | ||
| 829 | |||
| 830 | struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | ||
| 831 | |||
| 832 | int width = buf->fmt->width; | ||
| 833 | int height = buf->fmt->height; | ||
| 834 | enum v4l2_field field = buf->fmt->field; | ||
| 835 | |||
| 836 | BUG_ON(0 == buf->pt[0].dma); | ||
| 837 | BUG_ON(0 == buf->pt[1].dma); | ||
| 838 | BUG_ON(0 == buf->pt[2].dma); | ||
| 839 | |||
| 840 | DEB_CAP(("[size=%dx%d,fields=%s]\n", | ||
| 841 | width,height,v4l2_field_names[field])); | ||
| 842 | |||
| 843 | /* fixme: look at bytesperline! */ | ||
| 844 | |||
| 845 | /* fixme: what happens for user space buffers here?. The offsets are | ||
| 846 | most likely wrong, this version here only works for page-aligned | ||
| 847 | buffers, modifications to the pagetable-functions are necessary...*/ | ||
| 848 | |||
| 849 | vdma1.pitch = width*2; | ||
| 850 | vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); | ||
| 851 | vdma1.base_page = buf->pt[0].dma | ME1; | ||
| 852 | |||
| 853 | if( 0 != vv->vflip ) { | ||
| 854 | vdma1.prot_addr = buf->pt[0].offset; | ||
| 855 | vdma1.base_even = ((vdma1.pitch/2)*height)+buf->pt[0].offset; | ||
| 856 | vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); | ||
| 857 | } else { | ||
| 858 | vdma1.base_even = buf->pt[0].offset; | ||
| 859 | vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); | ||
| 860 | vdma1.prot_addr = (vdma1.pitch/2)*height+buf->pt[0].offset; | ||
| 861 | } | ||
| 862 | |||
| 863 | vdma2.num_line_byte = 0; /* unused */ | ||
| 864 | vdma2.base_page = buf->pt[1].dma | ME1; | ||
| 865 | |||
| 866 | vdma3.num_line_byte = 0; /* unused */ | ||
| 867 | vdma3.base_page = buf->pt[2].dma | ME1; | ||
| 868 | |||
| 869 | switch( sfmt->depth ) { | ||
| 870 | case 12: { | ||
| 871 | calc_planar_420(vv,buf,&vdma2,&vdma3); | ||
| 872 | break; | ||
| 873 | } | ||
| 874 | case 16: { | ||
| 875 | calc_planar_422(vv,buf,&vdma2,&vdma3); | ||
| 876 | break; | ||
| 877 | } | ||
| 878 | default: { | ||
| 879 | return -1; | ||
| 880 | } | ||
| 881 | } | ||
| 882 | |||
| 883 | if (V4L2_FIELD_HAS_BOTH(field)) { | ||
| 884 | } else if (field == V4L2_FIELD_ALTERNATE) { | ||
| 885 | /* fixme */ | ||
| 886 | vdma1.base_odd = vdma1.prot_addr; | ||
| 887 | vdma1.pitch /= 2; | ||
| 888 | vdma2.base_odd = vdma2.prot_addr; | ||
| 889 | vdma2.pitch /= 2; | ||
| 890 | vdma3.base_odd = vdma3.prot_addr; | ||
| 891 | vdma3.pitch /= 2; | ||
| 892 | } else if (field == V4L2_FIELD_TOP) { | ||
| 893 | vdma1.base_odd = vdma1.prot_addr; | ||
| 894 | vdma1.pitch /= 2; | ||
| 895 | vdma2.base_odd = vdma2.prot_addr; | ||
| 896 | vdma2.pitch /= 2; | ||
| 897 | vdma3.base_odd = vdma3.prot_addr; | ||
| 898 | vdma3.pitch /= 2; | ||
| 899 | } else if (field == V4L2_FIELD_BOTTOM) { | ||
| 900 | vdma1.base_odd = vdma1.base_even; | ||
| 901 | vdma1.base_even = vdma1.prot_addr; | ||
| 902 | vdma1.pitch /= 2; | ||
| 903 | vdma2.base_odd = vdma2.base_even; | ||
| 904 | vdma2.base_even = vdma2.prot_addr; | ||
| 905 | vdma2.pitch /= 2; | ||
| 906 | vdma3.base_odd = vdma3.base_even; | ||
| 907 | vdma3.base_even = vdma3.prot_addr; | ||
| 908 | vdma3.pitch /= 2; | ||
| 909 | } | ||
| 910 | |||
| 911 | if( 0 != vv->vflip ) { | ||
| 912 | vdma1.pitch *= -1; | ||
| 913 | vdma2.pitch *= -1; | ||
| 914 | vdma3.pitch *= -1; | ||
| 915 | } | ||
| 916 | |||
| 917 | saa7146_write_out_dma(dev, 1, &vdma1); | ||
| 918 | if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) { | ||
| 919 | saa7146_write_out_dma(dev, 3, &vdma2); | ||
| 920 | saa7146_write_out_dma(dev, 2, &vdma3); | ||
| 921 | } else { | ||
| 922 | saa7146_write_out_dma(dev, 2, &vdma2); | ||
| 923 | saa7146_write_out_dma(dev, 3, &vdma3); | ||
| 924 | } | ||
| 925 | return 0; | ||
| 926 | } | ||
| 927 | |||
| 928 | static void program_capture_engine(struct saa7146_dev *dev, int planar) | ||
| 929 | { | ||
| 930 | struct saa7146_vv *vv = dev->vv_data; | ||
| 931 | int count = 0; | ||
| 932 | |||
| 933 | unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; | ||
| 934 | unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; | ||
| 935 | |||
| 936 | /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ | ||
| 937 | WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); | ||
| 938 | WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); | ||
| 939 | |||
| 940 | /* set rps register 0 */ | ||
| 941 | WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4)); | ||
| 942 | WRITE_RPS0(MASK_27 | MASK_11); | ||
| 943 | |||
| 944 | /* turn on video-dma1 */ | ||
| 945 | WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); | ||
| 946 | WRITE_RPS0(MASK_06 | MASK_22); /* => mask */ | ||
| 947 | WRITE_RPS0(MASK_06 | MASK_22); /* => values */ | ||
| 948 | if( 0 != planar ) { | ||
| 949 | /* turn on video-dma2 */ | ||
| 950 | WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); | ||
| 951 | WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ | ||
| 952 | WRITE_RPS0(MASK_05 | MASK_21); /* => values */ | ||
| 953 | |||
| 954 | /* turn on video-dma3 */ | ||
| 955 | WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); | ||
| 956 | WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ | ||
| 957 | WRITE_RPS0(MASK_04 | MASK_20); /* => values */ | ||
| 958 | } | ||
| 959 | |||
| 960 | /* wait for o_fid_a/b / e_fid_a/b toggle */ | ||
| 961 | if ( vv->last_field == V4L2_FIELD_INTERLACED ) { | ||
| 962 | WRITE_RPS0(CMD_PAUSE | o_wait); | ||
| 963 | WRITE_RPS0(CMD_PAUSE | e_wait); | ||
| 964 | } else if ( vv->last_field == V4L2_FIELD_TOP ) { | ||
| 965 | WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); | ||
| 966 | WRITE_RPS0(CMD_PAUSE | o_wait); | ||
| 967 | } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { | ||
| 968 | WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); | ||
| 969 | WRITE_RPS0(CMD_PAUSE | e_wait); | ||
| 970 | } | ||
| 971 | |||
| 972 | /* turn off video-dma1 */ | ||
| 973 | WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); | ||
| 974 | WRITE_RPS0(MASK_22 | MASK_06); /* => mask */ | ||
| 975 | WRITE_RPS0(MASK_22); /* => values */ | ||
| 976 | if( 0 != planar ) { | ||
| 977 | /* turn off video-dma2 */ | ||
| 978 | WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); | ||
| 979 | WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ | ||
| 980 | WRITE_RPS0(MASK_21); /* => values */ | ||
| 981 | |||
| 982 | /* turn off video-dma3 */ | ||
| 983 | WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); | ||
| 984 | WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ | ||
| 985 | WRITE_RPS0(MASK_20); /* => values */ | ||
| 986 | } | ||
| 987 | |||
| 988 | /* generate interrupt */ | ||
| 989 | WRITE_RPS0(CMD_INTERRUPT); | ||
| 990 | |||
| 991 | /* stop */ | ||
| 992 | WRITE_RPS0(CMD_STOP); | ||
| 993 | } | ||
| 994 | |||
| 995 | void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) | ||
| 996 | { | ||
| 997 | struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | ||
| 998 | struct saa7146_vv *vv = dev->vv_data; | ||
| 999 | u32 vdma1_prot_addr; | ||
| 1000 | |||
| 1001 | DEB_CAP(("buf:%p, next:%p\n",buf,next)); | ||
| 1002 | |||
| 1003 | vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1); | ||
| 1004 | if( 0 == vdma1_prot_addr ) { | ||
| 1005 | /* clear out beginning of streaming bit (rps register 0)*/ | ||
| 1006 | DEB_CAP(("forcing sync to new frame\n")); | ||
| 1007 | saa7146_write(dev, MC2, MASK_27 ); | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); | ||
| 1011 | saa7146_set_output_format(dev, sfmt->trans); | ||
| 1012 | saa7146_disable_clipping(dev); | ||
| 1013 | |||
| 1014 | if ( vv->last_field == V4L2_FIELD_INTERLACED ) { | ||
| 1015 | } else if ( vv->last_field == V4L2_FIELD_TOP ) { | ||
| 1016 | vv->last_field = V4L2_FIELD_BOTTOM; | ||
| 1017 | } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { | ||
| 1018 | vv->last_field = V4L2_FIELD_TOP; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | if( 0 != IS_PLANAR(sfmt->trans)) { | ||
| 1022 | calculate_video_dma_grab_planar(dev, buf); | ||
| 1023 | program_capture_engine(dev,1); | ||
| 1024 | } else { | ||
| 1025 | calculate_video_dma_grab_packed(dev, buf); | ||
| 1026 | program_capture_engine(dev,0); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /* | ||
| 1030 | printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); | ||
| 1031 | printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); | ||
| 1032 | printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); | ||
| 1033 | printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); | ||
| 1034 | printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); | ||
| 1035 | printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); | ||
| 1036 | printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1)); | ||
| 1037 | */ | ||
| 1038 | |||
| 1039 | /* write the address of the rps-program */ | ||
| 1040 | saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); | ||
| 1041 | |||
| 1042 | /* turn on rps */ | ||
| 1043 | saa7146_write(dev, MC1, (MASK_12 | MASK_28)); | ||
| 1044 | } | ||
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c new file mode 100644 index 00000000000..b2ba9dc0dd6 --- /dev/null +++ b/drivers/media/common/saa7146_i2c.c | |||
| @@ -0,0 +1,421 @@ | |||
| 1 | #include <media/saa7146_vv.h> | ||
| 2 | |||
| 3 | static u32 saa7146_i2c_func(struct i2c_adapter *adapter) | ||
| 4 | { | ||
| 5 | //fm DEB_I2C(("'%s'.\n", adapter->name)); | ||
| 6 | |||
| 7 | return I2C_FUNC_I2C | ||
| 8 | | I2C_FUNC_SMBUS_QUICK | ||
| 9 | | I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE | ||
| 10 | | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; | ||
| 11 | } | ||
| 12 | |||
| 13 | /* this function returns the status-register of our i2c-device */ | ||
| 14 | static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) | ||
| 15 | { | ||
| 16 | u32 iicsta = saa7146_read(dev, I2C_STATUS); | ||
| 17 | /* | ||
| 18 | DEB_I2C(("status: 0x%08x\n",iicsta)); | ||
| 19 | */ | ||
| 20 | return iicsta; | ||
| 21 | } | ||
| 22 | |||
| 23 | /* this function runs through the i2c-messages and prepares the data to be | ||
| 24 | sent through the saa7146. have a look at the specifications p. 122 ff | ||
| 25 | to understand this. it returns the number of u32s to send, or -1 | ||
| 26 | in case of an error. */ | ||
| 27 | static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) | ||
| 28 | { | ||
| 29 | int h1, h2; | ||
| 30 | int i, j, addr; | ||
| 31 | int mem = 0, op_count = 0; | ||
| 32 | |||
| 33 | /* first determine size of needed memory */ | ||
| 34 | for(i = 0; i < num; i++) { | ||
| 35 | mem += m[i].len + 1; | ||
| 36 | } | ||
| 37 | |||
| 38 | /* worst case: we need one u32 for three bytes to be send | ||
| 39 | plus one extra byte to address the device */ | ||
| 40 | mem = 1 + ((mem-1) / 3); | ||
| 41 | |||
| 42 | /* we assume that op points to a memory of at least SAA7146_I2C_MEM bytes | ||
| 43 | size. if we exceed this limit... */ | ||
| 44 | if ( (4*mem) > SAA7146_I2C_MEM ) { | ||
| 45 | //fm DEB_I2C(("cannot prepare i2c-message.\n")); | ||
| 46 | return -ENOMEM; | ||
| 47 | } | ||
| 48 | |||
| 49 | /* be careful: clear out the i2c-mem first */ | ||
| 50 | memset(op,0,sizeof(__le32)*mem); | ||
| 51 | |||
| 52 | /* loop through all messages */ | ||
| 53 | for(i = 0; i < num; i++) { | ||
| 54 | |||
| 55 | /* insert the address of the i2c-slave. | ||
| 56 | note: we get 7 bit i2c-addresses, | ||
| 57 | so we have to perform a translation */ | ||
| 58 | addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); | ||
| 59 | h1 = op_count/3; h2 = op_count%3; | ||
| 60 | op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8)); | ||
| 61 | op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2)); | ||
| 62 | op_count++; | ||
| 63 | |||
| 64 | /* loop through all bytes of message i */ | ||
| 65 | for(j = 0; j < m[i].len; j++) { | ||
| 66 | /* insert the data bytes */ | ||
| 67 | h1 = op_count/3; h2 = op_count%3; | ||
| 68 | op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8)); | ||
| 69 | op[h1] |= cpu_to_le32( SAA7146_I2C_CONT << ((3-h2)*2)); | ||
| 70 | op_count++; | ||
| 71 | } | ||
| 72 | |||
| 73 | } | ||
| 74 | |||
| 75 | /* have a look at the last byte inserted: | ||
| 76 | if it was: ...CONT change it to ...STOP */ | ||
| 77 | h1 = (op_count-1)/3; h2 = (op_count-1)%3; | ||
| 78 | if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) { | ||
| 79 | op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2)); | ||
| 80 | op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2)); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* return the number of u32s to send */ | ||
| 84 | return mem; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* this functions loops through all i2c-messages. normally, it should determine | ||
| 88 | which bytes were read through the adapter and write them back to the corresponding | ||
| 89 | i2c-message. but instead, we simply write back all bytes. | ||
| 90 | fixme: this could be improved. */ | ||
| 91 | static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op) | ||
| 92 | { | ||
| 93 | int i, j; | ||
| 94 | int op_count = 0; | ||
| 95 | |||
| 96 | /* loop through all messages */ | ||
| 97 | for(i = 0; i < num; i++) { | ||
| 98 | |||
| 99 | op_count++; | ||
| 100 | |||
| 101 | /* loop through all bytes of message i */ | ||
| 102 | for(j = 0; j < m[i].len; j++) { | ||
| 103 | /* write back all bytes that could have been read */ | ||
| 104 | m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8)); | ||
| 105 | op_count++; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | /* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */ | ||
| 113 | static int saa7146_i2c_reset(struct saa7146_dev *dev) | ||
| 114 | { | ||
| 115 | /* get current status */ | ||
| 116 | u32 status = saa7146_i2c_status(dev); | ||
| 117 | |||
| 118 | /* clear registers for sure */ | ||
| 119 | saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); | ||
| 120 | saa7146_write(dev, I2C_TRANSFER, 0); | ||
| 121 | |||
| 122 | /* check if any operation is still in progress */ | ||
| 123 | if ( 0 != ( status & SAA7146_I2C_BUSY) ) { | ||
| 124 | |||
| 125 | /* yes, kill ongoing operation */ | ||
| 126 | DEB_I2C(("busy_state detected.\n")); | ||
| 127 | |||
| 128 | /* set "ABORT-OPERATION"-bit (bit 7)*/ | ||
| 129 | saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); | ||
| 130 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 131 | msleep(SAA7146_I2C_DELAY); | ||
| 132 | |||
| 133 | /* clear all error-bits pending; this is needed because p.123, note 1 */ | ||
| 134 | saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); | ||
| 135 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 136 | msleep(SAA7146_I2C_DELAY); | ||
| 137 | } | ||
| 138 | |||
| 139 | /* check if any error is (still) present. (this can be necessary because p.123, note 1) */ | ||
| 140 | status = saa7146_i2c_status(dev); | ||
| 141 | |||
| 142 | if ( dev->i2c_bitrate != status ) { | ||
| 143 | |||
| 144 | DEB_I2C(("error_state detected. status:0x%08x\n",status)); | ||
| 145 | |||
| 146 | /* Repeat the abort operation. This seems to be necessary | ||
| 147 | after serious protocol errors caused by e.g. the SAA7740 */ | ||
| 148 | saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); | ||
| 149 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 150 | msleep(SAA7146_I2C_DELAY); | ||
| 151 | |||
| 152 | /* clear all error-bits pending */ | ||
| 153 | saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); | ||
| 154 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 155 | msleep(SAA7146_I2C_DELAY); | ||
| 156 | |||
| 157 | /* the data sheet says it might be necessary to clear the status | ||
| 158 | twice after an abort */ | ||
| 159 | saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); | ||
| 160 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 161 | msleep(SAA7146_I2C_DELAY); | ||
| 162 | } | ||
| 163 | |||
| 164 | /* if any error is still present, a fatal error has occurred ... */ | ||
| 165 | status = saa7146_i2c_status(dev); | ||
| 166 | if ( dev->i2c_bitrate != status ) { | ||
| 167 | DEB_I2C(("fatal error. status:0x%08x\n",status)); | ||
| 168 | return -1; | ||
| 169 | } | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | /* this functions writes out the data-byte 'dword' to the i2c-device. | ||
| 175 | it returns 0 if ok, -1 if the transfer failed, -2 if the transfer | ||
| 176 | failed badly (e.g. address error) */ | ||
| 177 | static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay) | ||
| 178 | { | ||
| 179 | u32 status = 0, mc2 = 0; | ||
| 180 | int trial = 0; | ||
| 181 | unsigned long timeout; | ||
| 182 | |||
| 183 | /* write out i2c-command */ | ||
| 184 | DEB_I2C(("before: 0x%08x (status: 0x%08x), %d\n",*dword,saa7146_read(dev, I2C_STATUS), dev->i2c_op)); | ||
| 185 | |||
| 186 | if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) { | ||
| 187 | |||
| 188 | saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); | ||
| 189 | saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); | ||
| 190 | |||
| 191 | dev->i2c_op = 1; | ||
| 192 | SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); | ||
| 193 | SAA7146_IER_ENABLE(dev, MASK_16|MASK_17); | ||
| 194 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 195 | |||
| 196 | timeout = HZ/100 + 1; /* 10ms */ | ||
| 197 | timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout); | ||
| 198 | if (timeout == -ERESTARTSYS || dev->i2c_op) { | ||
| 199 | SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); | ||
| 200 | SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); | ||
| 201 | if (timeout == -ERESTARTSYS) | ||
| 202 | /* a signal arrived */ | ||
| 203 | return -ERESTARTSYS; | ||
| 204 | |||
| 205 | printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", | ||
| 206 | dev->name, __func__); | ||
| 207 | return -EIO; | ||
| 208 | } | ||
| 209 | status = saa7146_read(dev, I2C_STATUS); | ||
| 210 | } else { | ||
| 211 | saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); | ||
| 212 | saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); | ||
| 213 | saa7146_write(dev, MC2, (MASK_00 | MASK_16)); | ||
| 214 | |||
| 215 | /* do not poll for i2c-status before upload is complete */ | ||
| 216 | timeout = jiffies + HZ/100 + 1; /* 10ms */ | ||
| 217 | while(1) { | ||
| 218 | mc2 = (saa7146_read(dev, MC2) & 0x1); | ||
| 219 | if( 0 != mc2 ) { | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | if (time_after(jiffies,timeout)) { | ||
| 223 | printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", | ||
| 224 | dev->name, __func__); | ||
| 225 | return -EIO; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | /* wait until we get a transfer done or error */ | ||
| 229 | timeout = jiffies + HZ/100 + 1; /* 10ms */ | ||
| 230 | /* first read usually delivers bogus results... */ | ||
| 231 | saa7146_i2c_status(dev); | ||
| 232 | while(1) { | ||
| 233 | status = saa7146_i2c_status(dev); | ||
| 234 | if ((status & 0x3) != 1) | ||
| 235 | break; | ||
| 236 | if (time_after(jiffies,timeout)) { | ||
| 237 | /* this is normal when probing the bus | ||
| 238 | * (no answer from nonexisistant device...) | ||
| 239 | */ | ||
| 240 | printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", | ||
| 241 | dev->name, __func__); | ||
| 242 | return -EIO; | ||
| 243 | } | ||
| 244 | if (++trial < 50 && short_delay) | ||
| 245 | udelay(10); | ||
| 246 | else | ||
| 247 | msleep(1); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | /* give a detailed status report */ | ||
| 252 | if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR | | ||
| 253 | SAA7146_I2C_DTERR | SAA7146_I2C_DRERR | | ||
| 254 | SAA7146_I2C_AL | SAA7146_I2C_ERR | | ||
| 255 | SAA7146_I2C_BUSY)) ) { | ||
| 256 | |||
| 257 | if ( 0 == (status & SAA7146_I2C_ERR) || | ||
| 258 | 0 == (status & SAA7146_I2C_BUSY) ) { | ||
| 259 | /* it may take some time until ERR goes high - ignore */ | ||
| 260 | DEB_I2C(("unexpected i2c status %04x\n", status)); | ||
| 261 | } | ||
| 262 | if( 0 != (status & SAA7146_I2C_SPERR) ) { | ||
| 263 | DEB_I2C(("error due to invalid start/stop condition.\n")); | ||
| 264 | } | ||
| 265 | if( 0 != (status & SAA7146_I2C_DTERR) ) { | ||
| 266 | DEB_I2C(("error in data transmission.\n")); | ||
| 267 | } | ||
| 268 | if( 0 != (status & SAA7146_I2C_DRERR) ) { | ||
| 269 | DEB_I2C(("error when receiving data.\n")); | ||
| 270 | } | ||
| 271 | if( 0 != (status & SAA7146_I2C_AL) ) { | ||
| 272 | DEB_I2C(("error because arbitration lost.\n")); | ||
| 273 | } | ||
| 274 | |||
| 275 | /* we handle address-errors here */ | ||
| 276 | if( 0 != (status & SAA7146_I2C_APERR) ) { | ||
| 277 | DEB_I2C(("error in address phase.\n")); | ||
| 278 | return -EREMOTEIO; | ||
| 279 | } | ||
| 280 | |||
| 281 | return -EIO; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* read back data, just in case we were reading ... */ | ||
| 285 | *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER)); | ||
| 286 | |||
| 287 | DEB_I2C(("after: 0x%08x\n",*dword)); | ||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) | ||
| 292 | { | ||
| 293 | int i = 0, count = 0; | ||
| 294 | __le32 *buffer = dev->d_i2c.cpu_addr; | ||
| 295 | int err = 0; | ||
| 296 | int short_delay = 0; | ||
| 297 | |||
| 298 | if (mutex_lock_interruptible(&dev->i2c_lock)) | ||
| 299 | return -ERESTARTSYS; | ||
| 300 | |||
| 301 | for(i=0;i<num;i++) { | ||
| 302 | DEB_I2C(("msg:%d/%d\n",i+1,num)); | ||
| 303 | } | ||
| 304 | |||
| 305 | /* prepare the message(s), get number of u32s to transfer */ | ||
| 306 | count = saa7146_i2c_msg_prepare(msgs, num, buffer); | ||
| 307 | if ( 0 > count ) { | ||
| 308 | err = -1; | ||
| 309 | goto out; | ||
| 310 | } | ||
| 311 | |||
| 312 | if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) ) | ||
| 313 | short_delay = 1; | ||
| 314 | |||
| 315 | do { | ||
| 316 | /* reset the i2c-device if necessary */ | ||
| 317 | err = saa7146_i2c_reset(dev); | ||
| 318 | if ( 0 > err ) { | ||
| 319 | DEB_I2C(("could not reset i2c-device.\n")); | ||
| 320 | goto out; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* write out the u32s one after another */ | ||
| 324 | for(i = 0; i < count; i++) { | ||
| 325 | err = saa7146_i2c_writeout(dev, &buffer[i], short_delay); | ||
| 326 | if ( 0 != err) { | ||
| 327 | /* this one is unsatisfying: some i2c slaves on some | ||
| 328 | dvb cards don't acknowledge correctly, so the saa7146 | ||
| 329 | thinks that an address error occurred. in that case, the | ||
| 330 | transaction should be retrying, even if an address error | ||
| 331 | occurred. analog saa7146 based cards extensively rely on | ||
| 332 | i2c address probing, however, and address errors indicate that a | ||
| 333 | device is really *not* there. retrying in that case | ||
| 334 | increases the time the device needs to probe greatly, so | ||
| 335 | it should be avoided. So we bail out in irq mode after an | ||
| 336 | address error and trust the saa7146 address error detection. */ | ||
| 337 | if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) | ||
| 338 | goto out; | ||
| 339 | DEB_I2C(("error while sending message(s). starting again.\n")); | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | } | ||
| 343 | if( 0 == err ) { | ||
| 344 | err = num; | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | |||
| 348 | /* delay a bit before retrying */ | ||
| 349 | msleep(10); | ||
| 350 | |||
| 351 | } while (err != num && retries--); | ||
| 352 | |||
| 353 | /* quit if any error occurred */ | ||
| 354 | if (err != num) | ||
| 355 | goto out; | ||
| 356 | |||
| 357 | /* if any things had to be read, get the results */ | ||
| 358 | if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) { | ||
| 359 | DEB_I2C(("could not cleanup i2c-message.\n")); | ||
| 360 | err = -1; | ||
| 361 | goto out; | ||
| 362 | } | ||
| 363 | |||
| 364 | /* return the number of delivered messages */ | ||
| 365 | DEB_I2C(("transmission successful. (msg:%d).\n",err)); | ||
| 366 | out: | ||
| 367 | /* another bug in revision 0: the i2c-registers get uploaded randomly by other | ||
| 368 | uploads, so we better clear them out before continuing */ | ||
| 369 | if( 0 == dev->revision ) { | ||
| 370 | __le32 zero = 0; | ||
| 371 | saa7146_i2c_reset(dev); | ||
| 372 | if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) { | ||
| 373 | INFO(("revision 0 error. this should never happen.\n")); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | mutex_unlock(&dev->i2c_lock); | ||
| 378 | return err; | ||
| 379 | } | ||
| 380 | |||
| 381 | /* utility functions */ | ||
| 382 | static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) | ||
| 383 | { | ||
| 384 | struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); | ||
| 385 | struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); | ||
| 386 | |||
| 387 | /* use helper function to transfer data */ | ||
| 388 | return saa7146_i2c_transfer(dev, msg, num, adapter->retries); | ||
| 389 | } | ||
| 390 | |||
| 391 | |||
| 392 | /*****************************************************************************/ | ||
| 393 | /* i2c-adapter helper functions */ | ||
| 394 | |||
| 395 | /* exported algorithm data */ | ||
| 396 | static struct i2c_algorithm saa7146_algo = { | ||
| 397 | .master_xfer = saa7146_i2c_xfer, | ||
| 398 | .functionality = saa7146_i2c_func, | ||
| 399 | }; | ||
| 400 | |||
| 401 | int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate) | ||
| 402 | { | ||
| 403 | DEB_EE(("bitrate: 0x%08x\n",bitrate)); | ||
| 404 | |||
| 405 | /* enable i2c-port pins */ | ||
| 406 | saa7146_write(dev, MC1, (MASK_08 | MASK_24)); | ||
| 407 | |||
| 408 | dev->i2c_bitrate = bitrate; | ||
| 409 | saa7146_i2c_reset(dev); | ||
| 410 | |||
| 411 | if (i2c_adapter) { | ||
| 412 | i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev); | ||
| 413 | i2c_adapter->dev.parent = &dev->pci->dev; | ||
| 414 | i2c_adapter->algo = &saa7146_algo; | ||
| 415 | i2c_adapter->algo_data = NULL; | ||
| 416 | i2c_adapter->timeout = SAA7146_I2C_TIMEOUT; | ||
| 417 | i2c_adapter->retries = SAA7146_I2C_RETRIES; | ||
| 418 | } | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c new file mode 100644 index 00000000000..afe85801d6c --- /dev/null +++ b/drivers/media/common/saa7146_vbi.c | |||
| @@ -0,0 +1,510 @@ | |||
| 1 | #include <media/saa7146_vv.h> | ||
| 2 | |||
| 3 | static int vbi_pixel_to_capture = 720 * 2; | ||
| 4 | |||
| 5 | static int vbi_workaround(struct saa7146_dev *dev) | ||
| 6 | { | ||
| 7 | struct saa7146_vv *vv = dev->vv_data; | ||
| 8 | |||
| 9 | u32 *cpu; | ||
| 10 | dma_addr_t dma_addr; | ||
| 11 | |||
| 12 | int count = 0; | ||
| 13 | int i; | ||
| 14 | |||
| 15 | DECLARE_WAITQUEUE(wait, current); | ||
| 16 | |||
| 17 | DEB_VBI(("dev:%p\n",dev)); | ||
| 18 | |||
| 19 | /* once again, a bug in the saa7146: the brs acquisition | ||
| 20 | is buggy and especially the BXO-counter does not work | ||
| 21 | as specified. there is this workaround, but please | ||
| 22 | don't let me explain it. ;-) */ | ||
| 23 | |||
| 24 | cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); | ||
| 25 | if (NULL == cpu) | ||
| 26 | return -ENOMEM; | ||
| 27 | |||
| 28 | /* setup some basic programming, just for the workaround */ | ||
| 29 | saa7146_write(dev, BASE_EVEN3, dma_addr); | ||
| 30 | saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture); | ||
| 31 | saa7146_write(dev, PROT_ADDR3, dma_addr+4096); | ||
| 32 | saa7146_write(dev, PITCH3, vbi_pixel_to_capture); | ||
| 33 | saa7146_write(dev, BASE_PAGE3, 0x0); | ||
| 34 | saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0)); | ||
| 35 | saa7146_write(dev, MC2, MASK_04|MASK_20); | ||
| 36 | |||
| 37 | /* load brs-control register */ | ||
| 38 | WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); | ||
| 39 | /* BXO = 1h, BRS to outbound */ | ||
| 40 | WRITE_RPS1(0xc000008c); | ||
| 41 | /* wait for vbi_a or vbi_b*/ | ||
| 42 | if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { | ||
| 43 | DEB_D(("...using port b\n")); | ||
| 44 | WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); | ||
| 45 | WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); | ||
| 46 | /* | ||
| 47 | WRITE_RPS1(CMD_PAUSE | MASK_09); | ||
| 48 | */ | ||
| 49 | } else { | ||
| 50 | DEB_D(("...using port a\n")); | ||
| 51 | WRITE_RPS1(CMD_PAUSE | MASK_10); | ||
| 52 | } | ||
| 53 | /* upload brs */ | ||
| 54 | WRITE_RPS1(CMD_UPLOAD | MASK_08); | ||
| 55 | /* load brs-control register */ | ||
| 56 | WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); | ||
| 57 | /* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */ | ||
| 58 | WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19); | ||
| 59 | /* wait for brs_done */ | ||
| 60 | WRITE_RPS1(CMD_PAUSE | MASK_08); | ||
| 61 | /* upload brs */ | ||
| 62 | WRITE_RPS1(CMD_UPLOAD | MASK_08); | ||
| 63 | /* load video-dma3 NumLines3 and NumBytes3 */ | ||
| 64 | WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4)); | ||
| 65 | /* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */ | ||
| 66 | WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture)); | ||
| 67 | /* load brs-control register */ | ||
| 68 | WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); | ||
| 69 | /* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */ | ||
| 70 | WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start | ||
| 71 | /* wait for brs_done */ | ||
| 72 | WRITE_RPS1(CMD_PAUSE | MASK_08); | ||
| 73 | /* upload brs and video-dma3*/ | ||
| 74 | WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04); | ||
| 75 | /* load mc2 register: enable dma3 */ | ||
| 76 | WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4)); | ||
| 77 | WRITE_RPS1(MASK_20 | MASK_04); | ||
| 78 | /* generate interrupt */ | ||
| 79 | WRITE_RPS1(CMD_INTERRUPT); | ||
| 80 | /* stop rps1 */ | ||
| 81 | WRITE_RPS1(CMD_STOP); | ||
| 82 | |||
| 83 | /* we have to do the workaround twice to be sure that | ||
| 84 | everything is ok */ | ||
| 85 | for(i = 0; i < 2; i++) { | ||
| 86 | |||
| 87 | /* indicate to the irq handler that we do the workaround */ | ||
| 88 | saa7146_write(dev, MC2, MASK_31|MASK_15); | ||
| 89 | |||
| 90 | saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0)); | ||
| 91 | saa7146_write(dev, MC2, MASK_04|MASK_20); | ||
| 92 | |||
| 93 | /* enable rps1 irqs */ | ||
| 94 | SAA7146_IER_ENABLE(dev,MASK_28); | ||
| 95 | |||
| 96 | /* prepare to wait to be woken up by the irq-handler */ | ||
| 97 | add_wait_queue(&vv->vbi_wq, &wait); | ||
| 98 | current->state = TASK_INTERRUPTIBLE; | ||
| 99 | |||
| 100 | /* start rps1 to enable workaround */ | ||
| 101 | saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); | ||
| 102 | saa7146_write(dev, MC1, (MASK_13 | MASK_29)); | ||
| 103 | |||
| 104 | schedule(); | ||
| 105 | |||
| 106 | DEB_VBI(("brs bug workaround %d/1.\n",i)); | ||
| 107 | |||
| 108 | remove_wait_queue(&vv->vbi_wq, &wait); | ||
| 109 | current->state = TASK_RUNNING; | ||
| 110 | |||
| 111 | /* disable rps1 irqs */ | ||
| 112 | SAA7146_IER_DISABLE(dev,MASK_28); | ||
| 113 | |||
| 114 | /* stop video-dma3 */ | ||
| 115 | saa7146_write(dev, MC1, MASK_20); | ||
| 116 | |||
| 117 | if(signal_pending(current)) { | ||
| 118 | |||
| 119 | DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1))); | ||
| 120 | |||
| 121 | /* stop rps1 for sure */ | ||
| 122 | saa7146_write(dev, MC1, MASK_29); | ||
| 123 | |||
| 124 | pci_free_consistent(dev->pci, 4096, cpu, dma_addr); | ||
| 125 | return -EINTR; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | pci_free_consistent(dev->pci, 4096, cpu, dma_addr); | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) | ||
| 134 | { | ||
| 135 | struct saa7146_vv *vv = dev->vv_data; | ||
| 136 | |||
| 137 | struct saa7146_video_dma vdma3; | ||
| 138 | |||
| 139 | int count = 0; | ||
| 140 | unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; | ||
| 141 | unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; | ||
| 142 | |||
| 143 | /* | ||
| 144 | vdma3.base_even = 0xc8000000+2560*70; | ||
| 145 | vdma3.base_odd = 0xc8000000; | ||
| 146 | vdma3.prot_addr = 0xc8000000+2560*164; | ||
| 147 | vdma3.pitch = 2560; | ||
| 148 | vdma3.base_page = 0; | ||
| 149 | vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above! | ||
| 150 | */ | ||
| 151 | vdma3.base_even = buf->pt[2].offset; | ||
| 152 | vdma3.base_odd = buf->pt[2].offset + 16 * vbi_pixel_to_capture; | ||
| 153 | vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture; | ||
| 154 | vdma3.pitch = vbi_pixel_to_capture; | ||
| 155 | vdma3.base_page = buf->pt[2].dma | ME1; | ||
| 156 | vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture; | ||
| 157 | |||
| 158 | saa7146_write_out_dma(dev, 3, &vdma3); | ||
| 159 | |||
| 160 | /* write beginning of rps-program */ | ||
| 161 | count = 0; | ||
| 162 | |||
| 163 | /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */ | ||
| 164 | |||
| 165 | /* we don't wait here for the first field anymore. this is different from the video | ||
| 166 | capture and might cause that the first buffer is only half filled (with only | ||
| 167 | one field). but since this is some sort of streaming data, this is not that negative. | ||
| 168 | but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ | ||
| 169 | |||
| 170 | /* | ||
| 171 | WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); | ||
| 172 | WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait); | ||
| 173 | */ | ||
| 174 | /* set bit 1 */ | ||
| 175 | WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4)); | ||
| 176 | WRITE_RPS1(MASK_28 | MASK_12); | ||
| 177 | |||
| 178 | /* turn on video-dma3 */ | ||
| 179 | WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4)); | ||
| 180 | WRITE_RPS1(MASK_04 | MASK_20); /* => mask */ | ||
| 181 | WRITE_RPS1(MASK_04 | MASK_20); /* => values */ | ||
| 182 | |||
| 183 | /* wait for o_fid_a/b / e_fid_a/b toggle */ | ||
| 184 | WRITE_RPS1(CMD_PAUSE | o_wait); | ||
| 185 | WRITE_RPS1(CMD_PAUSE | e_wait); | ||
| 186 | |||
| 187 | /* generate interrupt */ | ||
| 188 | WRITE_RPS1(CMD_INTERRUPT); | ||
| 189 | |||
| 190 | /* stop */ | ||
| 191 | WRITE_RPS1(CMD_STOP); | ||
| 192 | |||
| 193 | /* enable rps1 irqs */ | ||
| 194 | SAA7146_IER_ENABLE(dev, MASK_28); | ||
| 195 | |||
| 196 | /* write the address of the rps-program */ | ||
| 197 | saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); | ||
| 198 | |||
| 199 | /* turn on rps */ | ||
| 200 | saa7146_write(dev, MC1, (MASK_13 | MASK_29)); | ||
| 201 | } | ||
| 202 | |||
| 203 | static int buffer_activate(struct saa7146_dev *dev, | ||
| 204 | struct saa7146_buf *buf, | ||
| 205 | struct saa7146_buf *next) | ||
| 206 | { | ||
| 207 | struct saa7146_vv *vv = dev->vv_data; | ||
| 208 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
| 209 | |||
| 210 | DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); | ||
| 211 | saa7146_set_vbi_capture(dev,buf,next); | ||
| 212 | |||
| 213 | mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); | ||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field) | ||
| 218 | { | ||
| 219 | struct file *file = q->priv_data; | ||
| 220 | struct saa7146_fh *fh = file->private_data; | ||
| 221 | struct saa7146_dev *dev = fh->dev; | ||
| 222 | struct saa7146_buf *buf = (struct saa7146_buf *)vb; | ||
| 223 | |||
| 224 | int err = 0; | ||
| 225 | int lines, llength, size; | ||
| 226 | |||
| 227 | lines = 16 * 2 ; /* 2 fields */ | ||
| 228 | llength = vbi_pixel_to_capture; | ||
| 229 | size = lines * llength; | ||
| 230 | |||
| 231 | DEB_VBI(("vb:%p\n",vb)); | ||
| 232 | |||
| 233 | if (0 != buf->vb.baddr && buf->vb.bsize < size) { | ||
| 234 | DEB_VBI(("size mismatch.\n")); | ||
| 235 | return -EINVAL; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (buf->vb.size != size) | ||
| 239 | saa7146_dma_free(dev,q,buf); | ||
| 240 | |||
| 241 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
| 242 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | ||
| 243 | |||
| 244 | buf->vb.width = llength; | ||
| 245 | buf->vb.height = lines; | ||
| 246 | buf->vb.size = size; | ||
| 247 | buf->vb.field = field; // FIXME: check this | ||
| 248 | |||
| 249 | saa7146_pgtable_free(dev->pci, &buf->pt[2]); | ||
| 250 | saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); | ||
| 251 | |||
| 252 | err = videobuf_iolock(q,&buf->vb, NULL); | ||
| 253 | if (err) | ||
| 254 | goto oops; | ||
| 255 | err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], | ||
| 256 | dma->sglist, dma->sglen); | ||
| 257 | if (0 != err) | ||
| 258 | return err; | ||
| 259 | } | ||
| 260 | buf->vb.state = VIDEOBUF_PREPARED; | ||
| 261 | buf->activate = buffer_activate; | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | |||
| 265 | oops: | ||
| 266 | DEB_VBI(("error out.\n")); | ||
| 267 | saa7146_dma_free(dev,q,buf); | ||
| 268 | |||
| 269 | return err; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
| 273 | { | ||
| 274 | int llength,lines; | ||
| 275 | |||
| 276 | lines = 16 * 2 ; /* 2 fields */ | ||
| 277 | llength = vbi_pixel_to_capture; | ||
| 278 | |||
| 279 | *size = lines * llength; | ||
| 280 | *count = 2; | ||
| 281 | |||
| 282 | DEB_VBI(("count:%d, size:%d\n",*count,*size)); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
| 288 | { | ||
| 289 | struct file *file = q->priv_data; | ||
| 290 | struct saa7146_fh *fh = file->private_data; | ||
| 291 | struct saa7146_dev *dev = fh->dev; | ||
| 292 | struct saa7146_vv *vv = dev->vv_data; | ||
| 293 | struct saa7146_buf *buf = (struct saa7146_buf *)vb; | ||
| 294 | |||
| 295 | DEB_VBI(("vb:%p\n",vb)); | ||
| 296 | saa7146_buffer_queue(dev,&vv->vbi_q,buf); | ||
| 297 | } | ||
| 298 | |||
| 299 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
| 300 | { | ||
| 301 | struct file *file = q->priv_data; | ||
| 302 | struct saa7146_fh *fh = file->private_data; | ||
| 303 | struct saa7146_dev *dev = fh->dev; | ||
| 304 | struct saa7146_buf *buf = (struct saa7146_buf *)vb; | ||
| 305 | |||
| 306 | DEB_VBI(("vb:%p\n",vb)); | ||
| 307 | saa7146_dma_free(dev,q,buf); | ||
| 308 | } | ||
| 309 | |||
| 310 | static struct videobuf_queue_ops vbi_qops = { | ||
| 311 | .buf_setup = buffer_setup, | ||
| 312 | .buf_prepare = buffer_prepare, | ||
| 313 | .buf_queue = buffer_queue, | ||
| 314 | .buf_release = buffer_release, | ||
| 315 | }; | ||
| 316 | |||
| 317 | /* ------------------------------------------------------------------ */ | ||
| 318 | |||
| 319 | static void vbi_stop(struct saa7146_fh *fh, struct file *file) | ||
| 320 | { | ||
| 321 | struct saa7146_dev *dev = fh->dev; | ||
| 322 | struct saa7146_vv *vv = dev->vv_data; | ||
| 323 | unsigned long flags; | ||
| 324 | DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); | ||
| 325 | |||
| 326 | spin_lock_irqsave(&dev->slock,flags); | ||
| 327 | |||
| 328 | /* disable rps1 */ | ||
| 329 | saa7146_write(dev, MC1, MASK_29); | ||
| 330 | |||
| 331 | /* disable rps1 irqs */ | ||
| 332 | SAA7146_IER_DISABLE(dev, MASK_28); | ||
| 333 | |||
| 334 | /* shut down dma 3 transfers */ | ||
| 335 | saa7146_write(dev, MC1, MASK_20); | ||
| 336 | |||
| 337 | if (vv->vbi_q.curr) { | ||
| 338 | saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); | ||
| 339 | } | ||
| 340 | |||
| 341 | videobuf_queue_cancel(&fh->vbi_q); | ||
| 342 | |||
| 343 | vv->vbi_streaming = NULL; | ||
| 344 | |||
| 345 | del_timer(&vv->vbi_q.timeout); | ||
| 346 | del_timer(&fh->vbi_read_timeout); | ||
| 347 | |||
| 348 | spin_unlock_irqrestore(&dev->slock, flags); | ||
| 349 | } | ||
| 350 | |||
| 351 | static void vbi_read_timeout(unsigned long data) | ||
| 352 | { | ||
| 353 | struct file *file = (struct file*)data; | ||
| 354 | struct saa7146_fh *fh = file->private_data; | ||
| 355 | struct saa7146_dev *dev = fh->dev; | ||
| 356 | |||
| 357 | DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); | ||
| 358 | |||
| 359 | vbi_stop(fh, file); | ||
| 360 | } | ||
| 361 | |||
| 362 | static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) | ||
| 363 | { | ||
| 364 | DEB_VBI(("dev:%p\n",dev)); | ||
| 365 | |||
| 366 | INIT_LIST_HEAD(&vv->vbi_q.queue); | ||
| 367 | |||
| 368 | init_timer(&vv->vbi_q.timeout); | ||
| 369 | vv->vbi_q.timeout.function = saa7146_buffer_timeout; | ||
| 370 | vv->vbi_q.timeout.data = (unsigned long)(&vv->vbi_q); | ||
| 371 | vv->vbi_q.dev = dev; | ||
| 372 | |||
| 373 | init_waitqueue_head(&vv->vbi_wq); | ||
| 374 | } | ||
| 375 | |||
| 376 | static int vbi_open(struct saa7146_dev *dev, struct file *file) | ||
| 377 | { | ||
| 378 | struct saa7146_fh *fh = file->private_data; | ||
| 379 | |||
| 380 | u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); | ||
| 381 | int ret = 0; | ||
| 382 | |||
| 383 | DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); | ||
| 384 | |||
| 385 | ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); | ||
| 386 | if (0 == ret) { | ||
| 387 | DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n")); | ||
| 388 | return -EBUSY; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* adjust arbitrition control for video dma 3 */ | ||
| 392 | arbtr_ctrl &= ~0x1f0000; | ||
| 393 | arbtr_ctrl |= 0x1d0000; | ||
| 394 | saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); | ||
| 395 | saa7146_write(dev, MC2, (MASK_04|MASK_20)); | ||
| 396 | |||
| 397 | memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt)); | ||
| 398 | |||
| 399 | fh->vbi_fmt.sampling_rate = 27000000; | ||
| 400 | fh->vbi_fmt.offset = 248; /* todo */ | ||
| 401 | fh->vbi_fmt.samples_per_line = vbi_pixel_to_capture; | ||
| 402 | fh->vbi_fmt.sample_format = V4L2_PIX_FMT_GREY; | ||
| 403 | |||
| 404 | /* fixme: this only works for PAL */ | ||
| 405 | fh->vbi_fmt.start[0] = 5; | ||
| 406 | fh->vbi_fmt.count[0] = 16; | ||
| 407 | fh->vbi_fmt.start[1] = 312; | ||
| 408 | fh->vbi_fmt.count[1] = 16; | ||
| 409 | |||
| 410 | videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops, | ||
| 411 | &dev->pci->dev, &dev->slock, | ||
| 412 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
| 413 | V4L2_FIELD_SEQ_TB, // FIXME: does this really work? | ||
| 414 | sizeof(struct saa7146_buf), | ||
| 415 | file, &dev->v4l2_lock); | ||
| 416 | |||
| 417 | init_timer(&fh->vbi_read_timeout); | ||
| 418 | fh->vbi_read_timeout.function = vbi_read_timeout; | ||
| 419 | fh->vbi_read_timeout.data = (unsigned long)file; | ||
| 420 | |||
| 421 | /* initialize the brs */ | ||
| 422 | if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { | ||
| 423 | saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19)); | ||
| 424 | } else { | ||
| 425 | saa7146_write(dev, BRS_CTRL, 0x00000001); | ||
| 426 | |||
| 427 | if (0 != (ret = vbi_workaround(dev))) { | ||
| 428 | DEB_VBI(("vbi workaround failed!\n")); | ||
| 429 | /* return ret;*/ | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | /* upload brs register */ | ||
| 434 | saa7146_write(dev, MC2, (MASK_08|MASK_24)); | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | static void vbi_close(struct saa7146_dev *dev, struct file *file) | ||
| 439 | { | ||
| 440 | struct saa7146_fh *fh = file->private_data; | ||
| 441 | struct saa7146_vv *vv = dev->vv_data; | ||
| 442 | DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); | ||
| 443 | |||
| 444 | if( fh == vv->vbi_streaming ) { | ||
| 445 | vbi_stop(fh, file); | ||
| 446 | } | ||
| 447 | saa7146_res_free(fh, RESOURCE_DMA3_BRS); | ||
| 448 | } | ||
| 449 | |||
| 450 | static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) | ||
| 451 | { | ||
| 452 | struct saa7146_vv *vv = dev->vv_data; | ||
| 453 | spin_lock(&dev->slock); | ||
| 454 | |||
| 455 | if (vv->vbi_q.curr) { | ||
| 456 | DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr)); | ||
| 457 | /* this must be += 2, one count for each field */ | ||
| 458 | vv->vbi_fieldcount+=2; | ||
| 459 | vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; | ||
| 460 | saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); | ||
| 461 | } else { | ||
| 462 | DEB_VBI(("dev:%p\n",dev)); | ||
| 463 | } | ||
| 464 | saa7146_buffer_next(dev,&vv->vbi_q,1); | ||
| 465 | |||
| 466 | spin_unlock(&dev->slock); | ||
| 467 | } | ||
| 468 | |||
| 469 | static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
| 470 | { | ||
| 471 | struct saa7146_fh *fh = file->private_data; | ||
| 472 | struct saa7146_dev *dev = fh->dev; | ||
| 473 | struct saa7146_vv *vv = dev->vv_data; | ||
| 474 | ssize_t ret = 0; | ||
| 475 | |||
| 476 | DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); | ||
| 477 | |||
| 478 | if( NULL == vv->vbi_streaming ) { | ||
| 479 | // fixme: check if dma3 is available | ||
| 480 | // fixme: activate vbi engine here if necessary. (really?) | ||
| 481 | vv->vbi_streaming = fh; | ||
| 482 | } | ||
| 483 | |||
| 484 | if( fh != vv->vbi_streaming ) { | ||
| 485 | DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming)); | ||
| 486 | return -EBUSY; | ||
| 487 | } | ||
| 488 | |||
| 489 | mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT); | ||
| 490 | ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1, | ||
| 491 | file->f_flags & O_NONBLOCK); | ||
| 492 | /* | ||
| 493 | printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3)); | ||
| 494 | printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3)); | ||
| 495 | printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3)); | ||
| 496 | printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3)); | ||
| 497 | printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3)); | ||
| 498 | printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3)); | ||
| 499 | printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL)); | ||
| 500 | */ | ||
| 501 | return ret; | ||
| 502 | } | ||
| 503 | |||
| 504 | struct saa7146_use_ops saa7146_vbi_uops = { | ||
| 505 | .init = vbi_init, | ||
| 506 | .open = vbi_open, | ||
| 507 | .release = vbi_close, | ||
| 508 | .irq_done = vbi_irq_done, | ||
| 509 | .read = vbi_read, | ||
| 510 | }; | ||
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c new file mode 100644 index 00000000000..9aafa4e969a --- /dev/null +++ b/drivers/media/common/saa7146_video.c | |||
| @@ -0,0 +1,1429 @@ | |||
| 1 | #include <media/saa7146_vv.h> | ||
| 2 | #include <media/v4l2-chip-ident.h> | ||
| 3 | |||
| 4 | static int max_memory = 32; | ||
| 5 | |||
| 6 | module_param(max_memory, int, 0644); | ||
| 7 | MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)"); | ||
| 8 | |||
| 9 | #define IS_CAPTURE_ACTIVE(fh) \ | ||
| 10 | (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh)) | ||
| 11 | |||
| 12 | #define IS_OVERLAY_ACTIVE(fh) \ | ||
| 13 | (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh)) | ||
| 14 | |||
| 15 | /* format descriptions for capture and preview */ | ||
| 16 | static struct saa7146_format formats[] = { | ||
| 17 | { | ||
| 18 | .name = "RGB-8 (3-3-2)", | ||
| 19 | .pixelformat = V4L2_PIX_FMT_RGB332, | ||
| 20 | .trans = RGB08_COMPOSED, | ||
| 21 | .depth = 8, | ||
| 22 | .flags = 0, | ||
| 23 | }, { | ||
| 24 | .name = "RGB-16 (5/B-6/G-5/R)", | ||
| 25 | .pixelformat = V4L2_PIX_FMT_RGB565, | ||
| 26 | .trans = RGB16_COMPOSED, | ||
| 27 | .depth = 16, | ||
| 28 | .flags = 0, | ||
| 29 | }, { | ||
| 30 | .name = "RGB-24 (B-G-R)", | ||
| 31 | .pixelformat = V4L2_PIX_FMT_BGR24, | ||
| 32 | .trans = RGB24_COMPOSED, | ||
| 33 | .depth = 24, | ||
| 34 | .flags = 0, | ||
| 35 | }, { | ||
| 36 | .name = "RGB-32 (B-G-R)", | ||
| 37 | .pixelformat = V4L2_PIX_FMT_BGR32, | ||
| 38 | .trans = RGB32_COMPOSED, | ||
| 39 | .depth = 32, | ||
| 40 | .flags = 0, | ||
| 41 | }, { | ||
| 42 | .name = "RGB-32 (R-G-B)", | ||
| 43 | .pixelformat = V4L2_PIX_FMT_RGB32, | ||
| 44 | .trans = RGB32_COMPOSED, | ||
| 45 | .depth = 32, | ||
| 46 | .flags = 0, | ||
| 47 | .swap = 0x2, | ||
| 48 | }, { | ||
| 49 | .name = "Greyscale-8", | ||
| 50 | .pixelformat = V4L2_PIX_FMT_GREY, | ||
| 51 | .trans = Y8, | ||
| 52 | .depth = 8, | ||
| 53 | .flags = 0, | ||
| 54 | }, { | ||
| 55 | .name = "YUV 4:2:2 planar (Y-Cb-Cr)", | ||
| 56 | .pixelformat = V4L2_PIX_FMT_YUV422P, | ||
| 57 | .trans = YUV422_DECOMPOSED, | ||
| 58 | .depth = 16, | ||
| 59 | .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, | ||
| 60 | }, { | ||
| 61 | .name = "YVU 4:2:0 planar (Y-Cb-Cr)", | ||
| 62 | .pixelformat = V4L2_PIX_FMT_YVU420, | ||
| 63 | .trans = YUV420_DECOMPOSED, | ||
| 64 | .depth = 12, | ||
| 65 | .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, | ||
| 66 | }, { | ||
| 67 | .name = "YUV 4:2:0 planar (Y-Cb-Cr)", | ||
| 68 | .pixelformat = V4L2_PIX_FMT_YUV420, | ||
| 69 | .trans = YUV420_DECOMPOSED, | ||
| 70 | .depth = 12, | ||
| 71 | .flags = FORMAT_IS_PLANAR, | ||
| 72 | }, { | ||
| 73 | .name = "YUV 4:2:2 (U-Y-V-Y)", | ||
| 74 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
| 75 | .trans = YUV422_COMPOSED, | ||
| 76 | .depth = 16, | ||
| 77 | .flags = 0, | ||
| 78 | } | ||
| 79 | }; | ||
| 80 | |||
| 81 | /* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps. | ||
| 82 | due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped | ||
| 83 | (like V4L2_PIX_FMT_YUYV) ... 8-( */ | ||
| 84 | |||
| 85 | static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format); | ||
| 86 | |||
| 87 | struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc) | ||
| 88 | { | ||
| 89 | int i, j = NUM_FORMATS; | ||
| 90 | |||
| 91 | for (i = 0; i < j; i++) { | ||
| 92 | if (formats[i].pixelformat == fourcc) { | ||
| 93 | return formats+i; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc)); | ||
| 98 | return NULL; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f); | ||
| 102 | |||
| 103 | int saa7146_start_preview(struct saa7146_fh *fh) | ||
| 104 | { | ||
| 105 | struct saa7146_dev *dev = fh->dev; | ||
| 106 | struct saa7146_vv *vv = dev->vv_data; | ||
| 107 | struct v4l2_format fmt; | ||
| 108 | int ret = 0, err = 0; | ||
| 109 | |||
| 110 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); | ||
| 111 | |||
| 112 | /* check if we have overlay informations */ | ||
| 113 | if( NULL == fh->ov.fh ) { | ||
| 114 | DEB_D(("no overlay data available. try S_FMT first.\n")); | ||
| 115 | return -EAGAIN; | ||
| 116 | } | ||
| 117 | |||
| 118 | /* check if streaming capture is running */ | ||
| 119 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
| 120 | DEB_D(("streaming capture is active.\n")); | ||
| 121 | return -EBUSY; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* check if overlay is running */ | ||
| 125 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
| 126 | if (vv->video_fh == fh) { | ||
| 127 | DEB_D(("overlay is already active.\n")); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | DEB_D(("overlay is already active in another open.\n")); | ||
| 131 | return -EBUSY; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { | ||
| 135 | DEB_D(("cannot get necessary overlay resources\n")); | ||
| 136 | return -EBUSY; | ||
| 137 | } | ||
| 138 | |||
| 139 | fmt.fmt.win = fh->ov.win; | ||
| 140 | err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt); | ||
| 141 | if (0 != err) { | ||
| 142 | saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | ||
| 143 | return -EBUSY; | ||
| 144 | } | ||
| 145 | fh->ov.win = fmt.fmt.win; | ||
| 146 | vv->ov_data = &fh->ov; | ||
| 147 | |||
| 148 | DEB_D(("%dx%d+%d+%d %s field=%s\n", | ||
| 149 | fh->ov.win.w.width,fh->ov.win.w.height, | ||
| 150 | fh->ov.win.w.left,fh->ov.win.w.top, | ||
| 151 | vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); | ||
| 152 | |||
| 153 | if (0 != (ret = saa7146_enable_overlay(fh))) { | ||
| 154 | DEB_D(("enabling overlay failed: %d\n",ret)); | ||
| 155 | saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | ||
| 156 | return ret; | ||
| 157 | } | ||
| 158 | |||
| 159 | vv->video_status = STATUS_OVERLAY; | ||
| 160 | vv->video_fh = fh; | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | EXPORT_SYMBOL_GPL(saa7146_start_preview); | ||
| 165 | |||
| 166 | int saa7146_stop_preview(struct saa7146_fh *fh) | ||
| 167 | { | ||
| 168 | struct saa7146_dev *dev = fh->dev; | ||
| 169 | struct saa7146_vv *vv = dev->vv_data; | ||
| 170 | |||
| 171 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); | ||
| 172 | |||
| 173 | /* check if streaming capture is running */ | ||
| 174 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
| 175 | DEB_D(("streaming capture is active.\n")); | ||
| 176 | return -EBUSY; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* check if overlay is running at all */ | ||
| 180 | if ((vv->video_status & STATUS_OVERLAY) == 0) { | ||
| 181 | DEB_D(("no active overlay.\n")); | ||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | if (vv->video_fh != fh) { | ||
| 186 | DEB_D(("overlay is active, but in another open.\n")); | ||
| 187 | return -EBUSY; | ||
| 188 | } | ||
| 189 | |||
| 190 | vv->video_status = 0; | ||
| 191 | vv->video_fh = NULL; | ||
| 192 | |||
| 193 | saa7146_disable_overlay(fh); | ||
| 194 | |||
| 195 | saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | EXPORT_SYMBOL_GPL(saa7146_stop_preview); | ||
| 200 | |||
| 201 | /********************************************************************************/ | ||
| 202 | /* device controls */ | ||
| 203 | |||
| 204 | static struct v4l2_queryctrl controls[] = { | ||
| 205 | { | ||
| 206 | .id = V4L2_CID_BRIGHTNESS, | ||
| 207 | .name = "Brightness", | ||
| 208 | .minimum = 0, | ||
| 209 | .maximum = 255, | ||
| 210 | .step = 1, | ||
| 211 | .default_value = 128, | ||
| 212 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 213 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 214 | },{ | ||
| 215 | .id = V4L2_CID_CONTRAST, | ||
| 216 | .name = "Contrast", | ||
| 217 | .minimum = 0, | ||
| 218 | .maximum = 127, | ||
| 219 | .step = 1, | ||
| 220 | .default_value = 64, | ||
| 221 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 222 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 223 | },{ | ||
| 224 | .id = V4L2_CID_SATURATION, | ||
| 225 | .name = "Saturation", | ||
| 226 | .minimum = 0, | ||
| 227 | .maximum = 127, | ||
| 228 | .step = 1, | ||
| 229 | .default_value = 64, | ||
| 230 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 231 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 232 | },{ | ||
| 233 | .id = V4L2_CID_VFLIP, | ||
| 234 | .name = "Vertical Flip", | ||
| 235 | .minimum = 0, | ||
| 236 | .maximum = 1, | ||
| 237 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 238 | },{ | ||
| 239 | .id = V4L2_CID_HFLIP, | ||
| 240 | .name = "Horizontal Flip", | ||
| 241 | .minimum = 0, | ||
| 242 | .maximum = 1, | ||
| 243 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 244 | }, | ||
| 245 | }; | ||
| 246 | static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl); | ||
| 247 | |||
| 248 | #define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 0) | ||
| 249 | |||
| 250 | static struct v4l2_queryctrl* ctrl_by_id(int id) | ||
| 251 | { | ||
| 252 | int i; | ||
| 253 | |||
| 254 | for (i = 0; i < NUM_CONTROLS; i++) | ||
| 255 | if (controls[i].id == id) | ||
| 256 | return controls+i; | ||
| 257 | return NULL; | ||
| 258 | } | ||
| 259 | |||
| 260 | /********************************************************************************/ | ||
| 261 | /* common pagetable functions */ | ||
| 262 | |||
| 263 | static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) | ||
| 264 | { | ||
| 265 | struct pci_dev *pci = dev->pci; | ||
| 266 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | ||
| 267 | struct scatterlist *list = dma->sglist; | ||
| 268 | int length = dma->sglen; | ||
| 269 | struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | ||
| 270 | |||
| 271 | DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); | ||
| 272 | |||
| 273 | if( 0 != IS_PLANAR(sfmt->trans)) { | ||
| 274 | struct saa7146_pgtable *pt1 = &buf->pt[0]; | ||
| 275 | struct saa7146_pgtable *pt2 = &buf->pt[1]; | ||
| 276 | struct saa7146_pgtable *pt3 = &buf->pt[2]; | ||
| 277 | __le32 *ptr1, *ptr2, *ptr3; | ||
| 278 | __le32 fill; | ||
| 279 | |||
| 280 | int size = buf->fmt->width*buf->fmt->height; | ||
| 281 | int i,p,m1,m2,m3,o1,o2; | ||
| 282 | |||
| 283 | switch( sfmt->depth ) { | ||
| 284 | case 12: { | ||
| 285 | /* create some offsets inside the page table */ | ||
| 286 | m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; | ||
| 287 | m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; | ||
| 288 | m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; | ||
| 289 | o1 = size%PAGE_SIZE; | ||
| 290 | o2 = (size+(size/4))%PAGE_SIZE; | ||
| 291 | DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | case 16: { | ||
| 295 | /* create some offsets inside the page table */ | ||
| 296 | m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; | ||
| 297 | m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; | ||
| 298 | m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; | ||
| 299 | o1 = size%PAGE_SIZE; | ||
| 300 | o2 = (size+(size/2))%PAGE_SIZE; | ||
| 301 | DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); | ||
| 302 | break; | ||
| 303 | } | ||
| 304 | default: { | ||
| 305 | return -1; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | ptr1 = pt1->cpu; | ||
| 310 | ptr2 = pt2->cpu; | ||
| 311 | ptr3 = pt3->cpu; | ||
| 312 | |||
| 313 | /* walk all pages, copy all page addresses to ptr1 */ | ||
| 314 | for (i = 0; i < length; i++, list++) { | ||
| 315 | for (p = 0; p * 4096 < list->length; p++, ptr1++) { | ||
| 316 | *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | /* | ||
| 320 | ptr1 = pt1->cpu; | ||
| 321 | for(j=0;j<40;j++) { | ||
| 322 | printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); | ||
| 323 | } | ||
| 324 | */ | ||
| 325 | |||
| 326 | /* if we have a user buffer, the first page may not be | ||
| 327 | aligned to a page boundary. */ | ||
| 328 | pt1->offset = dma->sglist->offset; | ||
| 329 | pt2->offset = pt1->offset+o1; | ||
| 330 | pt3->offset = pt1->offset+o2; | ||
| 331 | |||
| 332 | /* create video-dma2 page table */ | ||
| 333 | ptr1 = pt1->cpu; | ||
| 334 | for(i = m1; i <= m2 ; i++, ptr2++) { | ||
| 335 | *ptr2 = ptr1[i]; | ||
| 336 | } | ||
| 337 | fill = *(ptr2-1); | ||
| 338 | for(;i<1024;i++,ptr2++) { | ||
| 339 | *ptr2 = fill; | ||
| 340 | } | ||
| 341 | /* create video-dma3 page table */ | ||
| 342 | ptr1 = pt1->cpu; | ||
| 343 | for(i = m2; i <= m3; i++,ptr3++) { | ||
| 344 | *ptr3 = ptr1[i]; | ||
| 345 | } | ||
| 346 | fill = *(ptr3-1); | ||
| 347 | for(;i<1024;i++,ptr3++) { | ||
| 348 | *ptr3 = fill; | ||
| 349 | } | ||
| 350 | /* finally: finish up video-dma1 page table */ | ||
| 351 | ptr1 = pt1->cpu+m1; | ||
| 352 | fill = pt1->cpu[m1]; | ||
| 353 | for(i=m1;i<1024;i++,ptr1++) { | ||
| 354 | *ptr1 = fill; | ||
| 355 | } | ||
| 356 | /* | ||
| 357 | ptr1 = pt1->cpu; | ||
| 358 | ptr2 = pt2->cpu; | ||
| 359 | ptr3 = pt3->cpu; | ||
| 360 | for(j=0;j<40;j++) { | ||
| 361 | printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); | ||
| 362 | } | ||
| 363 | for(j=0;j<40;j++) { | ||
| 364 | printk("ptr2 %d: 0x%08x\n",j,ptr2[j]); | ||
| 365 | } | ||
| 366 | for(j=0;j<40;j++) { | ||
| 367 | printk("ptr3 %d: 0x%08x\n",j,ptr3[j]); | ||
| 368 | } | ||
| 369 | */ | ||
| 370 | } else { | ||
| 371 | struct saa7146_pgtable *pt = &buf->pt[0]; | ||
| 372 | return saa7146_pgtable_build_single(pci, pt, list, length); | ||
| 373 | } | ||
| 374 | |||
| 375 | return 0; | ||
| 376 | } | ||
| 377 | |||
| 378 | |||
| 379 | /********************************************************************************/ | ||
| 380 | /* file operations */ | ||
| 381 | |||
| 382 | static int video_begin(struct saa7146_fh *fh) | ||
| 383 | { | ||
| 384 | struct saa7146_dev *dev = fh->dev; | ||
| 385 | struct saa7146_vv *vv = dev->vv_data; | ||
| 386 | struct saa7146_format *fmt = NULL; | ||
| 387 | unsigned int resource; | ||
| 388 | int ret = 0, err = 0; | ||
| 389 | |||
| 390 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); | ||
| 391 | |||
| 392 | if ((vv->video_status & STATUS_CAPTURE) != 0) { | ||
| 393 | if (vv->video_fh == fh) { | ||
| 394 | DEB_S(("already capturing.\n")); | ||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | DEB_S(("already capturing in another open.\n")); | ||
| 398 | return -EBUSY; | ||
| 399 | } | ||
| 400 | |||
| 401 | if ((vv->video_status & STATUS_OVERLAY) != 0) { | ||
| 402 | DEB_S(("warning: suspending overlay video for streaming capture.\n")); | ||
| 403 | vv->ov_suspend = vv->video_fh; | ||
| 404 | err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ | ||
| 405 | if (0 != err) { | ||
| 406 | DEB_D(("suspending video failed. aborting\n")); | ||
| 407 | return err; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); | ||
| 412 | /* we need to have a valid format set here */ | ||
| 413 | BUG_ON(NULL == fmt); | ||
| 414 | |||
| 415 | if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { | ||
| 416 | resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; | ||
| 417 | } else { | ||
| 418 | resource = RESOURCE_DMA1_HPS; | ||
| 419 | } | ||
| 420 | |||
| 421 | ret = saa7146_res_get(fh, resource); | ||
| 422 | if (0 == ret) { | ||
| 423 | DEB_S(("cannot get capture resource %d\n",resource)); | ||
| 424 | if (vv->ov_suspend != NULL) { | ||
| 425 | saa7146_start_preview(vv->ov_suspend); | ||
| 426 | vv->ov_suspend = NULL; | ||
| 427 | } | ||
| 428 | return -EBUSY; | ||
| 429 | } | ||
| 430 | |||
| 431 | /* clear out beginning of streaming bit (rps register 0)*/ | ||
| 432 | saa7146_write(dev, MC2, MASK_27 ); | ||
| 433 | |||
| 434 | /* enable rps0 irqs */ | ||
| 435 | SAA7146_IER_ENABLE(dev, MASK_27); | ||
| 436 | |||
| 437 | vv->video_fh = fh; | ||
| 438 | vv->video_status = STATUS_CAPTURE; | ||
| 439 | |||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | static int video_end(struct saa7146_fh *fh, struct file *file) | ||
| 444 | { | ||
| 445 | struct saa7146_dev *dev = fh->dev; | ||
| 446 | struct saa7146_vv *vv = dev->vv_data; | ||
| 447 | struct saa7146_format *fmt = NULL; | ||
| 448 | unsigned long flags; | ||
| 449 | unsigned int resource; | ||
| 450 | u32 dmas = 0; | ||
| 451 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); | ||
| 452 | |||
| 453 | if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { | ||
| 454 | DEB_S(("not capturing.\n")); | ||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | if (vv->video_fh != fh) { | ||
| 459 | DEB_S(("capturing, but in another open.\n")); | ||
| 460 | return -EBUSY; | ||
| 461 | } | ||
| 462 | |||
| 463 | fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); | ||
| 464 | /* we need to have a valid format set here */ | ||
| 465 | BUG_ON(NULL == fmt); | ||
| 466 | |||
| 467 | if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { | ||
| 468 | resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; | ||
| 469 | dmas = MASK_22 | MASK_21 | MASK_20; | ||
| 470 | } else { | ||
| 471 | resource = RESOURCE_DMA1_HPS; | ||
| 472 | dmas = MASK_22; | ||
| 473 | } | ||
| 474 | spin_lock_irqsave(&dev->slock,flags); | ||
| 475 | |||
| 476 | /* disable rps0 */ | ||
| 477 | saa7146_write(dev, MC1, MASK_28); | ||
| 478 | |||
| 479 | /* disable rps0 irqs */ | ||
| 480 | SAA7146_IER_DISABLE(dev, MASK_27); | ||
| 481 | |||
| 482 | /* shut down all used video dma transfers */ | ||
| 483 | saa7146_write(dev, MC1, dmas); | ||
| 484 | |||
| 485 | spin_unlock_irqrestore(&dev->slock, flags); | ||
| 486 | |||
| 487 | vv->video_fh = NULL; | ||
| 488 | vv->video_status = 0; | ||
| 489 | |||
| 490 | saa7146_res_free(fh, resource); | ||
| 491 | |||
| 492 | if (vv->ov_suspend != NULL) { | ||
| 493 | saa7146_start_preview(vv->ov_suspend); | ||
| 494 | vv->ov_suspend = NULL; | ||
| 495 | } | ||
| 496 | |||
| 497 | return 0; | ||
| 498 | } | ||
| 499 | |||
| 500 | static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) | ||
| 501 | { | ||
| 502 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 503 | |||
| 504 | strcpy((char *)cap->driver, "saa7146 v4l2"); | ||
| 505 | strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); | ||
| 506 | sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
| 507 | cap->version = SAA7146_VERSION_CODE; | ||
| 508 | cap->capabilities = | ||
| 509 | V4L2_CAP_VIDEO_CAPTURE | | ||
| 510 | V4L2_CAP_VIDEO_OVERLAY | | ||
| 511 | V4L2_CAP_READWRITE | | ||
| 512 | V4L2_CAP_STREAMING; | ||
| 513 | cap->capabilities |= dev->ext_vv_data->capabilities; | ||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) | ||
| 518 | { | ||
| 519 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 520 | struct saa7146_vv *vv = dev->vv_data; | ||
| 521 | |||
| 522 | *fb = vv->ov_fb; | ||
| 523 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) | ||
| 528 | { | ||
| 529 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 530 | struct saa7146_vv *vv = dev->vv_data; | ||
| 531 | struct saa7146_format *fmt; | ||
| 532 | |||
| 533 | DEB_EE(("VIDIOC_S_FBUF\n")); | ||
| 534 | |||
| 535 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) | ||
| 536 | return -EPERM; | ||
| 537 | |||
| 538 | /* check args */ | ||
| 539 | fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat); | ||
| 540 | if (NULL == fmt) | ||
| 541 | return -EINVAL; | ||
| 542 | |||
| 543 | /* planar formats are not allowed for overlay video, clipping and video dma would clash */ | ||
| 544 | if (fmt->flags & FORMAT_IS_PLANAR) | ||
| 545 | DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n", | ||
| 546 | (char *)&fmt->pixelformat)); | ||
| 547 | |||
| 548 | /* check if overlay is running */ | ||
| 549 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
| 550 | if (vv->video_fh != fh) { | ||
| 551 | DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); | ||
| 552 | return -EBUSY; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | /* ok, accept it */ | ||
| 557 | vv->ov_fb = *fb; | ||
| 558 | vv->ov_fmt = fmt; | ||
| 559 | |||
| 560 | if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) { | ||
| 561 | vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; | ||
| 562 | DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline)); | ||
| 563 | } | ||
| 564 | return 0; | ||
| 565 | } | ||
| 566 | |||
| 567 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) | ||
| 568 | { | ||
| 569 | if (f->index >= NUM_FORMATS) | ||
| 570 | return -EINVAL; | ||
| 571 | strlcpy((char *)f->description, formats[f->index].name, | ||
| 572 | sizeof(f->description)); | ||
| 573 | f->pixelformat = formats[f->index].pixelformat; | ||
| 574 | return 0; | ||
| 575 | } | ||
| 576 | |||
| 577 | static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) | ||
| 578 | { | ||
| 579 | const struct v4l2_queryctrl *ctrl; | ||
| 580 | |||
| 581 | if ((c->id < V4L2_CID_BASE || | ||
| 582 | c->id >= V4L2_CID_LASTP1) && | ||
| 583 | (c->id < V4L2_CID_PRIVATE_BASE || | ||
| 584 | c->id >= V4L2_CID_PRIVATE_LASTP1)) | ||
| 585 | return -EINVAL; | ||
| 586 | |||
| 587 | ctrl = ctrl_by_id(c->id); | ||
| 588 | if (ctrl == NULL) | ||
| 589 | return -EINVAL; | ||
| 590 | |||
| 591 | DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id)); | ||
| 592 | *c = *ctrl; | ||
| 593 | return 0; | ||
| 594 | } | ||
| 595 | |||
| 596 | static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) | ||
| 597 | { | ||
| 598 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 599 | struct saa7146_vv *vv = dev->vv_data; | ||
| 600 | const struct v4l2_queryctrl *ctrl; | ||
| 601 | u32 value = 0; | ||
| 602 | |||
| 603 | ctrl = ctrl_by_id(c->id); | ||
| 604 | if (NULL == ctrl) | ||
| 605 | return -EINVAL; | ||
| 606 | switch (c->id) { | ||
| 607 | case V4L2_CID_BRIGHTNESS: | ||
| 608 | value = saa7146_read(dev, BCS_CTRL); | ||
| 609 | c->value = 0xff & (value >> 24); | ||
| 610 | DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value)); | ||
| 611 | break; | ||
| 612 | case V4L2_CID_CONTRAST: | ||
| 613 | value = saa7146_read(dev, BCS_CTRL); | ||
| 614 | c->value = 0x7f & (value >> 16); | ||
| 615 | DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value)); | ||
| 616 | break; | ||
| 617 | case V4L2_CID_SATURATION: | ||
| 618 | value = saa7146_read(dev, BCS_CTRL); | ||
| 619 | c->value = 0x7f & (value >> 0); | ||
| 620 | DEB_D(("V4L2_CID_SATURATION: %d\n", c->value)); | ||
| 621 | break; | ||
| 622 | case V4L2_CID_VFLIP: | ||
| 623 | c->value = vv->vflip; | ||
| 624 | DEB_D(("V4L2_CID_VFLIP: %d\n", c->value)); | ||
| 625 | break; | ||
| 626 | case V4L2_CID_HFLIP: | ||
| 627 | c->value = vv->hflip; | ||
| 628 | DEB_D(("V4L2_CID_HFLIP: %d\n", c->value)); | ||
| 629 | break; | ||
| 630 | default: | ||
| 631 | return -EINVAL; | ||
| 632 | } | ||
| 633 | return 0; | ||
| 634 | } | ||
| 635 | |||
| 636 | static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) | ||
| 637 | { | ||
| 638 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 639 | struct saa7146_vv *vv = dev->vv_data; | ||
| 640 | const struct v4l2_queryctrl *ctrl; | ||
| 641 | |||
| 642 | ctrl = ctrl_by_id(c->id); | ||
| 643 | if (NULL == ctrl) { | ||
| 644 | DEB_D(("unknown control %d\n", c->id)); | ||
| 645 | return -EINVAL; | ||
| 646 | } | ||
| 647 | |||
| 648 | switch (ctrl->type) { | ||
| 649 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
| 650 | case V4L2_CTRL_TYPE_MENU: | ||
| 651 | case V4L2_CTRL_TYPE_INTEGER: | ||
| 652 | if (c->value < ctrl->minimum) | ||
| 653 | c->value = ctrl->minimum; | ||
| 654 | if (c->value > ctrl->maximum) | ||
| 655 | c->value = ctrl->maximum; | ||
| 656 | break; | ||
| 657 | default: | ||
| 658 | /* nothing */; | ||
| 659 | } | ||
| 660 | |||
| 661 | switch (c->id) { | ||
| 662 | case V4L2_CID_BRIGHTNESS: { | ||
| 663 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
| 664 | value &= 0x00ffffff; | ||
| 665 | value |= (c->value << 24); | ||
| 666 | saa7146_write(dev, BCS_CTRL, value); | ||
| 667 | saa7146_write(dev, MC2, MASK_22 | MASK_06); | ||
| 668 | break; | ||
| 669 | } | ||
| 670 | case V4L2_CID_CONTRAST: { | ||
| 671 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
| 672 | value &= 0xff00ffff; | ||
| 673 | value |= (c->value << 16); | ||
| 674 | saa7146_write(dev, BCS_CTRL, value); | ||
| 675 | saa7146_write(dev, MC2, MASK_22 | MASK_06); | ||
| 676 | break; | ||
| 677 | } | ||
| 678 | case V4L2_CID_SATURATION: { | ||
| 679 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
| 680 | value &= 0xffffff00; | ||
| 681 | value |= (c->value << 0); | ||
| 682 | saa7146_write(dev, BCS_CTRL, value); | ||
| 683 | saa7146_write(dev, MC2, MASK_22 | MASK_06); | ||
| 684 | break; | ||
| 685 | } | ||
| 686 | case V4L2_CID_HFLIP: | ||
| 687 | /* fixme: we can support changing VFLIP and HFLIP here... */ | ||
| 688 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
| 689 | DEB_D(("V4L2_CID_HFLIP while active capture.\n")); | ||
| 690 | return -EBUSY; | ||
| 691 | } | ||
| 692 | vv->hflip = c->value; | ||
| 693 | break; | ||
| 694 | case V4L2_CID_VFLIP: | ||
| 695 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
| 696 | DEB_D(("V4L2_CID_VFLIP while active capture.\n")); | ||
| 697 | return -EBUSY; | ||
| 698 | } | ||
| 699 | vv->vflip = c->value; | ||
| 700 | break; | ||
| 701 | default: | ||
| 702 | return -EINVAL; | ||
| 703 | } | ||
| 704 | |||
| 705 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
| 706 | saa7146_stop_preview(fh); | ||
| 707 | saa7146_start_preview(fh); | ||
| 708 | } | ||
| 709 | return 0; | ||
| 710 | } | ||
| 711 | |||
| 712 | static int vidioc_g_parm(struct file *file, void *fh, | ||
| 713 | struct v4l2_streamparm *parm) | ||
| 714 | { | ||
| 715 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 716 | struct saa7146_vv *vv = dev->vv_data; | ||
| 717 | |||
| 718 | parm->parm.capture.readbuffers = 1; | ||
| 719 | v4l2_video_std_frame_period(vv->standard->id, | ||
| 720 | &parm->parm.capture.timeperframe); | ||
| 721 | return 0; | ||
| 722 | } | ||
| 723 | |||
| 724 | static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) | ||
| 725 | { | ||
| 726 | f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt; | ||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) | ||
| 731 | { | ||
| 732 | f->fmt.win = ((struct saa7146_fh *)fh)->ov.win; | ||
| 733 | return 0; | ||
| 734 | } | ||
| 735 | |||
| 736 | static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f) | ||
| 737 | { | ||
| 738 | f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt; | ||
| 739 | return 0; | ||
| 740 | } | ||
| 741 | |||
| 742 | static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) | ||
| 743 | { | ||
| 744 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 745 | struct saa7146_vv *vv = dev->vv_data; | ||
| 746 | struct saa7146_format *fmt; | ||
| 747 | enum v4l2_field field; | ||
| 748 | int maxw, maxh; | ||
| 749 | int calc_bpl; | ||
| 750 | |||
| 751 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); | ||
| 752 | |||
| 753 | fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat); | ||
| 754 | if (NULL == fmt) | ||
| 755 | return -EINVAL; | ||
| 756 | |||
| 757 | field = f->fmt.pix.field; | ||
| 758 | maxw = vv->standard->h_max_out; | ||
| 759 | maxh = vv->standard->v_max_out; | ||
| 760 | |||
| 761 | if (V4L2_FIELD_ANY == field) { | ||
| 762 | field = (f->fmt.pix.height > maxh / 2) | ||
| 763 | ? V4L2_FIELD_INTERLACED | ||
| 764 | : V4L2_FIELD_BOTTOM; | ||
| 765 | } | ||
| 766 | switch (field) { | ||
| 767 | case V4L2_FIELD_ALTERNATE: | ||
| 768 | vv->last_field = V4L2_FIELD_TOP; | ||
| 769 | maxh = maxh / 2; | ||
| 770 | break; | ||
| 771 | case V4L2_FIELD_TOP: | ||
| 772 | case V4L2_FIELD_BOTTOM: | ||
| 773 | vv->last_field = V4L2_FIELD_INTERLACED; | ||
| 774 | maxh = maxh / 2; | ||
| 775 | break; | ||
| 776 | case V4L2_FIELD_INTERLACED: | ||
| 777 | vv->last_field = V4L2_FIELD_INTERLACED; | ||
| 778 | break; | ||
| 779 | default: | ||
| 780 | DEB_D(("no known field mode '%d'.\n", field)); | ||
| 781 | return -EINVAL; | ||
| 782 | } | ||
| 783 | |||
| 784 | f->fmt.pix.field = field; | ||
| 785 | if (f->fmt.pix.width > maxw) | ||
| 786 | f->fmt.pix.width = maxw; | ||
| 787 | if (f->fmt.pix.height > maxh) | ||
| 788 | f->fmt.pix.height = maxh; | ||
| 789 | |||
| 790 | calc_bpl = (f->fmt.pix.width * fmt->depth) / 8; | ||
| 791 | |||
| 792 | if (f->fmt.pix.bytesperline < calc_bpl) | ||
| 793 | f->fmt.pix.bytesperline = calc_bpl; | ||
| 794 | |||
| 795 | if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */ | ||
| 796 | f->fmt.pix.bytesperline = calc_bpl; | ||
| 797 | |||
| 798 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; | ||
| 799 | DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width, | ||
| 800 | f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage)); | ||
| 801 | |||
| 802 | return 0; | ||
| 803 | } | ||
| 804 | |||
| 805 | |||
| 806 | static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) | ||
| 807 | { | ||
| 808 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 809 | struct saa7146_vv *vv = dev->vv_data; | ||
| 810 | struct v4l2_window *win = &f->fmt.win; | ||
| 811 | enum v4l2_field field; | ||
| 812 | int maxw, maxh; | ||
| 813 | |||
| 814 | DEB_EE(("dev:%p\n", dev)); | ||
| 815 | |||
| 816 | if (NULL == vv->ov_fb.base) { | ||
| 817 | DEB_D(("no fb base set.\n")); | ||
| 818 | return -EINVAL; | ||
| 819 | } | ||
| 820 | if (NULL == vv->ov_fmt) { | ||
| 821 | DEB_D(("no fb fmt set.\n")); | ||
| 822 | return -EINVAL; | ||
| 823 | } | ||
| 824 | if (win->w.width < 48 || win->w.height < 32) { | ||
| 825 | DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height)); | ||
| 826 | return -EINVAL; | ||
| 827 | } | ||
| 828 | if (win->clipcount > 16) { | ||
| 829 | DEB_D(("clipcount too big.\n")); | ||
| 830 | return -EINVAL; | ||
| 831 | } | ||
| 832 | |||
| 833 | field = win->field; | ||
| 834 | maxw = vv->standard->h_max_out; | ||
| 835 | maxh = vv->standard->v_max_out; | ||
| 836 | |||
| 837 | if (V4L2_FIELD_ANY == field) { | ||
| 838 | field = (win->w.height > maxh / 2) | ||
| 839 | ? V4L2_FIELD_INTERLACED | ||
| 840 | : V4L2_FIELD_TOP; | ||
| 841 | } | ||
| 842 | switch (field) { | ||
| 843 | case V4L2_FIELD_TOP: | ||
| 844 | case V4L2_FIELD_BOTTOM: | ||
| 845 | case V4L2_FIELD_ALTERNATE: | ||
| 846 | maxh = maxh / 2; | ||
| 847 | break; | ||
| 848 | case V4L2_FIELD_INTERLACED: | ||
| 849 | break; | ||
| 850 | default: | ||
| 851 | DEB_D(("no known field mode '%d'.\n", field)); | ||
| 852 | return -EINVAL; | ||
| 853 | } | ||
| 854 | |||
| 855 | win->field = field; | ||
| 856 | if (win->w.width > maxw) | ||
| 857 | win->w.width = maxw; | ||
| 858 | if (win->w.height > maxh) | ||
| 859 | win->w.height = maxh; | ||
| 860 | |||
| 861 | return 0; | ||
| 862 | } | ||
| 863 | |||
| 864 | static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f) | ||
| 865 | { | ||
| 866 | struct saa7146_fh *fh = __fh; | ||
| 867 | struct saa7146_dev *dev = fh->dev; | ||
| 868 | struct saa7146_vv *vv = dev->vv_data; | ||
| 869 | int err; | ||
| 870 | |||
| 871 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); | ||
| 872 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
| 873 | DEB_EE(("streaming capture is active\n")); | ||
| 874 | return -EBUSY; | ||
| 875 | } | ||
| 876 | err = vidioc_try_fmt_vid_cap(file, fh, f); | ||
| 877 | if (0 != err) | ||
| 878 | return err; | ||
| 879 | fh->video_fmt = f->fmt.pix; | ||
| 880 | DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat)); | ||
| 881 | return 0; | ||
| 882 | } | ||
| 883 | |||
| 884 | static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f) | ||
| 885 | { | ||
| 886 | struct saa7146_fh *fh = __fh; | ||
| 887 | struct saa7146_dev *dev = fh->dev; | ||
| 888 | struct saa7146_vv *vv = dev->vv_data; | ||
| 889 | int err; | ||
| 890 | |||
| 891 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh)); | ||
| 892 | err = vidioc_try_fmt_vid_overlay(file, fh, f); | ||
| 893 | if (0 != err) | ||
| 894 | return err; | ||
| 895 | fh->ov.win = f->fmt.win; | ||
| 896 | fh->ov.nclips = f->fmt.win.clipcount; | ||
| 897 | if (fh->ov.nclips > 16) | ||
| 898 | fh->ov.nclips = 16; | ||
| 899 | if (copy_from_user(fh->ov.clips, f->fmt.win.clips, | ||
| 900 | sizeof(struct v4l2_clip) * fh->ov.nclips)) { | ||
| 901 | return -EFAULT; | ||
| 902 | } | ||
| 903 | |||
| 904 | /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ | ||
| 905 | fh->ov.fh = fh; | ||
| 906 | |||
| 907 | /* check if our current overlay is active */ | ||
| 908 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
| 909 | saa7146_stop_preview(fh); | ||
| 910 | saa7146_start_preview(fh); | ||
| 911 | } | ||
| 912 | return 0; | ||
| 913 | } | ||
| 914 | |||
| 915 | static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) | ||
| 916 | { | ||
| 917 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 918 | struct saa7146_vv *vv = dev->vv_data; | ||
| 919 | |||
| 920 | *norm = vv->standard->id; | ||
| 921 | return 0; | ||
| 922 | } | ||
| 923 | |||
| 924 | /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) | ||
| 925 | PAL / NTSC / SECAM. if your hardware does not (or does more) | ||
| 926 | -- override this function in your extension */ | ||
| 927 | /* | ||
| 928 | case VIDIOC_ENUMSTD: | ||
| 929 | { | ||
| 930 | struct v4l2_standard *e = arg; | ||
| 931 | if (e->index < 0 ) | ||
| 932 | return -EINVAL; | ||
| 933 | if( e->index < dev->ext_vv_data->num_stds ) { | ||
| 934 | DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); | ||
| 935 | v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); | ||
| 936 | return 0; | ||
| 937 | } | ||
| 938 | return -EINVAL; | ||
| 939 | } | ||
| 940 | */ | ||
| 941 | |||
| 942 | static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) | ||
| 943 | { | ||
| 944 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
| 945 | struct saa7146_vv *vv = dev->vv_data; | ||
| 946 | int found = 0; | ||
| 947 | int err, i; | ||
| 948 | |||
| 949 | DEB_EE(("VIDIOC_S_STD\n")); | ||
| 950 | |||
| 951 | if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { | ||
| 952 | DEB_D(("cannot change video standard while streaming capture is active\n")); | ||
| 953 | return -EBUSY; | ||
| 954 | } | ||
| 955 | |||
| 956 | if ((vv->video_status & STATUS_OVERLAY) != 0) { | ||
| 957 | vv->ov_suspend = vv->video_fh; | ||
| 958 | err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ | ||
| 959 | if (0 != err) { | ||
| 960 | DEB_D(("suspending video failed. aborting\n")); | ||
| 961 | return err; | ||
| 962 | } | ||
| 963 | } | ||
| 964 | |||
| 965 | for (i = 0; i < dev->ext_vv_data->num_stds; i++) | ||
| 966 | if (*id & dev->ext_vv_data->stds[i].id) | ||
| 967 | break; | ||
| 968 | if (i != dev->ext_vv_data->num_stds) { | ||
| 969 | vv->standard = &dev->ext_vv_data->stds[i]; | ||
| 970 | if (NULL != dev->ext_vv_data->std_callback) | ||
| 971 | dev->ext_vv_data->std_callback(dev, vv->standard); | ||
| 972 | found = 1; | ||
| 973 | } | ||
| 974 | |||
| 975 | if (vv->ov_suspend != NULL) { | ||
| 976 | saa7146_start_preview(vv->ov_suspend); | ||
| 977 | vv->ov_suspend = NULL; | ||
| 978 | } | ||
| 979 | |||
| 980 | if (!found) { | ||
| 981 | DEB_EE(("VIDIOC_S_STD: standard not found.\n")); | ||
| 982 | return -EINVAL; | ||
| 983 | } | ||
| 984 | |||
| 985 | DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name)); | ||
| 986 | return 0; | ||
| 987 | } | ||
| 988 | |||
| 989 | static int vidioc_overlay(struct file *file, void *fh, unsigned int on) | ||
| 990 | { | ||
| 991 | int err; | ||
| 992 | |||
| 993 | DEB_D(("VIDIOC_OVERLAY on:%d\n", on)); | ||
| 994 | if (on) | ||
| 995 | err = saa7146_start_preview(fh); | ||
| 996 | else | ||
| 997 | err = saa7146_stop_preview(fh); | ||
| 998 | return err; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b) | ||
| 1002 | { | ||
| 1003 | struct saa7146_fh *fh = __fh; | ||
| 1004 | |||
| 1005 | if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1006 | return videobuf_reqbufs(&fh->video_q, b); | ||
| 1007 | if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
| 1008 | return videobuf_reqbufs(&fh->vbi_q, b); | ||
| 1009 | return -EINVAL; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | ||
| 1013 | { | ||
| 1014 | struct saa7146_fh *fh = __fh; | ||
| 1015 | |||
| 1016 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1017 | return videobuf_querybuf(&fh->video_q, buf); | ||
| 1018 | if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
| 1019 | return videobuf_querybuf(&fh->vbi_q, buf); | ||
| 1020 | return -EINVAL; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | ||
| 1024 | { | ||
| 1025 | struct saa7146_fh *fh = __fh; | ||
| 1026 | |||
| 1027 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1028 | return videobuf_qbuf(&fh->video_q, buf); | ||
| 1029 | if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
| 1030 | return videobuf_qbuf(&fh->vbi_q, buf); | ||
| 1031 | return -EINVAL; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | ||
| 1035 | { | ||
| 1036 | struct saa7146_fh *fh = __fh; | ||
| 1037 | |||
| 1038 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1039 | return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK); | ||
| 1040 | if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
| 1041 | return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK); | ||
| 1042 | return -EINVAL; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) | ||
| 1046 | { | ||
| 1047 | struct saa7146_fh *fh = __fh; | ||
| 1048 | int err; | ||
| 1049 | |||
| 1050 | DEB_D(("VIDIOC_STREAMON, type:%d\n", type)); | ||
| 1051 | |||
| 1052 | err = video_begin(fh); | ||
| 1053 | if (err) | ||
| 1054 | return err; | ||
| 1055 | if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1056 | return videobuf_streamon(&fh->video_q); | ||
| 1057 | if (type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
| 1058 | return videobuf_streamon(&fh->vbi_q); | ||
| 1059 | return -EINVAL; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) | ||
| 1063 | { | ||
| 1064 | struct saa7146_fh *fh = __fh; | ||
| 1065 | struct saa7146_dev *dev = fh->dev; | ||
| 1066 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1067 | int err; | ||
| 1068 | |||
| 1069 | DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type)); | ||
| 1070 | |||
| 1071 | /* ugly: we need to copy some checks from video_end(), | ||
| 1072 | because videobuf_streamoff() relies on the capture running. | ||
| 1073 | check and fix this */ | ||
| 1074 | if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { | ||
| 1075 | DEB_S(("not capturing.\n")); | ||
| 1076 | return 0; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | if (vv->video_fh != fh) { | ||
| 1080 | DEB_S(("capturing, but in another open.\n")); | ||
| 1081 | return -EBUSY; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | err = -EINVAL; | ||
| 1085 | if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 1086 | err = videobuf_streamoff(&fh->video_q); | ||
| 1087 | else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
| 1088 | err = videobuf_streamoff(&fh->vbi_q); | ||
| 1089 | if (0 != err) { | ||
| 1090 | DEB_D(("warning: videobuf_streamoff() failed.\n")); | ||
| 1091 | video_end(fh, file); | ||
| 1092 | } else { | ||
| 1093 | err = video_end(fh, file); | ||
| 1094 | } | ||
| 1095 | return err; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | static int vidioc_g_chip_ident(struct file *file, void *__fh, | ||
| 1099 | struct v4l2_dbg_chip_ident *chip) | ||
| 1100 | { | ||
| 1101 | struct saa7146_fh *fh = __fh; | ||
| 1102 | struct saa7146_dev *dev = fh->dev; | ||
| 1103 | |||
| 1104 | chip->ident = V4L2_IDENT_NONE; | ||
| 1105 | chip->revision = 0; | ||
| 1106 | if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) { | ||
| 1107 | chip->ident = V4L2_IDENT_SAA7146; | ||
| 1108 | return 0; | ||
| 1109 | } | ||
| 1110 | return v4l2_device_call_until_err(&dev->v4l2_dev, 0, | ||
| 1111 | core, g_chip_ident, chip); | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { | ||
| 1115 | .vidioc_querycap = vidioc_querycap, | ||
| 1116 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
| 1117 | .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap, | ||
| 1118 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
| 1119 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
| 1120 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
| 1121 | .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, | ||
| 1122 | .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, | ||
| 1123 | .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, | ||
| 1124 | .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, | ||
| 1125 | .vidioc_g_chip_ident = vidioc_g_chip_ident, | ||
| 1126 | |||
| 1127 | .vidioc_overlay = vidioc_overlay, | ||
| 1128 | .vidioc_g_fbuf = vidioc_g_fbuf, | ||
| 1129 | .vidioc_s_fbuf = vidioc_s_fbuf, | ||
| 1130 | .vidioc_reqbufs = vidioc_reqbufs, | ||
| 1131 | .vidioc_querybuf = vidioc_querybuf, | ||
| 1132 | .vidioc_qbuf = vidioc_qbuf, | ||
| 1133 | .vidioc_dqbuf = vidioc_dqbuf, | ||
| 1134 | .vidioc_g_std = vidioc_g_std, | ||
| 1135 | .vidioc_s_std = vidioc_s_std, | ||
| 1136 | .vidioc_queryctrl = vidioc_queryctrl, | ||
| 1137 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
| 1138 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
| 1139 | .vidioc_streamon = vidioc_streamon, | ||
| 1140 | .vidioc_streamoff = vidioc_streamoff, | ||
| 1141 | .vidioc_g_parm = vidioc_g_parm, | ||
| 1142 | }; | ||
| 1143 | |||
| 1144 | /*********************************************************************************/ | ||
| 1145 | /* buffer handling functions */ | ||
| 1146 | |||
| 1147 | static int buffer_activate (struct saa7146_dev *dev, | ||
| 1148 | struct saa7146_buf *buf, | ||
| 1149 | struct saa7146_buf *next) | ||
| 1150 | { | ||
| 1151 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1152 | |||
| 1153 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
| 1154 | saa7146_set_capture(dev,buf,next); | ||
| 1155 | |||
| 1156 | mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); | ||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf) | ||
| 1161 | { | ||
| 1162 | saa7146_pgtable_free(dev->pci, &buf->pt[0]); | ||
| 1163 | saa7146_pgtable_free(dev->pci, &buf->pt[1]); | ||
| 1164 | saa7146_pgtable_free(dev->pci, &buf->pt[2]); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | static int buffer_prepare(struct videobuf_queue *q, | ||
| 1168 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
| 1169 | { | ||
| 1170 | struct file *file = q->priv_data; | ||
| 1171 | struct saa7146_fh *fh = file->private_data; | ||
| 1172 | struct saa7146_dev *dev = fh->dev; | ||
| 1173 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1174 | struct saa7146_buf *buf = (struct saa7146_buf *)vb; | ||
| 1175 | int size,err = 0; | ||
| 1176 | |||
| 1177 | DEB_CAP(("vbuf:%p\n",vb)); | ||
| 1178 | |||
| 1179 | /* sanity checks */ | ||
| 1180 | if (fh->video_fmt.width < 48 || | ||
| 1181 | fh->video_fmt.height < 32 || | ||
| 1182 | fh->video_fmt.width > vv->standard->h_max_out || | ||
| 1183 | fh->video_fmt.height > vv->standard->v_max_out) { | ||
| 1184 | DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height)); | ||
| 1185 | return -EINVAL; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | size = fh->video_fmt.sizeimage; | ||
| 1189 | if (0 != buf->vb.baddr && buf->vb.bsize < size) { | ||
| 1190 | DEB_D(("size mismatch.\n")); | ||
| 1191 | return -EINVAL; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", | ||
| 1195 | fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field])); | ||
| 1196 | if (buf->vb.width != fh->video_fmt.width || | ||
| 1197 | buf->vb.bytesperline != fh->video_fmt.bytesperline || | ||
| 1198 | buf->vb.height != fh->video_fmt.height || | ||
| 1199 | buf->vb.size != size || | ||
| 1200 | buf->vb.field != field || | ||
| 1201 | buf->vb.field != fh->video_fmt.field || | ||
| 1202 | buf->fmt != &fh->video_fmt) { | ||
| 1203 | saa7146_dma_free(dev,q,buf); | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
| 1207 | struct saa7146_format *sfmt; | ||
| 1208 | |||
| 1209 | buf->vb.bytesperline = fh->video_fmt.bytesperline; | ||
| 1210 | buf->vb.width = fh->video_fmt.width; | ||
| 1211 | buf->vb.height = fh->video_fmt.height; | ||
| 1212 | buf->vb.size = size; | ||
| 1213 | buf->vb.field = field; | ||
| 1214 | buf->fmt = &fh->video_fmt; | ||
| 1215 | buf->vb.field = fh->video_fmt.field; | ||
| 1216 | |||
| 1217 | sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | ||
| 1218 | |||
| 1219 | release_all_pagetables(dev, buf); | ||
| 1220 | if( 0 != IS_PLANAR(sfmt->trans)) { | ||
| 1221 | saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); | ||
| 1222 | saa7146_pgtable_alloc(dev->pci, &buf->pt[1]); | ||
| 1223 | saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); | ||
| 1224 | } else { | ||
| 1225 | saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | err = videobuf_iolock(q,&buf->vb, &vv->ov_fb); | ||
| 1229 | if (err) | ||
| 1230 | goto oops; | ||
| 1231 | err = saa7146_pgtable_build(dev,buf); | ||
| 1232 | if (err) | ||
| 1233 | goto oops; | ||
| 1234 | } | ||
| 1235 | buf->vb.state = VIDEOBUF_PREPARED; | ||
| 1236 | buf->activate = buffer_activate; | ||
| 1237 | |||
| 1238 | return 0; | ||
| 1239 | |||
| 1240 | oops: | ||
| 1241 | DEB_D(("error out.\n")); | ||
| 1242 | saa7146_dma_free(dev,q,buf); | ||
| 1243 | |||
| 1244 | return err; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
| 1248 | { | ||
| 1249 | struct file *file = q->priv_data; | ||
| 1250 | struct saa7146_fh *fh = file->private_data; | ||
| 1251 | |||
| 1252 | if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS) | ||
| 1253 | *count = MAX_SAA7146_CAPTURE_BUFFERS; | ||
| 1254 | |||
| 1255 | *size = fh->video_fmt.sizeimage; | ||
| 1256 | |||
| 1257 | /* check if we exceed the "max_memory" parameter */ | ||
| 1258 | if( (*count * *size) > (max_memory*1048576) ) { | ||
| 1259 | *count = (max_memory*1048576) / *size; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size)); | ||
| 1263 | |||
| 1264 | return 0; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
| 1268 | { | ||
| 1269 | struct file *file = q->priv_data; | ||
| 1270 | struct saa7146_fh *fh = file->private_data; | ||
| 1271 | struct saa7146_dev *dev = fh->dev; | ||
| 1272 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1273 | struct saa7146_buf *buf = (struct saa7146_buf *)vb; | ||
| 1274 | |||
| 1275 | DEB_CAP(("vbuf:%p\n",vb)); | ||
| 1276 | saa7146_buffer_queue(fh->dev,&vv->video_q,buf); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
| 1280 | { | ||
| 1281 | struct file *file = q->priv_data; | ||
| 1282 | struct saa7146_fh *fh = file->private_data; | ||
| 1283 | struct saa7146_dev *dev = fh->dev; | ||
| 1284 | struct saa7146_buf *buf = (struct saa7146_buf *)vb; | ||
| 1285 | |||
| 1286 | DEB_CAP(("vbuf:%p\n",vb)); | ||
| 1287 | |||
| 1288 | saa7146_dma_free(dev,q,buf); | ||
| 1289 | |||
| 1290 | release_all_pagetables(dev, buf); | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | static struct videobuf_queue_ops video_qops = { | ||
| 1294 | .buf_setup = buffer_setup, | ||
| 1295 | .buf_prepare = buffer_prepare, | ||
| 1296 | .buf_queue = buffer_queue, | ||
| 1297 | .buf_release = buffer_release, | ||
| 1298 | }; | ||
| 1299 | |||
| 1300 | /********************************************************************************/ | ||
| 1301 | /* file operations */ | ||
| 1302 | |||
| 1303 | static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) | ||
| 1304 | { | ||
| 1305 | INIT_LIST_HEAD(&vv->video_q.queue); | ||
| 1306 | |||
| 1307 | init_timer(&vv->video_q.timeout); | ||
| 1308 | vv->video_q.timeout.function = saa7146_buffer_timeout; | ||
| 1309 | vv->video_q.timeout.data = (unsigned long)(&vv->video_q); | ||
| 1310 | vv->video_q.dev = dev; | ||
| 1311 | |||
| 1312 | /* set some default values */ | ||
| 1313 | vv->standard = &dev->ext_vv_data->stds[0]; | ||
| 1314 | |||
| 1315 | /* FIXME: what's this? */ | ||
| 1316 | vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A; | ||
| 1317 | vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | |||
| 1321 | static int video_open(struct saa7146_dev *dev, struct file *file) | ||
| 1322 | { | ||
| 1323 | struct saa7146_fh *fh = file->private_data; | ||
| 1324 | struct saa7146_format *sfmt; | ||
| 1325 | |||
| 1326 | fh->video_fmt.width = 384; | ||
| 1327 | fh->video_fmt.height = 288; | ||
| 1328 | fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24; | ||
| 1329 | fh->video_fmt.bytesperline = 0; | ||
| 1330 | fh->video_fmt.field = V4L2_FIELD_ANY; | ||
| 1331 | sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); | ||
| 1332 | fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; | ||
| 1333 | |||
| 1334 | videobuf_queue_sg_init(&fh->video_q, &video_qops, | ||
| 1335 | &dev->pci->dev, &dev->slock, | ||
| 1336 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
| 1337 | V4L2_FIELD_INTERLACED, | ||
| 1338 | sizeof(struct saa7146_buf), | ||
| 1339 | file, &dev->v4l2_lock); | ||
| 1340 | |||
| 1341 | return 0; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | |||
| 1345 | static void video_close(struct saa7146_dev *dev, struct file *file) | ||
| 1346 | { | ||
| 1347 | struct saa7146_fh *fh = file->private_data; | ||
| 1348 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1349 | struct videobuf_queue *q = &fh->video_q; | ||
| 1350 | int err; | ||
| 1351 | |||
| 1352 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
| 1353 | err = video_end(fh, file); | ||
| 1354 | } else if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
| 1355 | err = saa7146_stop_preview(fh); | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | videobuf_stop(q); | ||
| 1359 | |||
| 1360 | /* hmm, why is this function declared void? */ | ||
| 1361 | /* return err */ | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | |||
| 1365 | static void video_irq_done(struct saa7146_dev *dev, unsigned long st) | ||
| 1366 | { | ||
| 1367 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1368 | struct saa7146_dmaqueue *q = &vv->video_q; | ||
| 1369 | |||
| 1370 | spin_lock(&dev->slock); | ||
| 1371 | DEB_CAP(("called.\n")); | ||
| 1372 | |||
| 1373 | /* only finish the buffer if we have one... */ | ||
| 1374 | if( NULL != q->curr ) { | ||
| 1375 | saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); | ||
| 1376 | } | ||
| 1377 | saa7146_buffer_next(dev,q,0); | ||
| 1378 | |||
| 1379 | spin_unlock(&dev->slock); | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
| 1383 | { | ||
| 1384 | struct saa7146_fh *fh = file->private_data; | ||
| 1385 | struct saa7146_dev *dev = fh->dev; | ||
| 1386 | struct saa7146_vv *vv = dev->vv_data; | ||
| 1387 | ssize_t ret = 0; | ||
| 1388 | |||
| 1389 | DEB_EE(("called.\n")); | ||
| 1390 | |||
| 1391 | if ((vv->video_status & STATUS_CAPTURE) != 0) { | ||
| 1392 | /* fixme: should we allow read() captures while streaming capture? */ | ||
| 1393 | if (vv->video_fh == fh) { | ||
| 1394 | DEB_S(("already capturing.\n")); | ||
| 1395 | return -EBUSY; | ||
| 1396 | } | ||
| 1397 | DEB_S(("already capturing in another open.\n")); | ||
| 1398 | return -EBUSY; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | ret = video_begin(fh); | ||
| 1402 | if( 0 != ret) { | ||
| 1403 | goto out; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | ret = videobuf_read_one(&fh->video_q , data, count, ppos, | ||
| 1407 | file->f_flags & O_NONBLOCK); | ||
| 1408 | if (ret != 0) { | ||
| 1409 | video_end(fh, file); | ||
| 1410 | } else { | ||
| 1411 | ret = video_end(fh, file); | ||
| 1412 | } | ||
| 1413 | out: | ||
| 1414 | /* restart overlay if it was active before */ | ||
| 1415 | if (vv->ov_suspend != NULL) { | ||
| 1416 | saa7146_start_preview(vv->ov_suspend); | ||
| 1417 | vv->ov_suspend = NULL; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | return ret; | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | struct saa7146_use_ops saa7146_video_uops = { | ||
| 1424 | .init = video_init, | ||
| 1425 | .open = video_open, | ||
| 1426 | .release = video_close, | ||
| 1427 | .irq_done = video_irq_done, | ||
| 1428 | .read = video_read, | ||
| 1429 | }; | ||
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig new file mode 100644 index 00000000000..996302ae210 --- /dev/null +++ b/drivers/media/common/tuners/Kconfig | |||
| @@ -0,0 +1,207 @@ | |||
| 1 | config MEDIA_ATTACH | ||
| 2 | bool "Load and attach frontend and tuner driver modules as needed" | ||
| 3 | depends on VIDEO_MEDIA | ||
| 4 | depends on MODULES | ||
| 5 | help | ||
| 6 | Remove the static dependency of DVB card drivers on all | ||
| 7 | frontend modules for all possible card variants. Instead, | ||
| 8 | allow the card drivers to only load the frontend modules | ||
| 9 | they require. | ||
| 10 | |||
| 11 | Also, tuner module will automatically load a tuner driver | ||
| 12 | when needed, for analog mode. | ||
| 13 | |||
| 14 | This saves several KBytes of memory. | ||
| 15 | |||
| 16 | Note: You will need module-init-tools v3.2 or later for this feature. | ||
| 17 | |||
| 18 | If unsure say Y. | ||
| 19 | |||
| 20 | config MEDIA_TUNER | ||
| 21 | tristate | ||
| 22 | default VIDEO_MEDIA && I2C | ||
| 23 | depends on VIDEO_MEDIA && I2C | ||
| 24 | select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE | ||
| 25 | select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE | ||
| 26 | select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE | ||
| 27 | select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE | ||
| 28 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE | ||
| 29 | select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE | ||
| 30 | select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE | ||
| 31 | select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE | ||
| 32 | select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE | ||
| 33 | select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE | ||
| 34 | |||
| 35 | config MEDIA_TUNER_CUSTOMISE | ||
| 36 | bool "Customize analog and hybrid tuner modules to build" | ||
| 37 | depends on MEDIA_TUNER | ||
| 38 | default y if EXPERT | ||
| 39 | help | ||
| 40 | This allows the user to deselect tuner drivers unnecessary | ||
| 41 | for their hardware from the build. Use this option with care | ||
| 42 | as deselecting tuner drivers which are in fact necessary will | ||
| 43 | result in V4L/DVB devices which cannot be tuned due to lack of | ||
| 44 | driver support | ||
| 45 | |||
| 46 | If unsure say N. | ||
| 47 | |||
| 48 | menu "Customize TV tuners" | ||
| 49 | visible if MEDIA_TUNER_CUSTOMISE | ||
| 50 | |||
| 51 | config MEDIA_TUNER_SIMPLE | ||
| 52 | tristate "Simple tuner support" | ||
| 53 | depends on VIDEO_MEDIA && I2C | ||
| 54 | select MEDIA_TUNER_TDA9887 | ||
| 55 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 56 | help | ||
| 57 | Say Y here to include support for various simple tuners. | ||
| 58 | |||
| 59 | config MEDIA_TUNER_TDA8290 | ||
| 60 | tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" | ||
| 61 | depends on VIDEO_MEDIA && I2C | ||
| 62 | select MEDIA_TUNER_TDA827X | ||
| 63 | select MEDIA_TUNER_TDA18271 | ||
| 64 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 65 | help | ||
| 66 | Say Y here to include support for Philips TDA8290+8275(a) tuner. | ||
| 67 | |||
| 68 | config MEDIA_TUNER_TDA827X | ||
| 69 | tristate "Philips TDA827X silicon tuner" | ||
| 70 | depends on VIDEO_MEDIA && I2C | ||
| 71 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 72 | help | ||
| 73 | A DVB-T silicon tuner module. Say Y when you want to support this tuner. | ||
| 74 | |||
| 75 | config MEDIA_TUNER_TDA18271 | ||
| 76 | tristate "NXP TDA18271 silicon tuner" | ||
| 77 | depends on VIDEO_MEDIA && I2C | ||
| 78 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 79 | help | ||
| 80 | A silicon tuner module. Say Y when you want to support this tuner. | ||
| 81 | |||
| 82 | config MEDIA_TUNER_TDA9887 | ||
| 83 | tristate "TDA 9885/6/7 analog IF demodulator" | ||
| 84 | depends on VIDEO_MEDIA && I2C | ||
| 85 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 86 | help | ||
| 87 | Say Y here to include support for Philips TDA9885/6/7 | ||
| 88 | analog IF demodulator. | ||
| 89 | |||
| 90 | config MEDIA_TUNER_TEA5761 | ||
| 91 | tristate "TEA 5761 radio tuner (EXPERIMENTAL)" | ||
| 92 | depends on VIDEO_MEDIA && I2C | ||
| 93 | depends on EXPERIMENTAL | ||
| 94 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 95 | help | ||
| 96 | Say Y here to include support for the Philips TEA5761 radio tuner. | ||
| 97 | |||
| 98 | config MEDIA_TUNER_TEA5767 | ||
| 99 | tristate "TEA 5767 radio tuner" | ||
| 100 | depends on VIDEO_MEDIA && I2C | ||
| 101 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 102 | help | ||
| 103 | Say Y here to include support for the Philips TEA5767 radio tuner. | ||
| 104 | |||
| 105 | config MEDIA_TUNER_MT20XX | ||
| 106 | tristate "Microtune 2032 / 2050 tuners" | ||
| 107 | depends on VIDEO_MEDIA && I2C | ||
| 108 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 109 | help | ||
| 110 | Say Y here to include support for the MT2032 / MT2050 tuner. | ||
| 111 | |||
| 112 | config MEDIA_TUNER_MT2060 | ||
| 113 | tristate "Microtune MT2060 silicon IF tuner" | ||
| 114 | depends on VIDEO_MEDIA && I2C | ||
| 115 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 116 | help | ||
| 117 | A driver for the silicon IF tuner MT2060 from Microtune. | ||
| 118 | |||
| 119 | config MEDIA_TUNER_MT2266 | ||
| 120 | tristate "Microtune MT2266 silicon tuner" | ||
| 121 | depends on VIDEO_MEDIA && I2C | ||
| 122 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 123 | help | ||
| 124 | A driver for the silicon baseband tuner MT2266 from Microtune. | ||
| 125 | |||
| 126 | config MEDIA_TUNER_MT2131 | ||
| 127 | tristate "Microtune MT2131 silicon tuner" | ||
| 128 | depends on VIDEO_MEDIA && I2C | ||
| 129 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 130 | help | ||
| 131 | A driver for the silicon baseband tuner MT2131 from Microtune. | ||
| 132 | |||
| 133 | config MEDIA_TUNER_QT1010 | ||
| 134 | tristate "Quantek QT1010 silicon tuner" | ||
| 135 | depends on VIDEO_MEDIA && I2C | ||
| 136 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 137 | help | ||
| 138 | A driver for the silicon tuner QT1010 from Quantek. | ||
| 139 | |||
| 140 | config MEDIA_TUNER_XC2028 | ||
| 141 | tristate "XCeive xc2028/xc3028 tuners" | ||
| 142 | depends on VIDEO_MEDIA && I2C | ||
| 143 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 144 | help | ||
| 145 | Say Y here to include support for the xc2028/xc3028 tuners. | ||
| 146 | |||
| 147 | config MEDIA_TUNER_XC5000 | ||
| 148 | tristate "Xceive XC5000 silicon tuner" | ||
| 149 | depends on VIDEO_MEDIA && I2C | ||
| 150 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 151 | help | ||
| 152 | A driver for the silicon tuner XC5000 from Xceive. | ||
| 153 | This device is only used inside a SiP called together with a | ||
| 154 | demodulator for now. | ||
| 155 | |||
| 156 | config MEDIA_TUNER_XC4000 | ||
| 157 | tristate "Xceive XC4000 silicon tuner" | ||
| 158 | depends on VIDEO_MEDIA && I2C | ||
| 159 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 160 | help | ||
| 161 | A driver for the silicon tuner XC4000 from Xceive. | ||
| 162 | This device is only used inside a SiP called together with a | ||
| 163 | demodulator for now. | ||
| 164 | |||
| 165 | config MEDIA_TUNER_MXL5005S | ||
| 166 | tristate "MaxLinear MSL5005S silicon tuner" | ||
| 167 | depends on VIDEO_MEDIA && I2C | ||
| 168 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 169 | help | ||
| 170 | A driver for the silicon tuner MXL5005S from MaxLinear. | ||
| 171 | |||
| 172 | config MEDIA_TUNER_MXL5007T | ||
| 173 | tristate "MaxLinear MxL5007T silicon tuner" | ||
| 174 | depends on VIDEO_MEDIA && I2C | ||
| 175 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 176 | help | ||
| 177 | A driver for the silicon tuner MxL5007T from MaxLinear. | ||
| 178 | |||
| 179 | config MEDIA_TUNER_MC44S803 | ||
| 180 | tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" | ||
| 181 | depends on VIDEO_MEDIA && I2C | ||
| 182 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 183 | help | ||
| 184 | Say Y here to support the Freescale MC44S803 based tuners | ||
| 185 | |||
| 186 | config MEDIA_TUNER_MAX2165 | ||
| 187 | tristate "Maxim MAX2165 silicon tuner" | ||
| 188 | depends on VIDEO_MEDIA && I2C | ||
| 189 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 190 | help | ||
| 191 | A driver for the silicon tuner MAX2165 from Maxim. | ||
| 192 | |||
| 193 | config MEDIA_TUNER_TDA18218 | ||
| 194 | tristate "NXP TDA18218 silicon tuner" | ||
| 195 | depends on VIDEO_MEDIA && I2C | ||
| 196 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 197 | help | ||
| 198 | NXP TDA18218 silicon tuner driver. | ||
| 199 | |||
| 200 | config MEDIA_TUNER_TDA18212 | ||
| 201 | tristate "NXP TDA18212 silicon tuner" | ||
| 202 | depends on VIDEO_MEDIA && I2C | ||
| 203 | default m if MEDIA_TUNER_CUSTOMISE | ||
| 204 | help | ||
| 205 | NXP TDA18212 silicon tuner driver. | ||
| 206 | |||
| 207 | endmenu | ||
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile new file mode 100644 index 00000000000..20d24fca2cf --- /dev/null +++ b/drivers/media/common/tuners/Makefile | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | # | ||
| 2 | # Makefile for common V4L/DVB tuners | ||
| 3 | # | ||
| 4 | |||
| 5 | tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o | ||
| 6 | |||
| 7 | obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o | ||
| 8 | obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o | ||
| 9 | # tuner-types will be merged into tuner-simple, in the future | ||
| 10 | obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o | ||
| 11 | obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o | ||
| 12 | obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o | ||
| 13 | obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o | ||
| 14 | obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o | ||
| 15 | obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o | ||
| 16 | obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o | ||
| 17 | obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o | ||
| 18 | obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o | ||
| 19 | obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o | ||
| 20 | obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o | ||
| 21 | obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o | ||
| 22 | obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o | ||
| 23 | obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o | ||
| 24 | obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o | ||
| 25 | obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o | ||
| 26 | obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o | ||
| 27 | obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o | ||
| 28 | obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o | ||
| 29 | obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o | ||
| 30 | |||
| 31 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | ||
| 32 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | ||
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c new file mode 100644 index 00000000000..9883617b786 --- /dev/null +++ b/drivers/media/common/tuners/max2165.c | |||
| @@ -0,0 +1,441 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Maxim MAX2165 silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.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/module.h> | ||
| 23 | #include <linux/moduleparam.h> | ||
| 24 | #include <linux/videodev2.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/dvb/frontend.h> | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | |||
| 30 | #include "dvb_frontend.h" | ||
| 31 | |||
| 32 | #include "max2165.h" | ||
| 33 | #include "max2165_priv.h" | ||
| 34 | #include "tuner-i2c.h" | ||
| 35 | |||
| 36 | #define dprintk(args...) \ | ||
| 37 | do { \ | ||
| 38 | if (debug) \ | ||
| 39 | printk(KERN_DEBUG "max2165: " args); \ | ||
| 40 | } while (0) | ||
| 41 | |||
| 42 | static int debug; | ||
| 43 | module_param(debug, int, 0644); | ||
| 44 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 45 | |||
| 46 | static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data) | ||
| 47 | { | ||
| 48 | int ret; | ||
| 49 | u8 buf[] = { reg, data }; | ||
| 50 | struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; | ||
| 51 | |||
| 52 | msg.addr = priv->config->i2c_address; | ||
| 53 | |||
| 54 | if (debug >= 2) | ||
| 55 | dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); | ||
| 56 | |||
| 57 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
| 58 | |||
| 59 | if (ret != 1) | ||
| 60 | dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", | ||
| 61 | __func__, reg, data, ret); | ||
| 62 | |||
| 63 | return (ret != 1) ? -EIO : 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data) | ||
| 67 | { | ||
| 68 | int ret; | ||
| 69 | u8 dev_addr = priv->config->i2c_address; | ||
| 70 | |||
| 71 | u8 b0[] = { reg }; | ||
| 72 | u8 b1[] = { 0 }; | ||
| 73 | struct i2c_msg msg[] = { | ||
| 74 | { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 }, | ||
| 75 | { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }, | ||
| 76 | }; | ||
| 77 | |||
| 78 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
| 79 | if (ret != 2) { | ||
| 80 | dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); | ||
| 81 | return -EIO; | ||
| 82 | } | ||
| 83 | |||
| 84 | *p_data = b1[0]; | ||
| 85 | if (debug >= 2) | ||
| 86 | dprintk("%s: reg=0x%02X, data=0x%02X\n", | ||
| 87 | __func__, reg, b1[0]); | ||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg, | ||
| 92 | u8 mask, u8 data) | ||
| 93 | { | ||
| 94 | int ret; | ||
| 95 | u8 v; | ||
| 96 | |||
| 97 | data &= mask; | ||
| 98 | ret = max2165_read_reg(priv, reg, &v); | ||
| 99 | if (ret != 0) | ||
| 100 | return ret; | ||
| 101 | v &= ~mask; | ||
| 102 | v |= data; | ||
| 103 | ret = max2165_write_reg(priv, reg, v); | ||
| 104 | |||
| 105 | return ret; | ||
| 106 | } | ||
| 107 | |||
| 108 | static int max2165_read_rom_table(struct max2165_priv *priv) | ||
| 109 | { | ||
| 110 | u8 dat[3]; | ||
| 111 | int i; | ||
| 112 | |||
| 113 | for (i = 0; i < 3; i++) { | ||
| 114 | max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1); | ||
| 115 | max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]); | ||
| 116 | } | ||
| 117 | |||
| 118 | priv->tf_ntch_low_cfg = dat[0] >> 4; | ||
| 119 | priv->tf_ntch_hi_cfg = dat[0] & 0x0F; | ||
| 120 | priv->tf_balun_low_ref = dat[1] & 0x0F; | ||
| 121 | priv->tf_balun_hi_ref = dat[1] >> 4; | ||
| 122 | priv->bb_filter_7mhz_cfg = dat[2] & 0x0F; | ||
| 123 | priv->bb_filter_8mhz_cfg = dat[2] >> 4; | ||
| 124 | |||
| 125 | dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg); | ||
| 126 | dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg); | ||
| 127 | dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref); | ||
| 128 | dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref); | ||
| 129 | dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg); | ||
| 130 | dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg); | ||
| 131 | |||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/) | ||
| 136 | { | ||
| 137 | u8 v; | ||
| 138 | |||
| 139 | v = (osc / 2); | ||
| 140 | if (v == 2) | ||
| 141 | v = 0x7; | ||
| 142 | else | ||
| 143 | v -= 8; | ||
| 144 | |||
| 145 | max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v); | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) | ||
| 151 | { | ||
| 152 | u8 val; | ||
| 153 | |||
| 154 | if (bw == BANDWIDTH_8_MHZ) | ||
| 155 | val = priv->bb_filter_8mhz_cfg; | ||
| 156 | else | ||
| 157 | val = priv->bb_filter_7mhz_cfg; | ||
| 158 | |||
| 159 | max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4); | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) | ||
| 165 | { | ||
| 166 | u32 remainder; | ||
| 167 | u32 q, f = 0; | ||
| 168 | int i; | ||
| 169 | |||
| 170 | if (0 == divisor) | ||
| 171 | return -1; | ||
| 172 | |||
| 173 | q = dividend / divisor; | ||
| 174 | remainder = dividend - q * divisor; | ||
| 175 | |||
| 176 | for (i = 0; i < 31; i++) { | ||
| 177 | remainder <<= 1; | ||
| 178 | if (remainder >= divisor) { | ||
| 179 | f += 1; | ||
| 180 | remainder -= divisor; | ||
| 181 | } | ||
| 182 | f <<= 1; | ||
| 183 | } | ||
| 184 | |||
| 185 | *quotient = q; | ||
| 186 | *fraction = f; | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int max2165_set_rf(struct max2165_priv *priv, u32 freq) | ||
| 192 | { | ||
| 193 | u8 tf; | ||
| 194 | u8 tf_ntch; | ||
| 195 | u32 t; | ||
| 196 | u32 quotient, fraction; | ||
| 197 | |||
| 198 | /* Set PLL divider according to RF frequency */ | ||
| 199 | fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, | ||
| 200 | "ient, &fraction); | ||
| 201 | |||
| 202 | /* 20-bit fraction */ | ||
| 203 | fraction >>= 12; | ||
| 204 | |||
| 205 | max2165_write_reg(priv, REG_NDIV_INT, quotient); | ||
| 206 | max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16); | ||
| 207 | max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8); | ||
| 208 | max2165_write_reg(priv, REG_NDIV_FRAC0, fraction); | ||
| 209 | |||
| 210 | /* Norch Filter */ | ||
| 211 | tf_ntch = (freq < 725000000) ? | ||
| 212 | priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg; | ||
| 213 | |||
| 214 | /* Tracking filter balun */ | ||
| 215 | t = priv->tf_balun_low_ref; | ||
| 216 | t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref) | ||
| 217 | * (freq / 1000 - 470000) / (780000 - 470000); | ||
| 218 | |||
| 219 | tf = t; | ||
| 220 | dprintk("tf = %X\n", tf); | ||
| 221 | tf |= tf_ntch << 4; | ||
| 222 | |||
| 223 | max2165_write_reg(priv, REG_TRACK_FILTER, tf); | ||
| 224 | |||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | static void max2165_debug_status(struct max2165_priv *priv) | ||
| 229 | { | ||
| 230 | u8 status, autotune; | ||
| 231 | u8 auto_vco_success, auto_vco_active; | ||
| 232 | u8 pll_locked; | ||
| 233 | u8 dc_offset_low, dc_offset_hi; | ||
| 234 | u8 signal_lv_over_threshold; | ||
| 235 | u8 vco, vco_sub_band, adc; | ||
| 236 | |||
| 237 | max2165_read_reg(priv, REG_STATUS, &status); | ||
| 238 | max2165_read_reg(priv, REG_AUTOTUNE, &autotune); | ||
| 239 | |||
| 240 | auto_vco_success = (status >> 6) & 0x01; | ||
| 241 | auto_vco_active = (status >> 5) & 0x01; | ||
| 242 | pll_locked = (status >> 4) & 0x01; | ||
| 243 | dc_offset_low = (status >> 3) & 0x01; | ||
| 244 | dc_offset_hi = (status >> 2) & 0x01; | ||
| 245 | signal_lv_over_threshold = status & 0x01; | ||
| 246 | |||
| 247 | vco = autotune >> 6; | ||
| 248 | vco_sub_band = (autotune >> 3) & 0x7; | ||
| 249 | adc = autotune & 0x7; | ||
| 250 | |||
| 251 | dprintk("auto VCO active: %d, auto VCO success: %d\n", | ||
| 252 | auto_vco_active, auto_vco_success); | ||
| 253 | dprintk("PLL locked: %d\n", pll_locked); | ||
| 254 | dprintk("DC offset low: %d, DC offset high: %d\n", | ||
| 255 | dc_offset_low, dc_offset_hi); | ||
| 256 | dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold); | ||
| 257 | dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); | ||
| 258 | } | ||
| 259 | |||
| 260 | static int max2165_set_params(struct dvb_frontend *fe, | ||
| 261 | struct dvb_frontend_parameters *params) | ||
| 262 | { | ||
| 263 | struct max2165_priv *priv = fe->tuner_priv; | ||
| 264 | int ret; | ||
| 265 | |||
| 266 | dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency); | ||
| 267 | if (fe->ops.info.type == FE_ATSC) { | ||
| 268 | return -EINVAL; | ||
| 269 | } else if (fe->ops.info.type == FE_OFDM) { | ||
| 270 | dprintk("%s() OFDM\n", __func__); | ||
| 271 | switch (params->u.ofdm.bandwidth) { | ||
| 272 | case BANDWIDTH_6_MHZ: | ||
| 273 | return -EINVAL; | ||
| 274 | case BANDWIDTH_7_MHZ: | ||
| 275 | case BANDWIDTH_8_MHZ: | ||
| 276 | priv->frequency = params->frequency; | ||
| 277 | priv->bandwidth = params->u.ofdm.bandwidth; | ||
| 278 | break; | ||
| 279 | default: | ||
| 280 | printk(KERN_ERR "MAX2165 bandwidth not set!\n"); | ||
| 281 | return -EINVAL; | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | printk(KERN_ERR "MAX2165 modulation type not supported!\n"); | ||
| 285 | return -EINVAL; | ||
| 286 | } | ||
| 287 | |||
| 288 | dprintk("%s() frequency=%d\n", __func__, priv->frequency); | ||
| 289 | |||
| 290 | if (fe->ops.i2c_gate_ctrl) | ||
| 291 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 292 | max2165_set_bandwidth(priv, priv->bandwidth); | ||
| 293 | ret = max2165_set_rf(priv, priv->frequency); | ||
| 294 | mdelay(50); | ||
| 295 | max2165_debug_status(priv); | ||
| 296 | if (fe->ops.i2c_gate_ctrl) | ||
| 297 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 298 | |||
| 299 | if (ret != 0) | ||
| 300 | return -EREMOTEIO; | ||
| 301 | |||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq) | ||
| 306 | { | ||
| 307 | struct max2165_priv *priv = fe->tuner_priv; | ||
| 308 | dprintk("%s()\n", __func__); | ||
| 309 | *freq = priv->frequency; | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
| 314 | { | ||
| 315 | struct max2165_priv *priv = fe->tuner_priv; | ||
| 316 | dprintk("%s()\n", __func__); | ||
| 317 | |||
| 318 | *bw = priv->bandwidth; | ||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | |||
| 322 | static int max2165_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 323 | { | ||
| 324 | struct max2165_priv *priv = fe->tuner_priv; | ||
| 325 | u16 lock_status = 0; | ||
| 326 | |||
| 327 | dprintk("%s()\n", __func__); | ||
| 328 | |||
| 329 | if (fe->ops.i2c_gate_ctrl) | ||
| 330 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 331 | |||
| 332 | max2165_debug_status(priv); | ||
| 333 | *status = lock_status; | ||
| 334 | |||
| 335 | if (fe->ops.i2c_gate_ctrl) | ||
| 336 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 337 | |||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | static int max2165_sleep(struct dvb_frontend *fe) | ||
| 342 | { | ||
| 343 | dprintk("%s()\n", __func__); | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | static int max2165_init(struct dvb_frontend *fe) | ||
| 348 | { | ||
| 349 | struct max2165_priv *priv = fe->tuner_priv; | ||
| 350 | dprintk("%s()\n", __func__); | ||
| 351 | |||
| 352 | if (fe->ops.i2c_gate_ctrl) | ||
| 353 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 354 | |||
| 355 | /* Setup initial values */ | ||
| 356 | /* Fractional Mode on */ | ||
| 357 | max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18); | ||
| 358 | /* LNA on */ | ||
| 359 | max2165_write_reg(priv, REG_LNA, 0x01); | ||
| 360 | max2165_write_reg(priv, REG_PLL_CFG, 0x7A); | ||
| 361 | max2165_write_reg(priv, REG_TEST, 0x08); | ||
| 362 | max2165_write_reg(priv, REG_SHUTDOWN, 0x40); | ||
| 363 | max2165_write_reg(priv, REG_VCO_CTRL, 0x84); | ||
| 364 | max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3); | ||
| 365 | max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75); | ||
| 366 | max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00); | ||
| 367 | max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00); | ||
| 368 | |||
| 369 | max2165_set_osc(priv, priv->config->osc_clk); | ||
| 370 | |||
| 371 | max2165_read_rom_table(priv); | ||
| 372 | |||
| 373 | max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ); | ||
| 374 | |||
| 375 | if (fe->ops.i2c_gate_ctrl) | ||
| 376 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 377 | |||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | static int max2165_release(struct dvb_frontend *fe) | ||
| 382 | { | ||
| 383 | struct max2165_priv *priv = fe->tuner_priv; | ||
| 384 | dprintk("%s()\n", __func__); | ||
| 385 | |||
| 386 | kfree(priv); | ||
| 387 | fe->tuner_priv = NULL; | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static const struct dvb_tuner_ops max2165_tuner_ops = { | ||
| 393 | .info = { | ||
| 394 | .name = "Maxim MAX2165", | ||
| 395 | .frequency_min = 470000000, | ||
| 396 | .frequency_max = 780000000, | ||
| 397 | .frequency_step = 50000, | ||
| 398 | }, | ||
| 399 | |||
| 400 | .release = max2165_release, | ||
| 401 | .init = max2165_init, | ||
| 402 | .sleep = max2165_sleep, | ||
| 403 | |||
| 404 | .set_params = max2165_set_params, | ||
| 405 | .set_analog_params = NULL, | ||
| 406 | .get_frequency = max2165_get_frequency, | ||
| 407 | .get_bandwidth = max2165_get_bandwidth, | ||
| 408 | .get_status = max2165_get_status | ||
| 409 | }; | ||
| 410 | |||
| 411 | struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, | ||
| 412 | struct i2c_adapter *i2c, | ||
| 413 | struct max2165_config *cfg) | ||
| 414 | { | ||
| 415 | struct max2165_priv *priv = NULL; | ||
| 416 | |||
| 417 | dprintk("%s(%d-%04x)\n", __func__, | ||
| 418 | i2c ? i2c_adapter_id(i2c) : -1, | ||
| 419 | cfg ? cfg->i2c_address : -1); | ||
| 420 | |||
| 421 | priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL); | ||
| 422 | if (priv == NULL) | ||
| 423 | return NULL; | ||
| 424 | |||
| 425 | memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops, | ||
| 426 | sizeof(struct dvb_tuner_ops)); | ||
| 427 | |||
| 428 | priv->config = cfg; | ||
| 429 | priv->i2c = i2c; | ||
| 430 | fe->tuner_priv = priv; | ||
| 431 | |||
| 432 | max2165_init(fe); | ||
| 433 | max2165_debug_status(priv); | ||
| 434 | |||
| 435 | return fe; | ||
| 436 | } | ||
| 437 | EXPORT_SYMBOL(max2165_attach); | ||
| 438 | |||
| 439 | MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); | ||
| 440 | MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); | ||
| 441 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/max2165.h b/drivers/media/common/tuners/max2165.h new file mode 100644 index 00000000000..c063c36a93d --- /dev/null +++ b/drivers/media/common/tuners/max2165.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Maxim MAX2165 silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.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 | #ifndef __MAX2165_H__ | ||
| 23 | #define __MAX2165_H__ | ||
| 24 | |||
| 25 | struct dvb_frontend; | ||
| 26 | struct i2c_adapter; | ||
| 27 | |||
| 28 | struct max2165_config { | ||
| 29 | u8 i2c_address; | ||
| 30 | u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ | ||
| 31 | }; | ||
| 32 | |||
| 33 | #if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ | ||
| 34 | (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) | ||
| 35 | extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, | ||
| 36 | struct i2c_adapter *i2c, | ||
| 37 | struct max2165_config *cfg); | ||
| 38 | #else | ||
| 39 | static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, | ||
| 40 | struct i2c_adapter *i2c, | ||
| 41 | struct max2165_config *cfg) | ||
| 42 | { | ||
| 43 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #endif | ||
diff --git a/drivers/media/common/tuners/max2165_priv.h b/drivers/media/common/tuners/max2165_priv.h new file mode 100644 index 00000000000..91bbe021a08 --- /dev/null +++ b/drivers/media/common/tuners/max2165_priv.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Maxim MAX2165 silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.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 | #ifndef __MAX2165_PRIV_H__ | ||
| 23 | #define __MAX2165_PRIV_H__ | ||
| 24 | |||
| 25 | #define REG_NDIV_INT 0x00 | ||
| 26 | #define REG_NDIV_FRAC2 0x01 | ||
| 27 | #define REG_NDIV_FRAC1 0x02 | ||
| 28 | #define REG_NDIV_FRAC0 0x03 | ||
| 29 | #define REG_TRACK_FILTER 0x04 | ||
| 30 | #define REG_LNA 0x05 | ||
| 31 | #define REG_PLL_CFG 0x06 | ||
| 32 | #define REG_TEST 0x07 | ||
| 33 | #define REG_SHUTDOWN 0x08 | ||
| 34 | #define REG_VCO_CTRL 0x09 | ||
| 35 | #define REG_BASEBAND_CTRL 0x0A | ||
| 36 | #define REG_DC_OFFSET_CTRL 0x0B | ||
| 37 | #define REG_DC_OFFSET_DAC 0x0C | ||
| 38 | #define REG_ROM_TABLE_ADDR 0x0D | ||
| 39 | |||
| 40 | /* Read Only Registers */ | ||
| 41 | #define REG_ROM_TABLE_DATA 0x10 | ||
| 42 | #define REG_STATUS 0x11 | ||
| 43 | #define REG_AUTOTUNE 0x12 | ||
| 44 | |||
| 45 | struct max2165_priv { | ||
| 46 | struct max2165_config *config; | ||
| 47 | struct i2c_adapter *i2c; | ||
| 48 | |||
| 49 | u32 frequency; | ||
| 50 | u32 bandwidth; | ||
| 51 | |||
| 52 | u8 tf_ntch_low_cfg; | ||
| 53 | u8 tf_ntch_hi_cfg; | ||
| 54 | u8 tf_balun_low_ref; | ||
| 55 | u8 tf_balun_hi_ref; | ||
| 56 | u8 bb_filter_7mhz_cfg; | ||
| 57 | u8 bb_filter_8mhz_cfg; | ||
| 58 | }; | ||
| 59 | |||
| 60 | #endif | ||
diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c new file mode 100644 index 00000000000..fe5c4b8d83e --- /dev/null +++ b/drivers/media/common/tuners/mc44s803.c | |||
| @@ -0,0 +1,372 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> | ||
| 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/module.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/dvb/frontend.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | |||
| 28 | #include "dvb_frontend.h" | ||
| 29 | |||
| 30 | #include "mc44s803.h" | ||
| 31 | #include "mc44s803_priv.h" | ||
| 32 | |||
| 33 | #define mc_printk(level, format, arg...) \ | ||
| 34 | printk(level "mc44s803: " format , ## arg) | ||
| 35 | |||
| 36 | /* Writes a single register */ | ||
| 37 | static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) | ||
| 38 | { | ||
| 39 | u8 buf[3]; | ||
| 40 | struct i2c_msg msg = { | ||
| 41 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 | ||
| 42 | }; | ||
| 43 | |||
| 44 | buf[0] = (val & 0xff0000) >> 16; | ||
| 45 | buf[1] = (val & 0xff00) >> 8; | ||
| 46 | buf[2] = (val & 0xff); | ||
| 47 | |||
| 48 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 49 | mc_printk(KERN_WARNING, "I2C write failed\n"); | ||
| 50 | return -EREMOTEIO; | ||
| 51 | } | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* Reads a single register */ | ||
| 56 | static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) | ||
| 57 | { | ||
| 58 | u32 wval; | ||
| 59 | u8 buf[3]; | ||
| 60 | int ret; | ||
| 61 | struct i2c_msg msg[] = { | ||
| 62 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, | ||
| 63 | .buf = buf, .len = 3 }, | ||
| 64 | }; | ||
| 65 | |||
| 66 | wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | | ||
| 67 | MC44S803_REG_SM(reg, MC44S803_D); | ||
| 68 | |||
| 69 | ret = mc44s803_writereg(priv, wval); | ||
| 70 | if (ret) | ||
| 71 | return ret; | ||
| 72 | |||
| 73 | if (i2c_transfer(priv->i2c, msg, 1) != 1) { | ||
| 74 | mc_printk(KERN_WARNING, "I2C read failed\n"); | ||
| 75 | return -EREMOTEIO; | ||
| 76 | } | ||
| 77 | |||
| 78 | *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int mc44s803_release(struct dvb_frontend *fe) | ||
| 84 | { | ||
| 85 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
| 86 | |||
| 87 | fe->tuner_priv = NULL; | ||
| 88 | kfree(priv); | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int mc44s803_init(struct dvb_frontend *fe) | ||
| 94 | { | ||
| 95 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
| 96 | u32 val; | ||
| 97 | int err; | ||
| 98 | |||
| 99 | if (fe->ops.i2c_gate_ctrl) | ||
| 100 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 101 | |||
| 102 | /* Reset chip */ | ||
| 103 | val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | | ||
| 104 | MC44S803_REG_SM(1, MC44S803_RS); | ||
| 105 | |||
| 106 | err = mc44s803_writereg(priv, val); | ||
| 107 | if (err) | ||
| 108 | goto exit; | ||
| 109 | |||
| 110 | val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); | ||
| 111 | |||
| 112 | err = mc44s803_writereg(priv, val); | ||
| 113 | if (err) | ||
| 114 | goto exit; | ||
| 115 | |||
| 116 | /* Power Up and Start Osc */ | ||
| 117 | |||
| 118 | val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | | ||
| 119 | MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | | ||
| 120 | MC44S803_REG_SM(1, MC44S803_OSCSEL); | ||
| 121 | |||
| 122 | err = mc44s803_writereg(priv, val); | ||
| 123 | if (err) | ||
| 124 | goto exit; | ||
| 125 | |||
| 126 | val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | | ||
| 127 | MC44S803_REG_SM(0x200, MC44S803_POWER); | ||
| 128 | |||
| 129 | err = mc44s803_writereg(priv, val); | ||
| 130 | if (err) | ||
| 131 | goto exit; | ||
| 132 | |||
| 133 | msleep(10); | ||
| 134 | |||
| 135 | val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | | ||
| 136 | MC44S803_REG_SM(0x40, MC44S803_REFOSC) | | ||
| 137 | MC44S803_REG_SM(1, MC44S803_OSCSEL); | ||
| 138 | |||
| 139 | err = mc44s803_writereg(priv, val); | ||
| 140 | if (err) | ||
| 141 | goto exit; | ||
| 142 | |||
| 143 | msleep(20); | ||
| 144 | |||
| 145 | /* Setup Mixer */ | ||
| 146 | |||
| 147 | val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | | ||
| 148 | MC44S803_REG_SM(1, MC44S803_TRI_STATE) | | ||
| 149 | MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); | ||
| 150 | |||
| 151 | err = mc44s803_writereg(priv, val); | ||
| 152 | if (err) | ||
| 153 | goto exit; | ||
| 154 | |||
| 155 | /* Setup Cirquit Adjust */ | ||
| 156 | |||
| 157 | val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | | ||
| 158 | MC44S803_REG_SM(1, MC44S803_G1) | | ||
| 159 | MC44S803_REG_SM(1, MC44S803_G3) | | ||
| 160 | MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | | ||
| 161 | MC44S803_REG_SM(1, MC44S803_G6) | | ||
| 162 | MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | | ||
| 163 | MC44S803_REG_SM(0x3, MC44S803_LP) | | ||
| 164 | MC44S803_REG_SM(1, MC44S803_CLRF) | | ||
| 165 | MC44S803_REG_SM(1, MC44S803_CLIF); | ||
| 166 | |||
| 167 | err = mc44s803_writereg(priv, val); | ||
| 168 | if (err) | ||
| 169 | goto exit; | ||
| 170 | |||
| 171 | val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | | ||
| 172 | MC44S803_REG_SM(1, MC44S803_G1) | | ||
| 173 | MC44S803_REG_SM(1, MC44S803_G3) | | ||
| 174 | MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | | ||
| 175 | MC44S803_REG_SM(1, MC44S803_G6) | | ||
| 176 | MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | | ||
| 177 | MC44S803_REG_SM(0x3, MC44S803_LP); | ||
| 178 | |||
| 179 | err = mc44s803_writereg(priv, val); | ||
| 180 | if (err) | ||
| 181 | goto exit; | ||
| 182 | |||
| 183 | /* Setup Digtune */ | ||
| 184 | |||
| 185 | val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | | ||
| 186 | MC44S803_REG_SM(3, MC44S803_XOD); | ||
| 187 | |||
| 188 | err = mc44s803_writereg(priv, val); | ||
| 189 | if (err) | ||
| 190 | goto exit; | ||
| 191 | |||
| 192 | /* Setup AGC */ | ||
| 193 | |||
| 194 | val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | | ||
| 195 | MC44S803_REG_SM(1, MC44S803_AT1) | | ||
| 196 | MC44S803_REG_SM(1, MC44S803_AT2) | | ||
| 197 | MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | | ||
| 198 | MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | | ||
| 199 | MC44S803_REG_SM(1, MC44S803_LNA0); | ||
| 200 | |||
| 201 | err = mc44s803_writereg(priv, val); | ||
| 202 | if (err) | ||
| 203 | goto exit; | ||
| 204 | |||
| 205 | if (fe->ops.i2c_gate_ctrl) | ||
| 206 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 207 | return 0; | ||
| 208 | |||
| 209 | exit: | ||
| 210 | if (fe->ops.i2c_gate_ctrl) | ||
| 211 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 212 | |||
| 213 | mc_printk(KERN_WARNING, "I/O Error\n"); | ||
| 214 | return err; | ||
| 215 | } | ||
| 216 | |||
| 217 | static int mc44s803_set_params(struct dvb_frontend *fe, | ||
| 218 | struct dvb_frontend_parameters *params) | ||
| 219 | { | ||
| 220 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
| 221 | u32 r1, r2, n1, n2, lo1, lo2, freq, val; | ||
| 222 | int err; | ||
| 223 | |||
| 224 | priv->frequency = params->frequency; | ||
| 225 | |||
| 226 | r1 = MC44S803_OSC / 1000000; | ||
| 227 | r2 = MC44S803_OSC / 100000; | ||
| 228 | |||
| 229 | n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000; | ||
| 230 | freq = MC44S803_OSC / r1 * n1; | ||
| 231 | lo1 = ((60 * n1) + (r1 / 2)) / r1; | ||
| 232 | freq = freq - params->frequency; | ||
| 233 | |||
| 234 | n2 = (freq - MC44S803_IF2 + 50000) / 100000; | ||
| 235 | lo2 = ((60 * n2) + (r2 / 2)) / r2; | ||
| 236 | |||
| 237 | if (fe->ops.i2c_gate_ctrl) | ||
| 238 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 239 | |||
| 240 | val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | | ||
| 241 | MC44S803_REG_SM(r1-1, MC44S803_R1) | | ||
| 242 | MC44S803_REG_SM(r2-1, MC44S803_R2) | | ||
| 243 | MC44S803_REG_SM(1, MC44S803_REFBUF_EN); | ||
| 244 | |||
| 245 | err = mc44s803_writereg(priv, val); | ||
| 246 | if (err) | ||
| 247 | goto exit; | ||
| 248 | |||
| 249 | val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | | ||
| 250 | MC44S803_REG_SM(n1-2, MC44S803_LO1); | ||
| 251 | |||
| 252 | err = mc44s803_writereg(priv, val); | ||
| 253 | if (err) | ||
| 254 | goto exit; | ||
| 255 | |||
| 256 | val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | | ||
| 257 | MC44S803_REG_SM(n2-2, MC44S803_LO2); | ||
| 258 | |||
| 259 | err = mc44s803_writereg(priv, val); | ||
| 260 | if (err) | ||
| 261 | goto exit; | ||
| 262 | |||
| 263 | val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | | ||
| 264 | MC44S803_REG_SM(1, MC44S803_DA) | | ||
| 265 | MC44S803_REG_SM(lo1, MC44S803_LO_REF) | | ||
| 266 | MC44S803_REG_SM(1, MC44S803_AT); | ||
| 267 | |||
| 268 | err = mc44s803_writereg(priv, val); | ||
| 269 | if (err) | ||
| 270 | goto exit; | ||
| 271 | |||
| 272 | val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | | ||
| 273 | MC44S803_REG_SM(2, MC44S803_DA) | | ||
| 274 | MC44S803_REG_SM(lo2, MC44S803_LO_REF) | | ||
| 275 | MC44S803_REG_SM(1, MC44S803_AT); | ||
| 276 | |||
| 277 | err = mc44s803_writereg(priv, val); | ||
| 278 | if (err) | ||
| 279 | goto exit; | ||
| 280 | |||
| 281 | if (fe->ops.i2c_gate_ctrl) | ||
| 282 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | |||
| 286 | exit: | ||
| 287 | if (fe->ops.i2c_gate_ctrl) | ||
| 288 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 289 | |||
| 290 | mc_printk(KERN_WARNING, "I/O Error\n"); | ||
| 291 | return err; | ||
| 292 | } | ||
| 293 | |||
| 294 | static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 295 | { | ||
| 296 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
| 297 | *frequency = priv->frequency; | ||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | static const struct dvb_tuner_ops mc44s803_tuner_ops = { | ||
| 302 | .info = { | ||
| 303 | .name = "Freescale MC44S803", | ||
| 304 | .frequency_min = 48000000, | ||
| 305 | .frequency_max = 1000000000, | ||
| 306 | .frequency_step = 100000, | ||
| 307 | }, | ||
| 308 | |||
| 309 | .release = mc44s803_release, | ||
| 310 | .init = mc44s803_init, | ||
| 311 | .set_params = mc44s803_set_params, | ||
| 312 | .get_frequency = mc44s803_get_frequency | ||
| 313 | }; | ||
| 314 | |||
| 315 | /* This functions tries to identify a MC44S803 tuner by reading the ID | ||
| 316 | register. This is hasty. */ | ||
| 317 | struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, | ||
| 318 | struct i2c_adapter *i2c, struct mc44s803_config *cfg) | ||
| 319 | { | ||
| 320 | struct mc44s803_priv *priv; | ||
| 321 | u32 reg; | ||
| 322 | u8 id; | ||
| 323 | int ret; | ||
| 324 | |||
| 325 | reg = 0; | ||
| 326 | |||
| 327 | priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); | ||
| 328 | if (priv == NULL) | ||
| 329 | return NULL; | ||
| 330 | |||
| 331 | priv->cfg = cfg; | ||
| 332 | priv->i2c = i2c; | ||
| 333 | priv->fe = fe; | ||
| 334 | |||
| 335 | if (fe->ops.i2c_gate_ctrl) | ||
| 336 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 337 | |||
| 338 | ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); | ||
| 339 | if (ret) | ||
| 340 | goto error; | ||
| 341 | |||
| 342 | id = MC44S803_REG_MS(reg, MC44S803_ID); | ||
| 343 | |||
| 344 | if (id != 0x14) { | ||
| 345 | mc_printk(KERN_ERR, "unsupported ID " | ||
| 346 | "(%x should be 0x14)\n", id); | ||
| 347 | goto error; | ||
| 348 | } | ||
| 349 | |||
| 350 | mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); | ||
| 351 | memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, | ||
| 352 | sizeof(struct dvb_tuner_ops)); | ||
| 353 | |||
| 354 | fe->tuner_priv = priv; | ||
| 355 | |||
| 356 | if (fe->ops.i2c_gate_ctrl) | ||
| 357 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 358 | |||
| 359 | return fe; | ||
| 360 | |||
| 361 | error: | ||
| 362 | if (fe->ops.i2c_gate_ctrl) | ||
| 363 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 364 | |||
| 365 | kfree(priv); | ||
| 366 | return NULL; | ||
| 367 | } | ||
| 368 | EXPORT_SYMBOL(mc44s803_attach); | ||
| 369 | |||
| 370 | MODULE_AUTHOR("Jochen Friedrich"); | ||
| 371 | MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); | ||
| 372 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/mc44s803.h b/drivers/media/common/tuners/mc44s803.h new file mode 100644 index 00000000000..34f3892d3f6 --- /dev/null +++ b/drivers/media/common/tuners/mc44s803.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> | ||
| 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 | #ifndef MC44S803_H | ||
| 23 | #define MC44S803_H | ||
| 24 | |||
| 25 | struct dvb_frontend; | ||
| 26 | struct i2c_adapter; | ||
| 27 | |||
| 28 | struct mc44s803_config { | ||
| 29 | u8 i2c_address; | ||
| 30 | u8 dig_out; | ||
| 31 | }; | ||
| 32 | |||
| 33 | #if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ | ||
| 34 | (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) | ||
| 35 | extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, | ||
| 36 | struct i2c_adapter *i2c, struct mc44s803_config *cfg); | ||
| 37 | #else | ||
| 38 | static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, | ||
| 39 | struct i2c_adapter *i2c, struct mc44s803_config *cfg) | ||
| 40 | { | ||
| 41 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 42 | return NULL; | ||
| 43 | } | ||
| 44 | #endif /* CONFIG_MEDIA_TUNER_MC44S803 */ | ||
| 45 | |||
| 46 | #endif | ||
diff --git a/drivers/media/common/tuners/mc44s803_priv.h b/drivers/media/common/tuners/mc44s803_priv.h new file mode 100644 index 00000000000..14a92780906 --- /dev/null +++ b/drivers/media/common/tuners/mc44s803_priv.h | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> | ||
| 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 | #ifndef MC44S803_PRIV_H | ||
| 23 | #define MC44S803_PRIV_H | ||
| 24 | |||
| 25 | /* This driver is based on the information available in the datasheet | ||
| 26 | http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf | ||
| 27 | |||
| 28 | SPI or I2C Address : 0xc0-0xc6 | ||
| 29 | |||
| 30 | Reg.No | Function | ||
| 31 | ------------------------------------------- | ||
| 32 | 00 | Power Down | ||
| 33 | 01 | Reference Oszillator | ||
| 34 | 02 | Reference Dividers | ||
| 35 | 03 | Mixer and Reference Buffer | ||
| 36 | 04 | Reset/Serial Out | ||
| 37 | 05 | LO 1 | ||
| 38 | 06 | LO 2 | ||
| 39 | 07 | Circuit Adjust | ||
| 40 | 08 | Test | ||
| 41 | 09 | Digital Tune | ||
| 42 | 0A | LNA AGC | ||
| 43 | 0B | Data Register Address | ||
| 44 | 0C | Regulator Test | ||
| 45 | 0D | VCO Test | ||
| 46 | 0E | LNA Gain/Input Power | ||
| 47 | 0F | ID Bits | ||
| 48 | |||
| 49 | */ | ||
| 50 | |||
| 51 | #define MC44S803_OSC 26000000 /* 26 MHz */ | ||
| 52 | #define MC44S803_IF1 1086000000 /* 1086 MHz */ | ||
| 53 | #define MC44S803_IF2 36125000 /* 36.125 MHz */ | ||
| 54 | |||
| 55 | #define MC44S803_REG_POWER 0 | ||
| 56 | #define MC44S803_REG_REFOSC 1 | ||
| 57 | #define MC44S803_REG_REFDIV 2 | ||
| 58 | #define MC44S803_REG_MIXER 3 | ||
| 59 | #define MC44S803_REG_RESET 4 | ||
| 60 | #define MC44S803_REG_LO1 5 | ||
| 61 | #define MC44S803_REG_LO2 6 | ||
| 62 | #define MC44S803_REG_CIRCADJ 7 | ||
| 63 | #define MC44S803_REG_TEST 8 | ||
| 64 | #define MC44S803_REG_DIGTUNE 9 | ||
| 65 | #define MC44S803_REG_LNAAGC 0x0A | ||
| 66 | #define MC44S803_REG_DATAREG 0x0B | ||
| 67 | #define MC44S803_REG_REGTEST 0x0C | ||
| 68 | #define MC44S803_REG_VCOTEST 0x0D | ||
| 69 | #define MC44S803_REG_LNAGAIN 0x0E | ||
| 70 | #define MC44S803_REG_ID 0x0F | ||
| 71 | |||
| 72 | /* Register definitions */ | ||
| 73 | #define MC44S803_ADDR 0x0F | ||
| 74 | #define MC44S803_ADDR_S 0 | ||
| 75 | /* REG_POWER */ | ||
| 76 | #define MC44S803_POWER 0xFFFFF0 | ||
| 77 | #define MC44S803_POWER_S 4 | ||
| 78 | /* REG_REFOSC */ | ||
| 79 | #define MC44S803_REFOSC 0x1FF0 | ||
| 80 | #define MC44S803_REFOSC_S 4 | ||
| 81 | #define MC44S803_OSCSEL 0x2000 | ||
| 82 | #define MC44S803_OSCSEL_S 13 | ||
| 83 | /* REG_REFDIV */ | ||
| 84 | #define MC44S803_R2 0x1FF0 | ||
| 85 | #define MC44S803_R2_S 4 | ||
| 86 | #define MC44S803_REFBUF_EN 0x2000 | ||
| 87 | #define MC44S803_REFBUF_EN_S 13 | ||
| 88 | #define MC44S803_R1 0x7C000 | ||
| 89 | #define MC44S803_R1_S 14 | ||
| 90 | /* REG_MIXER */ | ||
| 91 | #define MC44S803_R3 0x70 | ||
| 92 | #define MC44S803_R3_S 4 | ||
| 93 | #define MC44S803_MUX3 0x80 | ||
| 94 | #define MC44S803_MUX3_S 7 | ||
| 95 | #define MC44S803_MUX4 0x100 | ||
| 96 | #define MC44S803_MUX4_S 8 | ||
| 97 | #define MC44S803_OSC_SCR 0x200 | ||
| 98 | #define MC44S803_OSC_SCR_S 9 | ||
| 99 | #define MC44S803_TRI_STATE 0x400 | ||
| 100 | #define MC44S803_TRI_STATE_S 10 | ||
| 101 | #define MC44S803_BUF_GAIN 0x800 | ||
| 102 | #define MC44S803_BUF_GAIN_S 11 | ||
| 103 | #define MC44S803_BUF_IO 0x1000 | ||
| 104 | #define MC44S803_BUF_IO_S 12 | ||
| 105 | #define MC44S803_MIXER_RES 0xFE000 | ||
| 106 | #define MC44S803_MIXER_RES_S 13 | ||
| 107 | /* REG_RESET */ | ||
| 108 | #define MC44S803_RS 0x10 | ||
| 109 | #define MC44S803_RS_S 4 | ||
| 110 | #define MC44S803_SO 0x20 | ||
| 111 | #define MC44S803_SO_S 5 | ||
| 112 | /* REG_LO1 */ | ||
| 113 | #define MC44S803_LO1 0xFFF0 | ||
| 114 | #define MC44S803_LO1_S 4 | ||
| 115 | /* REG_LO2 */ | ||
| 116 | #define MC44S803_LO2 0x7FFF0 | ||
| 117 | #define MC44S803_LO2_S 4 | ||
| 118 | /* REG_CIRCADJ */ | ||
| 119 | #define MC44S803_G1 0x20 | ||
| 120 | #define MC44S803_G1_S 5 | ||
| 121 | #define MC44S803_G3 0x80 | ||
| 122 | #define MC44S803_G3_S 7 | ||
| 123 | #define MC44S803_CIRCADJ_RES 0x300 | ||
| 124 | #define MC44S803_CIRCADJ_RES_S 8 | ||
| 125 | #define MC44S803_G6 0x400 | ||
| 126 | #define MC44S803_G6_S 10 | ||
| 127 | #define MC44S803_G7 0x800 | ||
| 128 | #define MC44S803_G7_S 11 | ||
| 129 | #define MC44S803_S1 0x1000 | ||
| 130 | #define MC44S803_S1_S 12 | ||
| 131 | #define MC44S803_LP 0x7E000 | ||
| 132 | #define MC44S803_LP_S 13 | ||
| 133 | #define MC44S803_CLRF 0x80000 | ||
| 134 | #define MC44S803_CLRF_S 19 | ||
| 135 | #define MC44S803_CLIF 0x100000 | ||
| 136 | #define MC44S803_CLIF_S 20 | ||
| 137 | /* REG_TEST */ | ||
| 138 | /* REG_DIGTUNE */ | ||
| 139 | #define MC44S803_DA 0xF0 | ||
| 140 | #define MC44S803_DA_S 4 | ||
| 141 | #define MC44S803_XOD 0x300 | ||
| 142 | #define MC44S803_XOD_S 8 | ||
| 143 | #define MC44S803_RST 0x10000 | ||
| 144 | #define MC44S803_RST_S 16 | ||
| 145 | #define MC44S803_LO_REF 0x1FFF00 | ||
| 146 | #define MC44S803_LO_REF_S 8 | ||
| 147 | #define MC44S803_AT 0x200000 | ||
| 148 | #define MC44S803_AT_S 21 | ||
| 149 | #define MC44S803_MT 0x400000 | ||
| 150 | #define MC44S803_MT_S 22 | ||
| 151 | /* REG_LNAAGC */ | ||
| 152 | #define MC44S803_G 0x3F0 | ||
| 153 | #define MC44S803_G_S 4 | ||
| 154 | #define MC44S803_AT1 0x400 | ||
| 155 | #define MC44S803_AT1_S 10 | ||
| 156 | #define MC44S803_AT2 0x800 | ||
| 157 | #define MC44S803_AT2_S 11 | ||
| 158 | #define MC44S803_HL_GR_EN 0x8000 | ||
| 159 | #define MC44S803_HL_GR_EN_S 15 | ||
| 160 | #define MC44S803_AGC_AN_DIG 0x10000 | ||
| 161 | #define MC44S803_AGC_AN_DIG_S 16 | ||
| 162 | #define MC44S803_ATTEN_EN 0x20000 | ||
| 163 | #define MC44S803_ATTEN_EN_S 17 | ||
| 164 | #define MC44S803_AGC_READ_EN 0x40000 | ||
| 165 | #define MC44S803_AGC_READ_EN_S 18 | ||
| 166 | #define MC44S803_LNA0 0x80000 | ||
| 167 | #define MC44S803_LNA0_S 19 | ||
| 168 | #define MC44S803_AGC_SEL 0x100000 | ||
| 169 | #define MC44S803_AGC_SEL_S 20 | ||
| 170 | #define MC44S803_AT0 0x200000 | ||
| 171 | #define MC44S803_AT0_S 21 | ||
| 172 | #define MC44S803_B 0xC00000 | ||
| 173 | #define MC44S803_B_S 22 | ||
| 174 | /* REG_DATAREG */ | ||
| 175 | #define MC44S803_D 0xF0 | ||
| 176 | #define MC44S803_D_S 4 | ||
| 177 | /* REG_REGTEST */ | ||
| 178 | /* REG_VCOTEST */ | ||
| 179 | /* REG_LNAGAIN */ | ||
| 180 | #define MC44S803_IF_PWR 0x700 | ||
| 181 | #define MC44S803_IF_PWR_S 8 | ||
| 182 | #define MC44S803_RF_PWR 0x3800 | ||
| 183 | #define MC44S803_RF_PWR_S 11 | ||
| 184 | #define MC44S803_LNA_GAIN 0xFC000 | ||
| 185 | #define MC44S803_LNA_GAIN_S 14 | ||
| 186 | /* REG_ID */ | ||
| 187 | #define MC44S803_ID 0x3E00 | ||
| 188 | #define MC44S803_ID_S 9 | ||
| 189 | |||
| 190 | /* Some macros to read/write fields */ | ||
| 191 | |||
| 192 | /* First shift, then mask */ | ||
| 193 | #define MC44S803_REG_SM(_val, _reg) \ | ||
| 194 | (((_val) << _reg##_S) & (_reg)) | ||
| 195 | |||
| 196 | /* First mask, then shift */ | ||
| 197 | #define MC44S803_REG_MS(_val, _reg) \ | ||
| 198 | (((_val) & (_reg)) >> _reg##_S) | ||
| 199 | |||
| 200 | struct mc44s803_priv { | ||
| 201 | struct mc44s803_config *cfg; | ||
| 202 | struct i2c_adapter *i2c; | ||
| 203 | struct dvb_frontend *fe; | ||
| 204 | |||
| 205 | u32 frequency; | ||
| 206 | }; | ||
| 207 | |||
| 208 | #endif | ||
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c new file mode 100644 index 00000000000..2d0e7689c6a --- /dev/null +++ b/drivers/media/common/tuners/mt2060.c | |||
| @@ -0,0 +1,404 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Olivier DANET <odanet@caramail.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 | /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/dvb/frontend.h> | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | |||
| 30 | #include "dvb_frontend.h" | ||
| 31 | |||
| 32 | #include "mt2060.h" | ||
| 33 | #include "mt2060_priv.h" | ||
| 34 | |||
| 35 | static int debug; | ||
| 36 | module_param(debug, int, 0644); | ||
| 37 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 38 | |||
| 39 | #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) | ||
| 40 | |||
| 41 | // Reads a single register | ||
| 42 | static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) | ||
| 43 | { | ||
| 44 | struct i2c_msg msg[2] = { | ||
| 45 | { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | ||
| 46 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
| 47 | }; | ||
| 48 | |||
| 49 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
| 50 | printk(KERN_WARNING "mt2060 I2C read failed\n"); | ||
| 51 | return -EREMOTEIO; | ||
| 52 | } | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | // Writes a single register | ||
| 57 | static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) | ||
| 58 | { | ||
| 59 | u8 buf[2] = { reg, val }; | ||
| 60 | struct i2c_msg msg = { | ||
| 61 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 | ||
| 62 | }; | ||
| 63 | |||
| 64 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 65 | printk(KERN_WARNING "mt2060 I2C write failed\n"); | ||
| 66 | return -EREMOTEIO; | ||
| 67 | } | ||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | // Writes a set of consecutive registers | ||
| 72 | static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) | ||
| 73 | { | ||
| 74 | struct i2c_msg msg = { | ||
| 75 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len | ||
| 76 | }; | ||
| 77 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 78 | printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); | ||
| 79 | return -EREMOTEIO; | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | // Initialisation sequences | ||
| 85 | // LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49 | ||
| 86 | static u8 mt2060_config1[] = { | ||
| 87 | REG_LO1C1, | ||
| 88 | 0x3F, 0x74, 0x00, 0x08, 0x93 | ||
| 89 | }; | ||
| 90 | |||
| 91 | // FMCG=2, GP2=0, GP1=0 | ||
| 92 | static u8 mt2060_config2[] = { | ||
| 93 | REG_MISC_CTRL, | ||
| 94 | 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42 | ||
| 95 | }; | ||
| 96 | |||
| 97 | // VGAG=3, V1CSE=1 | ||
| 98 | |||
| 99 | #ifdef MT2060_SPURCHECK | ||
| 100 | /* The function below calculates the frequency offset between the output frequency if2 | ||
| 101 | and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */ | ||
| 102 | static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2) | ||
| 103 | { | ||
| 104 | int I,J; | ||
| 105 | int dia,diamin,diff; | ||
| 106 | diamin=1000000; | ||
| 107 | for (I = 1; I < 10; I++) { | ||
| 108 | J = ((2*I*lo1)/lo2+1)/2; | ||
| 109 | diff = I*(int)lo1-J*(int)lo2; | ||
| 110 | if (diff < 0) diff=-diff; | ||
| 111 | dia = (diff-(int)if2); | ||
| 112 | if (dia < 0) dia=-dia; | ||
| 113 | if (diamin > dia) diamin=dia; | ||
| 114 | } | ||
| 115 | return diamin; | ||
| 116 | } | ||
| 117 | |||
| 118 | #define BANDWIDTH 4000 // kHz | ||
| 119 | |||
| 120 | /* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */ | ||
| 121 | static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) | ||
| 122 | { | ||
| 123 | u32 Spur,Sp1,Sp2; | ||
| 124 | int I,J; | ||
| 125 | I=0; | ||
| 126 | J=1000; | ||
| 127 | |||
| 128 | Spur=mt2060_spurcalc(lo1,lo2,if2); | ||
| 129 | if (Spur < BANDWIDTH) { | ||
| 130 | /* Potential spurs detected */ | ||
| 131 | dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)", | ||
| 132 | (int)lo1,(int)lo2); | ||
| 133 | I=1000; | ||
| 134 | Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2); | ||
| 135 | Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2); | ||
| 136 | |||
| 137 | if (Sp1 < Sp2) { | ||
| 138 | J=-J; I=-I; Spur=Sp2; | ||
| 139 | } else | ||
| 140 | Spur=Sp1; | ||
| 141 | |||
| 142 | while (Spur < BANDWIDTH) { | ||
| 143 | I += J; | ||
| 144 | Spur = mt2060_spurcalc(lo1+I,lo2+I,if2); | ||
| 145 | } | ||
| 146 | dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)", | ||
| 147 | (int)(lo1+I),(int)(lo2+I)); | ||
| 148 | } | ||
| 149 | return I; | ||
| 150 | } | ||
| 151 | #endif | ||
| 152 | |||
| 153 | #define IF2 36150 // IF2 frequency = 36.150 MHz | ||
| 154 | #define FREF 16000 // Quartz oscillator 16 MHz | ||
| 155 | |||
| 156 | static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
| 157 | { | ||
| 158 | struct mt2060_priv *priv; | ||
| 159 | int ret=0; | ||
| 160 | int i=0; | ||
| 161 | u32 freq; | ||
| 162 | u8 lnaband; | ||
| 163 | u32 f_lo1,f_lo2; | ||
| 164 | u32 div1,num1,div2,num2; | ||
| 165 | u8 b[8]; | ||
| 166 | u32 if1; | ||
| 167 | |||
| 168 | priv = fe->tuner_priv; | ||
| 169 | |||
| 170 | if1 = priv->if1_freq; | ||
| 171 | b[0] = REG_LO1B1; | ||
| 172 | b[1] = 0xFF; | ||
| 173 | |||
| 174 | if (fe->ops.i2c_gate_ctrl) | ||
| 175 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 176 | |||
| 177 | mt2060_writeregs(priv,b,2); | ||
| 178 | |||
| 179 | freq = params->frequency / 1000; // Hz -> kHz | ||
| 180 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
| 181 | |||
| 182 | f_lo1 = freq + if1 * 1000; | ||
| 183 | f_lo1 = (f_lo1 / 250) * 250; | ||
| 184 | f_lo2 = f_lo1 - freq - IF2; | ||
| 185 | // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise | ||
| 186 | f_lo2 = ((f_lo2 + 25) / 50) * 50; | ||
| 187 | priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, | ||
| 188 | |||
| 189 | #ifdef MT2060_SPURCHECK | ||
| 190 | // LO-related spurs detection and correction | ||
| 191 | num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2); | ||
| 192 | f_lo1 += num1; | ||
| 193 | f_lo2 += num1; | ||
| 194 | #endif | ||
| 195 | //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) | ||
| 196 | num1 = f_lo1 / (FREF / 64); | ||
| 197 | div1 = num1 / 64; | ||
| 198 | num1 &= 0x3f; | ||
| 199 | |||
| 200 | // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) | ||
| 201 | num2 = f_lo2 * 64 / (FREF / 128); | ||
| 202 | div2 = num2 / 8192; | ||
| 203 | num2 &= 0x1fff; | ||
| 204 | |||
| 205 | if (freq <= 95000) lnaband = 0xB0; else | ||
| 206 | if (freq <= 180000) lnaband = 0xA0; else | ||
| 207 | if (freq <= 260000) lnaband = 0x90; else | ||
| 208 | if (freq <= 335000) lnaband = 0x80; else | ||
| 209 | if (freq <= 425000) lnaband = 0x70; else | ||
| 210 | if (freq <= 480000) lnaband = 0x60; else | ||
| 211 | if (freq <= 570000) lnaband = 0x50; else | ||
| 212 | if (freq <= 645000) lnaband = 0x40; else | ||
| 213 | if (freq <= 730000) lnaband = 0x30; else | ||
| 214 | if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10; | ||
| 215 | |||
| 216 | b[0] = REG_LO1C1; | ||
| 217 | b[1] = lnaband | ((num1 >>2) & 0x0F); | ||
| 218 | b[2] = div1; | ||
| 219 | b[3] = (num2 & 0x0F) | ((num1 & 3) << 4); | ||
| 220 | b[4] = num2 >> 4; | ||
| 221 | b[5] = ((num2 >>12) & 1) | (div2 << 1); | ||
| 222 | |||
| 223 | dprintk("IF1: %dMHz",(int)if1); | ||
| 224 | dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); | ||
| 225 | dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); | ||
| 226 | dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); | ||
| 227 | |||
| 228 | mt2060_writeregs(priv,b,6); | ||
| 229 | |||
| 230 | //Waits for pll lock or timeout | ||
| 231 | i = 0; | ||
| 232 | do { | ||
| 233 | mt2060_readreg(priv,REG_LO_STATUS,b); | ||
| 234 | if ((b[0] & 0x88)==0x88) | ||
| 235 | break; | ||
| 236 | msleep(4); | ||
| 237 | i++; | ||
| 238 | } while (i<10); | ||
| 239 | |||
| 240 | if (fe->ops.i2c_gate_ctrl) | ||
| 241 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 242 | |||
| 243 | return ret; | ||
| 244 | } | ||
| 245 | |||
| 246 | static void mt2060_calibrate(struct mt2060_priv *priv) | ||
| 247 | { | ||
| 248 | u8 b = 0; | ||
| 249 | int i = 0; | ||
| 250 | |||
| 251 | if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) | ||
| 252 | return; | ||
| 253 | if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) | ||
| 254 | return; | ||
| 255 | |||
| 256 | /* initialize the clock output */ | ||
| 257 | mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30); | ||
| 258 | |||
| 259 | do { | ||
| 260 | b |= (1 << 6); // FM1SS; | ||
| 261 | mt2060_writereg(priv, REG_LO2C1,b); | ||
| 262 | msleep(20); | ||
| 263 | |||
| 264 | if (i == 0) { | ||
| 265 | b |= (1 << 7); // FM1CA; | ||
| 266 | mt2060_writereg(priv, REG_LO2C1,b); | ||
| 267 | b &= ~(1 << 7); // FM1CA; | ||
| 268 | msleep(20); | ||
| 269 | } | ||
| 270 | |||
| 271 | b &= ~(1 << 6); // FM1SS | ||
| 272 | mt2060_writereg(priv, REG_LO2C1,b); | ||
| 273 | |||
| 274 | msleep(20); | ||
| 275 | i++; | ||
| 276 | } while (i < 9); | ||
| 277 | |||
| 278 | i = 0; | ||
| 279 | while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) | ||
| 280 | msleep(20); | ||
| 281 | |||
| 282 | if (i <= 10) { | ||
| 283 | mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) | ||
| 284 | dprintk("calibration was successful: %d", (int)priv->fmfreq); | ||
| 285 | } else | ||
| 286 | dprintk("FMCAL timed out"); | ||
| 287 | } | ||
| 288 | |||
| 289 | static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 290 | { | ||
| 291 | struct mt2060_priv *priv = fe->tuner_priv; | ||
| 292 | *frequency = priv->frequency; | ||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 297 | { | ||
| 298 | struct mt2060_priv *priv = fe->tuner_priv; | ||
| 299 | *bandwidth = priv->bandwidth; | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | |||
| 303 | static int mt2060_init(struct dvb_frontend *fe) | ||
| 304 | { | ||
| 305 | struct mt2060_priv *priv = fe->tuner_priv; | ||
| 306 | int ret; | ||
| 307 | |||
| 308 | if (fe->ops.i2c_gate_ctrl) | ||
| 309 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 310 | |||
| 311 | ret = mt2060_writereg(priv, REG_VGAG, | ||
| 312 | (priv->cfg->clock_out << 6) | 0x33); | ||
| 313 | |||
| 314 | if (fe->ops.i2c_gate_ctrl) | ||
| 315 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 316 | |||
| 317 | return ret; | ||
| 318 | } | ||
| 319 | |||
| 320 | static int mt2060_sleep(struct dvb_frontend *fe) | ||
| 321 | { | ||
| 322 | struct mt2060_priv *priv = fe->tuner_priv; | ||
| 323 | int ret; | ||
| 324 | |||
| 325 | if (fe->ops.i2c_gate_ctrl) | ||
| 326 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 327 | |||
| 328 | ret = mt2060_writereg(priv, REG_VGAG, | ||
| 329 | (priv->cfg->clock_out << 6) | 0x30); | ||
| 330 | |||
| 331 | if (fe->ops.i2c_gate_ctrl) | ||
| 332 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 333 | |||
| 334 | return ret; | ||
| 335 | } | ||
| 336 | |||
| 337 | static int mt2060_release(struct dvb_frontend *fe) | ||
| 338 | { | ||
| 339 | kfree(fe->tuner_priv); | ||
| 340 | fe->tuner_priv = NULL; | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | static const struct dvb_tuner_ops mt2060_tuner_ops = { | ||
| 345 | .info = { | ||
| 346 | .name = "Microtune MT2060", | ||
| 347 | .frequency_min = 48000000, | ||
| 348 | .frequency_max = 860000000, | ||
| 349 | .frequency_step = 50000, | ||
| 350 | }, | ||
| 351 | |||
| 352 | .release = mt2060_release, | ||
| 353 | |||
| 354 | .init = mt2060_init, | ||
| 355 | .sleep = mt2060_sleep, | ||
| 356 | |||
| 357 | .set_params = mt2060_set_params, | ||
| 358 | .get_frequency = mt2060_get_frequency, | ||
| 359 | .get_bandwidth = mt2060_get_bandwidth | ||
| 360 | }; | ||
| 361 | |||
| 362 | /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ | ||
| 363 | struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) | ||
| 364 | { | ||
| 365 | struct mt2060_priv *priv = NULL; | ||
| 366 | u8 id = 0; | ||
| 367 | |||
| 368 | priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); | ||
| 369 | if (priv == NULL) | ||
| 370 | return NULL; | ||
| 371 | |||
| 372 | priv->cfg = cfg; | ||
| 373 | priv->i2c = i2c; | ||
| 374 | priv->if1_freq = if1; | ||
| 375 | |||
| 376 | if (fe->ops.i2c_gate_ctrl) | ||
| 377 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 378 | |||
| 379 | if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { | ||
| 380 | kfree(priv); | ||
| 381 | return NULL; | ||
| 382 | } | ||
| 383 | |||
| 384 | if (id != PART_REV) { | ||
| 385 | kfree(priv); | ||
| 386 | return NULL; | ||
| 387 | } | ||
| 388 | printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1); | ||
| 389 | memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
| 390 | |||
| 391 | fe->tuner_priv = priv; | ||
| 392 | |||
| 393 | mt2060_calibrate(priv); | ||
| 394 | |||
| 395 | if (fe->ops.i2c_gate_ctrl) | ||
| 396 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 397 | |||
| 398 | return fe; | ||
| 399 | } | ||
| 400 | EXPORT_SYMBOL(mt2060_attach); | ||
| 401 | |||
| 402 | MODULE_AUTHOR("Olivier DANET"); | ||
| 403 | MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver"); | ||
| 404 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/mt2060.h b/drivers/media/common/tuners/mt2060.h new file mode 100644 index 00000000000..cb60caffb6b --- /dev/null +++ b/drivers/media/common/tuners/mt2060.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Olivier DANET <odanet@caramail.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 | #ifndef MT2060_H | ||
| 23 | #define MT2060_H | ||
| 24 | |||
| 25 | struct dvb_frontend; | ||
| 26 | struct i2c_adapter; | ||
| 27 | |||
| 28 | struct mt2060_config { | ||
| 29 | u8 i2c_address; | ||
| 30 | u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ | ||
| 31 | }; | ||
| 32 | |||
| 33 | #if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) | ||
| 34 | extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); | ||
| 35 | #else | ||
| 36 | static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) | ||
| 37 | { | ||
| 38 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 39 | return NULL; | ||
| 40 | } | ||
| 41 | #endif // CONFIG_MEDIA_TUNER_MT2060 | ||
| 42 | |||
| 43 | #endif | ||
diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h new file mode 100644 index 00000000000..5eaccdefd0b --- /dev/null +++ b/drivers/media/common/tuners/mt2060_priv.h | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Olivier DANET <odanet@caramail.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 | #ifndef MT2060_PRIV_H | ||
| 23 | #define MT2060_PRIV_H | ||
| 24 | |||
| 25 | // Uncomment the #define below to enable spurs checking. The results where quite unconvincing. | ||
| 26 | // #define MT2060_SPURCHECK | ||
| 27 | |||
| 28 | /* This driver is based on the information available in the datasheet of the | ||
| 29 | "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map : | ||
| 30 | |||
| 31 | I2C Address : 0x60 | ||
| 32 | |||
| 33 | Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults ) | ||
| 34 | -------------------------------------------------------------------------------- | ||
| 35 | 00 | [ PART ] | [ REV ] | R = 0x63 | ||
| 36 | 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F | ||
| 37 | 02 | [ DIV1 ] | RW = 0x74 | ||
| 38 | 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00 | ||
| 39 | 04 | NUM2(11:4) ] | RW = 0x08 | ||
| 40 | 05 | [ DIV2 ] |NUM2(12)| RW = 0x93 | ||
| 41 | 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R | ||
| 42 | 07 | [ FMF ] | R | ||
| 43 | 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R | ||
| 44 | 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20 | ||
| 45 | 0A | ?? | ||
| 46 | 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30 | ||
| 47 | 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF | ||
| 48 | 0D | 1 | 0 | [ V1CS ] | RW = 0xB0 | ||
| 49 | 0E | ?? | ||
| 50 | 0F | ?? | ||
| 51 | 10 | ?? | ||
| 52 | 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42 | ||
| 53 | |||
| 54 | PART : Part code : 6 for MT2060 | ||
| 55 | REV : Revision code : 3 for current revision | ||
| 56 | LNABAND : Input frequency range : ( See code for details ) | ||
| 57 | NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details ) | ||
| 58 | FM1CA : Calibration Start Bit | ||
| 59 | FM1SS : Calibration Single Step bit | ||
| 60 | L1LK : LO1 Lock Detect | ||
| 61 | TAD1 : Tune Line ADC ( ? ) | ||
| 62 | L2LK : LO2 Lock Detect | ||
| 63 | TAD2 : Tune Line ADC ( ? ) | ||
| 64 | FMF : Estimated first IF Center frequency Offset ( ? ) | ||
| 65 | FM1CAL : Calibration done bit | ||
| 66 | TEMP : On chip temperature sensor | ||
| 67 | FMCG : Mixer 1 Cap Gain ( ? ) | ||
| 68 | GP01 / GP02 : Programmable digital outputs. Unconnected pins ? | ||
| 69 | V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? ) | ||
| 70 | V1CS : LO1 Capacitor Selection Value ( ? ) | ||
| 71 | LOTO : LO Timeout ( ? ) | ||
| 72 | VGAG : Tuner Output gain | ||
| 73 | */ | ||
| 74 | |||
| 75 | #define I2C_ADDRESS 0x60 | ||
| 76 | |||
| 77 | #define REG_PART_REV 0 | ||
| 78 | #define REG_LO1C1 1 | ||
| 79 | #define REG_LO1C2 2 | ||
| 80 | #define REG_LO2C1 3 | ||
| 81 | #define REG_LO2C2 4 | ||
| 82 | #define REG_LO2C3 5 | ||
| 83 | #define REG_LO_STATUS 6 | ||
| 84 | #define REG_FM_FREQ 7 | ||
| 85 | #define REG_MISC_STAT 8 | ||
| 86 | #define REG_MISC_CTRL 9 | ||
| 87 | #define REG_RESERVED_A 0x0A | ||
| 88 | #define REG_VGAG 0x0B | ||
| 89 | #define REG_LO1B1 0x0C | ||
| 90 | #define REG_LO1B2 0x0D | ||
| 91 | #define REG_LOTO 0x11 | ||
| 92 | |||
| 93 | #define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips | ||
| 94 | |||
| 95 | struct mt2060_priv { | ||
| 96 | struct mt2060_config *cfg; | ||
| 97 | struct i2c_adapter *i2c; | ||
| 98 | |||
| 99 | u32 frequency; | ||
| 100 | u32 bandwidth; | ||
| 101 | u16 if1_freq; | ||
| 102 | u8 fmfreq; | ||
| 103 | }; | ||
| 104 | |||
| 105 | #endif | ||
diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/common/tuners/mt20xx.c new file mode 100644 index 00000000000..d0e70e10a71 --- /dev/null +++ b/drivers/media/common/tuners/mt20xx.c | |||
| @@ -0,0 +1,672 @@ | |||
| 1 | /* | ||
| 2 | * i2c tv tuner chip device driver | ||
| 3 | * controls microtune tuners, mt2032 + mt2050 at the moment. | ||
| 4 | * | ||
| 5 | * This "mt20xx" module was split apart from the original "tuner" module. | ||
| 6 | */ | ||
| 7 | #include <linux/delay.h> | ||
| 8 | #include <linux/i2c.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/videodev2.h> | ||
| 11 | #include "tuner-i2c.h" | ||
| 12 | #include "mt20xx.h" | ||
| 13 | |||
| 14 | static int debug; | ||
| 15 | module_param(debug, int, 0644); | ||
| 16 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 17 | |||
| 18 | /* ---------------------------------------------------------------------- */ | ||
| 19 | |||
| 20 | static unsigned int optimize_vco = 1; | ||
| 21 | module_param(optimize_vco, int, 0644); | ||
| 22 | |||
| 23 | static unsigned int tv_antenna = 1; | ||
| 24 | module_param(tv_antenna, int, 0644); | ||
| 25 | |||
| 26 | static unsigned int radio_antenna; | ||
| 27 | module_param(radio_antenna, int, 0644); | ||
| 28 | |||
| 29 | /* ---------------------------------------------------------------------- */ | ||
| 30 | |||
| 31 | #define MT2032 0x04 | ||
| 32 | #define MT2030 0x06 | ||
| 33 | #define MT2040 0x07 | ||
| 34 | #define MT2050 0x42 | ||
| 35 | |||
| 36 | static char *microtune_part[] = { | ||
| 37 | [ MT2030 ] = "MT2030", | ||
| 38 | [ MT2032 ] = "MT2032", | ||
| 39 | [ MT2040 ] = "MT2040", | ||
| 40 | [ MT2050 ] = "MT2050", | ||
| 41 | }; | ||
| 42 | |||
| 43 | struct microtune_priv { | ||
| 44 | struct tuner_i2c_props i2c_props; | ||
| 45 | |||
| 46 | unsigned int xogc; | ||
| 47 | //unsigned int radio_if2; | ||
| 48 | |||
| 49 | u32 frequency; | ||
| 50 | }; | ||
| 51 | |||
| 52 | static int microtune_release(struct dvb_frontend *fe) | ||
| 53 | { | ||
| 54 | kfree(fe->tuner_priv); | ||
| 55 | fe->tuner_priv = NULL; | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 61 | { | ||
| 62 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 63 | *frequency = priv->frequency; | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | // IsSpurInBand()? | ||
| 68 | static int mt2032_spurcheck(struct dvb_frontend *fe, | ||
| 69 | int f1, int f2, int spectrum_from,int spectrum_to) | ||
| 70 | { | ||
| 71 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 72 | int n1=1,n2,f; | ||
| 73 | |||
| 74 | f1=f1/1000; //scale to kHz to avoid 32bit overflows | ||
| 75 | f2=f2/1000; | ||
| 76 | spectrum_from/=1000; | ||
| 77 | spectrum_to/=1000; | ||
| 78 | |||
| 79 | tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", | ||
| 80 | f1,f2,spectrum_from,spectrum_to); | ||
| 81 | |||
| 82 | do { | ||
| 83 | n2=-n1; | ||
| 84 | f=n1*(f1-f2); | ||
| 85 | do { | ||
| 86 | n2--; | ||
| 87 | f=f-f2; | ||
| 88 | tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); | ||
| 89 | |||
| 90 | if( (f>spectrum_from) && (f<spectrum_to)) | ||
| 91 | tuner_dbg("mt2032 spurcheck triggered: %d\n",n1); | ||
| 92 | } while ( (f>(f2-spectrum_to)) || (n2>-5)); | ||
| 93 | n1++; | ||
| 94 | } while (n1<5); | ||
| 95 | |||
| 96 | return 1; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int mt2032_compute_freq(struct dvb_frontend *fe, | ||
| 100 | unsigned int rfin, | ||
| 101 | unsigned int if1, unsigned int if2, | ||
| 102 | unsigned int spectrum_from, | ||
| 103 | unsigned int spectrum_to, | ||
| 104 | unsigned char *buf, | ||
| 105 | int *ret_sel, | ||
| 106 | unsigned int xogc) //all in Hz | ||
| 107 | { | ||
| 108 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 109 | unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, | ||
| 110 | desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; | ||
| 111 | |||
| 112 | fref= 5250 *1000; //5.25MHz | ||
| 113 | desired_lo1=rfin+if1; | ||
| 114 | |||
| 115 | lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); | ||
| 116 | lo1n=lo1/8; | ||
| 117 | lo1a=lo1-(lo1n*8); | ||
| 118 | |||
| 119 | s=rfin/1000/1000+1090; | ||
| 120 | |||
| 121 | if(optimize_vco) { | ||
| 122 | if(s>1890) sel=0; | ||
| 123 | else if(s>1720) sel=1; | ||
| 124 | else if(s>1530) sel=2; | ||
| 125 | else if(s>1370) sel=3; | ||
| 126 | else sel=4; // >1090 | ||
| 127 | } | ||
| 128 | else { | ||
| 129 | if(s>1790) sel=0; // <1958 | ||
| 130 | else if(s>1617) sel=1; | ||
| 131 | else if(s>1449) sel=2; | ||
| 132 | else if(s>1291) sel=3; | ||
| 133 | else sel=4; // >1090 | ||
| 134 | } | ||
| 135 | *ret_sel=sel; | ||
| 136 | |||
| 137 | lo1freq=(lo1a+8*lo1n)*fref; | ||
| 138 | |||
| 139 | tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", | ||
| 140 | rfin,lo1,lo1n,lo1a,sel,lo1freq); | ||
| 141 | |||
| 142 | desired_lo2=lo1freq-rfin-if2; | ||
| 143 | lo2=(desired_lo2)/fref; | ||
| 144 | lo2n=lo2/8; | ||
| 145 | lo2a=lo2-(lo2n*8); | ||
| 146 | lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith | ||
| 147 | lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; | ||
| 148 | |||
| 149 | tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", | ||
| 150 | rfin,lo2,lo2n,lo2a,lo2num,lo2freq); | ||
| 151 | |||
| 152 | if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || | ||
| 153 | lo2n > 30) { | ||
| 154 | tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", | ||
| 155 | lo1a, lo1n, lo2a,lo2n); | ||
| 156 | return(-1); | ||
| 157 | } | ||
| 158 | |||
| 159 | mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); | ||
| 160 | // should recalculate lo1 (one step up/down) | ||
| 161 | |||
| 162 | // set up MT2032 register map for transfer over i2c | ||
| 163 | buf[0]=lo1n-1; | ||
| 164 | buf[1]=lo1a | (sel<<4); | ||
| 165 | buf[2]=0x86; // LOGC | ||
| 166 | buf[3]=0x0f; //reserved | ||
| 167 | buf[4]=0x1f; | ||
| 168 | buf[5]=(lo2n-1) | (lo2a<<5); | ||
| 169 | if(rfin >400*1000*1000) | ||
| 170 | buf[6]=0xe4; | ||
| 171 | else | ||
| 172 | buf[6]=0xf4; // set PKEN per rev 1.2 | ||
| 173 | buf[7]=8+xogc; | ||
| 174 | buf[8]=0xc3; //reserved | ||
| 175 | buf[9]=0x4e; //reserved | ||
| 176 | buf[10]=0xec; //reserved | ||
| 177 | buf[11]=(lo2num&0xff); | ||
| 178 | buf[12]=(lo2num>>8) |0x80; // Lo2RST | ||
| 179 | |||
| 180 | return 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | static int mt2032_check_lo_lock(struct dvb_frontend *fe) | ||
| 184 | { | ||
| 185 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 186 | int try,lock=0; | ||
| 187 | unsigned char buf[2]; | ||
| 188 | |||
| 189 | for(try=0;try<10;try++) { | ||
| 190 | buf[0]=0x0e; | ||
| 191 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
| 192 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
| 193 | tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); | ||
| 194 | lock=buf[0] &0x06; | ||
| 195 | |||
| 196 | if (lock==6) | ||
| 197 | break; | ||
| 198 | |||
| 199 | tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); | ||
| 200 | udelay(1000); | ||
| 201 | } | ||
| 202 | return lock; | ||
| 203 | } | ||
| 204 | |||
| 205 | static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) | ||
| 206 | { | ||
| 207 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 208 | unsigned char buf[2]; | ||
| 209 | int tad1; | ||
| 210 | |||
| 211 | buf[0]=0x0f; | ||
| 212 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
| 213 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
| 214 | tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); | ||
| 215 | tad1=buf[0]&0x07; | ||
| 216 | |||
| 217 | if(tad1 ==0) return lock; | ||
| 218 | if(tad1 ==1) return lock; | ||
| 219 | |||
| 220 | if(tad1==2) { | ||
| 221 | if(sel==0) | ||
| 222 | return lock; | ||
| 223 | else sel--; | ||
| 224 | } | ||
| 225 | else { | ||
| 226 | if(sel<4) | ||
| 227 | sel++; | ||
| 228 | else | ||
| 229 | return lock; | ||
| 230 | } | ||
| 231 | |||
| 232 | tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); | ||
| 233 | |||
| 234 | buf[0]=0x0f; | ||
| 235 | buf[1]=sel; | ||
| 236 | tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
| 237 | lock=mt2032_check_lo_lock(fe); | ||
| 238 | return lock; | ||
| 239 | } | ||
| 240 | |||
| 241 | |||
| 242 | static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, | ||
| 243 | unsigned int if1, unsigned int if2, | ||
| 244 | unsigned int from, unsigned int to) | ||
| 245 | { | ||
| 246 | unsigned char buf[21]; | ||
| 247 | int lint_try,ret,sel,lock=0; | ||
| 248 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 249 | |||
| 250 | tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", | ||
| 251 | rfin,if1,if2,from,to); | ||
| 252 | |||
| 253 | buf[0]=0; | ||
| 254 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
| 255 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); | ||
| 256 | |||
| 257 | buf[0]=0; | ||
| 258 | ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); | ||
| 259 | if (ret<0) | ||
| 260 | return; | ||
| 261 | |||
| 262 | // send only the relevant registers per Rev. 1.2 | ||
| 263 | buf[0]=0; | ||
| 264 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); | ||
| 265 | buf[5]=5; | ||
| 266 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); | ||
| 267 | buf[11]=11; | ||
| 268 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); | ||
| 269 | if(ret!=3) | ||
| 270 | tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); | ||
| 271 | |||
| 272 | // wait for PLLs to lock (per manual), retry LINT if not. | ||
| 273 | for(lint_try=0; lint_try<2; lint_try++) { | ||
| 274 | lock=mt2032_check_lo_lock(fe); | ||
| 275 | |||
| 276 | if(optimize_vco) | ||
| 277 | lock=mt2032_optimize_vco(fe,sel,lock); | ||
| 278 | if(lock==6) break; | ||
| 279 | |||
| 280 | tuner_dbg("mt2032: re-init PLLs by LINT\n"); | ||
| 281 | buf[0]=7; | ||
| 282 | buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs | ||
| 283 | tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
| 284 | mdelay(10); | ||
| 285 | buf[1]=8+priv->xogc; | ||
| 286 | tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
| 287 | } | ||
| 288 | |||
| 289 | if (lock!=6) | ||
| 290 | tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); | ||
| 291 | |||
| 292 | buf[0]=2; | ||
| 293 | buf[1]=0x20; // LOGC for optimal phase noise | ||
| 294 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
| 295 | if (ret!=2) | ||
| 296 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); | ||
| 297 | } | ||
| 298 | |||
| 299 | |||
| 300 | static int mt2032_set_tv_freq(struct dvb_frontend *fe, | ||
| 301 | struct analog_parameters *params) | ||
| 302 | { | ||
| 303 | int if2,from,to; | ||
| 304 | |||
| 305 | // signal bandwidth and picture carrier | ||
| 306 | if (params->std & V4L2_STD_525_60) { | ||
| 307 | // NTSC | ||
| 308 | from = 40750*1000; | ||
| 309 | to = 46750*1000; | ||
| 310 | if2 = 45750*1000; | ||
| 311 | } else { | ||
| 312 | // PAL | ||
| 313 | from = 32900*1000; | ||
| 314 | to = 39900*1000; | ||
| 315 | if2 = 38900*1000; | ||
| 316 | } | ||
| 317 | |||
| 318 | mt2032_set_if_freq(fe, params->frequency*62500, | ||
| 319 | 1090*1000*1000, if2, from, to); | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | static int mt2032_set_radio_freq(struct dvb_frontend *fe, | ||
| 325 | struct analog_parameters *params) | ||
| 326 | { | ||
| 327 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 328 | int if2; | ||
| 329 | |||
| 330 | if (params->std & V4L2_STD_525_60) { | ||
| 331 | tuner_dbg("pinnacle ntsc\n"); | ||
| 332 | if2 = 41300 * 1000; | ||
| 333 | } else { | ||
| 334 | tuner_dbg("pinnacle pal\n"); | ||
| 335 | if2 = 33300 * 1000; | ||
| 336 | } | ||
| 337 | |||
| 338 | // per Manual for FM tuning: first if center freq. 1085 MHz | ||
| 339 | mt2032_set_if_freq(fe, params->frequency * 125 / 2, | ||
| 340 | 1085*1000*1000,if2,if2,if2); | ||
| 341 | |||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | static int mt2032_set_params(struct dvb_frontend *fe, | ||
| 346 | struct analog_parameters *params) | ||
| 347 | { | ||
| 348 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 349 | int ret = -EINVAL; | ||
| 350 | |||
| 351 | switch (params->mode) { | ||
| 352 | case V4L2_TUNER_RADIO: | ||
| 353 | ret = mt2032_set_radio_freq(fe, params); | ||
| 354 | priv->frequency = params->frequency * 125 / 2; | ||
| 355 | break; | ||
| 356 | case V4L2_TUNER_ANALOG_TV: | ||
| 357 | case V4L2_TUNER_DIGITAL_TV: | ||
| 358 | ret = mt2032_set_tv_freq(fe, params); | ||
| 359 | priv->frequency = params->frequency * 62500; | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | |||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | |||
| 366 | static struct dvb_tuner_ops mt2032_tuner_ops = { | ||
| 367 | .set_analog_params = mt2032_set_params, | ||
| 368 | .release = microtune_release, | ||
| 369 | .get_frequency = microtune_get_frequency, | ||
| 370 | }; | ||
| 371 | |||
| 372 | // Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 | ||
| 373 | static int mt2032_init(struct dvb_frontend *fe) | ||
| 374 | { | ||
| 375 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 376 | unsigned char buf[21]; | ||
| 377 | int ret,xogc,xok=0; | ||
| 378 | |||
| 379 | // Initialize Registers per spec. | ||
| 380 | buf[1]=2; // Index to register 2 | ||
| 381 | buf[2]=0xff; | ||
| 382 | buf[3]=0x0f; | ||
| 383 | buf[4]=0x1f; | ||
| 384 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); | ||
| 385 | |||
| 386 | buf[5]=6; // Index register 6 | ||
| 387 | buf[6]=0xe4; | ||
| 388 | buf[7]=0x8f; | ||
| 389 | buf[8]=0xc3; | ||
| 390 | buf[9]=0x4e; | ||
| 391 | buf[10]=0xec; | ||
| 392 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); | ||
| 393 | |||
| 394 | buf[12]=13; // Index register 13 | ||
| 395 | buf[13]=0x32; | ||
| 396 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); | ||
| 397 | |||
| 398 | // Adjust XOGC (register 7), wait for XOK | ||
| 399 | xogc=7; | ||
| 400 | do { | ||
| 401 | tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); | ||
| 402 | mdelay(10); | ||
| 403 | buf[0]=0x0e; | ||
| 404 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
| 405 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
| 406 | xok=buf[0]&0x01; | ||
| 407 | tuner_dbg("mt2032: xok = 0x%02x\n",xok); | ||
| 408 | if (xok == 1) break; | ||
| 409 | |||
| 410 | xogc--; | ||
| 411 | tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); | ||
| 412 | if (xogc == 3) { | ||
| 413 | xogc=4; // min. 4 per spec | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | buf[0]=0x07; | ||
| 417 | buf[1]=0x88 + xogc; | ||
| 418 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
| 419 | if (ret!=2) | ||
| 420 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); | ||
| 421 | } while (xok != 1 ); | ||
| 422 | priv->xogc=xogc; | ||
| 423 | |||
| 424 | memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
| 425 | |||
| 426 | return(1); | ||
| 427 | } | ||
| 428 | |||
| 429 | static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) | ||
| 430 | { | ||
| 431 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 432 | unsigned char buf[2]; | ||
| 433 | int ret; | ||
| 434 | |||
| 435 | buf[0] = 6; | ||
| 436 | buf[1] = antenna ? 0x11 : 0x10; | ||
| 437 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
| 438 | tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); | ||
| 439 | } | ||
| 440 | |||
| 441 | static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) | ||
| 442 | { | ||
| 443 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 444 | unsigned int if1=1218*1000*1000; | ||
| 445 | unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; | ||
| 446 | int ret; | ||
| 447 | unsigned char buf[6]; | ||
| 448 | |||
| 449 | tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", | ||
| 450 | freq,if1,if2); | ||
| 451 | |||
| 452 | f_lo1=freq+if1; | ||
| 453 | f_lo1=(f_lo1/1000000)*1000000; | ||
| 454 | |||
| 455 | f_lo2=f_lo1-freq-if2; | ||
| 456 | f_lo2=(f_lo2/50000)*50000; | ||
| 457 | |||
| 458 | lo1=f_lo1/4000000; | ||
| 459 | lo2=f_lo2/4000000; | ||
| 460 | |||
| 461 | f_lo1_modulo= f_lo1-(lo1*4000000); | ||
| 462 | f_lo2_modulo= f_lo2-(lo2*4000000); | ||
| 463 | |||
| 464 | num1=4*f_lo1_modulo/4000000; | ||
| 465 | num2=4096*(f_lo2_modulo/1000)/4000; | ||
| 466 | |||
| 467 | // todo spurchecks | ||
| 468 | |||
| 469 | div1a=(lo1/12)-1; | ||
| 470 | div1b=lo1-(div1a+1)*12; | ||
| 471 | |||
| 472 | div2a=(lo2/8)-1; | ||
| 473 | div2b=lo2-(div2a+1)*8; | ||
| 474 | |||
| 475 | if (debug > 1) { | ||
| 476 | tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); | ||
| 477 | tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", | ||
| 478 | num1,num2,div1a,div1b,div2a,div2b); | ||
| 479 | } | ||
| 480 | |||
| 481 | buf[0]=1; | ||
| 482 | buf[1]= 4*div1b + num1; | ||
| 483 | if(freq<275*1000*1000) buf[1] = buf[1]|0x80; | ||
| 484 | |||
| 485 | buf[2]=div1a; | ||
| 486 | buf[3]=32*div2b + num2/256; | ||
| 487 | buf[4]=num2-(num2/256)*256; | ||
| 488 | buf[5]=div2a; | ||
| 489 | if(num2!=0) buf[5]=buf[5]|0x40; | ||
| 490 | |||
| 491 | if (debug > 1) { | ||
| 492 | int i; | ||
| 493 | tuner_dbg("bufs is: "); | ||
| 494 | for(i=0;i<6;i++) | ||
| 495 | printk("%x ",buf[i]); | ||
| 496 | printk("\n"); | ||
| 497 | } | ||
| 498 | |||
| 499 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); | ||
| 500 | if (ret!=6) | ||
| 501 | tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); | ||
| 502 | } | ||
| 503 | |||
| 504 | static int mt2050_set_tv_freq(struct dvb_frontend *fe, | ||
| 505 | struct analog_parameters *params) | ||
| 506 | { | ||
| 507 | unsigned int if2; | ||
| 508 | |||
| 509 | if (params->std & V4L2_STD_525_60) { | ||
| 510 | // NTSC | ||
| 511 | if2 = 45750*1000; | ||
| 512 | } else { | ||
| 513 | // PAL | ||
| 514 | if2 = 38900*1000; | ||
| 515 | } | ||
| 516 | if (V4L2_TUNER_DIGITAL_TV == params->mode) { | ||
| 517 | // DVB (pinnacle 300i) | ||
| 518 | if2 = 36150*1000; | ||
| 519 | } | ||
| 520 | mt2050_set_if_freq(fe, params->frequency*62500, if2); | ||
| 521 | mt2050_set_antenna(fe, tv_antenna); | ||
| 522 | |||
| 523 | return 0; | ||
| 524 | } | ||
| 525 | |||
| 526 | static int mt2050_set_radio_freq(struct dvb_frontend *fe, | ||
| 527 | struct analog_parameters *params) | ||
| 528 | { | ||
| 529 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 530 | int if2; | ||
| 531 | |||
| 532 | if (params->std & V4L2_STD_525_60) { | ||
| 533 | tuner_dbg("pinnacle ntsc\n"); | ||
| 534 | if2 = 41300 * 1000; | ||
| 535 | } else { | ||
| 536 | tuner_dbg("pinnacle pal\n"); | ||
| 537 | if2 = 33300 * 1000; | ||
| 538 | } | ||
| 539 | |||
| 540 | mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); | ||
| 541 | mt2050_set_antenna(fe, radio_antenna); | ||
| 542 | |||
| 543 | return 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | static int mt2050_set_params(struct dvb_frontend *fe, | ||
| 547 | struct analog_parameters *params) | ||
| 548 | { | ||
| 549 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 550 | int ret = -EINVAL; | ||
| 551 | |||
| 552 | switch (params->mode) { | ||
| 553 | case V4L2_TUNER_RADIO: | ||
| 554 | ret = mt2050_set_radio_freq(fe, params); | ||
| 555 | priv->frequency = params->frequency * 125 / 2; | ||
| 556 | break; | ||
| 557 | case V4L2_TUNER_ANALOG_TV: | ||
| 558 | case V4L2_TUNER_DIGITAL_TV: | ||
| 559 | ret = mt2050_set_tv_freq(fe, params); | ||
| 560 | priv->frequency = params->frequency * 62500; | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | |||
| 564 | return ret; | ||
| 565 | } | ||
| 566 | |||
| 567 | static struct dvb_tuner_ops mt2050_tuner_ops = { | ||
| 568 | .set_analog_params = mt2050_set_params, | ||
| 569 | .release = microtune_release, | ||
| 570 | .get_frequency = microtune_get_frequency, | ||
| 571 | }; | ||
| 572 | |||
| 573 | static int mt2050_init(struct dvb_frontend *fe) | ||
| 574 | { | ||
| 575 | struct microtune_priv *priv = fe->tuner_priv; | ||
| 576 | unsigned char buf[2]; | ||
| 577 | int ret; | ||
| 578 | |||
| 579 | buf[0]=6; | ||
| 580 | buf[1]=0x10; | ||
| 581 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power | ||
| 582 | |||
| 583 | buf[0]=0x0f; | ||
| 584 | buf[1]=0x0f; | ||
| 585 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo | ||
| 586 | |||
| 587 | buf[0]=0x0d; | ||
| 588 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
| 589 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
| 590 | |||
| 591 | tuner_dbg("mt2050: sro is %x\n",buf[0]); | ||
| 592 | |||
| 593 | memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
| 594 | |||
| 595 | return 0; | ||
| 596 | } | ||
| 597 | |||
| 598 | struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, | ||
| 599 | struct i2c_adapter* i2c_adap, | ||
| 600 | u8 i2c_addr) | ||
| 601 | { | ||
| 602 | struct microtune_priv *priv = NULL; | ||
| 603 | char *name; | ||
| 604 | unsigned char buf[21]; | ||
| 605 | int company_code; | ||
| 606 | |||
| 607 | priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); | ||
| 608 | if (priv == NULL) | ||
| 609 | return NULL; | ||
| 610 | fe->tuner_priv = priv; | ||
| 611 | |||
| 612 | priv->i2c_props.addr = i2c_addr; | ||
| 613 | priv->i2c_props.adap = i2c_adap; | ||
| 614 | priv->i2c_props.name = "mt20xx"; | ||
| 615 | |||
| 616 | //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ | ||
| 617 | |||
| 618 | memset(buf,0,sizeof(buf)); | ||
| 619 | |||
| 620 | name = "unknown"; | ||
| 621 | |||
| 622 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
| 623 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); | ||
| 624 | if (debug) { | ||
| 625 | int i; | ||
| 626 | tuner_dbg("MT20xx hexdump:"); | ||
| 627 | for(i=0;i<21;i++) { | ||
| 628 | printk(" %02x",buf[i]); | ||
| 629 | if(((i+1)%8)==0) printk(" "); | ||
| 630 | } | ||
| 631 | printk("\n"); | ||
| 632 | } | ||
| 633 | company_code = buf[0x11] << 8 | buf[0x12]; | ||
| 634 | tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", | ||
| 635 | company_code,buf[0x13],buf[0x14]); | ||
| 636 | |||
| 637 | |||
| 638 | if (buf[0x13] < ARRAY_SIZE(microtune_part) && | ||
| 639 | NULL != microtune_part[buf[0x13]]) | ||
| 640 | name = microtune_part[buf[0x13]]; | ||
| 641 | switch (buf[0x13]) { | ||
| 642 | case MT2032: | ||
| 643 | mt2032_init(fe); | ||
| 644 | break; | ||
| 645 | case MT2050: | ||
| 646 | mt2050_init(fe); | ||
| 647 | break; | ||
| 648 | default: | ||
| 649 | tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", | ||
| 650 | name); | ||
| 651 | return NULL; | ||
| 652 | } | ||
| 653 | |||
| 654 | strlcpy(fe->ops.tuner_ops.info.name, name, | ||
| 655 | sizeof(fe->ops.tuner_ops.info.name)); | ||
| 656 | tuner_info("microtune %s found, OK\n",name); | ||
| 657 | return fe; | ||
| 658 | } | ||
| 659 | |||
| 660 | EXPORT_SYMBOL_GPL(microtune_attach); | ||
| 661 | |||
| 662 | MODULE_DESCRIPTION("Microtune tuner driver"); | ||
| 663 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | ||
| 664 | MODULE_LICENSE("GPL"); | ||
| 665 | |||
| 666 | /* | ||
| 667 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 668 | * --------------------------------------------------------------------------- | ||
| 669 | * Local variables: | ||
| 670 | * c-basic-offset: 8 | ||
| 671 | * End: | ||
| 672 | */ | ||
diff --git a/drivers/media/common/tuners/mt20xx.h b/drivers/media/common/tuners/mt20xx.h new file mode 100644 index 00000000000..259553a2490 --- /dev/null +++ b/drivers/media/common/tuners/mt20xx.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or | ||
| 5 | (at your option) any later version. | ||
| 6 | |||
| 7 | This program is distributed in the hope that it will be useful, | ||
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | GNU General Public License for more details. | ||
| 11 | |||
| 12 | You should have received a copy of the GNU General Public License | ||
| 13 | along with this program; if not, write to the Free Software | ||
| 14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __MT20XX_H__ | ||
| 18 | #define __MT20XX_H__ | ||
| 19 | |||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include "dvb_frontend.h" | ||
| 22 | |||
| 23 | #if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) | ||
| 24 | extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, | ||
| 25 | struct i2c_adapter* i2c_adap, | ||
| 26 | u8 i2c_addr); | ||
| 27 | #else | ||
| 28 | static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, | ||
| 29 | struct i2c_adapter* i2c_adap, | ||
| 30 | u8 i2c_addr) | ||
| 31 | { | ||
| 32 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 33 | return NULL; | ||
| 34 | } | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #endif /* __MT20XX_H__ */ | ||
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c new file mode 100644 index 00000000000..a4f830bb25d --- /dev/null +++ b/drivers/media/common/tuners/mt2131.c | |||
| @@ -0,0 +1,315 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
| 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/module.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/dvb/frontend.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | |||
| 28 | #include "dvb_frontend.h" | ||
| 29 | |||
| 30 | #include "mt2131.h" | ||
| 31 | #include "mt2131_priv.h" | ||
| 32 | |||
| 33 | static int debug; | ||
| 34 | module_param(debug, int, 0644); | ||
| 35 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 36 | |||
| 37 | #define dprintk(level,fmt, arg...) if (debug >= level) \ | ||
| 38 | printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) | ||
| 39 | |||
| 40 | static u8 mt2131_config1[] = { | ||
| 41 | 0x01, | ||
| 42 | 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, | ||
| 43 | 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, | ||
| 44 | 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, | ||
| 45 | 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 | ||
| 46 | }; | ||
| 47 | |||
| 48 | static u8 mt2131_config2[] = { | ||
| 49 | 0x10, | ||
| 50 | 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 | ||
| 51 | }; | ||
| 52 | |||
| 53 | static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) | ||
| 54 | { | ||
| 55 | struct i2c_msg msg[2] = { | ||
| 56 | { .addr = priv->cfg->i2c_address, .flags = 0, | ||
| 57 | .buf = ®, .len = 1 }, | ||
| 58 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, | ||
| 59 | .buf = val, .len = 1 }, | ||
| 60 | }; | ||
| 61 | |||
| 62 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
| 63 | printk(KERN_WARNING "mt2131 I2C read failed\n"); | ||
| 64 | return -EREMOTEIO; | ||
| 65 | } | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) | ||
| 70 | { | ||
| 71 | u8 buf[2] = { reg, val }; | ||
| 72 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, | ||
| 73 | .buf = buf, .len = 2 }; | ||
| 74 | |||
| 75 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 76 | printk(KERN_WARNING "mt2131 I2C write failed\n"); | ||
| 77 | return -EREMOTEIO; | ||
| 78 | } | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) | ||
| 83 | { | ||
| 84 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, | ||
| 85 | .flags = 0, .buf = buf, .len = len }; | ||
| 86 | |||
| 87 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 88 | printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", | ||
| 89 | (int)len); | ||
| 90 | return -EREMOTEIO; | ||
| 91 | } | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static int mt2131_set_params(struct dvb_frontend *fe, | ||
| 96 | struct dvb_frontend_parameters *params) | ||
| 97 | { | ||
| 98 | struct mt2131_priv *priv; | ||
| 99 | int ret=0, i; | ||
| 100 | u32 freq; | ||
| 101 | u8 if_band_center; | ||
| 102 | u32 f_lo1, f_lo2; | ||
| 103 | u32 div1, num1, div2, num2; | ||
| 104 | u8 b[8]; | ||
| 105 | u8 lockval = 0; | ||
| 106 | |||
| 107 | priv = fe->tuner_priv; | ||
| 108 | if (fe->ops.info.type == FE_OFDM) | ||
| 109 | priv->bandwidth = params->u.ofdm.bandwidth; | ||
| 110 | else | ||
| 111 | priv->bandwidth = 0; | ||
| 112 | |||
| 113 | freq = params->frequency / 1000; // Hz -> kHz | ||
| 114 | dprintk(1, "%s() freq=%d\n", __func__, freq); | ||
| 115 | |||
| 116 | f_lo1 = freq + MT2131_IF1 * 1000; | ||
| 117 | f_lo1 = (f_lo1 / 250) * 250; | ||
| 118 | f_lo2 = f_lo1 - freq - MT2131_IF2; | ||
| 119 | |||
| 120 | priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; | ||
| 121 | |||
| 122 | /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ | ||
| 123 | num1 = f_lo1 * 64 / (MT2131_FREF / 128); | ||
| 124 | div1 = num1 / 8192; | ||
| 125 | num1 &= 0x1fff; | ||
| 126 | |||
| 127 | /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ | ||
| 128 | num2 = f_lo2 * 64 / (MT2131_FREF / 128); | ||
| 129 | div2 = num2 / 8192; | ||
| 130 | num2 &= 0x1fff; | ||
| 131 | |||
| 132 | if (freq <= 82500) if_band_center = 0x00; else | ||
| 133 | if (freq <= 137500) if_band_center = 0x01; else | ||
| 134 | if (freq <= 192500) if_band_center = 0x02; else | ||
| 135 | if (freq <= 247500) if_band_center = 0x03; else | ||
| 136 | if (freq <= 302500) if_band_center = 0x04; else | ||
| 137 | if (freq <= 357500) if_band_center = 0x05; else | ||
| 138 | if (freq <= 412500) if_band_center = 0x06; else | ||
| 139 | if (freq <= 467500) if_band_center = 0x07; else | ||
| 140 | if (freq <= 522500) if_band_center = 0x08; else | ||
| 141 | if (freq <= 577500) if_band_center = 0x09; else | ||
| 142 | if (freq <= 632500) if_band_center = 0x0A; else | ||
| 143 | if (freq <= 687500) if_band_center = 0x0B; else | ||
| 144 | if (freq <= 742500) if_band_center = 0x0C; else | ||
| 145 | if (freq <= 797500) if_band_center = 0x0D; else | ||
| 146 | if (freq <= 852500) if_band_center = 0x0E; else | ||
| 147 | if (freq <= 907500) if_band_center = 0x0F; else | ||
| 148 | if (freq <= 962500) if_band_center = 0x10; else | ||
| 149 | if (freq <= 1017500) if_band_center = 0x11; else | ||
| 150 | if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; | ||
| 151 | |||
| 152 | b[0] = 1; | ||
| 153 | b[1] = (num1 >> 5) & 0xFF; | ||
| 154 | b[2] = (num1 & 0x1F); | ||
| 155 | b[3] = div1; | ||
| 156 | b[4] = (num2 >> 5) & 0xFF; | ||
| 157 | b[5] = num2 & 0x1F; | ||
| 158 | b[6] = div2; | ||
| 159 | |||
| 160 | dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); | ||
| 161 | dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); | ||
| 162 | dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); | ||
| 163 | dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", | ||
| 164 | (int)div1, (int)num1, (int)div2, (int)num2); | ||
| 165 | dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", | ||
| 166 | (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], | ||
| 167 | (int)b[6]); | ||
| 168 | |||
| 169 | ret = mt2131_writeregs(priv,b,7); | ||
| 170 | if (ret < 0) | ||
| 171 | return ret; | ||
| 172 | |||
| 173 | mt2131_writereg(priv, 0x0b, if_band_center); | ||
| 174 | |||
| 175 | /* Wait for lock */ | ||
| 176 | i = 0; | ||
| 177 | do { | ||
| 178 | mt2131_readreg(priv, 0x08, &lockval); | ||
| 179 | if ((lockval & 0x88) == 0x88) | ||
| 180 | break; | ||
| 181 | msleep(4); | ||
| 182 | i++; | ||
| 183 | } while (i < 10); | ||
| 184 | |||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 189 | { | ||
| 190 | struct mt2131_priv *priv = fe->tuner_priv; | ||
| 191 | dprintk(1, "%s()\n", __func__); | ||
| 192 | *frequency = priv->frequency; | ||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 197 | { | ||
| 198 | struct mt2131_priv *priv = fe->tuner_priv; | ||
| 199 | dprintk(1, "%s()\n", __func__); | ||
| 200 | *bandwidth = priv->bandwidth; | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 205 | { | ||
| 206 | struct mt2131_priv *priv = fe->tuner_priv; | ||
| 207 | u8 lock_status = 0; | ||
| 208 | u8 afc_status = 0; | ||
| 209 | |||
| 210 | *status = 0; | ||
| 211 | |||
| 212 | mt2131_readreg(priv, 0x08, &lock_status); | ||
| 213 | if ((lock_status & 0x88) == 0x88) | ||
| 214 | *status = TUNER_STATUS_LOCKED; | ||
| 215 | |||
| 216 | mt2131_readreg(priv, 0x09, &afc_status); | ||
| 217 | dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", | ||
| 218 | __func__, lock_status, afc_status); | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int mt2131_init(struct dvb_frontend *fe) | ||
| 224 | { | ||
| 225 | struct mt2131_priv *priv = fe->tuner_priv; | ||
| 226 | int ret; | ||
| 227 | dprintk(1, "%s()\n", __func__); | ||
| 228 | |||
| 229 | if ((ret = mt2131_writeregs(priv, mt2131_config1, | ||
| 230 | sizeof(mt2131_config1))) < 0) | ||
| 231 | return ret; | ||
| 232 | |||
| 233 | mt2131_writereg(priv, 0x0b, 0x09); | ||
| 234 | mt2131_writereg(priv, 0x15, 0x47); | ||
| 235 | mt2131_writereg(priv, 0x07, 0xf2); | ||
| 236 | mt2131_writereg(priv, 0x0b, 0x01); | ||
| 237 | |||
| 238 | if ((ret = mt2131_writeregs(priv, mt2131_config2, | ||
| 239 | sizeof(mt2131_config2))) < 0) | ||
| 240 | return ret; | ||
| 241 | |||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int mt2131_release(struct dvb_frontend *fe) | ||
| 246 | { | ||
| 247 | dprintk(1, "%s()\n", __func__); | ||
| 248 | kfree(fe->tuner_priv); | ||
| 249 | fe->tuner_priv = NULL; | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static const struct dvb_tuner_ops mt2131_tuner_ops = { | ||
| 254 | .info = { | ||
| 255 | .name = "Microtune MT2131", | ||
| 256 | .frequency_min = 48000000, | ||
| 257 | .frequency_max = 860000000, | ||
| 258 | .frequency_step = 50000, | ||
| 259 | }, | ||
| 260 | |||
| 261 | .release = mt2131_release, | ||
| 262 | .init = mt2131_init, | ||
| 263 | |||
| 264 | .set_params = mt2131_set_params, | ||
| 265 | .get_frequency = mt2131_get_frequency, | ||
| 266 | .get_bandwidth = mt2131_get_bandwidth, | ||
| 267 | .get_status = mt2131_get_status | ||
| 268 | }; | ||
| 269 | |||
| 270 | struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, | ||
| 271 | struct i2c_adapter *i2c, | ||
| 272 | struct mt2131_config *cfg, u16 if1) | ||
| 273 | { | ||
| 274 | struct mt2131_priv *priv = NULL; | ||
| 275 | u8 id = 0; | ||
| 276 | |||
| 277 | dprintk(1, "%s()\n", __func__); | ||
| 278 | |||
| 279 | priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); | ||
| 280 | if (priv == NULL) | ||
| 281 | return NULL; | ||
| 282 | |||
| 283 | priv->cfg = cfg; | ||
| 284 | priv->bandwidth = 6000000; /* 6MHz */ | ||
| 285 | priv->i2c = i2c; | ||
| 286 | |||
| 287 | if (mt2131_readreg(priv, 0, &id) != 0) { | ||
| 288 | kfree(priv); | ||
| 289 | return NULL; | ||
| 290 | } | ||
| 291 | if ( (id != 0x3E) && (id != 0x3F) ) { | ||
| 292 | printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", | ||
| 293 | cfg->i2c_address); | ||
| 294 | kfree(priv); | ||
| 295 | return NULL; | ||
| 296 | } | ||
| 297 | |||
| 298 | printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", | ||
| 299 | cfg->i2c_address); | ||
| 300 | memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, | ||
| 301 | sizeof(struct dvb_tuner_ops)); | ||
| 302 | |||
| 303 | fe->tuner_priv = priv; | ||
| 304 | return fe; | ||
| 305 | } | ||
| 306 | EXPORT_SYMBOL(mt2131_attach); | ||
| 307 | |||
| 308 | MODULE_AUTHOR("Steven Toth"); | ||
| 309 | MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); | ||
| 310 | MODULE_LICENSE("GPL"); | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Local variables: | ||
| 314 | * c-basic-offset: 8 | ||
| 315 | */ | ||
diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h new file mode 100644 index 00000000000..6632de640df --- /dev/null +++ b/drivers/media/common/tuners/mt2131.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
| 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 | #ifndef __MT2131_H__ | ||
| 23 | #define __MT2131_H__ | ||
| 24 | |||
| 25 | struct dvb_frontend; | ||
| 26 | struct i2c_adapter; | ||
| 27 | |||
| 28 | struct mt2131_config { | ||
| 29 | u8 i2c_address; | ||
| 30 | u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ | ||
| 31 | }; | ||
| 32 | |||
| 33 | #if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) | ||
| 34 | extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, | ||
| 35 | struct i2c_adapter *i2c, | ||
| 36 | struct mt2131_config *cfg, | ||
| 37 | u16 if1); | ||
| 38 | #else | ||
| 39 | static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, | ||
| 40 | struct i2c_adapter *i2c, | ||
| 41 | struct mt2131_config *cfg, | ||
| 42 | u16 if1) | ||
| 43 | { | ||
| 44 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 45 | return NULL; | ||
| 46 | } | ||
| 47 | #endif /* CONFIG_MEDIA_TUNER_MT2131 */ | ||
| 48 | |||
| 49 | #endif /* __MT2131_H__ */ | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Local variables: | ||
| 53 | * c-basic-offset: 8 | ||
| 54 | */ | ||
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h new file mode 100644 index 00000000000..4e05a67e88c --- /dev/null +++ b/drivers/media/common/tuners/mt2131_priv.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
| 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 | #ifndef __MT2131_PRIV_H__ | ||
| 23 | #define __MT2131_PRIV_H__ | ||
| 24 | |||
| 25 | /* Regs */ | ||
| 26 | #define MT2131_PWR 0x07 | ||
| 27 | #define MT2131_UPC_1 0x0b | ||
| 28 | #define MT2131_AGC_RL 0x10 | ||
| 29 | #define MT2131_MISC_2 0x15 | ||
| 30 | |||
| 31 | /* frequency values in KHz */ | ||
| 32 | #define MT2131_IF1 1220 | ||
| 33 | #define MT2131_IF2 44000 | ||
| 34 | #define MT2131_FREF 16000 | ||
| 35 | |||
| 36 | struct mt2131_priv { | ||
| 37 | struct mt2131_config *cfg; | ||
| 38 | struct i2c_adapter *i2c; | ||
| 39 | |||
| 40 | u32 frequency; | ||
| 41 | u32 bandwidth; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #endif /* __MT2131_PRIV_H__ */ | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Local variables: | ||
| 48 | * c-basic-offset: 8 | ||
| 49 | */ | ||
diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c new file mode 100644 index 00000000000..25a8ea342c4 --- /dev/null +++ b/drivers/media/common/tuners/mt2266.c | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Olivier DANET <odanet@caramail.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 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/dvb/frontend.h> | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | |||
| 23 | #include "dvb_frontend.h" | ||
| 24 | #include "mt2266.h" | ||
| 25 | |||
| 26 | #define I2C_ADDRESS 0x60 | ||
| 27 | |||
| 28 | #define REG_PART_REV 0 | ||
| 29 | #define REG_TUNE 1 | ||
| 30 | #define REG_BAND 6 | ||
| 31 | #define REG_BANDWIDTH 8 | ||
| 32 | #define REG_LOCK 0x12 | ||
| 33 | |||
| 34 | #define PART_REV 0x85 | ||
| 35 | |||
| 36 | struct mt2266_priv { | ||
| 37 | struct mt2266_config *cfg; | ||
| 38 | struct i2c_adapter *i2c; | ||
| 39 | |||
| 40 | u32 frequency; | ||
| 41 | u32 bandwidth; | ||
| 42 | u8 band; | ||
| 43 | }; | ||
| 44 | |||
| 45 | #define MT2266_VHF 1 | ||
| 46 | #define MT2266_UHF 0 | ||
| 47 | |||
| 48 | /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ | ||
| 49 | |||
| 50 | static int debug; | ||
| 51 | module_param(debug, int, 0644); | ||
| 52 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 53 | |||
| 54 | #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) | ||
| 55 | |||
| 56 | // Reads a single register | ||
| 57 | static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) | ||
| 58 | { | ||
| 59 | struct i2c_msg msg[2] = { | ||
| 60 | { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | ||
| 61 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
| 62 | }; | ||
| 63 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
| 64 | printk(KERN_WARNING "MT2266 I2C read failed\n"); | ||
| 65 | return -EREMOTEIO; | ||
| 66 | } | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | // Writes a single register | ||
| 71 | static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) | ||
| 72 | { | ||
| 73 | u8 buf[2] = { reg, val }; | ||
| 74 | struct i2c_msg msg = { | ||
| 75 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 | ||
| 76 | }; | ||
| 77 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 78 | printk(KERN_WARNING "MT2266 I2C write failed\n"); | ||
| 79 | return -EREMOTEIO; | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | // Writes a set of consecutive registers | ||
| 85 | static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) | ||
| 86 | { | ||
| 87 | struct i2c_msg msg = { | ||
| 88 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len | ||
| 89 | }; | ||
| 90 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 91 | printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); | ||
| 92 | return -EREMOTEIO; | ||
| 93 | } | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | // Initialisation sequences | ||
| 98 | static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, | ||
| 99 | 0x00, 0x52, 0x99, 0x3f }; | ||
| 100 | |||
| 101 | static u8 mt2266_init2[] = { | ||
| 102 | 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, | ||
| 103 | 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, | ||
| 104 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, | ||
| 105 | 0xff, 0x00, 0x77, 0x0f, 0x2d | ||
| 106 | }; | ||
| 107 | |||
| 108 | static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, | ||
| 109 | 0x22, 0x22, 0x22, 0x22 }; | ||
| 110 | |||
| 111 | static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, | ||
| 112 | 0x32, 0x32, 0x32, 0x32 }; | ||
| 113 | |||
| 114 | static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, | ||
| 115 | 0xa7, 0xa7, 0xa7, 0xa7 }; | ||
| 116 | |||
| 117 | static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, | ||
| 118 | 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; | ||
| 119 | |||
| 120 | static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, | ||
| 121 | 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; | ||
| 122 | |||
| 123 | #define FREF 30000 // Quartz oscillator 30 MHz | ||
| 124 | |||
| 125 | static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
| 126 | { | ||
| 127 | struct mt2266_priv *priv; | ||
| 128 | int ret=0; | ||
| 129 | u32 freq; | ||
| 130 | u32 tune; | ||
| 131 | u8 lnaband; | ||
| 132 | u8 b[10]; | ||
| 133 | int i; | ||
| 134 | u8 band; | ||
| 135 | |||
| 136 | priv = fe->tuner_priv; | ||
| 137 | |||
| 138 | freq = params->frequency / 1000; // Hz -> kHz | ||
| 139 | if (freq < 470000 && freq > 230000) | ||
| 140 | return -EINVAL; /* Gap between VHF and UHF bands */ | ||
| 141 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
| 142 | priv->frequency = freq * 1000; | ||
| 143 | |||
| 144 | tune = 2 * freq * (8192/16) / (FREF/16); | ||
| 145 | band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; | ||
| 146 | if (band == MT2266_VHF) | ||
| 147 | tune *= 2; | ||
| 148 | |||
| 149 | switch (params->u.ofdm.bandwidth) { | ||
| 150 | case BANDWIDTH_6_MHZ: | ||
| 151 | mt2266_writeregs(priv, mt2266_init_6mhz, | ||
| 152 | sizeof(mt2266_init_6mhz)); | ||
| 153 | break; | ||
| 154 | case BANDWIDTH_7_MHZ: | ||
| 155 | mt2266_writeregs(priv, mt2266_init_7mhz, | ||
| 156 | sizeof(mt2266_init_7mhz)); | ||
| 157 | break; | ||
| 158 | case BANDWIDTH_8_MHZ: | ||
| 159 | default: | ||
| 160 | mt2266_writeregs(priv, mt2266_init_8mhz, | ||
| 161 | sizeof(mt2266_init_8mhz)); | ||
| 162 | break; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (band == MT2266_VHF && priv->band == MT2266_UHF) { | ||
| 166 | dprintk("Switch from UHF to VHF"); | ||
| 167 | mt2266_writereg(priv, 0x05, 0x04); | ||
| 168 | mt2266_writereg(priv, 0x19, 0x61); | ||
| 169 | mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); | ||
| 170 | } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { | ||
| 171 | dprintk("Switch from VHF to UHF"); | ||
| 172 | mt2266_writereg(priv, 0x05, 0x52); | ||
| 173 | mt2266_writereg(priv, 0x19, 0x61); | ||
| 174 | mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); | ||
| 175 | } | ||
| 176 | msleep(10); | ||
| 177 | |||
| 178 | if (freq <= 495000) | ||
| 179 | lnaband = 0xEE; | ||
| 180 | else if (freq <= 525000) | ||
| 181 | lnaband = 0xDD; | ||
| 182 | else if (freq <= 550000) | ||
| 183 | lnaband = 0xCC; | ||
| 184 | else if (freq <= 580000) | ||
| 185 | lnaband = 0xBB; | ||
| 186 | else if (freq <= 605000) | ||
| 187 | lnaband = 0xAA; | ||
| 188 | else if (freq <= 630000) | ||
| 189 | lnaband = 0x99; | ||
| 190 | else if (freq <= 655000) | ||
| 191 | lnaband = 0x88; | ||
| 192 | else if (freq <= 685000) | ||
| 193 | lnaband = 0x77; | ||
| 194 | else if (freq <= 710000) | ||
| 195 | lnaband = 0x66; | ||
| 196 | else if (freq <= 735000) | ||
| 197 | lnaband = 0x55; | ||
| 198 | else if (freq <= 765000) | ||
| 199 | lnaband = 0x44; | ||
| 200 | else if (freq <= 802000) | ||
| 201 | lnaband = 0x33; | ||
| 202 | else if (freq <= 840000) | ||
| 203 | lnaband = 0x22; | ||
| 204 | else | ||
| 205 | lnaband = 0x11; | ||
| 206 | |||
| 207 | b[0] = REG_TUNE; | ||
| 208 | b[1] = (tune >> 8) & 0x1F; | ||
| 209 | b[2] = tune & 0xFF; | ||
| 210 | b[3] = tune >> 13; | ||
| 211 | mt2266_writeregs(priv,b,4); | ||
| 212 | |||
| 213 | dprintk("set_parms: tune=%d band=%d %s", | ||
| 214 | (int) tune, (int) lnaband, | ||
| 215 | (band == MT2266_UHF) ? "UHF" : "VHF"); | ||
| 216 | dprintk("set_parms: [1..3]: %2x %2x %2x", | ||
| 217 | (int) b[1], (int) b[2], (int)b[3]); | ||
| 218 | |||
| 219 | if (band == MT2266_UHF) { | ||
| 220 | b[0] = 0x05; | ||
| 221 | b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; | ||
| 222 | b[2] = lnaband; | ||
| 223 | mt2266_writeregs(priv, b, 3); | ||
| 224 | } | ||
| 225 | |||
| 226 | /* Wait for pll lock or timeout */ | ||
| 227 | i = 0; | ||
| 228 | do { | ||
| 229 | mt2266_readreg(priv,REG_LOCK,b); | ||
| 230 | if (b[0] & 0x40) | ||
| 231 | break; | ||
| 232 | msleep(10); | ||
| 233 | i++; | ||
| 234 | } while (i<10); | ||
| 235 | dprintk("Lock when i=%i",(int)i); | ||
| 236 | |||
| 237 | if (band == MT2266_UHF && priv->band == MT2266_VHF) | ||
| 238 | mt2266_writereg(priv, 0x05, 0x62); | ||
| 239 | |||
| 240 | priv->band = band; | ||
| 241 | |||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | static void mt2266_calibrate(struct mt2266_priv *priv) | ||
| 246 | { | ||
| 247 | mt2266_writereg(priv, 0x11, 0x03); | ||
| 248 | mt2266_writereg(priv, 0x11, 0x01); | ||
| 249 | mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); | ||
| 250 | mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); | ||
| 251 | mt2266_writereg(priv, 0x33, 0x5e); | ||
| 252 | mt2266_writereg(priv, 0x10, 0x10); | ||
| 253 | mt2266_writereg(priv, 0x10, 0x00); | ||
| 254 | mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); | ||
| 255 | msleep(25); | ||
| 256 | mt2266_writereg(priv, 0x17, 0x6d); | ||
| 257 | mt2266_writereg(priv, 0x1c, 0x00); | ||
| 258 | msleep(75); | ||
| 259 | mt2266_writereg(priv, 0x17, 0x6d); | ||
| 260 | mt2266_writereg(priv, 0x1c, 0xff); | ||
| 261 | } | ||
| 262 | |||
| 263 | static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 264 | { | ||
| 265 | struct mt2266_priv *priv = fe->tuner_priv; | ||
| 266 | *frequency = priv->frequency; | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 271 | { | ||
| 272 | struct mt2266_priv *priv = fe->tuner_priv; | ||
| 273 | *bandwidth = priv->bandwidth; | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | static int mt2266_init(struct dvb_frontend *fe) | ||
| 278 | { | ||
| 279 | int ret; | ||
| 280 | struct mt2266_priv *priv = fe->tuner_priv; | ||
| 281 | ret = mt2266_writereg(priv, 0x17, 0x6d); | ||
| 282 | if (ret < 0) | ||
| 283 | return ret; | ||
| 284 | ret = mt2266_writereg(priv, 0x1c, 0xff); | ||
| 285 | if (ret < 0) | ||
| 286 | return ret; | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | static int mt2266_sleep(struct dvb_frontend *fe) | ||
| 291 | { | ||
| 292 | struct mt2266_priv *priv = fe->tuner_priv; | ||
| 293 | mt2266_writereg(priv, 0x17, 0x6d); | ||
| 294 | mt2266_writereg(priv, 0x1c, 0x00); | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | static int mt2266_release(struct dvb_frontend *fe) | ||
| 299 | { | ||
| 300 | kfree(fe->tuner_priv); | ||
| 301 | fe->tuner_priv = NULL; | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | static const struct dvb_tuner_ops mt2266_tuner_ops = { | ||
| 306 | .info = { | ||
| 307 | .name = "Microtune MT2266", | ||
| 308 | .frequency_min = 174000000, | ||
| 309 | .frequency_max = 862000000, | ||
| 310 | .frequency_step = 50000, | ||
| 311 | }, | ||
| 312 | .release = mt2266_release, | ||
| 313 | .init = mt2266_init, | ||
| 314 | .sleep = mt2266_sleep, | ||
| 315 | .set_params = mt2266_set_params, | ||
| 316 | .get_frequency = mt2266_get_frequency, | ||
| 317 | .get_bandwidth = mt2266_get_bandwidth | ||
| 318 | }; | ||
| 319 | |||
| 320 | struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) | ||
| 321 | { | ||
| 322 | struct mt2266_priv *priv = NULL; | ||
| 323 | u8 id = 0; | ||
| 324 | |||
| 325 | priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); | ||
| 326 | if (priv == NULL) | ||
| 327 | return NULL; | ||
| 328 | |||
| 329 | priv->cfg = cfg; | ||
| 330 | priv->i2c = i2c; | ||
| 331 | priv->band = MT2266_UHF; | ||
| 332 | |||
| 333 | if (mt2266_readreg(priv, 0, &id)) { | ||
| 334 | kfree(priv); | ||
| 335 | return NULL; | ||
| 336 | } | ||
| 337 | if (id != PART_REV) { | ||
| 338 | kfree(priv); | ||
| 339 | return NULL; | ||
| 340 | } | ||
| 341 | printk(KERN_INFO "MT2266: successfully identified\n"); | ||
| 342 | memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
| 343 | |||
| 344 | fe->tuner_priv = priv; | ||
| 345 | mt2266_calibrate(priv); | ||
| 346 | return fe; | ||
| 347 | } | ||
| 348 | EXPORT_SYMBOL(mt2266_attach); | ||
| 349 | |||
| 350 | MODULE_AUTHOR("Olivier DANET"); | ||
| 351 | MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); | ||
| 352 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/mt2266.h b/drivers/media/common/tuners/mt2266.h new file mode 100644 index 00000000000..4d083882d04 --- /dev/null +++ b/drivers/media/common/tuners/mt2266.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Olivier DANET <odanet@caramail.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 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef MT2266_H | ||
| 18 | #define MT2266_H | ||
| 19 | |||
| 20 | struct dvb_frontend; | ||
| 21 | struct i2c_adapter; | ||
| 22 | |||
| 23 | struct mt2266_config { | ||
| 24 | u8 i2c_address; | ||
| 25 | }; | ||
| 26 | |||
| 27 | #if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) | ||
| 28 | extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); | ||
| 29 | #else | ||
| 30 | static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) | ||
| 31 | { | ||
| 32 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 33 | return NULL; | ||
| 34 | } | ||
| 35 | #endif // CONFIG_MEDIA_TUNER_MT2266 | ||
| 36 | |||
| 37 | #endif | ||
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c new file mode 100644 index 00000000000..56fe75c94de --- /dev/null +++ b/drivers/media/common/tuners/mxl5005s.c | |||
| @@ -0,0 +1,4118 @@ | |||
| 1 | /* | ||
| 2 | MaxLinear MXL5005S VSB/QAM/DVBT tuner driver | ||
| 3 | |||
| 4 | Copyright (C) 2008 MaxLinear | ||
| 5 | Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> | ||
| 6 | Functions: | ||
| 7 | mxl5005s_reset() | ||
| 8 | mxl5005s_writereg() | ||
| 9 | mxl5005s_writeregs() | ||
| 10 | mxl5005s_init() | ||
| 11 | mxl5005s_reconfigure() | ||
| 12 | mxl5005s_AssignTunerMode() | ||
| 13 | mxl5005s_set_params() | ||
| 14 | mxl5005s_get_frequency() | ||
| 15 | mxl5005s_get_bandwidth() | ||
| 16 | mxl5005s_release() | ||
| 17 | mxl5005s_attach() | ||
| 18 | |||
| 19 | Copyright (C) 2008 Realtek | ||
| 20 | Copyright (C) 2008 Jan Hoogenraad | ||
| 21 | Functions: | ||
| 22 | mxl5005s_SetRfFreqHz() | ||
| 23 | |||
| 24 | This program is free software; you can redistribute it and/or modify | ||
| 25 | it under the terms of the GNU General Public License as published by | ||
| 26 | the Free Software Foundation; either version 2 of the License, or | ||
| 27 | (at your option) any later version. | ||
| 28 | |||
| 29 | This program is distributed in the hope that it will be useful, | ||
| 30 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 31 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 32 | GNU General Public License for more details. | ||
| 33 | |||
| 34 | You should have received a copy of the GNU General Public License | ||
| 35 | along with this program; if not, write to the Free Software | ||
| 36 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 37 | |||
| 38 | */ | ||
| 39 | |||
| 40 | /* | ||
| 41 | History of this driver (Steven Toth): | ||
| 42 | I was given a public release of a linux driver that included | ||
| 43 | support for the MaxLinear MXL5005S silicon tuner. Analysis of | ||
| 44 | the tuner driver showed clearly three things. | ||
| 45 | |||
| 46 | 1. The tuner driver didn't support the LinuxTV tuner API | ||
| 47 | so the code Realtek added had to be removed. | ||
| 48 | |||
| 49 | 2. A significant amount of the driver is reference driver code | ||
| 50 | from MaxLinear, I felt it was important to identify and | ||
| 51 | preserve this. | ||
| 52 | |||
| 53 | 3. New code has to be added to interface correctly with the | ||
| 54 | LinuxTV API, as a regular kernel module. | ||
| 55 | |||
| 56 | Other than the reference driver enum's, I've clearly marked | ||
| 57 | sections of the code and retained the copyright of the | ||
| 58 | respective owners. | ||
| 59 | */ | ||
| 60 | #include <linux/kernel.h> | ||
| 61 | #include <linux/init.h> | ||
| 62 | #include <linux/module.h> | ||
| 63 | #include <linux/string.h> | ||
| 64 | #include <linux/slab.h> | ||
| 65 | #include <linux/delay.h> | ||
| 66 | #include "dvb_frontend.h" | ||
| 67 | #include "mxl5005s.h" | ||
| 68 | |||
| 69 | static int debug; | ||
| 70 | |||
| 71 | #define dprintk(level, arg...) do { \ | ||
| 72 | if (level <= debug) \ | ||
| 73 | printk(arg); \ | ||
| 74 | } while (0) | ||
| 75 | |||
| 76 | #define TUNER_REGS_NUM 104 | ||
| 77 | #define INITCTRL_NUM 40 | ||
| 78 | |||
| 79 | #ifdef _MXL_PRODUCTION | ||
| 80 | #define CHCTRL_NUM 39 | ||
| 81 | #else | ||
| 82 | #define CHCTRL_NUM 36 | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #define MXLCTRL_NUM 189 | ||
| 86 | #define MASTER_CONTROL_ADDR 9 | ||
| 87 | |||
| 88 | /* Enumeration of Master Control Register State */ | ||
| 89 | enum master_control_state { | ||
| 90 | MC_LOAD_START = 1, | ||
| 91 | MC_POWER_DOWN, | ||
| 92 | MC_SYNTH_RESET, | ||
| 93 | MC_SEQ_OFF | ||
| 94 | }; | ||
| 95 | |||
| 96 | /* Enumeration of MXL5005 Tuner Modulation Type */ | ||
| 97 | enum { | ||
| 98 | MXL_DEFAULT_MODULATION = 0, | ||
| 99 | MXL_DVBT, | ||
| 100 | MXL_ATSC, | ||
| 101 | MXL_QAM, | ||
| 102 | MXL_ANALOG_CABLE, | ||
| 103 | MXL_ANALOG_OTA | ||
| 104 | }; | ||
| 105 | |||
| 106 | /* MXL5005 Tuner Register Struct */ | ||
| 107 | struct TunerReg { | ||
| 108 | u16 Reg_Num; /* Tuner Register Address */ | ||
| 109 | u16 Reg_Val; /* Current sw programmed value waiting to be written */ | ||
| 110 | }; | ||
| 111 | |||
| 112 | enum { | ||
| 113 | /* Initialization Control Names */ | ||
| 114 | DN_IQTN_AMP_CUT = 1, /* 1 */ | ||
| 115 | BB_MODE, /* 2 */ | ||
| 116 | BB_BUF, /* 3 */ | ||
| 117 | BB_BUF_OA, /* 4 */ | ||
| 118 | BB_ALPF_BANDSELECT, /* 5 */ | ||
| 119 | BB_IQSWAP, /* 6 */ | ||
| 120 | BB_DLPF_BANDSEL, /* 7 */ | ||
| 121 | RFSYN_CHP_GAIN, /* 8 */ | ||
| 122 | RFSYN_EN_CHP_HIGAIN, /* 9 */ | ||
| 123 | AGC_IF, /* 10 */ | ||
| 124 | AGC_RF, /* 11 */ | ||
| 125 | IF_DIVVAL, /* 12 */ | ||
| 126 | IF_VCO_BIAS, /* 13 */ | ||
| 127 | CHCAL_INT_MOD_IF, /* 14 */ | ||
| 128 | CHCAL_FRAC_MOD_IF, /* 15 */ | ||
| 129 | DRV_RES_SEL, /* 16 */ | ||
| 130 | I_DRIVER, /* 17 */ | ||
| 131 | EN_AAF, /* 18 */ | ||
| 132 | EN_3P, /* 19 */ | ||
| 133 | EN_AUX_3P, /* 20 */ | ||
| 134 | SEL_AAF_BAND, /* 21 */ | ||
| 135 | SEQ_ENCLK16_CLK_OUT, /* 22 */ | ||
| 136 | SEQ_SEL4_16B, /* 23 */ | ||
| 137 | XTAL_CAPSELECT, /* 24 */ | ||
| 138 | IF_SEL_DBL, /* 25 */ | ||
| 139 | RFSYN_R_DIV, /* 26 */ | ||
| 140 | SEQ_EXTSYNTHCALIF, /* 27 */ | ||
| 141 | SEQ_EXTDCCAL, /* 28 */ | ||
| 142 | AGC_EN_RSSI, /* 29 */ | ||
| 143 | RFA_ENCLKRFAGC, /* 30 */ | ||
| 144 | RFA_RSSI_REFH, /* 31 */ | ||
| 145 | RFA_RSSI_REF, /* 32 */ | ||
| 146 | RFA_RSSI_REFL, /* 33 */ | ||
| 147 | RFA_FLR, /* 34 */ | ||
| 148 | RFA_CEIL, /* 35 */ | ||
| 149 | SEQ_EXTIQFSMPULSE, /* 36 */ | ||
| 150 | OVERRIDE_1, /* 37 */ | ||
| 151 | BB_INITSTATE_DLPF_TUNE, /* 38 */ | ||
| 152 | TG_R_DIV, /* 39 */ | ||
| 153 | EN_CHP_LIN_B, /* 40 */ | ||
| 154 | |||
| 155 | /* Channel Change Control Names */ | ||
| 156 | DN_POLY = 51, /* 51 */ | ||
| 157 | DN_RFGAIN, /* 52 */ | ||
| 158 | DN_CAP_RFLPF, /* 53 */ | ||
| 159 | DN_EN_VHFUHFBAR, /* 54 */ | ||
| 160 | DN_GAIN_ADJUST, /* 55 */ | ||
| 161 | DN_IQTNBUF_AMP, /* 56 */ | ||
| 162 | DN_IQTNGNBFBIAS_BST, /* 57 */ | ||
| 163 | RFSYN_EN_OUTMUX, /* 58 */ | ||
| 164 | RFSYN_SEL_VCO_OUT, /* 59 */ | ||
| 165 | RFSYN_SEL_VCO_HI, /* 60 */ | ||
| 166 | RFSYN_SEL_DIVM, /* 61 */ | ||
| 167 | RFSYN_RF_DIV_BIAS, /* 62 */ | ||
| 168 | DN_SEL_FREQ, /* 63 */ | ||
| 169 | RFSYN_VCO_BIAS, /* 64 */ | ||
| 170 | CHCAL_INT_MOD_RF, /* 65 */ | ||
| 171 | CHCAL_FRAC_MOD_RF, /* 66 */ | ||
| 172 | RFSYN_LPF_R, /* 67 */ | ||
| 173 | CHCAL_EN_INT_RF, /* 68 */ | ||
| 174 | TG_LO_DIVVAL, /* 69 */ | ||
| 175 | TG_LO_SELVAL, /* 70 */ | ||
| 176 | TG_DIV_VAL, /* 71 */ | ||
| 177 | TG_VCO_BIAS, /* 72 */ | ||
| 178 | SEQ_EXTPOWERUP, /* 73 */ | ||
| 179 | OVERRIDE_2, /* 74 */ | ||
| 180 | OVERRIDE_3, /* 75 */ | ||
| 181 | OVERRIDE_4, /* 76 */ | ||
| 182 | SEQ_FSM_PULSE, /* 77 */ | ||
| 183 | GPIO_4B, /* 78 */ | ||
| 184 | GPIO_3B, /* 79 */ | ||
| 185 | GPIO_4, /* 80 */ | ||
| 186 | GPIO_3, /* 81 */ | ||
| 187 | GPIO_1B, /* 82 */ | ||
| 188 | DAC_A_ENABLE, /* 83 */ | ||
| 189 | DAC_B_ENABLE, /* 84 */ | ||
| 190 | DAC_DIN_A, /* 85 */ | ||
| 191 | DAC_DIN_B, /* 86 */ | ||
| 192 | #ifdef _MXL_PRODUCTION | ||
| 193 | RFSYN_EN_DIV, /* 87 */ | ||
| 194 | RFSYN_DIVM, /* 88 */ | ||
| 195 | DN_BYPASS_AGC_I2C /* 89 */ | ||
| 196 | #endif | ||
| 197 | }; | ||
| 198 | |||
| 199 | /* | ||
| 200 | * The following context is source code provided by MaxLinear. | ||
| 201 | * MaxLinear source code - Common_MXL.h (?) | ||
| 202 | */ | ||
| 203 | |||
| 204 | /* Constants */ | ||
| 205 | #define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104 | ||
| 206 | #define MXL5005S_LATCH_BYTE 0xfe | ||
| 207 | |||
| 208 | /* Register address, MSB, and LSB */ | ||
| 209 | #define MXL5005S_BB_IQSWAP_ADDR 59 | ||
| 210 | #define MXL5005S_BB_IQSWAP_MSB 0 | ||
| 211 | #define MXL5005S_BB_IQSWAP_LSB 0 | ||
| 212 | |||
| 213 | #define MXL5005S_BB_DLPF_BANDSEL_ADDR 53 | ||
| 214 | #define MXL5005S_BB_DLPF_BANDSEL_MSB 4 | ||
| 215 | #define MXL5005S_BB_DLPF_BANDSEL_LSB 3 | ||
| 216 | |||
| 217 | /* Standard modes */ | ||
| 218 | enum { | ||
| 219 | MXL5005S_STANDARD_DVBT, | ||
| 220 | MXL5005S_STANDARD_ATSC, | ||
| 221 | }; | ||
| 222 | #define MXL5005S_STANDARD_MODE_NUM 2 | ||
| 223 | |||
| 224 | /* Bandwidth modes */ | ||
| 225 | enum { | ||
| 226 | MXL5005S_BANDWIDTH_6MHZ = 6000000, | ||
| 227 | MXL5005S_BANDWIDTH_7MHZ = 7000000, | ||
| 228 | MXL5005S_BANDWIDTH_8MHZ = 8000000, | ||
| 229 | }; | ||
| 230 | #define MXL5005S_BANDWIDTH_MODE_NUM 3 | ||
| 231 | |||
| 232 | /* MXL5005 Tuner Control Struct */ | ||
| 233 | struct TunerControl { | ||
| 234 | u16 Ctrl_Num; /* Control Number */ | ||
| 235 | u16 size; /* Number of bits to represent Value */ | ||
| 236 | u16 addr[25]; /* Array of Tuner Register Address for each bit pos */ | ||
| 237 | u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */ | ||
| 238 | u16 val[25]; /* Binary representation of Value */ | ||
| 239 | }; | ||
| 240 | |||
| 241 | /* MXL5005 Tuner Struct */ | ||
| 242 | struct mxl5005s_state { | ||
| 243 | u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */ | ||
| 244 | u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */ | ||
| 245 | u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */ | ||
| 246 | u32 IF_OUT; /* Desired IF Out Frequency */ | ||
| 247 | u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */ | ||
| 248 | u32 RF_IN; /* RF Input Frequency */ | ||
| 249 | u32 Fxtal; /* XTAL Frequency */ | ||
| 250 | u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */ | ||
| 251 | u16 TOP; /* Value: take over point */ | ||
| 252 | u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */ | ||
| 253 | u8 DIV_OUT; /* 4MHz or 16MHz */ | ||
| 254 | u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */ | ||
| 255 | u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */ | ||
| 256 | |||
| 257 | /* Modulation Type; */ | ||
| 258 | /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ | ||
| 259 | u8 Mod_Type; | ||
| 260 | |||
| 261 | /* Tracking Filter Type */ | ||
| 262 | /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ | ||
| 263 | u8 TF_Type; | ||
| 264 | |||
| 265 | /* Calculated Settings */ | ||
| 266 | u32 RF_LO; /* Synth RF LO Frequency */ | ||
| 267 | u32 IF_LO; /* Synth IF LO Frequency */ | ||
| 268 | u32 TG_LO; /* Synth TG_LO Frequency */ | ||
| 269 | |||
| 270 | /* Pointers to ControlName Arrays */ | ||
| 271 | u16 Init_Ctrl_Num; /* Number of INIT Control Names */ | ||
| 272 | struct TunerControl | ||
| 273 | Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */ | ||
| 274 | |||
| 275 | u16 CH_Ctrl_Num; /* Number of CH Control Names */ | ||
| 276 | struct TunerControl | ||
| 277 | CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */ | ||
| 278 | |||
| 279 | u16 MXL_Ctrl_Num; /* Number of MXL Control Names */ | ||
| 280 | struct TunerControl | ||
| 281 | MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */ | ||
| 282 | |||
| 283 | /* Pointer to Tuner Register Array */ | ||
| 284 | u16 TunerRegs_Num; /* Number of Tuner Registers */ | ||
| 285 | struct TunerReg | ||
| 286 | TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */ | ||
| 287 | |||
| 288 | /* Linux driver framework specific */ | ||
| 289 | struct mxl5005s_config *config; | ||
| 290 | struct dvb_frontend *frontend; | ||
| 291 | struct i2c_adapter *i2c; | ||
| 292 | |||
| 293 | /* Cache values */ | ||
| 294 | u32 current_mode; | ||
| 295 | |||
| 296 | }; | ||
| 297 | |||
| 298 | static u16 MXL_GetMasterControl(u8 *MasterReg, int state); | ||
| 299 | static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value); | ||
| 300 | static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value); | ||
| 301 | static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, | ||
| 302 | u8 bitVal); | ||
| 303 | static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, | ||
| 304 | u8 *RegVal, int *count); | ||
| 305 | static u32 MXL_Ceiling(u32 value, u32 resolution); | ||
| 306 | static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal); | ||
| 307 | static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, | ||
| 308 | u32 value, u16 controlGroup); | ||
| 309 | static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); | ||
| 310 | static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, | ||
| 311 | u8 *RegVal, int *count); | ||
| 312 | static u32 MXL_GetXtalInt(u32 Xtal_Freq); | ||
| 313 | static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); | ||
| 314 | static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); | ||
| 315 | static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); | ||
| 316 | static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, | ||
| 317 | u8 *RegVal, int *count); | ||
| 318 | static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, | ||
| 319 | u8 *datatable, u8 len); | ||
| 320 | static u16 MXL_IFSynthInit(struct dvb_frontend *fe); | ||
| 321 | static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, | ||
| 322 | u32 bandwidth); | ||
| 323 | static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, | ||
| 324 | u32 bandwidth); | ||
| 325 | |||
| 326 | /* ---------------------------------------------------------------- | ||
| 327 | * Begin: Custom code salvaged from the Realtek driver. | ||
| 328 | * Copyright (C) 2008 Realtek | ||
| 329 | * Copyright (C) 2008 Jan Hoogenraad | ||
| 330 | * This code is placed under the terms of the GNU General Public License | ||
| 331 | * | ||
| 332 | * Released by Realtek under GPLv2. | ||
| 333 | * Thanks to Realtek for a lot of support we received ! | ||
| 334 | * | ||
| 335 | * Revision: 080314 - original version | ||
| 336 | */ | ||
| 337 | |||
| 338 | static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz) | ||
| 339 | { | ||
| 340 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 341 | unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
| 342 | unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
| 343 | int TableLen; | ||
| 344 | |||
| 345 | u32 IfDivval = 0; | ||
| 346 | unsigned char MasterControlByte; | ||
| 347 | |||
| 348 | dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz); | ||
| 349 | |||
| 350 | /* Set MxL5005S tuner RF frequency according to example code. */ | ||
| 351 | |||
| 352 | /* Tuner RF frequency setting stage 0 */ | ||
| 353 | MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); | ||
| 354 | AddrTable[0] = MASTER_CONTROL_ADDR; | ||
| 355 | ByteTable[0] |= state->config->AgcMasterByte; | ||
| 356 | |||
| 357 | mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); | ||
| 358 | |||
| 359 | /* Tuner RF frequency setting stage 1 */ | ||
| 360 | MXL_TuneRF(fe, RfFreqHz); | ||
| 361 | |||
| 362 | MXL_ControlRead(fe, IF_DIVVAL, &IfDivval); | ||
| 363 | |||
| 364 | MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0); | ||
| 365 | MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1); | ||
| 366 | MXL_ControlWrite(fe, IF_DIVVAL, 8); | ||
| 367 | MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen); | ||
| 368 | |||
| 369 | MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); | ||
| 370 | AddrTable[TableLen] = MASTER_CONTROL_ADDR ; | ||
| 371 | ByteTable[TableLen] = MasterControlByte | | ||
| 372 | state->config->AgcMasterByte; | ||
| 373 | TableLen += 1; | ||
| 374 | |||
| 375 | mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); | ||
| 376 | |||
| 377 | /* Wait 30 ms. */ | ||
| 378 | msleep(150); | ||
| 379 | |||
| 380 | /* Tuner RF frequency setting stage 2 */ | ||
| 381 | MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1); | ||
| 382 | MXL_ControlWrite(fe, IF_DIVVAL, IfDivval); | ||
| 383 | MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen); | ||
| 384 | |||
| 385 | MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); | ||
| 386 | AddrTable[TableLen] = MASTER_CONTROL_ADDR ; | ||
| 387 | ByteTable[TableLen] = MasterControlByte | | ||
| 388 | state->config->AgcMasterByte ; | ||
| 389 | TableLen += 1; | ||
| 390 | |||
| 391 | mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); | ||
| 392 | |||
| 393 | msleep(100); | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | /* End: Custom code taken from the Realtek driver */ | ||
| 398 | |||
| 399 | /* ---------------------------------------------------------------- | ||
| 400 | * Begin: Reference driver code found in the Realtek driver. | ||
| 401 | * Copyright (C) 2008 MaxLinear | ||
| 402 | */ | ||
| 403 | static u16 MXL5005_RegisterInit(struct dvb_frontend *fe) | ||
| 404 | { | ||
| 405 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 406 | state->TunerRegs_Num = TUNER_REGS_NUM ; | ||
| 407 | |||
| 408 | state->TunerRegs[0].Reg_Num = 9 ; | ||
| 409 | state->TunerRegs[0].Reg_Val = 0x40 ; | ||
| 410 | |||
| 411 | state->TunerRegs[1].Reg_Num = 11 ; | ||
| 412 | state->TunerRegs[1].Reg_Val = 0x19 ; | ||
| 413 | |||
| 414 | state->TunerRegs[2].Reg_Num = 12 ; | ||
| 415 | state->TunerRegs[2].Reg_Val = 0x60 ; | ||
| 416 | |||
| 417 | state->TunerRegs[3].Reg_Num = 13 ; | ||
| 418 | state->TunerRegs[3].Reg_Val = 0x00 ; | ||
| 419 | |||
| 420 | state->TunerRegs[4].Reg_Num = 14 ; | ||
| 421 | state->TunerRegs[4].Reg_Val = 0x00 ; | ||
| 422 | |||
| 423 | state->TunerRegs[5].Reg_Num = 15 ; | ||
| 424 | state->TunerRegs[5].Reg_Val = 0xC0 ; | ||
| 425 | |||
| 426 | state->TunerRegs[6].Reg_Num = 16 ; | ||
| 427 | state->TunerRegs[6].Reg_Val = 0x00 ; | ||
| 428 | |||
| 429 | state->TunerRegs[7].Reg_Num = 17 ; | ||
| 430 | state->TunerRegs[7].Reg_Val = 0x00 ; | ||
| 431 | |||
| 432 | state->TunerRegs[8].Reg_Num = 18 ; | ||
| 433 | state->TunerRegs[8].Reg_Val = 0x00 ; | ||
| 434 | |||
| 435 | state->TunerRegs[9].Reg_Num = 19 ; | ||
| 436 | state->TunerRegs[9].Reg_Val = 0x34 ; | ||
| 437 | |||
| 438 | state->TunerRegs[10].Reg_Num = 21 ; | ||
| 439 | state->TunerRegs[10].Reg_Val = 0x00 ; | ||
| 440 | |||
| 441 | state->TunerRegs[11].Reg_Num = 22 ; | ||
| 442 | state->TunerRegs[11].Reg_Val = 0x6B ; | ||
| 443 | |||
| 444 | state->TunerRegs[12].Reg_Num = 23 ; | ||
| 445 | state->TunerRegs[12].Reg_Val = 0x35 ; | ||
| 446 | |||
| 447 | state->TunerRegs[13].Reg_Num = 24 ; | ||
| 448 | state->TunerRegs[13].Reg_Val = 0x70 ; | ||
| 449 | |||
| 450 | state->TunerRegs[14].Reg_Num = 25 ; | ||
| 451 | state->TunerRegs[14].Reg_Val = 0x3E ; | ||
| 452 | |||
| 453 | state->TunerRegs[15].Reg_Num = 26 ; | ||
| 454 | state->TunerRegs[15].Reg_Val = 0x82 ; | ||
| 455 | |||
| 456 | state->TunerRegs[16].Reg_Num = 31 ; | ||
| 457 | state->TunerRegs[16].Reg_Val = 0x00 ; | ||
| 458 | |||
| 459 | state->TunerRegs[17].Reg_Num = 32 ; | ||
| 460 | state->TunerRegs[17].Reg_Val = 0x40 ; | ||
| 461 | |||
| 462 | state->TunerRegs[18].Reg_Num = 33 ; | ||
| 463 | state->TunerRegs[18].Reg_Val = 0x53 ; | ||
| 464 | |||
| 465 | state->TunerRegs[19].Reg_Num = 34 ; | ||
| 466 | state->TunerRegs[19].Reg_Val = 0x81 ; | ||
| 467 | |||
| 468 | state->TunerRegs[20].Reg_Num = 35 ; | ||
| 469 | state->TunerRegs[20].Reg_Val = 0xC9 ; | ||
| 470 | |||
| 471 | state->TunerRegs[21].Reg_Num = 36 ; | ||
| 472 | state->TunerRegs[21].Reg_Val = 0x01 ; | ||
| 473 | |||
| 474 | state->TunerRegs[22].Reg_Num = 37 ; | ||
| 475 | state->TunerRegs[22].Reg_Val = 0x00 ; | ||
| 476 | |||
| 477 | state->TunerRegs[23].Reg_Num = 41 ; | ||
| 478 | state->TunerRegs[23].Reg_Val = 0x00 ; | ||
| 479 | |||
| 480 | state->TunerRegs[24].Reg_Num = 42 ; | ||
| 481 | state->TunerRegs[24].Reg_Val = 0xF8 ; | ||
| 482 | |||
| 483 | state->TunerRegs[25].Reg_Num = 43 ; | ||
| 484 | state->TunerRegs[25].Reg_Val = 0x43 ; | ||
| 485 | |||
| 486 | state->TunerRegs[26].Reg_Num = 44 ; | ||
| 487 | state->TunerRegs[26].Reg_Val = 0x20 ; | ||
| 488 | |||
| 489 | state->TunerRegs[27].Reg_Num = 45 ; | ||
| 490 | state->TunerRegs[27].Reg_Val = 0x80 ; | ||
| 491 | |||
| 492 | state->TunerRegs[28].Reg_Num = 46 ; | ||
| 493 | state->TunerRegs[28].Reg_Val = 0x88 ; | ||
| 494 | |||
| 495 | state->TunerRegs[29].Reg_Num = 47 ; | ||
| 496 | state->TunerRegs[29].Reg_Val = 0x86 ; | ||
| 497 | |||
| 498 | state->TunerRegs[30].Reg_Num = 48 ; | ||
| 499 | state->TunerRegs[30].Reg_Val = 0x00 ; | ||
| 500 | |||
| 501 | state->TunerRegs[31].Reg_Num = 49 ; | ||
| 502 | state->TunerRegs[31].Reg_Val = 0x00 ; | ||
| 503 | |||
| 504 | state->TunerRegs[32].Reg_Num = 53 ; | ||
| 505 | state->TunerRegs[32].Reg_Val = 0x94 ; | ||
| 506 | |||
| 507 | state->TunerRegs[33].Reg_Num = 54 ; | ||
| 508 | state->TunerRegs[33].Reg_Val = 0xFA ; | ||
| 509 | |||
| 510 | state->TunerRegs[34].Reg_Num = 55 ; | ||
| 511 | state->TunerRegs[34].Reg_Val = 0x92 ; | ||
| 512 | |||
| 513 | state->TunerRegs[35].Reg_Num = 56 ; | ||
| 514 | state->TunerRegs[35].Reg_Val = 0x80 ; | ||
| 515 | |||
| 516 | state->TunerRegs[36].Reg_Num = 57 ; | ||
| 517 | state->TunerRegs[36].Reg_Val = 0x41 ; | ||
| 518 | |||
| 519 | state->TunerRegs[37].Reg_Num = 58 ; | ||
| 520 | state->TunerRegs[37].Reg_Val = 0xDB ; | ||
| 521 | |||
| 522 | state->TunerRegs[38].Reg_Num = 59 ; | ||
| 523 | state->TunerRegs[38].Reg_Val = 0x00 ; | ||
| 524 | |||
| 525 | state->TunerRegs[39].Reg_Num = 60 ; | ||
| 526 | state->TunerRegs[39].Reg_Val = 0x00 ; | ||
| 527 | |||
| 528 | state->TunerRegs[40].Reg_Num = 61 ; | ||
| 529 | state->TunerRegs[40].Reg_Val = 0x00 ; | ||
| 530 | |||
| 531 | state->TunerRegs[41].Reg_Num = 62 ; | ||
| 532 | state->TunerRegs[41].Reg_Val = 0x00 ; | ||
| 533 | |||
| 534 | state->TunerRegs[42].Reg_Num = 65 ; | ||
| 535 | state->TunerRegs[42].Reg_Val = 0xF8 ; | ||
| 536 | |||
| 537 | state->TunerRegs[43].Reg_Num = 66 ; | ||
| 538 | state->TunerRegs[43].Reg_Val = 0xE4 ; | ||
| 539 | |||
| 540 | state->TunerRegs[44].Reg_Num = 67 ; | ||
| 541 | state->TunerRegs[44].Reg_Val = 0x90 ; | ||
| 542 | |||
| 543 | state->TunerRegs[45].Reg_Num = 68 ; | ||
| 544 | state->TunerRegs[45].Reg_Val = 0xC0 ; | ||
| 545 | |||
| 546 | state->TunerRegs[46].Reg_Num = 69 ; | ||
| 547 | state->TunerRegs[46].Reg_Val = 0x01 ; | ||
| 548 | |||
| 549 | state->TunerRegs[47].Reg_Num = 70 ; | ||
| 550 | state->TunerRegs[47].Reg_Val = 0x50 ; | ||
| 551 | |||
| 552 | state->TunerRegs[48].Reg_Num = 71 ; | ||
| 553 | state->TunerRegs[48].Reg_Val = 0x06 ; | ||
| 554 | |||
| 555 | state->TunerRegs[49].Reg_Num = 72 ; | ||
| 556 | state->TunerRegs[49].Reg_Val = 0x00 ; | ||
| 557 | |||
| 558 | state->TunerRegs[50].Reg_Num = 73 ; | ||
| 559 | state->TunerRegs[50].Reg_Val = 0x20 ; | ||
| 560 | |||
| 561 | state->TunerRegs[51].Reg_Num = 76 ; | ||
| 562 | state->TunerRegs[51].Reg_Val = 0xBB ; | ||
| 563 | |||
| 564 | state->TunerRegs[52].Reg_Num = 77 ; | ||
| 565 | state->TunerRegs[52].Reg_Val = 0x13 ; | ||
| 566 | |||
| 567 | state->TunerRegs[53].Reg_Num = 81 ; | ||
| 568 | state->TunerRegs[53].Reg_Val = 0x04 ; | ||
| 569 | |||
| 570 | state->TunerRegs[54].Reg_Num = 82 ; | ||
| 571 | state->TunerRegs[54].Reg_Val = 0x75 ; | ||
| 572 | |||
| 573 | state->TunerRegs[55].Reg_Num = 83 ; | ||
| 574 | state->TunerRegs[55].Reg_Val = 0x00 ; | ||
| 575 | |||
| 576 | state->TunerRegs[56].Reg_Num = 84 ; | ||
| 577 | state->TunerRegs[56].Reg_Val = 0x00 ; | ||
| 578 | |||
| 579 | state->TunerRegs[57].Reg_Num = 85 ; | ||
| 580 | state->TunerRegs[57].Reg_Val = 0x00 ; | ||
| 581 | |||
| 582 | state->TunerRegs[58].Reg_Num = 91 ; | ||
| 583 | state->TunerRegs[58].Reg_Val = 0x70 ; | ||
| 584 | |||
| 585 | state->TunerRegs[59].Reg_Num = 92 ; | ||
| 586 | state->TunerRegs[59].Reg_Val = 0x00 ; | ||
| 587 | |||
| 588 | state->TunerRegs[60].Reg_Num = 93 ; | ||
| 589 | state->TunerRegs[60].Reg_Val = 0x00 ; | ||
| 590 | |||
| 591 | state->TunerRegs[61].Reg_Num = 94 ; | ||
| 592 | state->TunerRegs[61].Reg_Val = 0x00 ; | ||
| 593 | |||
| 594 | state->TunerRegs[62].Reg_Num = 95 ; | ||
| 595 | state->TunerRegs[62].Reg_Val = 0x0C ; | ||
| 596 | |||
| 597 | state->TunerRegs[63].Reg_Num = 96 ; | ||
| 598 | state->TunerRegs[63].Reg_Val = 0x00 ; | ||
| 599 | |||
| 600 | state->TunerRegs[64].Reg_Num = 97 ; | ||
| 601 | state->TunerRegs[64].Reg_Val = 0x00 ; | ||
| 602 | |||
| 603 | state->TunerRegs[65].Reg_Num = 98 ; | ||
| 604 | state->TunerRegs[65].Reg_Val = 0xE2 ; | ||
| 605 | |||
| 606 | state->TunerRegs[66].Reg_Num = 99 ; | ||
| 607 | state->TunerRegs[66].Reg_Val = 0x00 ; | ||
| 608 | |||
| 609 | state->TunerRegs[67].Reg_Num = 100 ; | ||
| 610 | state->TunerRegs[67].Reg_Val = 0x00 ; | ||
| 611 | |||
| 612 | state->TunerRegs[68].Reg_Num = 101 ; | ||
| 613 | state->TunerRegs[68].Reg_Val = 0x12 ; | ||
| 614 | |||
| 615 | state->TunerRegs[69].Reg_Num = 102 ; | ||
| 616 | state->TunerRegs[69].Reg_Val = 0x80 ; | ||
| 617 | |||
| 618 | state->TunerRegs[70].Reg_Num = 103 ; | ||
| 619 | state->TunerRegs[70].Reg_Val = 0x32 ; | ||
| 620 | |||
| 621 | state->TunerRegs[71].Reg_Num = 104 ; | ||
| 622 | state->TunerRegs[71].Reg_Val = 0xB4 ; | ||
| 623 | |||
| 624 | state->TunerRegs[72].Reg_Num = 105 ; | ||
| 625 | state->TunerRegs[72].Reg_Val = 0x60 ; | ||
| 626 | |||
| 627 | state->TunerRegs[73].Reg_Num = 106 ; | ||
| 628 | state->TunerRegs[73].Reg_Val = 0x83 ; | ||
| 629 | |||
| 630 | state->TunerRegs[74].Reg_Num = 107 ; | ||
| 631 | state->TunerRegs[74].Reg_Val = 0x84 ; | ||
| 632 | |||
| 633 | state->TunerRegs[75].Reg_Num = 108 ; | ||
| 634 | state->TunerRegs[75].Reg_Val = 0x9C ; | ||
| 635 | |||
| 636 | state->TunerRegs[76].Reg_Num = 109 ; | ||
| 637 | state->TunerRegs[76].Reg_Val = 0x02 ; | ||
| 638 | |||
| 639 | state->TunerRegs[77].Reg_Num = 110 ; | ||
| 640 | state->TunerRegs[77].Reg_Val = 0x81 ; | ||
| 641 | |||
| 642 | state->TunerRegs[78].Reg_Num = 111 ; | ||
| 643 | state->TunerRegs[78].Reg_Val = 0xC0 ; | ||
| 644 | |||
| 645 | state->TunerRegs[79].Reg_Num = 112 ; | ||
| 646 | state->TunerRegs[79].Reg_Val = 0x10 ; | ||
| 647 | |||
| 648 | state->TunerRegs[80].Reg_Num = 131 ; | ||
| 649 | state->TunerRegs[80].Reg_Val = 0x8A ; | ||
| 650 | |||
| 651 | state->TunerRegs[81].Reg_Num = 132 ; | ||
| 652 | state->TunerRegs[81].Reg_Val = 0x10 ; | ||
| 653 | |||
| 654 | state->TunerRegs[82].Reg_Num = 133 ; | ||
| 655 | state->TunerRegs[82].Reg_Val = 0x24 ; | ||
| 656 | |||
| 657 | state->TunerRegs[83].Reg_Num = 134 ; | ||
| 658 | state->TunerRegs[83].Reg_Val = 0x00 ; | ||
| 659 | |||
| 660 | state->TunerRegs[84].Reg_Num = 135 ; | ||
| 661 | state->TunerRegs[84].Reg_Val = 0x00 ; | ||
| 662 | |||
| 663 | state->TunerRegs[85].Reg_Num = 136 ; | ||
| 664 | state->TunerRegs[85].Reg_Val = 0x7E ; | ||
| 665 | |||
| 666 | state->TunerRegs[86].Reg_Num = 137 ; | ||
| 667 | state->TunerRegs[86].Reg_Val = 0x40 ; | ||
| 668 | |||
| 669 | state->TunerRegs[87].Reg_Num = 138 ; | ||
| 670 | state->TunerRegs[87].Reg_Val = 0x38 ; | ||
| 671 | |||
| 672 | state->TunerRegs[88].Reg_Num = 146 ; | ||
| 673 | state->TunerRegs[88].Reg_Val = 0xF6 ; | ||
| 674 | |||
| 675 | state->TunerRegs[89].Reg_Num = 147 ; | ||
| 676 | state->TunerRegs[89].Reg_Val = 0x1A ; | ||
| 677 | |||
| 678 | state->TunerRegs[90].Reg_Num = 148 ; | ||
| 679 | state->TunerRegs[90].Reg_Val = 0x62 ; | ||
| 680 | |||
| 681 | state->TunerRegs[91].Reg_Num = 149 ; | ||
| 682 | state->TunerRegs[91].Reg_Val = 0x33 ; | ||
| 683 | |||
| 684 | state->TunerRegs[92].Reg_Num = 150 ; | ||
| 685 | state->TunerRegs[92].Reg_Val = 0x80 ; | ||
| 686 | |||
| 687 | state->TunerRegs[93].Reg_Num = 156 ; | ||
| 688 | state->TunerRegs[93].Reg_Val = 0x56 ; | ||
| 689 | |||
| 690 | state->TunerRegs[94].Reg_Num = 157 ; | ||
| 691 | state->TunerRegs[94].Reg_Val = 0x17 ; | ||
| 692 | |||
| 693 | state->TunerRegs[95].Reg_Num = 158 ; | ||
| 694 | state->TunerRegs[95].Reg_Val = 0xA9 ; | ||
| 695 | |||
| 696 | state->TunerRegs[96].Reg_Num = 159 ; | ||
| 697 | state->TunerRegs[96].Reg_Val = 0x00 ; | ||
| 698 | |||
| 699 | state->TunerRegs[97].Reg_Num = 160 ; | ||
| 700 | state->TunerRegs[97].Reg_Val = 0x00 ; | ||
| 701 | |||
| 702 | state->TunerRegs[98].Reg_Num = 161 ; | ||
| 703 | state->TunerRegs[98].Reg_Val = 0x00 ; | ||
| 704 | |||
| 705 | state->TunerRegs[99].Reg_Num = 162 ; | ||
| 706 | state->TunerRegs[99].Reg_Val = 0x40 ; | ||
| 707 | |||
| 708 | state->TunerRegs[100].Reg_Num = 166 ; | ||
| 709 | state->TunerRegs[100].Reg_Val = 0xAE ; | ||
| 710 | |||
| 711 | state->TunerRegs[101].Reg_Num = 167 ; | ||
| 712 | state->TunerRegs[101].Reg_Val = 0x1B ; | ||
| 713 | |||
| 714 | state->TunerRegs[102].Reg_Num = 168 ; | ||
| 715 | state->TunerRegs[102].Reg_Val = 0xF2 ; | ||
| 716 | |||
| 717 | state->TunerRegs[103].Reg_Num = 195 ; | ||
| 718 | state->TunerRegs[103].Reg_Val = 0x00 ; | ||
| 719 | |||
| 720 | return 0 ; | ||
| 721 | } | ||
| 722 | |||
| 723 | static u16 MXL5005_ControlInit(struct dvb_frontend *fe) | ||
| 724 | { | ||
| 725 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 726 | state->Init_Ctrl_Num = INITCTRL_NUM; | ||
| 727 | |||
| 728 | state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ; | ||
| 729 | state->Init_Ctrl[0].size = 1 ; | ||
| 730 | state->Init_Ctrl[0].addr[0] = 73; | ||
| 731 | state->Init_Ctrl[0].bit[0] = 7; | ||
| 732 | state->Init_Ctrl[0].val[0] = 0; | ||
| 733 | |||
| 734 | state->Init_Ctrl[1].Ctrl_Num = BB_MODE ; | ||
| 735 | state->Init_Ctrl[1].size = 1 ; | ||
| 736 | state->Init_Ctrl[1].addr[0] = 53; | ||
| 737 | state->Init_Ctrl[1].bit[0] = 2; | ||
| 738 | state->Init_Ctrl[1].val[0] = 1; | ||
| 739 | |||
| 740 | state->Init_Ctrl[2].Ctrl_Num = BB_BUF ; | ||
| 741 | state->Init_Ctrl[2].size = 2 ; | ||
| 742 | state->Init_Ctrl[2].addr[0] = 53; | ||
| 743 | state->Init_Ctrl[2].bit[0] = 1; | ||
| 744 | state->Init_Ctrl[2].val[0] = 0; | ||
| 745 | state->Init_Ctrl[2].addr[1] = 57; | ||
| 746 | state->Init_Ctrl[2].bit[1] = 0; | ||
| 747 | state->Init_Ctrl[2].val[1] = 1; | ||
| 748 | |||
| 749 | state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ; | ||
| 750 | state->Init_Ctrl[3].size = 1 ; | ||
| 751 | state->Init_Ctrl[3].addr[0] = 53; | ||
| 752 | state->Init_Ctrl[3].bit[0] = 0; | ||
| 753 | state->Init_Ctrl[3].val[0] = 0; | ||
| 754 | |||
| 755 | state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ; | ||
| 756 | state->Init_Ctrl[4].size = 3 ; | ||
| 757 | state->Init_Ctrl[4].addr[0] = 53; | ||
| 758 | state->Init_Ctrl[4].bit[0] = 5; | ||
| 759 | state->Init_Ctrl[4].val[0] = 0; | ||
| 760 | state->Init_Ctrl[4].addr[1] = 53; | ||
| 761 | state->Init_Ctrl[4].bit[1] = 6; | ||
| 762 | state->Init_Ctrl[4].val[1] = 0; | ||
| 763 | state->Init_Ctrl[4].addr[2] = 53; | ||
| 764 | state->Init_Ctrl[4].bit[2] = 7; | ||
| 765 | state->Init_Ctrl[4].val[2] = 1; | ||
| 766 | |||
| 767 | state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ; | ||
| 768 | state->Init_Ctrl[5].size = 1 ; | ||
| 769 | state->Init_Ctrl[5].addr[0] = 59; | ||
| 770 | state->Init_Ctrl[5].bit[0] = 0; | ||
| 771 | state->Init_Ctrl[5].val[0] = 0; | ||
| 772 | |||
| 773 | state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ; | ||
| 774 | state->Init_Ctrl[6].size = 2 ; | ||
| 775 | state->Init_Ctrl[6].addr[0] = 53; | ||
| 776 | state->Init_Ctrl[6].bit[0] = 3; | ||
| 777 | state->Init_Ctrl[6].val[0] = 0; | ||
| 778 | state->Init_Ctrl[6].addr[1] = 53; | ||
| 779 | state->Init_Ctrl[6].bit[1] = 4; | ||
| 780 | state->Init_Ctrl[6].val[1] = 1; | ||
| 781 | |||
| 782 | state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ; | ||
| 783 | state->Init_Ctrl[7].size = 4 ; | ||
| 784 | state->Init_Ctrl[7].addr[0] = 22; | ||
| 785 | state->Init_Ctrl[7].bit[0] = 4; | ||
| 786 | state->Init_Ctrl[7].val[0] = 0; | ||
| 787 | state->Init_Ctrl[7].addr[1] = 22; | ||
| 788 | state->Init_Ctrl[7].bit[1] = 5; | ||
| 789 | state->Init_Ctrl[7].val[1] = 1; | ||
| 790 | state->Init_Ctrl[7].addr[2] = 22; | ||
| 791 | state->Init_Ctrl[7].bit[2] = 6; | ||
| 792 | state->Init_Ctrl[7].val[2] = 1; | ||
| 793 | state->Init_Ctrl[7].addr[3] = 22; | ||
| 794 | state->Init_Ctrl[7].bit[3] = 7; | ||
| 795 | state->Init_Ctrl[7].val[3] = 0; | ||
| 796 | |||
| 797 | state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ; | ||
| 798 | state->Init_Ctrl[8].size = 1 ; | ||
| 799 | state->Init_Ctrl[8].addr[0] = 22; | ||
| 800 | state->Init_Ctrl[8].bit[0] = 2; | ||
| 801 | state->Init_Ctrl[8].val[0] = 0; | ||
| 802 | |||
| 803 | state->Init_Ctrl[9].Ctrl_Num = AGC_IF ; | ||
| 804 | state->Init_Ctrl[9].size = 4 ; | ||
| 805 | state->Init_Ctrl[9].addr[0] = 76; | ||
| 806 | state->Init_Ctrl[9].bit[0] = 0; | ||
| 807 | state->Init_Ctrl[9].val[0] = 1; | ||
| 808 | state->Init_Ctrl[9].addr[1] = 76; | ||
| 809 | state->Init_Ctrl[9].bit[1] = 1; | ||
| 810 | state->Init_Ctrl[9].val[1] = 1; | ||
| 811 | state->Init_Ctrl[9].addr[2] = 76; | ||
| 812 | state->Init_Ctrl[9].bit[2] = 2; | ||
| 813 | state->Init_Ctrl[9].val[2] = 0; | ||
| 814 | state->Init_Ctrl[9].addr[3] = 76; | ||
| 815 | state->Init_Ctrl[9].bit[3] = 3; | ||
| 816 | state->Init_Ctrl[9].val[3] = 1; | ||
| 817 | |||
| 818 | state->Init_Ctrl[10].Ctrl_Num = AGC_RF ; | ||
| 819 | state->Init_Ctrl[10].size = 4 ; | ||
| 820 | state->Init_Ctrl[10].addr[0] = 76; | ||
| 821 | state->Init_Ctrl[10].bit[0] = 4; | ||
| 822 | state->Init_Ctrl[10].val[0] = 1; | ||
| 823 | state->Init_Ctrl[10].addr[1] = 76; | ||
| 824 | state->Init_Ctrl[10].bit[1] = 5; | ||
| 825 | state->Init_Ctrl[10].val[1] = 1; | ||
| 826 | state->Init_Ctrl[10].addr[2] = 76; | ||
| 827 | state->Init_Ctrl[10].bit[2] = 6; | ||
| 828 | state->Init_Ctrl[10].val[2] = 0; | ||
| 829 | state->Init_Ctrl[10].addr[3] = 76; | ||
| 830 | state->Init_Ctrl[10].bit[3] = 7; | ||
| 831 | state->Init_Ctrl[10].val[3] = 1; | ||
| 832 | |||
| 833 | state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ; | ||
| 834 | state->Init_Ctrl[11].size = 5 ; | ||
| 835 | state->Init_Ctrl[11].addr[0] = 43; | ||
| 836 | state->Init_Ctrl[11].bit[0] = 3; | ||
| 837 | state->Init_Ctrl[11].val[0] = 0; | ||
| 838 | state->Init_Ctrl[11].addr[1] = 43; | ||
| 839 | state->Init_Ctrl[11].bit[1] = 4; | ||
| 840 | state->Init_Ctrl[11].val[1] = 0; | ||
| 841 | state->Init_Ctrl[11].addr[2] = 43; | ||
| 842 | state->Init_Ctrl[11].bit[2] = 5; | ||
| 843 | state->Init_Ctrl[11].val[2] = 0; | ||
| 844 | state->Init_Ctrl[11].addr[3] = 43; | ||
| 845 | state->Init_Ctrl[11].bit[3] = 6; | ||
| 846 | state->Init_Ctrl[11].val[3] = 1; | ||
| 847 | state->Init_Ctrl[11].addr[4] = 43; | ||
| 848 | state->Init_Ctrl[11].bit[4] = 7; | ||
| 849 | state->Init_Ctrl[11].val[4] = 0; | ||
| 850 | |||
| 851 | state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ; | ||
| 852 | state->Init_Ctrl[12].size = 6 ; | ||
| 853 | state->Init_Ctrl[12].addr[0] = 44; | ||
| 854 | state->Init_Ctrl[12].bit[0] = 2; | ||
| 855 | state->Init_Ctrl[12].val[0] = 0; | ||
| 856 | state->Init_Ctrl[12].addr[1] = 44; | ||
| 857 | state->Init_Ctrl[12].bit[1] = 3; | ||
| 858 | state->Init_Ctrl[12].val[1] = 0; | ||
| 859 | state->Init_Ctrl[12].addr[2] = 44; | ||
| 860 | state->Init_Ctrl[12].bit[2] = 4; | ||
| 861 | state->Init_Ctrl[12].val[2] = 0; | ||
| 862 | state->Init_Ctrl[12].addr[3] = 44; | ||
| 863 | state->Init_Ctrl[12].bit[3] = 5; | ||
| 864 | state->Init_Ctrl[12].val[3] = 1; | ||
| 865 | state->Init_Ctrl[12].addr[4] = 44; | ||
| 866 | state->Init_Ctrl[12].bit[4] = 6; | ||
| 867 | state->Init_Ctrl[12].val[4] = 0; | ||
| 868 | state->Init_Ctrl[12].addr[5] = 44; | ||
| 869 | state->Init_Ctrl[12].bit[5] = 7; | ||
| 870 | state->Init_Ctrl[12].val[5] = 0; | ||
| 871 | |||
| 872 | state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ; | ||
| 873 | state->Init_Ctrl[13].size = 7 ; | ||
| 874 | state->Init_Ctrl[13].addr[0] = 11; | ||
| 875 | state->Init_Ctrl[13].bit[0] = 0; | ||
| 876 | state->Init_Ctrl[13].val[0] = 1; | ||
| 877 | state->Init_Ctrl[13].addr[1] = 11; | ||
| 878 | state->Init_Ctrl[13].bit[1] = 1; | ||
| 879 | state->Init_Ctrl[13].val[1] = 0; | ||
| 880 | state->Init_Ctrl[13].addr[2] = 11; | ||
| 881 | state->Init_Ctrl[13].bit[2] = 2; | ||
| 882 | state->Init_Ctrl[13].val[2] = 0; | ||
| 883 | state->Init_Ctrl[13].addr[3] = 11; | ||
| 884 | state->Init_Ctrl[13].bit[3] = 3; | ||
| 885 | state->Init_Ctrl[13].val[3] = 1; | ||
| 886 | state->Init_Ctrl[13].addr[4] = 11; | ||
| 887 | state->Init_Ctrl[13].bit[4] = 4; | ||
| 888 | state->Init_Ctrl[13].val[4] = 1; | ||
| 889 | state->Init_Ctrl[13].addr[5] = 11; | ||
| 890 | state->Init_Ctrl[13].bit[5] = 5; | ||
| 891 | state->Init_Ctrl[13].val[5] = 0; | ||
| 892 | state->Init_Ctrl[13].addr[6] = 11; | ||
| 893 | state->Init_Ctrl[13].bit[6] = 6; | ||
| 894 | state->Init_Ctrl[13].val[6] = 0; | ||
| 895 | |||
| 896 | state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ; | ||
| 897 | state->Init_Ctrl[14].size = 16 ; | ||
| 898 | state->Init_Ctrl[14].addr[0] = 13; | ||
| 899 | state->Init_Ctrl[14].bit[0] = 0; | ||
| 900 | state->Init_Ctrl[14].val[0] = 0; | ||
| 901 | state->Init_Ctrl[14].addr[1] = 13; | ||
| 902 | state->Init_Ctrl[14].bit[1] = 1; | ||
| 903 | state->Init_Ctrl[14].val[1] = 0; | ||
| 904 | state->Init_Ctrl[14].addr[2] = 13; | ||
| 905 | state->Init_Ctrl[14].bit[2] = 2; | ||
| 906 | state->Init_Ctrl[14].val[2] = 0; | ||
| 907 | state->Init_Ctrl[14].addr[3] = 13; | ||
| 908 | state->Init_Ctrl[14].bit[3] = 3; | ||
| 909 | state->Init_Ctrl[14].val[3] = 0; | ||
| 910 | state->Init_Ctrl[14].addr[4] = 13; | ||
| 911 | state->Init_Ctrl[14].bit[4] = 4; | ||
| 912 | state->Init_Ctrl[14].val[4] = 0; | ||
| 913 | state->Init_Ctrl[14].addr[5] = 13; | ||
| 914 | state->Init_Ctrl[14].bit[5] = 5; | ||
| 915 | state->Init_Ctrl[14].val[5] = 0; | ||
| 916 | state->Init_Ctrl[14].addr[6] = 13; | ||
| 917 | state->Init_Ctrl[14].bit[6] = 6; | ||
| 918 | state->Init_Ctrl[14].val[6] = 0; | ||
| 919 | state->Init_Ctrl[14].addr[7] = 13; | ||
| 920 | state->Init_Ctrl[14].bit[7] = 7; | ||
| 921 | state->Init_Ctrl[14].val[7] = 0; | ||
| 922 | state->Init_Ctrl[14].addr[8] = 12; | ||
| 923 | state->Init_Ctrl[14].bit[8] = 0; | ||
| 924 | state->Init_Ctrl[14].val[8] = 0; | ||
| 925 | state->Init_Ctrl[14].addr[9] = 12; | ||
| 926 | state->Init_Ctrl[14].bit[9] = 1; | ||
| 927 | state->Init_Ctrl[14].val[9] = 0; | ||
| 928 | state->Init_Ctrl[14].addr[10] = 12; | ||
| 929 | state->Init_Ctrl[14].bit[10] = 2; | ||
| 930 | state->Init_Ctrl[14].val[10] = 0; | ||
| 931 | state->Init_Ctrl[14].addr[11] = 12; | ||
| 932 | state->Init_Ctrl[14].bit[11] = 3; | ||
| 933 | state->Init_Ctrl[14].val[11] = 0; | ||
| 934 | state->Init_Ctrl[14].addr[12] = 12; | ||
| 935 | state->Init_Ctrl[14].bit[12] = 4; | ||
| 936 | state->Init_Ctrl[14].val[12] = 0; | ||
| 937 | state->Init_Ctrl[14].addr[13] = 12; | ||
| 938 | state->Init_Ctrl[14].bit[13] = 5; | ||
| 939 | state->Init_Ctrl[14].val[13] = 1; | ||
| 940 | state->Init_Ctrl[14].addr[14] = 12; | ||
| 941 | state->Init_Ctrl[14].bit[14] = 6; | ||
| 942 | state->Init_Ctrl[14].val[14] = 1; | ||
| 943 | state->Init_Ctrl[14].addr[15] = 12; | ||
| 944 | state->Init_Ctrl[14].bit[15] = 7; | ||
| 945 | state->Init_Ctrl[14].val[15] = 0; | ||
| 946 | |||
| 947 | state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ; | ||
| 948 | state->Init_Ctrl[15].size = 3 ; | ||
| 949 | state->Init_Ctrl[15].addr[0] = 147; | ||
| 950 | state->Init_Ctrl[15].bit[0] = 2; | ||
| 951 | state->Init_Ctrl[15].val[0] = 0; | ||
| 952 | state->Init_Ctrl[15].addr[1] = 147; | ||
| 953 | state->Init_Ctrl[15].bit[1] = 3; | ||
| 954 | state->Init_Ctrl[15].val[1] = 1; | ||
| 955 | state->Init_Ctrl[15].addr[2] = 147; | ||
| 956 | state->Init_Ctrl[15].bit[2] = 4; | ||
| 957 | state->Init_Ctrl[15].val[2] = 1; | ||
| 958 | |||
| 959 | state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ; | ||
| 960 | state->Init_Ctrl[16].size = 2 ; | ||
| 961 | state->Init_Ctrl[16].addr[0] = 147; | ||
| 962 | state->Init_Ctrl[16].bit[0] = 0; | ||
| 963 | state->Init_Ctrl[16].val[0] = 0; | ||
| 964 | state->Init_Ctrl[16].addr[1] = 147; | ||
| 965 | state->Init_Ctrl[16].bit[1] = 1; | ||
| 966 | state->Init_Ctrl[16].val[1] = 1; | ||
| 967 | |||
| 968 | state->Init_Ctrl[17].Ctrl_Num = EN_AAF ; | ||
| 969 | state->Init_Ctrl[17].size = 1 ; | ||
| 970 | state->Init_Ctrl[17].addr[0] = 147; | ||
| 971 | state->Init_Ctrl[17].bit[0] = 7; | ||
| 972 | state->Init_Ctrl[17].val[0] = 0; | ||
| 973 | |||
| 974 | state->Init_Ctrl[18].Ctrl_Num = EN_3P ; | ||
| 975 | state->Init_Ctrl[18].size = 1 ; | ||
| 976 | state->Init_Ctrl[18].addr[0] = 147; | ||
| 977 | state->Init_Ctrl[18].bit[0] = 6; | ||
| 978 | state->Init_Ctrl[18].val[0] = 0; | ||
| 979 | |||
| 980 | state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ; | ||
| 981 | state->Init_Ctrl[19].size = 1 ; | ||
| 982 | state->Init_Ctrl[19].addr[0] = 156; | ||
| 983 | state->Init_Ctrl[19].bit[0] = 0; | ||
| 984 | state->Init_Ctrl[19].val[0] = 0; | ||
| 985 | |||
| 986 | state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ; | ||
| 987 | state->Init_Ctrl[20].size = 1 ; | ||
| 988 | state->Init_Ctrl[20].addr[0] = 147; | ||
| 989 | state->Init_Ctrl[20].bit[0] = 5; | ||
| 990 | state->Init_Ctrl[20].val[0] = 0; | ||
| 991 | |||
| 992 | state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ; | ||
| 993 | state->Init_Ctrl[21].size = 1 ; | ||
| 994 | state->Init_Ctrl[21].addr[0] = 137; | ||
| 995 | state->Init_Ctrl[21].bit[0] = 4; | ||
| 996 | state->Init_Ctrl[21].val[0] = 0; | ||
| 997 | |||
| 998 | state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ; | ||
| 999 | state->Init_Ctrl[22].size = 1 ; | ||
| 1000 | state->Init_Ctrl[22].addr[0] = 137; | ||
| 1001 | state->Init_Ctrl[22].bit[0] = 7; | ||
| 1002 | state->Init_Ctrl[22].val[0] = 0; | ||
| 1003 | |||
| 1004 | state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ; | ||
| 1005 | state->Init_Ctrl[23].size = 1 ; | ||
| 1006 | state->Init_Ctrl[23].addr[0] = 91; | ||
| 1007 | state->Init_Ctrl[23].bit[0] = 5; | ||
| 1008 | state->Init_Ctrl[23].val[0] = 1; | ||
| 1009 | |||
| 1010 | state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ; | ||
| 1011 | state->Init_Ctrl[24].size = 1 ; | ||
| 1012 | state->Init_Ctrl[24].addr[0] = 43; | ||
| 1013 | state->Init_Ctrl[24].bit[0] = 0; | ||
| 1014 | state->Init_Ctrl[24].val[0] = 1; | ||
| 1015 | |||
| 1016 | state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ; | ||
| 1017 | state->Init_Ctrl[25].size = 2 ; | ||
| 1018 | state->Init_Ctrl[25].addr[0] = 22; | ||
| 1019 | state->Init_Ctrl[25].bit[0] = 0; | ||
| 1020 | state->Init_Ctrl[25].val[0] = 1; | ||
| 1021 | state->Init_Ctrl[25].addr[1] = 22; | ||
| 1022 | state->Init_Ctrl[25].bit[1] = 1; | ||
| 1023 | state->Init_Ctrl[25].val[1] = 1; | ||
| 1024 | |||
| 1025 | state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ; | ||
| 1026 | state->Init_Ctrl[26].size = 1 ; | ||
| 1027 | state->Init_Ctrl[26].addr[0] = 134; | ||
| 1028 | state->Init_Ctrl[26].bit[0] = 2; | ||
| 1029 | state->Init_Ctrl[26].val[0] = 0; | ||
| 1030 | |||
| 1031 | state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ; | ||
| 1032 | state->Init_Ctrl[27].size = 1 ; | ||
| 1033 | state->Init_Ctrl[27].addr[0] = 137; | ||
| 1034 | state->Init_Ctrl[27].bit[0] = 3; | ||
| 1035 | state->Init_Ctrl[27].val[0] = 0; | ||
| 1036 | |||
| 1037 | state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ; | ||
| 1038 | state->Init_Ctrl[28].size = 1 ; | ||
| 1039 | state->Init_Ctrl[28].addr[0] = 77; | ||
| 1040 | state->Init_Ctrl[28].bit[0] = 7; | ||
| 1041 | state->Init_Ctrl[28].val[0] = 0; | ||
| 1042 | |||
| 1043 | state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ; | ||
| 1044 | state->Init_Ctrl[29].size = 1 ; | ||
| 1045 | state->Init_Ctrl[29].addr[0] = 166; | ||
| 1046 | state->Init_Ctrl[29].bit[0] = 7; | ||
| 1047 | state->Init_Ctrl[29].val[0] = 1; | ||
| 1048 | |||
| 1049 | state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ; | ||
| 1050 | state->Init_Ctrl[30].size = 3 ; | ||
| 1051 | state->Init_Ctrl[30].addr[0] = 166; | ||
| 1052 | state->Init_Ctrl[30].bit[0] = 0; | ||
| 1053 | state->Init_Ctrl[30].val[0] = 0; | ||
| 1054 | state->Init_Ctrl[30].addr[1] = 166; | ||
| 1055 | state->Init_Ctrl[30].bit[1] = 1; | ||
| 1056 | state->Init_Ctrl[30].val[1] = 1; | ||
| 1057 | state->Init_Ctrl[30].addr[2] = 166; | ||
| 1058 | state->Init_Ctrl[30].bit[2] = 2; | ||
| 1059 | state->Init_Ctrl[30].val[2] = 1; | ||
| 1060 | |||
| 1061 | state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ; | ||
| 1062 | state->Init_Ctrl[31].size = 3 ; | ||
| 1063 | state->Init_Ctrl[31].addr[0] = 166; | ||
| 1064 | state->Init_Ctrl[31].bit[0] = 3; | ||
| 1065 | state->Init_Ctrl[31].val[0] = 1; | ||
| 1066 | state->Init_Ctrl[31].addr[1] = 166; | ||
| 1067 | state->Init_Ctrl[31].bit[1] = 4; | ||
| 1068 | state->Init_Ctrl[31].val[1] = 0; | ||
| 1069 | state->Init_Ctrl[31].addr[2] = 166; | ||
| 1070 | state->Init_Ctrl[31].bit[2] = 5; | ||
| 1071 | state->Init_Ctrl[31].val[2] = 1; | ||
| 1072 | |||
| 1073 | state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ; | ||
| 1074 | state->Init_Ctrl[32].size = 3 ; | ||
| 1075 | state->Init_Ctrl[32].addr[0] = 167; | ||
| 1076 | state->Init_Ctrl[32].bit[0] = 0; | ||
| 1077 | state->Init_Ctrl[32].val[0] = 1; | ||
| 1078 | state->Init_Ctrl[32].addr[1] = 167; | ||
| 1079 | state->Init_Ctrl[32].bit[1] = 1; | ||
| 1080 | state->Init_Ctrl[32].val[1] = 1; | ||
| 1081 | state->Init_Ctrl[32].addr[2] = 167; | ||
| 1082 | state->Init_Ctrl[32].bit[2] = 2; | ||
| 1083 | state->Init_Ctrl[32].val[2] = 0; | ||
| 1084 | |||
| 1085 | state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ; | ||
| 1086 | state->Init_Ctrl[33].size = 4 ; | ||
| 1087 | state->Init_Ctrl[33].addr[0] = 168; | ||
| 1088 | state->Init_Ctrl[33].bit[0] = 0; | ||
| 1089 | state->Init_Ctrl[33].val[0] = 0; | ||
| 1090 | state->Init_Ctrl[33].addr[1] = 168; | ||
| 1091 | state->Init_Ctrl[33].bit[1] = 1; | ||
| 1092 | state->Init_Ctrl[33].val[1] = 1; | ||
| 1093 | state->Init_Ctrl[33].addr[2] = 168; | ||
| 1094 | state->Init_Ctrl[33].bit[2] = 2; | ||
| 1095 | state->Init_Ctrl[33].val[2] = 0; | ||
| 1096 | state->Init_Ctrl[33].addr[3] = 168; | ||
| 1097 | state->Init_Ctrl[33].bit[3] = 3; | ||
| 1098 | state->Init_Ctrl[33].val[3] = 0; | ||
| 1099 | |||
| 1100 | state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ; | ||
| 1101 | state->Init_Ctrl[34].size = 4 ; | ||
| 1102 | state->Init_Ctrl[34].addr[0] = 168; | ||
| 1103 | state->Init_Ctrl[34].bit[0] = 4; | ||
| 1104 | state->Init_Ctrl[34].val[0] = 1; | ||
| 1105 | state->Init_Ctrl[34].addr[1] = 168; | ||
| 1106 | state->Init_Ctrl[34].bit[1] = 5; | ||
| 1107 | state->Init_Ctrl[34].val[1] = 1; | ||
| 1108 | state->Init_Ctrl[34].addr[2] = 168; | ||
| 1109 | state->Init_Ctrl[34].bit[2] = 6; | ||
| 1110 | state->Init_Ctrl[34].val[2] = 1; | ||
| 1111 | state->Init_Ctrl[34].addr[3] = 168; | ||
| 1112 | state->Init_Ctrl[34].bit[3] = 7; | ||
| 1113 | state->Init_Ctrl[34].val[3] = 1; | ||
| 1114 | |||
| 1115 | state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ; | ||
| 1116 | state->Init_Ctrl[35].size = 1 ; | ||
| 1117 | state->Init_Ctrl[35].addr[0] = 135; | ||
| 1118 | state->Init_Ctrl[35].bit[0] = 0; | ||
| 1119 | state->Init_Ctrl[35].val[0] = 0; | ||
| 1120 | |||
| 1121 | state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ; | ||
| 1122 | state->Init_Ctrl[36].size = 1 ; | ||
| 1123 | state->Init_Ctrl[36].addr[0] = 56; | ||
| 1124 | state->Init_Ctrl[36].bit[0] = 3; | ||
| 1125 | state->Init_Ctrl[36].val[0] = 0; | ||
| 1126 | |||
| 1127 | state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ; | ||
| 1128 | state->Init_Ctrl[37].size = 7 ; | ||
| 1129 | state->Init_Ctrl[37].addr[0] = 59; | ||
| 1130 | state->Init_Ctrl[37].bit[0] = 1; | ||
| 1131 | state->Init_Ctrl[37].val[0] = 0; | ||
| 1132 | state->Init_Ctrl[37].addr[1] = 59; | ||
| 1133 | state->Init_Ctrl[37].bit[1] = 2; | ||
| 1134 | state->Init_Ctrl[37].val[1] = 0; | ||
| 1135 | state->Init_Ctrl[37].addr[2] = 59; | ||
| 1136 | state->Init_Ctrl[37].bit[2] = 3; | ||
| 1137 | state->Init_Ctrl[37].val[2] = 0; | ||
| 1138 | state->Init_Ctrl[37].addr[3] = 59; | ||
| 1139 | state->Init_Ctrl[37].bit[3] = 4; | ||
| 1140 | state->Init_Ctrl[37].val[3] = 0; | ||
| 1141 | state->Init_Ctrl[37].addr[4] = 59; | ||
| 1142 | state->Init_Ctrl[37].bit[4] = 5; | ||
| 1143 | state->Init_Ctrl[37].val[4] = 0; | ||
| 1144 | state->Init_Ctrl[37].addr[5] = 59; | ||
| 1145 | state->Init_Ctrl[37].bit[5] = 6; | ||
| 1146 | state->Init_Ctrl[37].val[5] = 0; | ||
| 1147 | state->Init_Ctrl[37].addr[6] = 59; | ||
| 1148 | state->Init_Ctrl[37].bit[6] = 7; | ||
| 1149 | state->Init_Ctrl[37].val[6] = 0; | ||
| 1150 | |||
| 1151 | state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ; | ||
| 1152 | state->Init_Ctrl[38].size = 6 ; | ||
| 1153 | state->Init_Ctrl[38].addr[0] = 32; | ||
| 1154 | state->Init_Ctrl[38].bit[0] = 2; | ||
| 1155 | state->Init_Ctrl[38].val[0] = 0; | ||
| 1156 | state->Init_Ctrl[38].addr[1] = 32; | ||
| 1157 | state->Init_Ctrl[38].bit[1] = 3; | ||
| 1158 | state->Init_Ctrl[38].val[1] = 0; | ||
| 1159 | state->Init_Ctrl[38].addr[2] = 32; | ||
| 1160 | state->Init_Ctrl[38].bit[2] = 4; | ||
| 1161 | state->Init_Ctrl[38].val[2] = 0; | ||
| 1162 | state->Init_Ctrl[38].addr[3] = 32; | ||
| 1163 | state->Init_Ctrl[38].bit[3] = 5; | ||
| 1164 | state->Init_Ctrl[38].val[3] = 0; | ||
| 1165 | state->Init_Ctrl[38].addr[4] = 32; | ||
| 1166 | state->Init_Ctrl[38].bit[4] = 6; | ||
| 1167 | state->Init_Ctrl[38].val[4] = 1; | ||
| 1168 | state->Init_Ctrl[38].addr[5] = 32; | ||
| 1169 | state->Init_Ctrl[38].bit[5] = 7; | ||
| 1170 | state->Init_Ctrl[38].val[5] = 0; | ||
| 1171 | |||
| 1172 | state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ; | ||
| 1173 | state->Init_Ctrl[39].size = 1 ; | ||
| 1174 | state->Init_Ctrl[39].addr[0] = 25; | ||
| 1175 | state->Init_Ctrl[39].bit[0] = 3; | ||
| 1176 | state->Init_Ctrl[39].val[0] = 1; | ||
| 1177 | |||
| 1178 | |||
| 1179 | state->CH_Ctrl_Num = CHCTRL_NUM ; | ||
| 1180 | |||
| 1181 | state->CH_Ctrl[0].Ctrl_Num = DN_POLY ; | ||
| 1182 | state->CH_Ctrl[0].size = 2 ; | ||
| 1183 | state->CH_Ctrl[0].addr[0] = 68; | ||
| 1184 | state->CH_Ctrl[0].bit[0] = 6; | ||
| 1185 | state->CH_Ctrl[0].val[0] = 1; | ||
| 1186 | state->CH_Ctrl[0].addr[1] = 68; | ||
| 1187 | state->CH_Ctrl[0].bit[1] = 7; | ||
| 1188 | state->CH_Ctrl[0].val[1] = 1; | ||
| 1189 | |||
| 1190 | state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ; | ||
| 1191 | state->CH_Ctrl[1].size = 2 ; | ||
| 1192 | state->CH_Ctrl[1].addr[0] = 70; | ||
| 1193 | state->CH_Ctrl[1].bit[0] = 6; | ||
| 1194 | state->CH_Ctrl[1].val[0] = 1; | ||
| 1195 | state->CH_Ctrl[1].addr[1] = 70; | ||
| 1196 | state->CH_Ctrl[1].bit[1] = 7; | ||
| 1197 | state->CH_Ctrl[1].val[1] = 0; | ||
| 1198 | |||
| 1199 | state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ; | ||
| 1200 | state->CH_Ctrl[2].size = 9 ; | ||
| 1201 | state->CH_Ctrl[2].addr[0] = 69; | ||
| 1202 | state->CH_Ctrl[2].bit[0] = 5; | ||
| 1203 | state->CH_Ctrl[2].val[0] = 0; | ||
| 1204 | state->CH_Ctrl[2].addr[1] = 69; | ||
| 1205 | state->CH_Ctrl[2].bit[1] = 6; | ||
| 1206 | state->CH_Ctrl[2].val[1] = 0; | ||
| 1207 | state->CH_Ctrl[2].addr[2] = 69; | ||
| 1208 | state->CH_Ctrl[2].bit[2] = 7; | ||
| 1209 | state->CH_Ctrl[2].val[2] = 0; | ||
| 1210 | state->CH_Ctrl[2].addr[3] = 68; | ||
| 1211 | state->CH_Ctrl[2].bit[3] = 0; | ||
| 1212 | state->CH_Ctrl[2].val[3] = 0; | ||
| 1213 | state->CH_Ctrl[2].addr[4] = 68; | ||
| 1214 | state->CH_Ctrl[2].bit[4] = 1; | ||
| 1215 | state->CH_Ctrl[2].val[4] = 0; | ||
| 1216 | state->CH_Ctrl[2].addr[5] = 68; | ||
| 1217 | state->CH_Ctrl[2].bit[5] = 2; | ||
| 1218 | state->CH_Ctrl[2].val[5] = 0; | ||
| 1219 | state->CH_Ctrl[2].addr[6] = 68; | ||
| 1220 | state->CH_Ctrl[2].bit[6] = 3; | ||
| 1221 | state->CH_Ctrl[2].val[6] = 0; | ||
| 1222 | state->CH_Ctrl[2].addr[7] = 68; | ||
| 1223 | state->CH_Ctrl[2].bit[7] = 4; | ||
| 1224 | state->CH_Ctrl[2].val[7] = 0; | ||
| 1225 | state->CH_Ctrl[2].addr[8] = 68; | ||
| 1226 | state->CH_Ctrl[2].bit[8] = 5; | ||
| 1227 | state->CH_Ctrl[2].val[8] = 0; | ||
| 1228 | |||
| 1229 | state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ; | ||
| 1230 | state->CH_Ctrl[3].size = 1 ; | ||
| 1231 | state->CH_Ctrl[3].addr[0] = 70; | ||
| 1232 | state->CH_Ctrl[3].bit[0] = 5; | ||
| 1233 | state->CH_Ctrl[3].val[0] = 0; | ||
| 1234 | |||
| 1235 | state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ; | ||
| 1236 | state->CH_Ctrl[4].size = 3 ; | ||
| 1237 | state->CH_Ctrl[4].addr[0] = 73; | ||
| 1238 | state->CH_Ctrl[4].bit[0] = 4; | ||
| 1239 | state->CH_Ctrl[4].val[0] = 0; | ||
| 1240 | state->CH_Ctrl[4].addr[1] = 73; | ||
| 1241 | state->CH_Ctrl[4].bit[1] = 5; | ||
| 1242 | state->CH_Ctrl[4].val[1] = 1; | ||
| 1243 | state->CH_Ctrl[4].addr[2] = 73; | ||
| 1244 | state->CH_Ctrl[4].bit[2] = 6; | ||
| 1245 | state->CH_Ctrl[4].val[2] = 0; | ||
| 1246 | |||
| 1247 | state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ; | ||
| 1248 | state->CH_Ctrl[5].size = 4 ; | ||
| 1249 | state->CH_Ctrl[5].addr[0] = 70; | ||
| 1250 | state->CH_Ctrl[5].bit[0] = 0; | ||
| 1251 | state->CH_Ctrl[5].val[0] = 0; | ||
| 1252 | state->CH_Ctrl[5].addr[1] = 70; | ||
| 1253 | state->CH_Ctrl[5].bit[1] = 1; | ||
| 1254 | state->CH_Ctrl[5].val[1] = 0; | ||
| 1255 | state->CH_Ctrl[5].addr[2] = 70; | ||
| 1256 | state->CH_Ctrl[5].bit[2] = 2; | ||
| 1257 | state->CH_Ctrl[5].val[2] = 0; | ||
| 1258 | state->CH_Ctrl[5].addr[3] = 70; | ||
| 1259 | state->CH_Ctrl[5].bit[3] = 3; | ||
| 1260 | state->CH_Ctrl[5].val[3] = 0; | ||
| 1261 | |||
| 1262 | state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ; | ||
| 1263 | state->CH_Ctrl[6].size = 1 ; | ||
| 1264 | state->CH_Ctrl[6].addr[0] = 70; | ||
| 1265 | state->CH_Ctrl[6].bit[0] = 4; | ||
| 1266 | state->CH_Ctrl[6].val[0] = 1; | ||
| 1267 | |||
| 1268 | state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ; | ||
| 1269 | state->CH_Ctrl[7].size = 1 ; | ||
| 1270 | state->CH_Ctrl[7].addr[0] = 111; | ||
| 1271 | state->CH_Ctrl[7].bit[0] = 4; | ||
| 1272 | state->CH_Ctrl[7].val[0] = 0; | ||
| 1273 | |||
| 1274 | state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ; | ||
| 1275 | state->CH_Ctrl[8].size = 1 ; | ||
| 1276 | state->CH_Ctrl[8].addr[0] = 111; | ||
| 1277 | state->CH_Ctrl[8].bit[0] = 7; | ||
| 1278 | state->CH_Ctrl[8].val[0] = 1; | ||
| 1279 | |||
| 1280 | state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ; | ||
| 1281 | state->CH_Ctrl[9].size = 1 ; | ||
| 1282 | state->CH_Ctrl[9].addr[0] = 111; | ||
| 1283 | state->CH_Ctrl[9].bit[0] = 6; | ||
| 1284 | state->CH_Ctrl[9].val[0] = 1; | ||
| 1285 | |||
| 1286 | state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ; | ||
| 1287 | state->CH_Ctrl[10].size = 1 ; | ||
| 1288 | state->CH_Ctrl[10].addr[0] = 111; | ||
| 1289 | state->CH_Ctrl[10].bit[0] = 5; | ||
| 1290 | state->CH_Ctrl[10].val[0] = 0; | ||
| 1291 | |||
| 1292 | state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ; | ||
| 1293 | state->CH_Ctrl[11].size = 2 ; | ||
| 1294 | state->CH_Ctrl[11].addr[0] = 110; | ||
| 1295 | state->CH_Ctrl[11].bit[0] = 0; | ||
| 1296 | state->CH_Ctrl[11].val[0] = 1; | ||
| 1297 | state->CH_Ctrl[11].addr[1] = 110; | ||
| 1298 | state->CH_Ctrl[11].bit[1] = 1; | ||
| 1299 | state->CH_Ctrl[11].val[1] = 0; | ||
| 1300 | |||
| 1301 | state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ; | ||
| 1302 | state->CH_Ctrl[12].size = 3 ; | ||
| 1303 | state->CH_Ctrl[12].addr[0] = 69; | ||
| 1304 | state->CH_Ctrl[12].bit[0] = 2; | ||
| 1305 | state->CH_Ctrl[12].val[0] = 0; | ||
| 1306 | state->CH_Ctrl[12].addr[1] = 69; | ||
| 1307 | state->CH_Ctrl[12].bit[1] = 3; | ||
| 1308 | state->CH_Ctrl[12].val[1] = 0; | ||
| 1309 | state->CH_Ctrl[12].addr[2] = 69; | ||
| 1310 | state->CH_Ctrl[12].bit[2] = 4; | ||
| 1311 | state->CH_Ctrl[12].val[2] = 0; | ||
| 1312 | |||
| 1313 | state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ; | ||
| 1314 | state->CH_Ctrl[13].size = 6 ; | ||
| 1315 | state->CH_Ctrl[13].addr[0] = 110; | ||
| 1316 | state->CH_Ctrl[13].bit[0] = 2; | ||
| 1317 | state->CH_Ctrl[13].val[0] = 0; | ||
| 1318 | state->CH_Ctrl[13].addr[1] = 110; | ||
| 1319 | state->CH_Ctrl[13].bit[1] = 3; | ||
| 1320 | state->CH_Ctrl[13].val[1] = 0; | ||
| 1321 | state->CH_Ctrl[13].addr[2] = 110; | ||
| 1322 | state->CH_Ctrl[13].bit[2] = 4; | ||
| 1323 | state->CH_Ctrl[13].val[2] = 0; | ||
| 1324 | state->CH_Ctrl[13].addr[3] = 110; | ||
| 1325 | state->CH_Ctrl[13].bit[3] = 5; | ||
| 1326 | state->CH_Ctrl[13].val[3] = 0; | ||
| 1327 | state->CH_Ctrl[13].addr[4] = 110; | ||
| 1328 | state->CH_Ctrl[13].bit[4] = 6; | ||
| 1329 | state->CH_Ctrl[13].val[4] = 0; | ||
| 1330 | state->CH_Ctrl[13].addr[5] = 110; | ||
| 1331 | state->CH_Ctrl[13].bit[5] = 7; | ||
| 1332 | state->CH_Ctrl[13].val[5] = 1; | ||
| 1333 | |||
| 1334 | state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ; | ||
| 1335 | state->CH_Ctrl[14].size = 7 ; | ||
| 1336 | state->CH_Ctrl[14].addr[0] = 14; | ||
| 1337 | state->CH_Ctrl[14].bit[0] = 0; | ||
| 1338 | state->CH_Ctrl[14].val[0] = 0; | ||
| 1339 | state->CH_Ctrl[14].addr[1] = 14; | ||
| 1340 | state->CH_Ctrl[14].bit[1] = 1; | ||
| 1341 | state->CH_Ctrl[14].val[1] = 0; | ||
| 1342 | state->CH_Ctrl[14].addr[2] = 14; | ||
| 1343 | state->CH_Ctrl[14].bit[2] = 2; | ||
| 1344 | state->CH_Ctrl[14].val[2] = 0; | ||
| 1345 | state->CH_Ctrl[14].addr[3] = 14; | ||
| 1346 | state->CH_Ctrl[14].bit[3] = 3; | ||
| 1347 | state->CH_Ctrl[14].val[3] = 0; | ||
| 1348 | state->CH_Ctrl[14].addr[4] = 14; | ||
| 1349 | state->CH_Ctrl[14].bit[4] = 4; | ||
| 1350 | state->CH_Ctrl[14].val[4] = 0; | ||
| 1351 | state->CH_Ctrl[14].addr[5] = 14; | ||
| 1352 | state->CH_Ctrl[14].bit[5] = 5; | ||
| 1353 | state->CH_Ctrl[14].val[5] = 0; | ||
| 1354 | state->CH_Ctrl[14].addr[6] = 14; | ||
| 1355 | state->CH_Ctrl[14].bit[6] = 6; | ||
| 1356 | state->CH_Ctrl[14].val[6] = 0; | ||
| 1357 | |||
| 1358 | state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ; | ||
| 1359 | state->CH_Ctrl[15].size = 18 ; | ||
| 1360 | state->CH_Ctrl[15].addr[0] = 17; | ||
| 1361 | state->CH_Ctrl[15].bit[0] = 6; | ||
| 1362 | state->CH_Ctrl[15].val[0] = 0; | ||
| 1363 | state->CH_Ctrl[15].addr[1] = 17; | ||
| 1364 | state->CH_Ctrl[15].bit[1] = 7; | ||
| 1365 | state->CH_Ctrl[15].val[1] = 0; | ||
| 1366 | state->CH_Ctrl[15].addr[2] = 16; | ||
| 1367 | state->CH_Ctrl[15].bit[2] = 0; | ||
| 1368 | state->CH_Ctrl[15].val[2] = 0; | ||
| 1369 | state->CH_Ctrl[15].addr[3] = 16; | ||
| 1370 | state->CH_Ctrl[15].bit[3] = 1; | ||
| 1371 | state->CH_Ctrl[15].val[3] = 0; | ||
| 1372 | state->CH_Ctrl[15].addr[4] = 16; | ||
| 1373 | state->CH_Ctrl[15].bit[4] = 2; | ||
| 1374 | state->CH_Ctrl[15].val[4] = 0; | ||
| 1375 | state->CH_Ctrl[15].addr[5] = 16; | ||
| 1376 | state->CH_Ctrl[15].bit[5] = 3; | ||
| 1377 | state->CH_Ctrl[15].val[5] = 0; | ||
| 1378 | state->CH_Ctrl[15].addr[6] = 16; | ||
| 1379 | state->CH_Ctrl[15].bit[6] = 4; | ||
| 1380 | state->CH_Ctrl[15].val[6] = 0; | ||
| 1381 | state->CH_Ctrl[15].addr[7] = 16; | ||
| 1382 | state->CH_Ctrl[15].bit[7] = 5; | ||
| 1383 | state->CH_Ctrl[15].val[7] = 0; | ||
| 1384 | state->CH_Ctrl[15].addr[8] = 16; | ||
| 1385 | state->CH_Ctrl[15].bit[8] = 6; | ||
| 1386 | state->CH_Ctrl[15].val[8] = 0; | ||
| 1387 | state->CH_Ctrl[15].addr[9] = 16; | ||
| 1388 | state->CH_Ctrl[15].bit[9] = 7; | ||
| 1389 | state->CH_Ctrl[15].val[9] = 0; | ||
| 1390 | state->CH_Ctrl[15].addr[10] = 15; | ||
| 1391 | state->CH_Ctrl[15].bit[10] = 0; | ||
| 1392 | state->CH_Ctrl[15].val[10] = 0; | ||
| 1393 | state->CH_Ctrl[15].addr[11] = 15; | ||
| 1394 | state->CH_Ctrl[15].bit[11] = 1; | ||
| 1395 | state->CH_Ctrl[15].val[11] = 0; | ||
| 1396 | state->CH_Ctrl[15].addr[12] = 15; | ||
| 1397 | state->CH_Ctrl[15].bit[12] = 2; | ||
| 1398 | state->CH_Ctrl[15].val[12] = 0; | ||
| 1399 | state->CH_Ctrl[15].addr[13] = 15; | ||
| 1400 | state->CH_Ctrl[15].bit[13] = 3; | ||
| 1401 | state->CH_Ctrl[15].val[13] = 0; | ||
| 1402 | state->CH_Ctrl[15].addr[14] = 15; | ||
| 1403 | state->CH_Ctrl[15].bit[14] = 4; | ||
| 1404 | state->CH_Ctrl[15].val[14] = 0; | ||
| 1405 | state->CH_Ctrl[15].addr[15] = 15; | ||
| 1406 | state->CH_Ctrl[15].bit[15] = 5; | ||
| 1407 | state->CH_Ctrl[15].val[15] = 0; | ||
| 1408 | state->CH_Ctrl[15].addr[16] = 15; | ||
| 1409 | state->CH_Ctrl[15].bit[16] = 6; | ||
| 1410 | state->CH_Ctrl[15].val[16] = 1; | ||
| 1411 | state->CH_Ctrl[15].addr[17] = 15; | ||
| 1412 | state->CH_Ctrl[15].bit[17] = 7; | ||
| 1413 | state->CH_Ctrl[15].val[17] = 1; | ||
| 1414 | |||
| 1415 | state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ; | ||
| 1416 | state->CH_Ctrl[16].size = 5 ; | ||
| 1417 | state->CH_Ctrl[16].addr[0] = 112; | ||
| 1418 | state->CH_Ctrl[16].bit[0] = 0; | ||
| 1419 | state->CH_Ctrl[16].val[0] = 0; | ||
| 1420 | state->CH_Ctrl[16].addr[1] = 112; | ||
| 1421 | state->CH_Ctrl[16].bit[1] = 1; | ||
| 1422 | state->CH_Ctrl[16].val[1] = 0; | ||
| 1423 | state->CH_Ctrl[16].addr[2] = 112; | ||
| 1424 | state->CH_Ctrl[16].bit[2] = 2; | ||
| 1425 | state->CH_Ctrl[16].val[2] = 0; | ||
| 1426 | state->CH_Ctrl[16].addr[3] = 112; | ||
| 1427 | state->CH_Ctrl[16].bit[3] = 3; | ||
| 1428 | state->CH_Ctrl[16].val[3] = 0; | ||
| 1429 | state->CH_Ctrl[16].addr[4] = 112; | ||
| 1430 | state->CH_Ctrl[16].bit[4] = 4; | ||
| 1431 | state->CH_Ctrl[16].val[4] = 1; | ||
| 1432 | |||
| 1433 | state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ; | ||
| 1434 | state->CH_Ctrl[17].size = 1 ; | ||
| 1435 | state->CH_Ctrl[17].addr[0] = 14; | ||
| 1436 | state->CH_Ctrl[17].bit[0] = 7; | ||
| 1437 | state->CH_Ctrl[17].val[0] = 0; | ||
| 1438 | |||
| 1439 | state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ; | ||
| 1440 | state->CH_Ctrl[18].size = 4 ; | ||
| 1441 | state->CH_Ctrl[18].addr[0] = 107; | ||
| 1442 | state->CH_Ctrl[18].bit[0] = 3; | ||
| 1443 | state->CH_Ctrl[18].val[0] = 0; | ||
| 1444 | state->CH_Ctrl[18].addr[1] = 107; | ||
| 1445 | state->CH_Ctrl[18].bit[1] = 4; | ||
| 1446 | state->CH_Ctrl[18].val[1] = 0; | ||
| 1447 | state->CH_Ctrl[18].addr[2] = 107; | ||
| 1448 | state->CH_Ctrl[18].bit[2] = 5; | ||
| 1449 | state->CH_Ctrl[18].val[2] = 0; | ||
| 1450 | state->CH_Ctrl[18].addr[3] = 107; | ||
| 1451 | state->CH_Ctrl[18].bit[3] = 6; | ||
| 1452 | state->CH_Ctrl[18].val[3] = 0; | ||
| 1453 | |||
| 1454 | state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ; | ||
| 1455 | state->CH_Ctrl[19].size = 3 ; | ||
| 1456 | state->CH_Ctrl[19].addr[0] = 107; | ||
| 1457 | state->CH_Ctrl[19].bit[0] = 7; | ||
| 1458 | state->CH_Ctrl[19].val[0] = 1; | ||
| 1459 | state->CH_Ctrl[19].addr[1] = 106; | ||
| 1460 | state->CH_Ctrl[19].bit[1] = 0; | ||
| 1461 | state->CH_Ctrl[19].val[1] = 1; | ||
| 1462 | state->CH_Ctrl[19].addr[2] = 106; | ||
| 1463 | state->CH_Ctrl[19].bit[2] = 1; | ||
| 1464 | state->CH_Ctrl[19].val[2] = 1; | ||
| 1465 | |||
| 1466 | state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ; | ||
| 1467 | state->CH_Ctrl[20].size = 11 ; | ||
| 1468 | state->CH_Ctrl[20].addr[0] = 109; | ||
| 1469 | state->CH_Ctrl[20].bit[0] = 2; | ||
| 1470 | state->CH_Ctrl[20].val[0] = 0; | ||
| 1471 | state->CH_Ctrl[20].addr[1] = 109; | ||
| 1472 | state->CH_Ctrl[20].bit[1] = 3; | ||
| 1473 | state->CH_Ctrl[20].val[1] = 0; | ||
| 1474 | state->CH_Ctrl[20].addr[2] = 109; | ||
| 1475 | state->CH_Ctrl[20].bit[2] = 4; | ||
| 1476 | state->CH_Ctrl[20].val[2] = 0; | ||
| 1477 | state->CH_Ctrl[20].addr[3] = 109; | ||
| 1478 | state->CH_Ctrl[20].bit[3] = 5; | ||
| 1479 | state->CH_Ctrl[20].val[3] = 0; | ||
| 1480 | state->CH_Ctrl[20].addr[4] = 109; | ||
| 1481 | state->CH_Ctrl[20].bit[4] = 6; | ||
| 1482 | state->CH_Ctrl[20].val[4] = 0; | ||
| 1483 | state->CH_Ctrl[20].addr[5] = 109; | ||
| 1484 | state->CH_Ctrl[20].bit[5] = 7; | ||
| 1485 | state->CH_Ctrl[20].val[5] = 0; | ||
| 1486 | state->CH_Ctrl[20].addr[6] = 108; | ||
| 1487 | state->CH_Ctrl[20].bit[6] = 0; | ||
| 1488 | state->CH_Ctrl[20].val[6] = 0; | ||
| 1489 | state->CH_Ctrl[20].addr[7] = 108; | ||
| 1490 | state->CH_Ctrl[20].bit[7] = 1; | ||
| 1491 | state->CH_Ctrl[20].val[7] = 0; | ||
| 1492 | state->CH_Ctrl[20].addr[8] = 108; | ||
| 1493 | state->CH_Ctrl[20].bit[8] = 2; | ||
| 1494 | state->CH_Ctrl[20].val[8] = 1; | ||
| 1495 | state->CH_Ctrl[20].addr[9] = 108; | ||
| 1496 | state->CH_Ctrl[20].bit[9] = 3; | ||
| 1497 | state->CH_Ctrl[20].val[9] = 1; | ||
| 1498 | state->CH_Ctrl[20].addr[10] = 108; | ||
| 1499 | state->CH_Ctrl[20].bit[10] = 4; | ||
| 1500 | state->CH_Ctrl[20].val[10] = 1; | ||
| 1501 | |||
| 1502 | state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ; | ||
| 1503 | state->CH_Ctrl[21].size = 6 ; | ||
| 1504 | state->CH_Ctrl[21].addr[0] = 106; | ||
| 1505 | state->CH_Ctrl[21].bit[0] = 2; | ||
| 1506 | state->CH_Ctrl[21].val[0] = 0; | ||
| 1507 | state->CH_Ctrl[21].addr[1] = 106; | ||
| 1508 | state->CH_Ctrl[21].bit[1] = 3; | ||
| 1509 | state->CH_Ctrl[21].val[1] = 0; | ||
| 1510 | state->CH_Ctrl[21].addr[2] = 106; | ||
| 1511 | state->CH_Ctrl[21].bit[2] = 4; | ||
| 1512 | state->CH_Ctrl[21].val[2] = 0; | ||
| 1513 | state->CH_Ctrl[21].addr[3] = 106; | ||
| 1514 | state->CH_Ctrl[21].bit[3] = 5; | ||
| 1515 | state->CH_Ctrl[21].val[3] = 0; | ||
| 1516 | state->CH_Ctrl[21].addr[4] = 106; | ||
| 1517 | state->CH_Ctrl[21].bit[4] = 6; | ||
| 1518 | state->CH_Ctrl[21].val[4] = 0; | ||
| 1519 | state->CH_Ctrl[21].addr[5] = 106; | ||
| 1520 | state->CH_Ctrl[21].bit[5] = 7; | ||
| 1521 | state->CH_Ctrl[21].val[5] = 1; | ||
| 1522 | |||
| 1523 | state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ; | ||
| 1524 | state->CH_Ctrl[22].size = 1 ; | ||
| 1525 | state->CH_Ctrl[22].addr[0] = 138; | ||
| 1526 | state->CH_Ctrl[22].bit[0] = 4; | ||
| 1527 | state->CH_Ctrl[22].val[0] = 1; | ||
| 1528 | |||
| 1529 | state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ; | ||
| 1530 | state->CH_Ctrl[23].size = 1 ; | ||
| 1531 | state->CH_Ctrl[23].addr[0] = 17; | ||
| 1532 | state->CH_Ctrl[23].bit[0] = 5; | ||
| 1533 | state->CH_Ctrl[23].val[0] = 0; | ||
| 1534 | |||
| 1535 | state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ; | ||
| 1536 | state->CH_Ctrl[24].size = 1 ; | ||
| 1537 | state->CH_Ctrl[24].addr[0] = 111; | ||
| 1538 | state->CH_Ctrl[24].bit[0] = 3; | ||
| 1539 | state->CH_Ctrl[24].val[0] = 0; | ||
| 1540 | |||
| 1541 | state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ; | ||
| 1542 | state->CH_Ctrl[25].size = 1 ; | ||
| 1543 | state->CH_Ctrl[25].addr[0] = 112; | ||
| 1544 | state->CH_Ctrl[25].bit[0] = 7; | ||
| 1545 | state->CH_Ctrl[25].val[0] = 0; | ||
| 1546 | |||
| 1547 | state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ; | ||
| 1548 | state->CH_Ctrl[26].size = 1 ; | ||
| 1549 | state->CH_Ctrl[26].addr[0] = 136; | ||
| 1550 | state->CH_Ctrl[26].bit[0] = 7; | ||
| 1551 | state->CH_Ctrl[26].val[0] = 0; | ||
| 1552 | |||
| 1553 | state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ; | ||
| 1554 | state->CH_Ctrl[27].size = 1 ; | ||
| 1555 | state->CH_Ctrl[27].addr[0] = 149; | ||
| 1556 | state->CH_Ctrl[27].bit[0] = 7; | ||
| 1557 | state->CH_Ctrl[27].val[0] = 0; | ||
| 1558 | |||
| 1559 | state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ; | ||
| 1560 | state->CH_Ctrl[28].size = 1 ; | ||
| 1561 | state->CH_Ctrl[28].addr[0] = 149; | ||
| 1562 | state->CH_Ctrl[28].bit[0] = 6; | ||
| 1563 | state->CH_Ctrl[28].val[0] = 0; | ||
| 1564 | |||
| 1565 | state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ; | ||
| 1566 | state->CH_Ctrl[29].size = 1 ; | ||
| 1567 | state->CH_Ctrl[29].addr[0] = 149; | ||
| 1568 | state->CH_Ctrl[29].bit[0] = 5; | ||
| 1569 | state->CH_Ctrl[29].val[0] = 1; | ||
| 1570 | |||
| 1571 | state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ; | ||
| 1572 | state->CH_Ctrl[30].size = 1 ; | ||
| 1573 | state->CH_Ctrl[30].addr[0] = 149; | ||
| 1574 | state->CH_Ctrl[30].bit[0] = 4; | ||
| 1575 | state->CH_Ctrl[30].val[0] = 1; | ||
| 1576 | |||
| 1577 | state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ; | ||
| 1578 | state->CH_Ctrl[31].size = 1 ; | ||
| 1579 | state->CH_Ctrl[31].addr[0] = 149; | ||
| 1580 | state->CH_Ctrl[31].bit[0] = 3; | ||
| 1581 | state->CH_Ctrl[31].val[0] = 0; | ||
| 1582 | |||
| 1583 | state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ; | ||
| 1584 | state->CH_Ctrl[32].size = 1 ; | ||
| 1585 | state->CH_Ctrl[32].addr[0] = 93; | ||
| 1586 | state->CH_Ctrl[32].bit[0] = 1; | ||
| 1587 | state->CH_Ctrl[32].val[0] = 0; | ||
| 1588 | |||
| 1589 | state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ; | ||
| 1590 | state->CH_Ctrl[33].size = 1 ; | ||
| 1591 | state->CH_Ctrl[33].addr[0] = 93; | ||
| 1592 | state->CH_Ctrl[33].bit[0] = 0; | ||
| 1593 | state->CH_Ctrl[33].val[0] = 0; | ||
| 1594 | |||
| 1595 | state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ; | ||
| 1596 | state->CH_Ctrl[34].size = 6 ; | ||
| 1597 | state->CH_Ctrl[34].addr[0] = 92; | ||
| 1598 | state->CH_Ctrl[34].bit[0] = 2; | ||
| 1599 | state->CH_Ctrl[34].val[0] = 0; | ||
| 1600 | state->CH_Ctrl[34].addr[1] = 92; | ||
| 1601 | state->CH_Ctrl[34].bit[1] = 3; | ||
| 1602 | state->CH_Ctrl[34].val[1] = 0; | ||
| 1603 | state->CH_Ctrl[34].addr[2] = 92; | ||
| 1604 | state->CH_Ctrl[34].bit[2] = 4; | ||
| 1605 | state->CH_Ctrl[34].val[2] = 0; | ||
| 1606 | state->CH_Ctrl[34].addr[3] = 92; | ||
| 1607 | state->CH_Ctrl[34].bit[3] = 5; | ||
| 1608 | state->CH_Ctrl[34].val[3] = 0; | ||
| 1609 | state->CH_Ctrl[34].addr[4] = 92; | ||
| 1610 | state->CH_Ctrl[34].bit[4] = 6; | ||
| 1611 | state->CH_Ctrl[34].val[4] = 0; | ||
| 1612 | state->CH_Ctrl[34].addr[5] = 92; | ||
| 1613 | state->CH_Ctrl[34].bit[5] = 7; | ||
| 1614 | state->CH_Ctrl[34].val[5] = 0; | ||
| 1615 | |||
| 1616 | state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ; | ||
| 1617 | state->CH_Ctrl[35].size = 6 ; | ||
| 1618 | state->CH_Ctrl[35].addr[0] = 93; | ||
| 1619 | state->CH_Ctrl[35].bit[0] = 2; | ||
| 1620 | state->CH_Ctrl[35].val[0] = 0; | ||
| 1621 | state->CH_Ctrl[35].addr[1] = 93; | ||
| 1622 | state->CH_Ctrl[35].bit[1] = 3; | ||
| 1623 | state->CH_Ctrl[35].val[1] = 0; | ||
| 1624 | state->CH_Ctrl[35].addr[2] = 93; | ||
| 1625 | state->CH_Ctrl[35].bit[2] = 4; | ||
| 1626 | state->CH_Ctrl[35].val[2] = 0; | ||
| 1627 | state->CH_Ctrl[35].addr[3] = 93; | ||
| 1628 | state->CH_Ctrl[35].bit[3] = 5; | ||
| 1629 | state->CH_Ctrl[35].val[3] = 0; | ||
| 1630 | state->CH_Ctrl[35].addr[4] = 93; | ||
| 1631 | state->CH_Ctrl[35].bit[4] = 6; | ||
| 1632 | state->CH_Ctrl[35].val[4] = 0; | ||
| 1633 | state->CH_Ctrl[35].addr[5] = 93; | ||
| 1634 | state->CH_Ctrl[35].bit[5] = 7; | ||
| 1635 | state->CH_Ctrl[35].val[5] = 0; | ||
| 1636 | |||
| 1637 | #ifdef _MXL_PRODUCTION | ||
| 1638 | state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ; | ||
| 1639 | state->CH_Ctrl[36].size = 1 ; | ||
| 1640 | state->CH_Ctrl[36].addr[0] = 109; | ||
| 1641 | state->CH_Ctrl[36].bit[0] = 1; | ||
| 1642 | state->CH_Ctrl[36].val[0] = 1; | ||
| 1643 | |||
| 1644 | state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ; | ||
| 1645 | state->CH_Ctrl[37].size = 2 ; | ||
| 1646 | state->CH_Ctrl[37].addr[0] = 112; | ||
| 1647 | state->CH_Ctrl[37].bit[0] = 5; | ||
| 1648 | state->CH_Ctrl[37].val[0] = 0; | ||
| 1649 | state->CH_Ctrl[37].addr[1] = 112; | ||
| 1650 | state->CH_Ctrl[37].bit[1] = 6; | ||
| 1651 | state->CH_Ctrl[37].val[1] = 0; | ||
| 1652 | |||
| 1653 | state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ; | ||
| 1654 | state->CH_Ctrl[38].size = 1 ; | ||
| 1655 | state->CH_Ctrl[38].addr[0] = 65; | ||
| 1656 | state->CH_Ctrl[38].bit[0] = 1; | ||
| 1657 | state->CH_Ctrl[38].val[0] = 0; | ||
| 1658 | #endif | ||
| 1659 | |||
| 1660 | return 0 ; | ||
| 1661 | } | ||
| 1662 | |||
| 1663 | static void InitTunerControls(struct dvb_frontend *fe) | ||
| 1664 | { | ||
| 1665 | MXL5005_RegisterInit(fe); | ||
| 1666 | MXL5005_ControlInit(fe); | ||
| 1667 | #ifdef _MXL_INTERNAL | ||
| 1668 | MXL5005_MXLControlInit(fe); | ||
| 1669 | #endif | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, | ||
| 1673 | u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */ | ||
| 1674 | u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */ | ||
| 1675 | u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */ | ||
| 1676 | u32 IF_out, /* Desired IF Out Frequency */ | ||
| 1677 | u32 Fxtal, /* XTAL Frequency */ | ||
| 1678 | u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */ | ||
| 1679 | u16 TOP, /* 0: Dual AGC; Value: take over point */ | ||
| 1680 | u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */ | ||
| 1681 | u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */ | ||
| 1682 | u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */ | ||
| 1683 | u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */ | ||
| 1684 | u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */ | ||
| 1685 | |||
| 1686 | /* Modulation Type; */ | ||
| 1687 | /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ | ||
| 1688 | u8 Mod_Type, | ||
| 1689 | |||
| 1690 | /* Tracking Filter */ | ||
| 1691 | /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ | ||
| 1692 | u8 TF_Type | ||
| 1693 | ) | ||
| 1694 | { | ||
| 1695 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 1696 | u16 status = 0; | ||
| 1697 | |||
| 1698 | state->Mode = Mode; | ||
| 1699 | state->IF_Mode = IF_mode; | ||
| 1700 | state->Chan_Bandwidth = Bandwidth; | ||
| 1701 | state->IF_OUT = IF_out; | ||
| 1702 | state->Fxtal = Fxtal; | ||
| 1703 | state->AGC_Mode = AGC_Mode; | ||
| 1704 | state->TOP = TOP; | ||
| 1705 | state->IF_OUT_LOAD = IF_OUT_LOAD; | ||
| 1706 | state->CLOCK_OUT = CLOCK_OUT; | ||
| 1707 | state->DIV_OUT = DIV_OUT; | ||
| 1708 | state->CAPSELECT = CAPSELECT; | ||
| 1709 | state->EN_RSSI = EN_RSSI; | ||
| 1710 | state->Mod_Type = Mod_Type; | ||
| 1711 | state->TF_Type = TF_Type; | ||
| 1712 | |||
| 1713 | /* Initialize all the controls and registers */ | ||
| 1714 | InitTunerControls(fe); | ||
| 1715 | |||
| 1716 | /* Synthesizer LO frequency calculation */ | ||
| 1717 | MXL_SynthIFLO_Calc(fe); | ||
| 1718 | |||
| 1719 | return status; | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) | ||
| 1723 | { | ||
| 1724 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 1725 | if (state->Mode == 1) /* Digital Mode */ | ||
| 1726 | state->IF_LO = state->IF_OUT; | ||
| 1727 | else /* Analog Mode */ { | ||
| 1728 | if (state->IF_Mode == 0) /* Analog Zero IF mode */ | ||
| 1729 | state->IF_LO = state->IF_OUT + 400000; | ||
| 1730 | else /* Analog Low IF mode */ | ||
| 1731 | state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2; | ||
| 1732 | } | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe) | ||
| 1736 | { | ||
| 1737 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 1738 | |||
| 1739 | if (state->Mode == 1) /* Digital Mode */ { | ||
| 1740 | /* remove 20.48MHz setting for 2.6.10 */ | ||
| 1741 | state->RF_LO = state->RF_IN; | ||
| 1742 | /* change for 2.6.6 */ | ||
| 1743 | state->TG_LO = state->RF_IN - 750000; | ||
| 1744 | } else /* Analog Mode */ { | ||
| 1745 | if (state->IF_Mode == 0) /* Analog Zero IF mode */ { | ||
| 1746 | state->RF_LO = state->RF_IN - 400000; | ||
| 1747 | state->TG_LO = state->RF_IN - 1750000; | ||
| 1748 | } else /* Analog Low IF mode */ { | ||
| 1749 | state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2; | ||
| 1750 | state->TG_LO = state->RF_IN - | ||
| 1751 | state->Chan_Bandwidth + 500000; | ||
| 1752 | } | ||
| 1753 | } | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe) | ||
| 1757 | { | ||
| 1758 | u16 status = 0; | ||
| 1759 | |||
| 1760 | status += MXL_ControlWrite(fe, OVERRIDE_1, 1); | ||
| 1761 | status += MXL_ControlWrite(fe, OVERRIDE_2, 1); | ||
| 1762 | status += MXL_ControlWrite(fe, OVERRIDE_3, 1); | ||
| 1763 | status += MXL_ControlWrite(fe, OVERRIDE_4, 1); | ||
| 1764 | |||
| 1765 | return status; | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | static u16 MXL_BlockInit(struct dvb_frontend *fe) | ||
| 1769 | { | ||
| 1770 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 1771 | u16 status = 0; | ||
| 1772 | |||
| 1773 | status += MXL_OverwriteICDefault(fe); | ||
| 1774 | |||
| 1775 | /* Downconverter Control Dig Ana */ | ||
| 1776 | status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0); | ||
| 1777 | |||
| 1778 | /* Filter Control Dig Ana */ | ||
| 1779 | status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1); | ||
| 1780 | status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2); | ||
| 1781 | status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0); | ||
| 1782 | status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1); | ||
| 1783 | status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0); | ||
| 1784 | |||
| 1785 | /* Initialize Low-Pass Filter */ | ||
| 1786 | if (state->Mode) { /* Digital Mode */ | ||
| 1787 | switch (state->Chan_Bandwidth) { | ||
| 1788 | case 8000000: | ||
| 1789 | status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0); | ||
| 1790 | break; | ||
| 1791 | case 7000000: | ||
| 1792 | status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2); | ||
| 1793 | break; | ||
| 1794 | case 6000000: | ||
| 1795 | status += MXL_ControlWrite(fe, | ||
| 1796 | BB_DLPF_BANDSEL, 3); | ||
| 1797 | break; | ||
| 1798 | } | ||
| 1799 | } else { /* Analog Mode */ | ||
| 1800 | switch (state->Chan_Bandwidth) { | ||
| 1801 | case 8000000: /* Low Zero */ | ||
| 1802 | status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, | ||
| 1803 | (state->IF_Mode ? 0 : 3)); | ||
| 1804 | break; | ||
| 1805 | case 7000000: | ||
| 1806 | status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, | ||
| 1807 | (state->IF_Mode ? 1 : 4)); | ||
| 1808 | break; | ||
| 1809 | case 6000000: | ||
| 1810 | status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, | ||
| 1811 | (state->IF_Mode ? 2 : 5)); | ||
| 1812 | break; | ||
| 1813 | } | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | /* Charge Pump Control Dig Ana */ | ||
| 1817 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8); | ||
| 1818 | status += MXL_ControlWrite(fe, | ||
| 1819 | RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1); | ||
| 1820 | status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0); | ||
| 1821 | |||
| 1822 | /* AGC TOP Control */ | ||
| 1823 | if (state->AGC_Mode == 0) /* Dual AGC */ { | ||
| 1824 | status += MXL_ControlWrite(fe, AGC_IF, 15); | ||
| 1825 | status += MXL_ControlWrite(fe, AGC_RF, 15); | ||
| 1826 | } else /* Single AGC Mode Dig Ana */ | ||
| 1827 | status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12); | ||
| 1828 | |||
| 1829 | if (state->TOP == 55) /* TOP == 5.5 */ | ||
| 1830 | status += MXL_ControlWrite(fe, AGC_IF, 0x0); | ||
| 1831 | |||
| 1832 | if (state->TOP == 72) /* TOP == 7.2 */ | ||
| 1833 | status += MXL_ControlWrite(fe, AGC_IF, 0x1); | ||
| 1834 | |||
| 1835 | if (state->TOP == 92) /* TOP == 9.2 */ | ||
| 1836 | status += MXL_ControlWrite(fe, AGC_IF, 0x2); | ||
| 1837 | |||
| 1838 | if (state->TOP == 110) /* TOP == 11.0 */ | ||
| 1839 | status += MXL_ControlWrite(fe, AGC_IF, 0x3); | ||
| 1840 | |||
| 1841 | if (state->TOP == 129) /* TOP == 12.9 */ | ||
| 1842 | status += MXL_ControlWrite(fe, AGC_IF, 0x4); | ||
| 1843 | |||
| 1844 | if (state->TOP == 147) /* TOP == 14.7 */ | ||
| 1845 | status += MXL_ControlWrite(fe, AGC_IF, 0x5); | ||
| 1846 | |||
| 1847 | if (state->TOP == 168) /* TOP == 16.8 */ | ||
| 1848 | status += MXL_ControlWrite(fe, AGC_IF, 0x6); | ||
| 1849 | |||
| 1850 | if (state->TOP == 194) /* TOP == 19.4 */ | ||
| 1851 | status += MXL_ControlWrite(fe, AGC_IF, 0x7); | ||
| 1852 | |||
| 1853 | if (state->TOP == 212) /* TOP == 21.2 */ | ||
| 1854 | status += MXL_ControlWrite(fe, AGC_IF, 0x9); | ||
| 1855 | |||
| 1856 | if (state->TOP == 232) /* TOP == 23.2 */ | ||
| 1857 | status += MXL_ControlWrite(fe, AGC_IF, 0xA); | ||
| 1858 | |||
| 1859 | if (state->TOP == 252) /* TOP == 25.2 */ | ||
| 1860 | status += MXL_ControlWrite(fe, AGC_IF, 0xB); | ||
| 1861 | |||
| 1862 | if (state->TOP == 271) /* TOP == 27.1 */ | ||
| 1863 | status += MXL_ControlWrite(fe, AGC_IF, 0xC); | ||
| 1864 | |||
| 1865 | if (state->TOP == 292) /* TOP == 29.2 */ | ||
| 1866 | status += MXL_ControlWrite(fe, AGC_IF, 0xD); | ||
| 1867 | |||
| 1868 | if (state->TOP == 317) /* TOP == 31.7 */ | ||
| 1869 | status += MXL_ControlWrite(fe, AGC_IF, 0xE); | ||
| 1870 | |||
| 1871 | if (state->TOP == 349) /* TOP == 34.9 */ | ||
| 1872 | status += MXL_ControlWrite(fe, AGC_IF, 0xF); | ||
| 1873 | |||
| 1874 | /* IF Synthesizer Control */ | ||
| 1875 | status += MXL_IFSynthInit(fe); | ||
| 1876 | |||
| 1877 | /* IF UpConverter Control */ | ||
| 1878 | if (state->IF_OUT_LOAD == 200) { | ||
| 1879 | status += MXL_ControlWrite(fe, DRV_RES_SEL, 6); | ||
| 1880 | status += MXL_ControlWrite(fe, I_DRIVER, 2); | ||
| 1881 | } | ||
| 1882 | if (state->IF_OUT_LOAD == 300) { | ||
| 1883 | status += MXL_ControlWrite(fe, DRV_RES_SEL, 4); | ||
| 1884 | status += MXL_ControlWrite(fe, I_DRIVER, 1); | ||
| 1885 | } | ||
| 1886 | |||
| 1887 | /* Anti-Alias Filtering Control | ||
| 1888 | * initialise Anti-Aliasing Filter | ||
| 1889 | */ | ||
| 1890 | if (state->Mode) { /* Digital Mode */ | ||
| 1891 | if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) { | ||
| 1892 | status += MXL_ControlWrite(fe, EN_AAF, 1); | ||
| 1893 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
| 1894 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
| 1895 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); | ||
| 1896 | } | ||
| 1897 | if ((state->IF_OUT == 36125000UL) || | ||
| 1898 | (state->IF_OUT == 36150000UL)) { | ||
| 1899 | status += MXL_ControlWrite(fe, EN_AAF, 1); | ||
| 1900 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
| 1901 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
| 1902 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); | ||
| 1903 | } | ||
| 1904 | if (state->IF_OUT > 36150000UL) { | ||
| 1905 | status += MXL_ControlWrite(fe, EN_AAF, 0); | ||
| 1906 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
| 1907 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
| 1908 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); | ||
| 1909 | } | ||
| 1910 | } else { /* Analog Mode */ | ||
| 1911 | if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) { | ||
| 1912 | status += MXL_ControlWrite(fe, EN_AAF, 1); | ||
| 1913 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
| 1914 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
| 1915 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); | ||
| 1916 | } | ||
| 1917 | if (state->IF_OUT > 5000000UL) { | ||
| 1918 | status += MXL_ControlWrite(fe, EN_AAF, 0); | ||
| 1919 | status += MXL_ControlWrite(fe, EN_3P, 0); | ||
| 1920 | status += MXL_ControlWrite(fe, EN_AUX_3P, 0); | ||
| 1921 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); | ||
| 1922 | } | ||
| 1923 | } | ||
| 1924 | |||
| 1925 | /* Demod Clock Out */ | ||
| 1926 | if (state->CLOCK_OUT) | ||
| 1927 | status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1); | ||
| 1928 | else | ||
| 1929 | status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0); | ||
| 1930 | |||
| 1931 | if (state->DIV_OUT == 1) | ||
| 1932 | status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1); | ||
| 1933 | if (state->DIV_OUT == 0) | ||
| 1934 | status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0); | ||
| 1935 | |||
| 1936 | /* Crystal Control */ | ||
| 1937 | if (state->CAPSELECT) | ||
| 1938 | status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1); | ||
| 1939 | else | ||
| 1940 | status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0); | ||
| 1941 | |||
| 1942 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) | ||
| 1943 | status += MXL_ControlWrite(fe, IF_SEL_DBL, 1); | ||
| 1944 | if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) | ||
| 1945 | status += MXL_ControlWrite(fe, IF_SEL_DBL, 0); | ||
| 1946 | |||
| 1947 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) | ||
| 1948 | status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3); | ||
| 1949 | if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL) | ||
| 1950 | status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0); | ||
| 1951 | |||
| 1952 | /* Misc Controls */ | ||
| 1953 | if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */ | ||
| 1954 | status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0); | ||
| 1955 | else | ||
| 1956 | status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1); | ||
| 1957 | |||
| 1958 | /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */ | ||
| 1959 | |||
| 1960 | /* Set TG_R_DIV */ | ||
| 1961 | status += MXL_ControlWrite(fe, TG_R_DIV, | ||
| 1962 | MXL_Ceiling(state->Fxtal, 1000000)); | ||
| 1963 | |||
| 1964 | /* Apply Default value to BB_INITSTATE_DLPF_TUNE */ | ||
| 1965 | |||
| 1966 | /* RSSI Control */ | ||
| 1967 | if (state->EN_RSSI) { | ||
| 1968 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 1969 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 1970 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
| 1971 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 1972 | |||
| 1973 | /* RSSI reference point */ | ||
| 1974 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); | ||
| 1975 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3); | ||
| 1976 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); | ||
| 1977 | |||
| 1978 | /* TOP point */ | ||
| 1979 | status += MXL_ControlWrite(fe, RFA_FLR, 0); | ||
| 1980 | status += MXL_ControlWrite(fe, RFA_CEIL, 12); | ||
| 1981 | } | ||
| 1982 | |||
| 1983 | /* Modulation type bit settings | ||
| 1984 | * Override the control values preset | ||
| 1985 | */ | ||
| 1986 | if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ { | ||
| 1987 | state->AGC_Mode = 1; /* Single AGC Mode */ | ||
| 1988 | |||
| 1989 | /* Enable RSSI */ | ||
| 1990 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 1991 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 1992 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
| 1993 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 1994 | |||
| 1995 | /* RSSI reference point */ | ||
| 1996 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
| 1997 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
| 1998 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); | ||
| 1999 | |||
| 2000 | /* TOP point */ | ||
| 2001 | status += MXL_ControlWrite(fe, RFA_FLR, 2); | ||
| 2002 | status += MXL_ControlWrite(fe, RFA_CEIL, 13); | ||
| 2003 | if (state->IF_OUT <= 6280000UL) /* Low IF */ | ||
| 2004 | status += MXL_ControlWrite(fe, BB_IQSWAP, 0); | ||
| 2005 | else /* High IF */ | ||
| 2006 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
| 2007 | |||
| 2008 | } | ||
| 2009 | if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ { | ||
| 2010 | state->AGC_Mode = 1; /* Single AGC Mode */ | ||
| 2011 | |||
| 2012 | /* Enable RSSI */ | ||
| 2013 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 2014 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 2015 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
| 2016 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 2017 | |||
| 2018 | /* RSSI reference point */ | ||
| 2019 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); | ||
| 2020 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4); | ||
| 2021 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); | ||
| 2022 | |||
| 2023 | /* TOP point */ | ||
| 2024 | status += MXL_ControlWrite(fe, RFA_FLR, 2); | ||
| 2025 | status += MXL_ControlWrite(fe, RFA_CEIL, 13); | ||
| 2026 | status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1); | ||
| 2027 | /* Low Zero */ | ||
| 2028 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); | ||
| 2029 | |||
| 2030 | if (state->IF_OUT <= 6280000UL) /* Low IF */ | ||
| 2031 | status += MXL_ControlWrite(fe, BB_IQSWAP, 0); | ||
| 2032 | else /* High IF */ | ||
| 2033 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
| 2034 | } | ||
| 2035 | if (state->Mod_Type == MXL_QAM) /* QAM Mode */ { | ||
| 2036 | state->Mode = MXL_DIGITAL_MODE; | ||
| 2037 | |||
| 2038 | /* state->AGC_Mode = 1; */ /* Single AGC Mode */ | ||
| 2039 | |||
| 2040 | /* Disable RSSI */ /* change here for v2.6.5 */ | ||
| 2041 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 2042 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 2043 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
| 2044 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 2045 | |||
| 2046 | /* RSSI reference point */ | ||
| 2047 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
| 2048 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
| 2049 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); | ||
| 2050 | /* change here for v2.6.5 */ | ||
| 2051 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
| 2052 | |||
| 2053 | if (state->IF_OUT <= 6280000UL) /* Low IF */ | ||
| 2054 | status += MXL_ControlWrite(fe, BB_IQSWAP, 0); | ||
| 2055 | else /* High IF */ | ||
| 2056 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
| 2057 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); | ||
| 2058 | |||
| 2059 | } | ||
| 2060 | if (state->Mod_Type == MXL_ANALOG_CABLE) { | ||
| 2061 | /* Analog Cable Mode */ | ||
| 2062 | /* state->Mode = MXL_DIGITAL_MODE; */ | ||
| 2063 | |||
| 2064 | state->AGC_Mode = 1; /* Single AGC Mode */ | ||
| 2065 | |||
| 2066 | /* Disable RSSI */ | ||
| 2067 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 2068 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 2069 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
| 2070 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 2071 | /* change for 2.6.3 */ | ||
| 2072 | status += MXL_ControlWrite(fe, AGC_IF, 1); | ||
| 2073 | status += MXL_ControlWrite(fe, AGC_RF, 15); | ||
| 2074 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | if (state->Mod_Type == MXL_ANALOG_OTA) { | ||
| 2078 | /* Analog OTA Terrestrial mode add for 2.6.7 */ | ||
| 2079 | /* state->Mode = MXL_ANALOG_MODE; */ | ||
| 2080 | |||
| 2081 | /* Enable RSSI */ | ||
| 2082 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 2083 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 2084 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
| 2085 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 2086 | |||
| 2087 | /* RSSI reference point */ | ||
| 2088 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
| 2089 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
| 2090 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); | ||
| 2091 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
| 2092 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
| 2093 | } | ||
| 2094 | |||
| 2095 | /* RSSI disable */ | ||
| 2096 | if (state->EN_RSSI == 0) { | ||
| 2097 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 2098 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 2099 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
| 2100 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | return status; | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | static u16 MXL_IFSynthInit(struct dvb_frontend *fe) | ||
| 2107 | { | ||
| 2108 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 2109 | u16 status = 0 ; | ||
| 2110 | u32 Fref = 0 ; | ||
| 2111 | u32 Kdbl, intModVal ; | ||
| 2112 | u32 fracModVal ; | ||
| 2113 | Kdbl = 2 ; | ||
| 2114 | |||
| 2115 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) | ||
| 2116 | Kdbl = 2 ; | ||
| 2117 | if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) | ||
| 2118 | Kdbl = 1 ; | ||
| 2119 | |||
| 2120 | /* IF Synthesizer Control */ | ||
| 2121 | if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ { | ||
| 2122 | if (state->IF_LO == 41000000UL) { | ||
| 2123 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2124 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2125 | Fref = 328000000UL ; | ||
| 2126 | } | ||
| 2127 | if (state->IF_LO == 47000000UL) { | ||
| 2128 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2129 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2130 | Fref = 376000000UL ; | ||
| 2131 | } | ||
| 2132 | if (state->IF_LO == 54000000UL) { | ||
| 2133 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
| 2134 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2135 | Fref = 324000000UL ; | ||
| 2136 | } | ||
| 2137 | if (state->IF_LO == 60000000UL) { | ||
| 2138 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
| 2139 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2140 | Fref = 360000000UL ; | ||
| 2141 | } | ||
| 2142 | if (state->IF_LO == 39250000UL) { | ||
| 2143 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2144 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2145 | Fref = 314000000UL ; | ||
| 2146 | } | ||
| 2147 | if (state->IF_LO == 39650000UL) { | ||
| 2148 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2149 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2150 | Fref = 317200000UL ; | ||
| 2151 | } | ||
| 2152 | if (state->IF_LO == 40150000UL) { | ||
| 2153 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2154 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2155 | Fref = 321200000UL ; | ||
| 2156 | } | ||
| 2157 | if (state->IF_LO == 40650000UL) { | ||
| 2158 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2159 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2160 | Fref = 325200000UL ; | ||
| 2161 | } | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) { | ||
| 2165 | if (state->IF_LO == 57000000UL) { | ||
| 2166 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
| 2167 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2168 | Fref = 342000000UL ; | ||
| 2169 | } | ||
| 2170 | if (state->IF_LO == 44000000UL) { | ||
| 2171 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2172 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2173 | Fref = 352000000UL ; | ||
| 2174 | } | ||
| 2175 | if (state->IF_LO == 43750000UL) { | ||
| 2176 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2177 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2178 | Fref = 350000000UL ; | ||
| 2179 | } | ||
| 2180 | if (state->IF_LO == 36650000UL) { | ||
| 2181 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2182 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2183 | Fref = 366500000UL ; | ||
| 2184 | } | ||
| 2185 | if (state->IF_LO == 36150000UL) { | ||
| 2186 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2187 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2188 | Fref = 361500000UL ; | ||
| 2189 | } | ||
| 2190 | if (state->IF_LO == 36000000UL) { | ||
| 2191 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2192 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2193 | Fref = 360000000UL ; | ||
| 2194 | } | ||
| 2195 | if (state->IF_LO == 35250000UL) { | ||
| 2196 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2197 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2198 | Fref = 352500000UL ; | ||
| 2199 | } | ||
| 2200 | if (state->IF_LO == 34750000UL) { | ||
| 2201 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2202 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2203 | Fref = 347500000UL ; | ||
| 2204 | } | ||
| 2205 | if (state->IF_LO == 6280000UL) { | ||
| 2206 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
| 2207 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2208 | Fref = 376800000UL ; | ||
| 2209 | } | ||
| 2210 | if (state->IF_LO == 5000000UL) { | ||
| 2211 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); | ||
| 2212 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2213 | Fref = 360000000UL ; | ||
| 2214 | } | ||
| 2215 | if (state->IF_LO == 4500000UL) { | ||
| 2216 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); | ||
| 2217 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2218 | Fref = 360000000UL ; | ||
| 2219 | } | ||
| 2220 | if (state->IF_LO == 4570000UL) { | ||
| 2221 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); | ||
| 2222 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2223 | Fref = 365600000UL ; | ||
| 2224 | } | ||
| 2225 | if (state->IF_LO == 4000000UL) { | ||
| 2226 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); | ||
| 2227 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2228 | Fref = 360000000UL ; | ||
| 2229 | } | ||
| 2230 | if (state->IF_LO == 57400000UL) { | ||
| 2231 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
| 2232 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2233 | Fref = 344400000UL ; | ||
| 2234 | } | ||
| 2235 | if (state->IF_LO == 44400000UL) { | ||
| 2236 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2237 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2238 | Fref = 355200000UL ; | ||
| 2239 | } | ||
| 2240 | if (state->IF_LO == 44150000UL) { | ||
| 2241 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
| 2242 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2243 | Fref = 353200000UL ; | ||
| 2244 | } | ||
| 2245 | if (state->IF_LO == 37050000UL) { | ||
| 2246 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2247 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2248 | Fref = 370500000UL ; | ||
| 2249 | } | ||
| 2250 | if (state->IF_LO == 36550000UL) { | ||
| 2251 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2252 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2253 | Fref = 365500000UL ; | ||
| 2254 | } | ||
| 2255 | if (state->IF_LO == 36125000UL) { | ||
| 2256 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
| 2257 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2258 | Fref = 361250000UL ; | ||
| 2259 | } | ||
| 2260 | if (state->IF_LO == 6000000UL) { | ||
| 2261 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
| 2262 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2263 | Fref = 360000000UL ; | ||
| 2264 | } | ||
| 2265 | if (state->IF_LO == 5400000UL) { | ||
| 2266 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
| 2267 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2268 | Fref = 324000000UL ; | ||
| 2269 | } | ||
| 2270 | if (state->IF_LO == 5380000UL) { | ||
| 2271 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
| 2272 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
| 2273 | Fref = 322800000UL ; | ||
| 2274 | } | ||
| 2275 | if (state->IF_LO == 5200000UL) { | ||
| 2276 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); | ||
| 2277 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2278 | Fref = 374400000UL ; | ||
| 2279 | } | ||
| 2280 | if (state->IF_LO == 4900000UL) { | ||
| 2281 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); | ||
| 2282 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2283 | Fref = 352800000UL ; | ||
| 2284 | } | ||
| 2285 | if (state->IF_LO == 4400000UL) { | ||
| 2286 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); | ||
| 2287 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2288 | Fref = 352000000UL ; | ||
| 2289 | } | ||
| 2290 | if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ { | ||
| 2291 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); | ||
| 2292 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
| 2293 | Fref = 365670000UL ; | ||
| 2294 | } | ||
| 2295 | } | ||
| 2296 | /* CHCAL_INT_MOD_IF */ | ||
| 2297 | /* CHCAL_FRAC_MOD_IF */ | ||
| 2298 | intModVal = Fref / (state->Fxtal * Kdbl/2); | ||
| 2299 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal); | ||
| 2300 | |||
| 2301 | fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) * | ||
| 2302 | intModVal); | ||
| 2303 | |||
| 2304 | fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000); | ||
| 2305 | status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal); | ||
| 2306 | |||
| 2307 | return status ; | ||
| 2308 | } | ||
| 2309 | |||
| 2310 | static u32 MXL_GetXtalInt(u32 Xtal_Freq) | ||
| 2311 | { | ||
| 2312 | if ((Xtal_Freq % 1000000) == 0) | ||
| 2313 | return (Xtal_Freq / 10000); | ||
| 2314 | else | ||
| 2315 | return (((Xtal_Freq / 1000000) + 1)*100); | ||
| 2316 | } | ||
| 2317 | |||
| 2318 | static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) | ||
| 2319 | { | ||
| 2320 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 2321 | u16 status = 0; | ||
| 2322 | u32 divider_val, E3, E4, E5, E5A; | ||
| 2323 | u32 Fmax, Fmin, FmaxBin, FminBin; | ||
| 2324 | u32 Kdbl_RF = 2; | ||
| 2325 | u32 tg_divval; | ||
| 2326 | u32 tg_lo; | ||
| 2327 | u32 Xtal_Int; | ||
| 2328 | |||
| 2329 | u32 Fref_TG; | ||
| 2330 | u32 Fvco; | ||
| 2331 | |||
| 2332 | Xtal_Int = MXL_GetXtalInt(state->Fxtal); | ||
| 2333 | |||
| 2334 | state->RF_IN = RF_Freq; | ||
| 2335 | |||
| 2336 | MXL_SynthRFTGLO_Calc(fe); | ||
| 2337 | |||
| 2338 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) | ||
| 2339 | Kdbl_RF = 2; | ||
| 2340 | if (state->Fxtal > 22000000 && state->Fxtal <= 32000000) | ||
| 2341 | Kdbl_RF = 1; | ||
| 2342 | |||
| 2343 | /* Downconverter Controls | ||
| 2344 | * Look-Up Table Implementation for: | ||
| 2345 | * DN_POLY | ||
| 2346 | * DN_RFGAIN | ||
| 2347 | * DN_CAP_RFLPF | ||
| 2348 | * DN_EN_VHFUHFBAR | ||
| 2349 | * DN_GAIN_ADJUST | ||
| 2350 | * Change the boundary reference from RF_IN to RF_LO | ||
| 2351 | */ | ||
| 2352 | if (state->RF_LO < 40000000UL) | ||
| 2353 | return -1; | ||
| 2354 | |||
| 2355 | if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { | ||
| 2356 | status += MXL_ControlWrite(fe, DN_POLY, 2); | ||
| 2357 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
| 2358 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423); | ||
| 2359 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
| 2360 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); | ||
| 2361 | } | ||
| 2362 | if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { | ||
| 2363 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
| 2364 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
| 2365 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222); | ||
| 2366 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
| 2367 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); | ||
| 2368 | } | ||
| 2369 | if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { | ||
| 2370 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
| 2371 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
| 2372 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147); | ||
| 2373 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
| 2374 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); | ||
| 2375 | } | ||
| 2376 | if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { | ||
| 2377 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
| 2378 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
| 2379 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9); | ||
| 2380 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
| 2381 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); | ||
| 2382 | } | ||
| 2383 | if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { | ||
| 2384 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
| 2385 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
| 2386 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); | ||
| 2387 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
| 2388 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); | ||
| 2389 | } | ||
| 2390 | if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) { | ||
| 2391 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
| 2392 | status += MXL_ControlWrite(fe, DN_RFGAIN, 1); | ||
| 2393 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); | ||
| 2394 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); | ||
| 2395 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); | ||
| 2396 | } | ||
| 2397 | if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) { | ||
| 2398 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
| 2399 | status += MXL_ControlWrite(fe, DN_RFGAIN, 2); | ||
| 2400 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); | ||
| 2401 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); | ||
| 2402 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); | ||
| 2403 | } | ||
| 2404 | if (state->RF_LO > 900000000UL) | ||
| 2405 | return -1; | ||
| 2406 | |||
| 2407 | /* DN_IQTNBUF_AMP */ | ||
| 2408 | /* DN_IQTNGNBFBIAS_BST */ | ||
| 2409 | if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { | ||
| 2410 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2411 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2412 | } | ||
| 2413 | if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { | ||
| 2414 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2415 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2416 | } | ||
| 2417 | if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { | ||
| 2418 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2419 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2420 | } | ||
| 2421 | if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { | ||
| 2422 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2423 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2424 | } | ||
| 2425 | if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { | ||
| 2426 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2427 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2428 | } | ||
| 2429 | if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) { | ||
| 2430 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2431 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2432 | } | ||
| 2433 | if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) { | ||
| 2434 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2435 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2436 | } | ||
| 2437 | if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) { | ||
| 2438 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2439 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2440 | } | ||
| 2441 | if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) { | ||
| 2442 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2443 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2444 | } | ||
| 2445 | if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) { | ||
| 2446 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2447 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2448 | } | ||
| 2449 | if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) { | ||
| 2450 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2451 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2452 | } | ||
| 2453 | if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) { | ||
| 2454 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2455 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2456 | } | ||
| 2457 | if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) { | ||
| 2458 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2459 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2460 | } | ||
| 2461 | if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) { | ||
| 2462 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
| 2463 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
| 2464 | } | ||
| 2465 | if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) { | ||
| 2466 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); | ||
| 2467 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); | ||
| 2468 | } | ||
| 2469 | if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) { | ||
| 2470 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); | ||
| 2471 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | /* | ||
| 2475 | * Set RF Synth and LO Path Control | ||
| 2476 | * | ||
| 2477 | * Look-Up table implementation for: | ||
| 2478 | * RFSYN_EN_OUTMUX | ||
| 2479 | * RFSYN_SEL_VCO_OUT | ||
| 2480 | * RFSYN_SEL_VCO_HI | ||
| 2481 | * RFSYN_SEL_DIVM | ||
| 2482 | * RFSYN_RF_DIV_BIAS | ||
| 2483 | * DN_SEL_FREQ | ||
| 2484 | * | ||
| 2485 | * Set divider_val, Fmax, Fmix to use in Equations | ||
| 2486 | */ | ||
| 2487 | FminBin = 28000000UL ; | ||
| 2488 | FmaxBin = 42500000UL ; | ||
| 2489 | if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) { | ||
| 2490 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
| 2491 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
| 2492 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 2493 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2494 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2495 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
| 2496 | divider_val = 64 ; | ||
| 2497 | Fmax = FmaxBin ; | ||
| 2498 | Fmin = FminBin ; | ||
| 2499 | } | ||
| 2500 | FminBin = 42500000UL ; | ||
| 2501 | FmaxBin = 56000000UL ; | ||
| 2502 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2503 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
| 2504 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
| 2505 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 2506 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2507 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2508 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
| 2509 | divider_val = 64 ; | ||
| 2510 | Fmax = FmaxBin ; | ||
| 2511 | Fmin = FminBin ; | ||
| 2512 | } | ||
| 2513 | FminBin = 56000000UL ; | ||
| 2514 | FmaxBin = 85000000UL ; | ||
| 2515 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2516 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2517 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2518 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 2519 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2520 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2521 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
| 2522 | divider_val = 32 ; | ||
| 2523 | Fmax = FmaxBin ; | ||
| 2524 | Fmin = FminBin ; | ||
| 2525 | } | ||
| 2526 | FminBin = 85000000UL ; | ||
| 2527 | FmaxBin = 112000000UL ; | ||
| 2528 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2529 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2530 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2531 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 2532 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2533 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2534 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
| 2535 | divider_val = 32 ; | ||
| 2536 | Fmax = FmaxBin ; | ||
| 2537 | Fmin = FminBin ; | ||
| 2538 | } | ||
| 2539 | FminBin = 112000000UL ; | ||
| 2540 | FmaxBin = 170000000UL ; | ||
| 2541 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2542 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2543 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2544 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 2545 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2546 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2547 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); | ||
| 2548 | divider_val = 16 ; | ||
| 2549 | Fmax = FmaxBin ; | ||
| 2550 | Fmin = FminBin ; | ||
| 2551 | } | ||
| 2552 | FminBin = 170000000UL ; | ||
| 2553 | FmaxBin = 225000000UL ; | ||
| 2554 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2555 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2556 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2557 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 2558 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2559 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2560 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); | ||
| 2561 | divider_val = 16 ; | ||
| 2562 | Fmax = FmaxBin ; | ||
| 2563 | Fmin = FminBin ; | ||
| 2564 | } | ||
| 2565 | FminBin = 225000000UL ; | ||
| 2566 | FmaxBin = 300000000UL ; | ||
| 2567 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2568 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2569 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2570 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 2571 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2572 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2573 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4); | ||
| 2574 | divider_val = 8 ; | ||
| 2575 | Fmax = 340000000UL ; | ||
| 2576 | Fmin = FminBin ; | ||
| 2577 | } | ||
| 2578 | FminBin = 300000000UL ; | ||
| 2579 | FmaxBin = 340000000UL ; | ||
| 2580 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2581 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
| 2582 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
| 2583 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 2584 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2585 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2586 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 2587 | divider_val = 8 ; | ||
| 2588 | Fmax = FmaxBin ; | ||
| 2589 | Fmin = 225000000UL ; | ||
| 2590 | } | ||
| 2591 | FminBin = 340000000UL ; | ||
| 2592 | FmaxBin = 450000000UL ; | ||
| 2593 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2594 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
| 2595 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
| 2596 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 2597 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 2598 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2); | ||
| 2599 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 2600 | divider_val = 8 ; | ||
| 2601 | Fmax = FmaxBin ; | ||
| 2602 | Fmin = FminBin ; | ||
| 2603 | } | ||
| 2604 | FminBin = 450000000UL ; | ||
| 2605 | FmaxBin = 680000000UL ; | ||
| 2606 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2607 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2608 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2609 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 2610 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); | ||
| 2611 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2612 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 2613 | divider_val = 4 ; | ||
| 2614 | Fmax = FmaxBin ; | ||
| 2615 | Fmin = FminBin ; | ||
| 2616 | } | ||
| 2617 | FminBin = 680000000UL ; | ||
| 2618 | FmaxBin = 900000000UL ; | ||
| 2619 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
| 2620 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 2621 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 2622 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 2623 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); | ||
| 2624 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 2625 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 2626 | divider_val = 4 ; | ||
| 2627 | Fmax = FmaxBin ; | ||
| 2628 | Fmin = FminBin ; | ||
| 2629 | } | ||
| 2630 | |||
| 2631 | /* CHCAL_INT_MOD_RF | ||
| 2632 | * CHCAL_FRAC_MOD_RF | ||
| 2633 | * RFSYN_LPF_R | ||
| 2634 | * CHCAL_EN_INT_RF | ||
| 2635 | */ | ||
| 2636 | /* Equation E3 RFSYN_VCO_BIAS */ | ||
| 2637 | E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ; | ||
| 2638 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3); | ||
| 2639 | |||
| 2640 | /* Equation E4 CHCAL_INT_MOD_RF */ | ||
| 2641 | E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000); | ||
| 2642 | MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4); | ||
| 2643 | |||
| 2644 | /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */ | ||
| 2645 | E5 = ((2<<17)*(state->RF_LO/10000*divider_val - | ||
| 2646 | (E4*(2*state->Fxtal*Kdbl_RF)/10000))) / | ||
| 2647 | (2*state->Fxtal*Kdbl_RF/10000); | ||
| 2648 | |||
| 2649 | status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); | ||
| 2650 | |||
| 2651 | /* Equation E5A RFSYN_LPF_R */ | ||
| 2652 | E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; | ||
| 2653 | status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); | ||
| 2654 | |||
| 2655 | /* Euqation E5B CHCAL_EN_INIT_RF */ | ||
| 2656 | status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); | ||
| 2657 | /*if (E5 == 0) | ||
| 2658 | * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); | ||
| 2659 | *else | ||
| 2660 | * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); | ||
| 2661 | */ | ||
| 2662 | |||
| 2663 | /* | ||
| 2664 | * Set TG Synth | ||
| 2665 | * | ||
| 2666 | * Look-Up table implementation for: | ||
| 2667 | * TG_LO_DIVVAL | ||
| 2668 | * TG_LO_SELVAL | ||
| 2669 | * | ||
| 2670 | * Set divider_val, Fmax, Fmix to use in Equations | ||
| 2671 | */ | ||
| 2672 | if (state->TG_LO < 33000000UL) | ||
| 2673 | return -1; | ||
| 2674 | |||
| 2675 | FminBin = 33000000UL ; | ||
| 2676 | FmaxBin = 50000000UL ; | ||
| 2677 | if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) { | ||
| 2678 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6); | ||
| 2679 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); | ||
| 2680 | divider_val = 36 ; | ||
| 2681 | Fmax = FmaxBin ; | ||
| 2682 | Fmin = FminBin ; | ||
| 2683 | } | ||
| 2684 | FminBin = 50000000UL ; | ||
| 2685 | FmaxBin = 67000000UL ; | ||
| 2686 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2687 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1); | ||
| 2688 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); | ||
| 2689 | divider_val = 24 ; | ||
| 2690 | Fmax = FmaxBin ; | ||
| 2691 | Fmin = FminBin ; | ||
| 2692 | } | ||
| 2693 | FminBin = 67000000UL ; | ||
| 2694 | FmaxBin = 100000000UL ; | ||
| 2695 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2696 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC); | ||
| 2697 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); | ||
| 2698 | divider_val = 18 ; | ||
| 2699 | Fmax = FmaxBin ; | ||
| 2700 | Fmin = FminBin ; | ||
| 2701 | } | ||
| 2702 | FminBin = 100000000UL ; | ||
| 2703 | FmaxBin = 150000000UL ; | ||
| 2704 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2705 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); | ||
| 2706 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); | ||
| 2707 | divider_val = 12 ; | ||
| 2708 | Fmax = FmaxBin ; | ||
| 2709 | Fmin = FminBin ; | ||
| 2710 | } | ||
| 2711 | FminBin = 150000000UL ; | ||
| 2712 | FmaxBin = 200000000UL ; | ||
| 2713 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2714 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); | ||
| 2715 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); | ||
| 2716 | divider_val = 8 ; | ||
| 2717 | Fmax = FmaxBin ; | ||
| 2718 | Fmin = FminBin ; | ||
| 2719 | } | ||
| 2720 | FminBin = 200000000UL ; | ||
| 2721 | FmaxBin = 300000000UL ; | ||
| 2722 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2723 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); | ||
| 2724 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); | ||
| 2725 | divider_val = 6 ; | ||
| 2726 | Fmax = FmaxBin ; | ||
| 2727 | Fmin = FminBin ; | ||
| 2728 | } | ||
| 2729 | FminBin = 300000000UL ; | ||
| 2730 | FmaxBin = 400000000UL ; | ||
| 2731 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2732 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); | ||
| 2733 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); | ||
| 2734 | divider_val = 4 ; | ||
| 2735 | Fmax = FmaxBin ; | ||
| 2736 | Fmin = FminBin ; | ||
| 2737 | } | ||
| 2738 | FminBin = 400000000UL ; | ||
| 2739 | FmaxBin = 600000000UL ; | ||
| 2740 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2741 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); | ||
| 2742 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); | ||
| 2743 | divider_val = 3 ; | ||
| 2744 | Fmax = FmaxBin ; | ||
| 2745 | Fmin = FminBin ; | ||
| 2746 | } | ||
| 2747 | FminBin = 600000000UL ; | ||
| 2748 | FmaxBin = 900000000UL ; | ||
| 2749 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
| 2750 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); | ||
| 2751 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); | ||
| 2752 | divider_val = 2 ; | ||
| 2753 | Fmax = FmaxBin ; | ||
| 2754 | Fmin = FminBin ; | ||
| 2755 | } | ||
| 2756 | |||
| 2757 | /* TG_DIV_VAL */ | ||
| 2758 | tg_divval = (state->TG_LO*divider_val/100000) * | ||
| 2759 | (MXL_Ceiling(state->Fxtal, 1000000) * 100) / | ||
| 2760 | (state->Fxtal/1000); | ||
| 2761 | |||
| 2762 | status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval); | ||
| 2763 | |||
| 2764 | if (state->TG_LO > 600000000UL) | ||
| 2765 | status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1); | ||
| 2766 | |||
| 2767 | Fmax = 1800000000UL ; | ||
| 2768 | Fmin = 1200000000UL ; | ||
| 2769 | |||
| 2770 | /* prevent overflow of 32 bit unsigned integer, use | ||
| 2771 | * following equation. Edit for v2.6.4 | ||
| 2772 | */ | ||
| 2773 | /* Fref_TF = Fref_TG * 1000 */ | ||
| 2774 | Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000); | ||
| 2775 | |||
| 2776 | /* Fvco = Fvco/10 */ | ||
| 2777 | Fvco = (state->TG_LO/10000) * divider_val * Fref_TG; | ||
| 2778 | |||
| 2779 | tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; | ||
| 2780 | |||
| 2781 | /* below equation is same as above but much harder to debug. | ||
| 2782 | * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - | ||
| 2783 | * ((state->TG_LO/10000)*divider_val * | ||
| 2784 | * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * | ||
| 2785 | * Xtal_Int/100) + 8; | ||
| 2786 | */ | ||
| 2787 | |||
| 2788 | status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo); | ||
| 2789 | |||
| 2790 | /* add for 2.6.5 Special setting for QAM */ | ||
| 2791 | if (state->Mod_Type == MXL_QAM) { | ||
| 2792 | if (state->config->qam_gain != 0) | ||
| 2793 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, | ||
| 2794 | state->config->qam_gain); | ||
| 2795 | else if (state->RF_IN < 680000000) | ||
| 2796 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
| 2797 | else | ||
| 2798 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); | ||
| 2799 | } | ||
| 2800 | |||
| 2801 | /* Off Chip Tracking Filter Control */ | ||
| 2802 | if (state->TF_Type == MXL_TF_OFF) { | ||
| 2803 | /* Tracking Filter Off State; turn off all the banks */ | ||
| 2804 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2805 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 2806 | status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */ | ||
| 2807 | status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */ | ||
| 2808 | status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */ | ||
| 2809 | } | ||
| 2810 | |||
| 2811 | if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ { | ||
| 2812 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 2813 | status += MXL_ControlWrite(fe, DAC_DIN_A, 0); | ||
| 2814 | |||
| 2815 | if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { | ||
| 2816 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2817 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2818 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 2819 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2820 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2821 | } | ||
| 2822 | if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { | ||
| 2823 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2824 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2825 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2826 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2827 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2828 | } | ||
| 2829 | if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { | ||
| 2830 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2831 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2832 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2833 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2834 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2835 | } | ||
| 2836 | if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { | ||
| 2837 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2838 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2839 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2840 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2841 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2842 | } | ||
| 2843 | if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { | ||
| 2844 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2845 | status += MXL_ControlWrite(fe, DAC_DIN_B, 29); | ||
| 2846 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2847 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2848 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2849 | } | ||
| 2850 | if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { | ||
| 2851 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2852 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2853 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2854 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2855 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2856 | } | ||
| 2857 | if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { | ||
| 2858 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2859 | status += MXL_ControlWrite(fe, DAC_DIN_B, 16); | ||
| 2860 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2861 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2862 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2863 | } | ||
| 2864 | if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { | ||
| 2865 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2866 | status += MXL_ControlWrite(fe, DAC_DIN_B, 7); | ||
| 2867 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2868 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2869 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2870 | } | ||
| 2871 | if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { | ||
| 2872 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2873 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2874 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2875 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2876 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2877 | } | ||
| 2878 | } | ||
| 2879 | |||
| 2880 | if (state->TF_Type == MXL_TF_C_H) { | ||
| 2881 | |||
| 2882 | /* Tracking Filter type C-H for Hauppauge only */ | ||
| 2883 | status += MXL_ControlWrite(fe, DAC_DIN_A, 0); | ||
| 2884 | |||
| 2885 | if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { | ||
| 2886 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2887 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2888 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2889 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2890 | } | ||
| 2891 | if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { | ||
| 2892 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2893 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2894 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 2895 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2896 | } | ||
| 2897 | if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { | ||
| 2898 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2899 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2900 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 2901 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2902 | } | ||
| 2903 | if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { | ||
| 2904 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 2905 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2906 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2907 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2908 | } | ||
| 2909 | if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { | ||
| 2910 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2911 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2912 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2913 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2914 | } | ||
| 2915 | if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { | ||
| 2916 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2917 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2918 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2919 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2920 | } | ||
| 2921 | if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { | ||
| 2922 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2923 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2924 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2925 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2926 | } | ||
| 2927 | if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { | ||
| 2928 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2929 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2930 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2931 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2932 | } | ||
| 2933 | if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { | ||
| 2934 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 2935 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2936 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2937 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2938 | } | ||
| 2939 | } | ||
| 2940 | |||
| 2941 | if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */ | ||
| 2942 | |||
| 2943 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 2944 | |||
| 2945 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
| 2946 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 2947 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2948 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2949 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2950 | } | ||
| 2951 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
| 2952 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 2953 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 2954 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2955 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2956 | } | ||
| 2957 | if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { | ||
| 2958 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 2959 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2960 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2961 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2962 | } | ||
| 2963 | if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { | ||
| 2964 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 2965 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2966 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 2967 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 2968 | } | ||
| 2969 | if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { | ||
| 2970 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 2971 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2972 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2973 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 2974 | } | ||
| 2975 | if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { | ||
| 2976 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 2977 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2978 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2979 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 2980 | } | ||
| 2981 | if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { | ||
| 2982 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 2983 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 2984 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 2985 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2986 | } | ||
| 2987 | } | ||
| 2988 | |||
| 2989 | if (state->TF_Type == MXL_TF_D_L) { | ||
| 2990 | |||
| 2991 | /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */ | ||
| 2992 | status += MXL_ControlWrite(fe, DAC_DIN_A, 0); | ||
| 2993 | |||
| 2994 | /* if UHF and terrestrial => Turn off Tracking Filter */ | ||
| 2995 | if (state->RF_IN >= 471000000 && | ||
| 2996 | (state->RF_IN - 471000000)%6000000 != 0) { | ||
| 2997 | /* Turn off all the banks */ | ||
| 2998 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 2999 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3000 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3001 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 3002 | status += MXL_ControlWrite(fe, AGC_IF, 10); | ||
| 3003 | } else { | ||
| 3004 | /* if VHF or cable => Turn on Tracking Filter */ | ||
| 3005 | if (state->RF_IN >= 43000000 && | ||
| 3006 | state->RF_IN < 140000000) { | ||
| 3007 | |||
| 3008 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 3009 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3010 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3011 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3012 | } | ||
| 3013 | if (state->RF_IN >= 140000000 && | ||
| 3014 | state->RF_IN < 240000000) { | ||
| 3015 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 3016 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3017 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3018 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3019 | } | ||
| 3020 | if (state->RF_IN >= 240000000 && | ||
| 3021 | state->RF_IN < 340000000) { | ||
| 3022 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 3023 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3024 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3025 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3026 | } | ||
| 3027 | if (state->RF_IN >= 340000000 && | ||
| 3028 | state->RF_IN < 430000000) { | ||
| 3029 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 3030 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3031 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3032 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3033 | } | ||
| 3034 | if (state->RF_IN >= 430000000 && | ||
| 3035 | state->RF_IN < 470000000) { | ||
| 3036 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 3037 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3038 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3039 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3040 | } | ||
| 3041 | if (state->RF_IN >= 470000000 && | ||
| 3042 | state->RF_IN < 570000000) { | ||
| 3043 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 3044 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3045 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3046 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3047 | } | ||
| 3048 | if (state->RF_IN >= 570000000 && | ||
| 3049 | state->RF_IN < 620000000) { | ||
| 3050 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
| 3051 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3052 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3053 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3054 | } | ||
| 3055 | if (state->RF_IN >= 620000000 && | ||
| 3056 | state->RF_IN < 760000000) { | ||
| 3057 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 3058 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3059 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3060 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3061 | } | ||
| 3062 | if (state->RF_IN >= 760000000 && | ||
| 3063 | state->RF_IN <= 900000000) { | ||
| 3064 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
| 3065 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3066 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3067 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3068 | } | ||
| 3069 | } | ||
| 3070 | } | ||
| 3071 | |||
| 3072 | if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ { | ||
| 3073 | |||
| 3074 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 3075 | |||
| 3076 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
| 3077 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3078 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3079 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3080 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3081 | } | ||
| 3082 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
| 3083 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3084 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3085 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3086 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3087 | } | ||
| 3088 | if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { | ||
| 3089 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3090 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3091 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3092 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3093 | } | ||
| 3094 | if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { | ||
| 3095 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3096 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3097 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3098 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3099 | } | ||
| 3100 | if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { | ||
| 3101 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3102 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3103 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3104 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3105 | } | ||
| 3106 | if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { | ||
| 3107 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3108 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3109 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3110 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3111 | } | ||
| 3112 | if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { | ||
| 3113 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3114 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3115 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3116 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3117 | } | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | if (state->TF_Type == MXL_TF_F) { | ||
| 3121 | |||
| 3122 | /* Tracking Filter type F */ | ||
| 3123 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 3124 | |||
| 3125 | if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) { | ||
| 3126 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3127 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3128 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3129 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3130 | } | ||
| 3131 | if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) { | ||
| 3132 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3133 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3134 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3135 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3136 | } | ||
| 3137 | if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) { | ||
| 3138 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3139 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3140 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3141 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3142 | } | ||
| 3143 | if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) { | ||
| 3144 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3145 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3146 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3147 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3148 | } | ||
| 3149 | if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) { | ||
| 3150 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3151 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3152 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3153 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3154 | } | ||
| 3155 | if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) { | ||
| 3156 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3157 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3158 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3159 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3160 | } | ||
| 3161 | if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) { | ||
| 3162 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3163 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3164 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3165 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3166 | } | ||
| 3167 | } | ||
| 3168 | |||
| 3169 | if (state->TF_Type == MXL_TF_E_2) { | ||
| 3170 | |||
| 3171 | /* Tracking Filter type E_2 */ | ||
| 3172 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 3173 | |||
| 3174 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
| 3175 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3176 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3177 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3178 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3179 | } | ||
| 3180 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
| 3181 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3182 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3183 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3184 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3185 | } | ||
| 3186 | if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { | ||
| 3187 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3188 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3189 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3190 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3191 | } | ||
| 3192 | if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { | ||
| 3193 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3194 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3195 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3196 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3197 | } | ||
| 3198 | if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { | ||
| 3199 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3200 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3201 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3202 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3203 | } | ||
| 3204 | if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { | ||
| 3205 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3206 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3207 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3208 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3209 | } | ||
| 3210 | if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { | ||
| 3211 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3212 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3213 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3214 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3215 | } | ||
| 3216 | } | ||
| 3217 | |||
| 3218 | if (state->TF_Type == MXL_TF_G) { | ||
| 3219 | |||
| 3220 | /* Tracking Filter type G add for v2.6.8 */ | ||
| 3221 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 3222 | |||
| 3223 | if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) { | ||
| 3224 | |||
| 3225 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3226 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3227 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3228 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3229 | } | ||
| 3230 | if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) { | ||
| 3231 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3232 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3233 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3234 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3235 | } | ||
| 3236 | if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) { | ||
| 3237 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3238 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3239 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3240 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3241 | } | ||
| 3242 | if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { | ||
| 3243 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3244 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3245 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3246 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3247 | } | ||
| 3248 | if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) { | ||
| 3249 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3250 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3251 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3252 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3253 | } | ||
| 3254 | if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { | ||
| 3255 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3256 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3257 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3258 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3259 | } | ||
| 3260 | if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) { | ||
| 3261 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3262 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3263 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3264 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3265 | } | ||
| 3266 | if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) { | ||
| 3267 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3268 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3269 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3270 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3271 | } | ||
| 3272 | } | ||
| 3273 | |||
| 3274 | if (state->TF_Type == MXL_TF_E_NA) { | ||
| 3275 | |||
| 3276 | /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */ | ||
| 3277 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
| 3278 | |||
| 3279 | /* if UHF and terrestrial=> Turn off Tracking Filter */ | ||
| 3280 | if (state->RF_IN >= 471000000 && | ||
| 3281 | (state->RF_IN - 471000000)%6000000 != 0) { | ||
| 3282 | |||
| 3283 | /* Turn off all the banks */ | ||
| 3284 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3285 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3286 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3287 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3288 | |||
| 3289 | /* 2.6.12 Turn on RSSI */ | ||
| 3290 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
| 3291 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
| 3292 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
| 3293 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
| 3294 | |||
| 3295 | /* RSSI reference point */ | ||
| 3296 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
| 3297 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
| 3298 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); | ||
| 3299 | |||
| 3300 | /* following parameter is from analog OTA mode, | ||
| 3301 | * can be change to seek better performance */ | ||
| 3302 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
| 3303 | } else { | ||
| 3304 | /* if VHF or Cable => Turn on Tracking Filter */ | ||
| 3305 | |||
| 3306 | /* 2.6.12 Turn off RSSI */ | ||
| 3307 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
| 3308 | |||
| 3309 | /* change back from above condition */ | ||
| 3310 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); | ||
| 3311 | |||
| 3312 | |||
| 3313 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
| 3314 | |||
| 3315 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3316 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3317 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3318 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3319 | } | ||
| 3320 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
| 3321 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3322 | status += MXL_SetGPIO(fe, 4, 0); | ||
| 3323 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3324 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3325 | } | ||
| 3326 | if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { | ||
| 3327 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3328 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3329 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3330 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3331 | } | ||
| 3332 | if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { | ||
| 3333 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3334 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3335 | status += MXL_SetGPIO(fe, 1, 0); | ||
| 3336 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3337 | } | ||
| 3338 | if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { | ||
| 3339 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
| 3340 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3341 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3342 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3343 | } | ||
| 3344 | if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { | ||
| 3345 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3346 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3347 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3348 | status += MXL_SetGPIO(fe, 3, 0); | ||
| 3349 | } | ||
| 3350 | if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { | ||
| 3351 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
| 3352 | status += MXL_SetGPIO(fe, 4, 1); | ||
| 3353 | status += MXL_SetGPIO(fe, 1, 1); | ||
| 3354 | status += MXL_SetGPIO(fe, 3, 1); | ||
| 3355 | } | ||
| 3356 | } | ||
| 3357 | } | ||
| 3358 | return status ; | ||
| 3359 | } | ||
| 3360 | |||
| 3361 | static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val) | ||
| 3362 | { | ||
| 3363 | u16 status = 0; | ||
| 3364 | |||
| 3365 | if (GPIO_Num == 1) | ||
| 3366 | status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1); | ||
| 3367 | |||
| 3368 | /* GPIO2 is not available */ | ||
| 3369 | |||
| 3370 | if (GPIO_Num == 3) { | ||
| 3371 | if (GPIO_Val == 1) { | ||
| 3372 | status += MXL_ControlWrite(fe, GPIO_3, 0); | ||
| 3373 | status += MXL_ControlWrite(fe, GPIO_3B, 0); | ||
| 3374 | } | ||
| 3375 | if (GPIO_Val == 0) { | ||
| 3376 | status += MXL_ControlWrite(fe, GPIO_3, 1); | ||
| 3377 | status += MXL_ControlWrite(fe, GPIO_3B, 1); | ||
| 3378 | } | ||
| 3379 | if (GPIO_Val == 3) { /* tri-state */ | ||
| 3380 | status += MXL_ControlWrite(fe, GPIO_3, 0); | ||
| 3381 | status += MXL_ControlWrite(fe, GPIO_3B, 1); | ||
| 3382 | } | ||
| 3383 | } | ||
| 3384 | if (GPIO_Num == 4) { | ||
| 3385 | if (GPIO_Val == 1) { | ||
| 3386 | status += MXL_ControlWrite(fe, GPIO_4, 0); | ||
| 3387 | status += MXL_ControlWrite(fe, GPIO_4B, 0); | ||
| 3388 | } | ||
| 3389 | if (GPIO_Val == 0) { | ||
| 3390 | status += MXL_ControlWrite(fe, GPIO_4, 1); | ||
| 3391 | status += MXL_ControlWrite(fe, GPIO_4B, 1); | ||
| 3392 | } | ||
| 3393 | if (GPIO_Val == 3) { /* tri-state */ | ||
| 3394 | status += MXL_ControlWrite(fe, GPIO_4, 0); | ||
| 3395 | status += MXL_ControlWrite(fe, GPIO_4B, 1); | ||
| 3396 | } | ||
| 3397 | } | ||
| 3398 | |||
| 3399 | return status; | ||
| 3400 | } | ||
| 3401 | |||
| 3402 | static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value) | ||
| 3403 | { | ||
| 3404 | u16 status = 0; | ||
| 3405 | |||
| 3406 | /* Will write ALL Matching Control Name */ | ||
| 3407 | /* Write Matching INIT Control */ | ||
| 3408 | status += MXL_ControlWrite_Group(fe, ControlNum, value, 1); | ||
| 3409 | /* Write Matching CH Control */ | ||
| 3410 | status += MXL_ControlWrite_Group(fe, ControlNum, value, 2); | ||
| 3411 | #ifdef _MXL_INTERNAL | ||
| 3412 | /* Write Matching MXL Control */ | ||
| 3413 | status += MXL_ControlWrite_Group(fe, ControlNum, value, 3); | ||
| 3414 | #endif | ||
| 3415 | return status; | ||
| 3416 | } | ||
| 3417 | |||
| 3418 | static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, | ||
| 3419 | u32 value, u16 controlGroup) | ||
| 3420 | { | ||
| 3421 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3422 | u16 i, j, k; | ||
| 3423 | u32 highLimit; | ||
| 3424 | u32 ctrlVal; | ||
| 3425 | |||
| 3426 | if (controlGroup == 1) /* Initial Control */ { | ||
| 3427 | |||
| 3428 | for (i = 0; i < state->Init_Ctrl_Num; i++) { | ||
| 3429 | |||
| 3430 | if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { | ||
| 3431 | |||
| 3432 | highLimit = 1 << state->Init_Ctrl[i].size; | ||
| 3433 | if (value < highLimit) { | ||
| 3434 | for (j = 0; j < state->Init_Ctrl[i].size; j++) { | ||
| 3435 | state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); | ||
| 3436 | MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]), | ||
| 3437 | (u8)(state->Init_Ctrl[i].bit[j]), | ||
| 3438 | (u8)((value>>j) & 0x01)); | ||
| 3439 | } | ||
| 3440 | ctrlVal = 0; | ||
| 3441 | for (k = 0; k < state->Init_Ctrl[i].size; k++) | ||
| 3442 | ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); | ||
| 3443 | } else | ||
| 3444 | return -1; | ||
| 3445 | } | ||
| 3446 | } | ||
| 3447 | } | ||
| 3448 | if (controlGroup == 2) /* Chan change Control */ { | ||
| 3449 | |||
| 3450 | for (i = 0; i < state->CH_Ctrl_Num; i++) { | ||
| 3451 | |||
| 3452 | if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { | ||
| 3453 | |||
| 3454 | highLimit = 1 << state->CH_Ctrl[i].size; | ||
| 3455 | if (value < highLimit) { | ||
| 3456 | for (j = 0; j < state->CH_Ctrl[i].size; j++) { | ||
| 3457 | state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); | ||
| 3458 | MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]), | ||
| 3459 | (u8)(state->CH_Ctrl[i].bit[j]), | ||
| 3460 | (u8)((value>>j) & 0x01)); | ||
| 3461 | } | ||
| 3462 | ctrlVal = 0; | ||
| 3463 | for (k = 0; k < state->CH_Ctrl[i].size; k++) | ||
| 3464 | ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); | ||
| 3465 | } else | ||
| 3466 | return -1; | ||
| 3467 | } | ||
| 3468 | } | ||
| 3469 | } | ||
| 3470 | #ifdef _MXL_INTERNAL | ||
| 3471 | if (controlGroup == 3) /* Maxlinear Control */ { | ||
| 3472 | |||
| 3473 | for (i = 0; i < state->MXL_Ctrl_Num; i++) { | ||
| 3474 | |||
| 3475 | if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { | ||
| 3476 | |||
| 3477 | highLimit = (1 << state->MXL_Ctrl[i].size); | ||
| 3478 | if (value < highLimit) { | ||
| 3479 | for (j = 0; j < state->MXL_Ctrl[i].size; j++) { | ||
| 3480 | state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); | ||
| 3481 | MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]), | ||
| 3482 | (u8)(state->MXL_Ctrl[i].bit[j]), | ||
| 3483 | (u8)((value>>j) & 0x01)); | ||
| 3484 | } | ||
| 3485 | ctrlVal = 0; | ||
| 3486 | for (k = 0; k < state->MXL_Ctrl[i].size; k++) | ||
| 3487 | ctrlVal += state-> | ||
| 3488 | MXL_Ctrl[i].val[k] * | ||
| 3489 | (1 << k); | ||
| 3490 | } else | ||
| 3491 | return -1; | ||
| 3492 | } | ||
| 3493 | } | ||
| 3494 | } | ||
| 3495 | #endif | ||
| 3496 | return 0 ; /* successful return */ | ||
| 3497 | } | ||
| 3498 | |||
| 3499 | static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal) | ||
| 3500 | { | ||
| 3501 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3502 | int i ; | ||
| 3503 | |||
| 3504 | for (i = 0; i < 104; i++) { | ||
| 3505 | if (RegNum == state->TunerRegs[i].Reg_Num) { | ||
| 3506 | *RegVal = (u8)(state->TunerRegs[i].Reg_Val); | ||
| 3507 | return 0; | ||
| 3508 | } | ||
| 3509 | } | ||
| 3510 | |||
| 3511 | return 1; | ||
| 3512 | } | ||
| 3513 | |||
| 3514 | static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value) | ||
| 3515 | { | ||
| 3516 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3517 | u32 ctrlVal ; | ||
| 3518 | u16 i, k ; | ||
| 3519 | |||
| 3520 | for (i = 0; i < state->Init_Ctrl_Num ; i++) { | ||
| 3521 | |||
| 3522 | if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { | ||
| 3523 | |||
| 3524 | ctrlVal = 0; | ||
| 3525 | for (k = 0; k < state->Init_Ctrl[i].size; k++) | ||
| 3526 | ctrlVal += state->Init_Ctrl[i].val[k] * (1<<k); | ||
| 3527 | *value = ctrlVal; | ||
| 3528 | return 0; | ||
| 3529 | } | ||
| 3530 | } | ||
| 3531 | |||
| 3532 | for (i = 0; i < state->CH_Ctrl_Num ; i++) { | ||
| 3533 | |||
| 3534 | if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { | ||
| 3535 | |||
| 3536 | ctrlVal = 0; | ||
| 3537 | for (k = 0; k < state->CH_Ctrl[i].size; k++) | ||
| 3538 | ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); | ||
| 3539 | *value = ctrlVal; | ||
| 3540 | return 0; | ||
| 3541 | |||
| 3542 | } | ||
| 3543 | } | ||
| 3544 | |||
| 3545 | #ifdef _MXL_INTERNAL | ||
| 3546 | for (i = 0; i < state->MXL_Ctrl_Num ; i++) { | ||
| 3547 | |||
| 3548 | if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { | ||
| 3549 | |||
| 3550 | ctrlVal = 0; | ||
| 3551 | for (k = 0; k < state->MXL_Ctrl[i].size; k++) | ||
| 3552 | ctrlVal += state->MXL_Ctrl[i].val[k] * (1<<k); | ||
| 3553 | *value = ctrlVal; | ||
| 3554 | return 0; | ||
| 3555 | |||
| 3556 | } | ||
| 3557 | } | ||
| 3558 | #endif | ||
| 3559 | return 1; | ||
| 3560 | } | ||
| 3561 | |||
| 3562 | static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, | ||
| 3563 | u8 bitVal) | ||
| 3564 | { | ||
| 3565 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3566 | int i ; | ||
| 3567 | |||
| 3568 | const u8 AND_MAP[8] = { | ||
| 3569 | 0xFE, 0xFD, 0xFB, 0xF7, | ||
| 3570 | 0xEF, 0xDF, 0xBF, 0x7F } ; | ||
| 3571 | |||
| 3572 | const u8 OR_MAP[8] = { | ||
| 3573 | 0x01, 0x02, 0x04, 0x08, | ||
| 3574 | 0x10, 0x20, 0x40, 0x80 } ; | ||
| 3575 | |||
| 3576 | for (i = 0; i < state->TunerRegs_Num; i++) { | ||
| 3577 | if (state->TunerRegs[i].Reg_Num == address) { | ||
| 3578 | if (bitVal) | ||
| 3579 | state->TunerRegs[i].Reg_Val |= OR_MAP[bit]; | ||
| 3580 | else | ||
| 3581 | state->TunerRegs[i].Reg_Val &= AND_MAP[bit]; | ||
| 3582 | break ; | ||
| 3583 | } | ||
| 3584 | } | ||
| 3585 | } | ||
| 3586 | |||
| 3587 | static u32 MXL_Ceiling(u32 value, u32 resolution) | ||
| 3588 | { | ||
| 3589 | return value / resolution + (value % resolution > 0 ? 1 : 0); | ||
| 3590 | } | ||
| 3591 | |||
| 3592 | /* Retrieve the Initialzation Registers */ | ||
| 3593 | static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, | ||
| 3594 | u8 *RegVal, int *count) | ||
| 3595 | { | ||
| 3596 | u16 status = 0; | ||
| 3597 | int i ; | ||
| 3598 | |||
| 3599 | u8 RegAddr[] = { | ||
| 3600 | 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73, | ||
| 3601 | 76, 77, 91, 134, 135, 137, 147, | ||
| 3602 | 156, 166, 167, 168, 25 }; | ||
| 3603 | |||
| 3604 | *count = ARRAY_SIZE(RegAddr); | ||
| 3605 | |||
| 3606 | status += MXL_BlockInit(fe); | ||
| 3607 | |||
| 3608 | for (i = 0 ; i < *count; i++) { | ||
| 3609 | RegNum[i] = RegAddr[i]; | ||
| 3610 | status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); | ||
| 3611 | } | ||
| 3612 | |||
| 3613 | return status; | ||
| 3614 | } | ||
| 3615 | |||
| 3616 | static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, | ||
| 3617 | int *count) | ||
| 3618 | { | ||
| 3619 | u16 status = 0; | ||
| 3620 | int i ; | ||
| 3621 | |||
| 3622 | /* add 77, 166, 167, 168 register for 2.6.12 */ | ||
| 3623 | #ifdef _MXL_PRODUCTION | ||
| 3624 | u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106, | ||
| 3625 | 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; | ||
| 3626 | #else | ||
| 3627 | u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106, | ||
| 3628 | 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; | ||
| 3629 | /* | ||
| 3630 | u8 RegAddr[171]; | ||
| 3631 | for (i = 0; i <= 170; i++) | ||
| 3632 | RegAddr[i] = i; | ||
| 3633 | */ | ||
| 3634 | #endif | ||
| 3635 | |||
| 3636 | *count = ARRAY_SIZE(RegAddr); | ||
| 3637 | |||
| 3638 | for (i = 0 ; i < *count; i++) { | ||
| 3639 | RegNum[i] = RegAddr[i]; | ||
| 3640 | status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); | ||
| 3641 | } | ||
| 3642 | |||
| 3643 | return status; | ||
| 3644 | } | ||
| 3645 | |||
| 3646 | static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, | ||
| 3647 | u8 *RegVal, int *count) | ||
| 3648 | { | ||
| 3649 | u16 status = 0; | ||
| 3650 | int i; | ||
| 3651 | |||
| 3652 | u8 RegAddr[] = {43, 136}; | ||
| 3653 | |||
| 3654 | *count = ARRAY_SIZE(RegAddr); | ||
| 3655 | |||
| 3656 | for (i = 0; i < *count; i++) { | ||
| 3657 | RegNum[i] = RegAddr[i]; | ||
| 3658 | status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); | ||
| 3659 | } | ||
| 3660 | |||
| 3661 | return status; | ||
| 3662 | } | ||
| 3663 | |||
| 3664 | static u16 MXL_GetMasterControl(u8 *MasterReg, int state) | ||
| 3665 | { | ||
| 3666 | if (state == 1) /* Load_Start */ | ||
| 3667 | *MasterReg = 0xF3; | ||
| 3668 | if (state == 2) /* Power_Down */ | ||
| 3669 | *MasterReg = 0x41; | ||
| 3670 | if (state == 3) /* Synth_Reset */ | ||
| 3671 | *MasterReg = 0xB1; | ||
| 3672 | if (state == 4) /* Seq_Off */ | ||
| 3673 | *MasterReg = 0xF1; | ||
| 3674 | |||
| 3675 | return 0; | ||
| 3676 | } | ||
| 3677 | |||
| 3678 | #ifdef _MXL_PRODUCTION | ||
| 3679 | static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range) | ||
| 3680 | { | ||
| 3681 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3682 | u16 status = 0 ; | ||
| 3683 | |||
| 3684 | if (VCO_Range == 1) { | ||
| 3685 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
| 3686 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 3687 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 3688 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
| 3689 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 3690 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 3691 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 3692 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
| 3693 | /* Analog Low IF Mode */ | ||
| 3694 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3695 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3696 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); | ||
| 3697 | status += MXL_ControlWrite(fe, | ||
| 3698 | CHCAL_FRAC_MOD_RF, 180224); | ||
| 3699 | } | ||
| 3700 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
| 3701 | /* Analog Zero IF Mode */ | ||
| 3702 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3703 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3704 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); | ||
| 3705 | status += MXL_ControlWrite(fe, | ||
| 3706 | CHCAL_FRAC_MOD_RF, 222822); | ||
| 3707 | } | ||
| 3708 | if (state->Mode == 1) /* Digital Mode */ { | ||
| 3709 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3710 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3711 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); | ||
| 3712 | status += MXL_ControlWrite(fe, | ||
| 3713 | CHCAL_FRAC_MOD_RF, 229376); | ||
| 3714 | } | ||
| 3715 | } | ||
| 3716 | |||
| 3717 | if (VCO_Range == 2) { | ||
| 3718 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
| 3719 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 3720 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 3721 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
| 3722 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 3723 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 3724 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 3725 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3726 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3727 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); | ||
| 3728 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
| 3729 | /* Analog Low IF Mode */ | ||
| 3730 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3731 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3732 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
| 3733 | status += MXL_ControlWrite(fe, | ||
| 3734 | CHCAL_FRAC_MOD_RF, 206438); | ||
| 3735 | } | ||
| 3736 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
| 3737 | /* Analog Zero IF Mode */ | ||
| 3738 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3739 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3740 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
| 3741 | status += MXL_ControlWrite(fe, | ||
| 3742 | CHCAL_FRAC_MOD_RF, 206438); | ||
| 3743 | } | ||
| 3744 | if (state->Mode == 1) /* Digital Mode */ { | ||
| 3745 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
| 3746 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3747 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); | ||
| 3748 | status += MXL_ControlWrite(fe, | ||
| 3749 | CHCAL_FRAC_MOD_RF, 16384); | ||
| 3750 | } | ||
| 3751 | } | ||
| 3752 | |||
| 3753 | if (VCO_Range == 3) { | ||
| 3754 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
| 3755 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 3756 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 3757 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
| 3758 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 3759 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 3760 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 3761 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3762 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3763 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
| 3764 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
| 3765 | /* Analog Low IF Mode */ | ||
| 3766 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3767 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3768 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); | ||
| 3769 | status += MXL_ControlWrite(fe, | ||
| 3770 | CHCAL_FRAC_MOD_RF, 173670); | ||
| 3771 | } | ||
| 3772 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
| 3773 | /* Analog Zero IF Mode */ | ||
| 3774 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3775 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3776 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); | ||
| 3777 | status += MXL_ControlWrite(fe, | ||
| 3778 | CHCAL_FRAC_MOD_RF, 173670); | ||
| 3779 | } | ||
| 3780 | if (state->Mode == 1) /* Digital Mode */ { | ||
| 3781 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3782 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
| 3783 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
| 3784 | status += MXL_ControlWrite(fe, | ||
| 3785 | CHCAL_FRAC_MOD_RF, 245760); | ||
| 3786 | } | ||
| 3787 | } | ||
| 3788 | |||
| 3789 | if (VCO_Range == 4) { | ||
| 3790 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
| 3791 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
| 3792 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
| 3793 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
| 3794 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
| 3795 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
| 3796 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
| 3797 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3798 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3799 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
| 3800 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
| 3801 | /* Analog Low IF Mode */ | ||
| 3802 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3803 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3804 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
| 3805 | status += MXL_ControlWrite(fe, | ||
| 3806 | CHCAL_FRAC_MOD_RF, 206438); | ||
| 3807 | } | ||
| 3808 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
| 3809 | /* Analog Zero IF Mode */ | ||
| 3810 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3811 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3812 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
| 3813 | status += MXL_ControlWrite(fe, | ||
| 3814 | CHCAL_FRAC_MOD_RF, 206438); | ||
| 3815 | } | ||
| 3816 | if (state->Mode == 1) /* Digital Mode */ { | ||
| 3817 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
| 3818 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
| 3819 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
| 3820 | status += MXL_ControlWrite(fe, | ||
| 3821 | CHCAL_FRAC_MOD_RF, 212992); | ||
| 3822 | } | ||
| 3823 | } | ||
| 3824 | |||
| 3825 | return status; | ||
| 3826 | } | ||
| 3827 | |||
| 3828 | static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) | ||
| 3829 | { | ||
| 3830 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3831 | u16 status = 0; | ||
| 3832 | |||
| 3833 | if (Hystersis == 1) | ||
| 3834 | status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1); | ||
| 3835 | |||
| 3836 | return status; | ||
| 3837 | } | ||
| 3838 | #endif | ||
| 3839 | /* End: Reference driver code found in the Realtek driver that | ||
| 3840 | * is copyright MaxLinear */ | ||
| 3841 | |||
| 3842 | /* ---------------------------------------------------------------- | ||
| 3843 | * Begin: Everything after here is new code to adapt the | ||
| 3844 | * proprietary Realtek driver into a Linux API tuner. | ||
| 3845 | * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> | ||
| 3846 | */ | ||
| 3847 | static int mxl5005s_reset(struct dvb_frontend *fe) | ||
| 3848 | { | ||
| 3849 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3850 | int ret = 0; | ||
| 3851 | |||
| 3852 | u8 buf[2] = { 0xff, 0x00 }; | ||
| 3853 | struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, | ||
| 3854 | .buf = buf, .len = 2 }; | ||
| 3855 | |||
| 3856 | dprintk(2, "%s()\n", __func__); | ||
| 3857 | |||
| 3858 | if (fe->ops.i2c_gate_ctrl) | ||
| 3859 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 3860 | |||
| 3861 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
| 3862 | printk(KERN_WARNING "mxl5005s I2C reset failed\n"); | ||
| 3863 | ret = -EREMOTEIO; | ||
| 3864 | } | ||
| 3865 | |||
| 3866 | if (fe->ops.i2c_gate_ctrl) | ||
| 3867 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 3868 | |||
| 3869 | return ret; | ||
| 3870 | } | ||
| 3871 | |||
| 3872 | /* Write a single byte to a single reg, latch the value if required by | ||
| 3873 | * following the transaction with the latch byte. | ||
| 3874 | */ | ||
| 3875 | static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch) | ||
| 3876 | { | ||
| 3877 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3878 | u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE }; | ||
| 3879 | struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, | ||
| 3880 | .buf = buf, .len = 3 }; | ||
| 3881 | |||
| 3882 | if (latch == 0) | ||
| 3883 | msg.len = 2; | ||
| 3884 | |||
| 3885 | dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr); | ||
| 3886 | |||
| 3887 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
| 3888 | printk(KERN_WARNING "mxl5005s I2C write failed\n"); | ||
| 3889 | return -EREMOTEIO; | ||
| 3890 | } | ||
| 3891 | return 0; | ||
| 3892 | } | ||
| 3893 | |||
| 3894 | static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, | ||
| 3895 | u8 *datatable, u8 len) | ||
| 3896 | { | ||
| 3897 | int ret = 0, i; | ||
| 3898 | |||
| 3899 | if (fe->ops.i2c_gate_ctrl) | ||
| 3900 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 3901 | |||
| 3902 | for (i = 0 ; i < len-1; i++) { | ||
| 3903 | ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0); | ||
| 3904 | if (ret < 0) | ||
| 3905 | break; | ||
| 3906 | } | ||
| 3907 | |||
| 3908 | ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1); | ||
| 3909 | |||
| 3910 | if (fe->ops.i2c_gate_ctrl) | ||
| 3911 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 3912 | |||
| 3913 | return ret; | ||
| 3914 | } | ||
| 3915 | |||
| 3916 | static int mxl5005s_init(struct dvb_frontend *fe) | ||
| 3917 | { | ||
| 3918 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3919 | |||
| 3920 | dprintk(1, "%s()\n", __func__); | ||
| 3921 | state->current_mode = MXL_QAM; | ||
| 3922 | return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); | ||
| 3923 | } | ||
| 3924 | |||
| 3925 | static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, | ||
| 3926 | u32 bandwidth) | ||
| 3927 | { | ||
| 3928 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3929 | |||
| 3930 | u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
| 3931 | u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
| 3932 | int TableLen; | ||
| 3933 | |||
| 3934 | dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); | ||
| 3935 | |||
| 3936 | mxl5005s_reset(fe); | ||
| 3937 | |||
| 3938 | /* Tuner initialization stage 0 */ | ||
| 3939 | MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); | ||
| 3940 | AddrTable[0] = MASTER_CONTROL_ADDR; | ||
| 3941 | ByteTable[0] |= state->config->AgcMasterByte; | ||
| 3942 | |||
| 3943 | mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); | ||
| 3944 | |||
| 3945 | mxl5005s_AssignTunerMode(fe, mod_type, bandwidth); | ||
| 3946 | |||
| 3947 | /* Tuner initialization stage 1 */ | ||
| 3948 | MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen); | ||
| 3949 | |||
| 3950 | mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); | ||
| 3951 | |||
| 3952 | return 0; | ||
| 3953 | } | ||
| 3954 | |||
| 3955 | static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, | ||
| 3956 | u32 bandwidth) | ||
| 3957 | { | ||
| 3958 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3959 | struct mxl5005s_config *c = state->config; | ||
| 3960 | |||
| 3961 | InitTunerControls(fe); | ||
| 3962 | |||
| 3963 | /* Set MxL5005S parameters. */ | ||
| 3964 | MXL5005_TunerConfig( | ||
| 3965 | fe, | ||
| 3966 | c->mod_mode, | ||
| 3967 | c->if_mode, | ||
| 3968 | bandwidth, | ||
| 3969 | c->if_freq, | ||
| 3970 | c->xtal_freq, | ||
| 3971 | c->agc_mode, | ||
| 3972 | c->top, | ||
| 3973 | c->output_load, | ||
| 3974 | c->clock_out, | ||
| 3975 | c->div_out, | ||
| 3976 | c->cap_select, | ||
| 3977 | c->rssi_enable, | ||
| 3978 | mod_type, | ||
| 3979 | c->tracking_filter); | ||
| 3980 | |||
| 3981 | return 0; | ||
| 3982 | } | ||
| 3983 | |||
| 3984 | static int mxl5005s_set_params(struct dvb_frontend *fe, | ||
| 3985 | struct dvb_frontend_parameters *params) | ||
| 3986 | { | ||
| 3987 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 3988 | u32 req_mode, req_bw = 0; | ||
| 3989 | int ret; | ||
| 3990 | |||
| 3991 | dprintk(1, "%s()\n", __func__); | ||
| 3992 | |||
| 3993 | if (fe->ops.info.type == FE_ATSC) { | ||
| 3994 | switch (params->u.vsb.modulation) { | ||
| 3995 | case VSB_8: | ||
| 3996 | req_mode = MXL_ATSC; break; | ||
| 3997 | default: | ||
| 3998 | case QAM_64: | ||
| 3999 | case QAM_256: | ||
| 4000 | case QAM_AUTO: | ||
| 4001 | req_mode = MXL_QAM; break; | ||
| 4002 | } | ||
| 4003 | } else | ||
| 4004 | req_mode = MXL_DVBT; | ||
| 4005 | |||
| 4006 | /* Change tuner for new modulation type if reqd */ | ||
| 4007 | if (req_mode != state->current_mode) { | ||
| 4008 | switch (req_mode) { | ||
| 4009 | case MXL_ATSC: | ||
| 4010 | case MXL_QAM: | ||
| 4011 | req_bw = MXL5005S_BANDWIDTH_6MHZ; | ||
| 4012 | break; | ||
| 4013 | case MXL_DVBT: | ||
| 4014 | default: | ||
| 4015 | /* Assume DVB-T */ | ||
| 4016 | switch (params->u.ofdm.bandwidth) { | ||
| 4017 | case BANDWIDTH_6_MHZ: | ||
| 4018 | req_bw = MXL5005S_BANDWIDTH_6MHZ; | ||
| 4019 | break; | ||
| 4020 | case BANDWIDTH_7_MHZ: | ||
| 4021 | req_bw = MXL5005S_BANDWIDTH_7MHZ; | ||
| 4022 | break; | ||
| 4023 | case BANDWIDTH_AUTO: | ||
| 4024 | case BANDWIDTH_8_MHZ: | ||
| 4025 | req_bw = MXL5005S_BANDWIDTH_8MHZ; | ||
| 4026 | break; | ||
| 4027 | default: | ||
| 4028 | return -EINVAL; | ||
| 4029 | } | ||
| 4030 | } | ||
| 4031 | |||
| 4032 | state->current_mode = req_mode; | ||
| 4033 | ret = mxl5005s_reconfigure(fe, req_mode, req_bw); | ||
| 4034 | |||
| 4035 | } else | ||
| 4036 | ret = 0; | ||
| 4037 | |||
| 4038 | if (ret == 0) { | ||
| 4039 | dprintk(1, "%s() freq=%d\n", __func__, params->frequency); | ||
| 4040 | ret = mxl5005s_SetRfFreqHz(fe, params->frequency); | ||
| 4041 | } | ||
| 4042 | |||
| 4043 | return ret; | ||
| 4044 | } | ||
| 4045 | |||
| 4046 | static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 4047 | { | ||
| 4048 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 4049 | dprintk(1, "%s()\n", __func__); | ||
| 4050 | |||
| 4051 | *frequency = state->RF_IN; | ||
| 4052 | |||
| 4053 | return 0; | ||
| 4054 | } | ||
| 4055 | |||
| 4056 | static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 4057 | { | ||
| 4058 | struct mxl5005s_state *state = fe->tuner_priv; | ||
| 4059 | dprintk(1, "%s()\n", __func__); | ||
| 4060 | |||
| 4061 | *bandwidth = state->Chan_Bandwidth; | ||
| 4062 | |||
| 4063 | return 0; | ||
| 4064 | } | ||
| 4065 | |||
| 4066 | static int mxl5005s_release(struct dvb_frontend *fe) | ||
| 4067 | { | ||
| 4068 | dprintk(1, "%s()\n", __func__); | ||
| 4069 | kfree(fe->tuner_priv); | ||
| 4070 | fe->tuner_priv = NULL; | ||
| 4071 | return 0; | ||
| 4072 | } | ||
| 4073 | |||
| 4074 | static const struct dvb_tuner_ops mxl5005s_tuner_ops = { | ||
| 4075 | .info = { | ||
| 4076 | .name = "MaxLinear MXL5005S", | ||
| 4077 | .frequency_min = 48000000, | ||
| 4078 | .frequency_max = 860000000, | ||
| 4079 | .frequency_step = 50000, | ||
| 4080 | }, | ||
| 4081 | |||
| 4082 | .release = mxl5005s_release, | ||
| 4083 | .init = mxl5005s_init, | ||
| 4084 | |||
| 4085 | .set_params = mxl5005s_set_params, | ||
| 4086 | .get_frequency = mxl5005s_get_frequency, | ||
| 4087 | .get_bandwidth = mxl5005s_get_bandwidth, | ||
| 4088 | }; | ||
| 4089 | |||
| 4090 | struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, | ||
| 4091 | struct i2c_adapter *i2c, | ||
| 4092 | struct mxl5005s_config *config) | ||
| 4093 | { | ||
| 4094 | struct mxl5005s_state *state = NULL; | ||
| 4095 | dprintk(1, "%s()\n", __func__); | ||
| 4096 | |||
| 4097 | state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL); | ||
| 4098 | if (state == NULL) | ||
| 4099 | return NULL; | ||
| 4100 | |||
| 4101 | state->frontend = fe; | ||
| 4102 | state->config = config; | ||
| 4103 | state->i2c = i2c; | ||
| 4104 | |||
| 4105 | printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", | ||
| 4106 | config->i2c_address); | ||
| 4107 | |||
| 4108 | memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops, | ||
| 4109 | sizeof(struct dvb_tuner_ops)); | ||
| 4110 | |||
| 4111 | fe->tuner_priv = state; | ||
| 4112 | return fe; | ||
| 4113 | } | ||
| 4114 | EXPORT_SYMBOL(mxl5005s_attach); | ||
| 4115 | |||
| 4116 | MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); | ||
| 4117 | MODULE_AUTHOR("Steven Toth"); | ||
| 4118 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h new file mode 100644 index 00000000000..fc8a1ffc53b --- /dev/null +++ b/drivers/media/common/tuners/mxl5005s.h | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | /* | ||
| 2 | MaxLinear MXL5005S VSB/QAM/DVBT tuner driver | ||
| 3 | |||
| 4 | Copyright (C) 2008 MaxLinear | ||
| 5 | Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2 of the License, or | ||
| 10 | (at your option) any later version. | ||
| 11 | |||
| 12 | This program is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 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 | |||
| 23 | #ifndef __MXL5005S_H | ||
| 24 | #define __MXL5005S_H | ||
| 25 | |||
| 26 | #include <linux/i2c.h> | ||
| 27 | #include "dvb_frontend.h" | ||
| 28 | |||
| 29 | struct mxl5005s_config { | ||
| 30 | |||
| 31 | /* 7 bit i2c address */ | ||
| 32 | u8 i2c_address; | ||
| 33 | |||
| 34 | #define IF_FREQ_4570000HZ 4570000 | ||
| 35 | #define IF_FREQ_4571429HZ 4571429 | ||
| 36 | #define IF_FREQ_5380000HZ 5380000 | ||
| 37 | #define IF_FREQ_36000000HZ 36000000 | ||
| 38 | #define IF_FREQ_36125000HZ 36125000 | ||
| 39 | #define IF_FREQ_36166667HZ 36166667 | ||
| 40 | #define IF_FREQ_44000000HZ 44000000 | ||
| 41 | u32 if_freq; | ||
| 42 | |||
| 43 | #define CRYSTAL_FREQ_4000000HZ 4000000 | ||
| 44 | #define CRYSTAL_FREQ_16000000HZ 16000000 | ||
| 45 | #define CRYSTAL_FREQ_25000000HZ 25000000 | ||
| 46 | #define CRYSTAL_FREQ_28800000HZ 28800000 | ||
| 47 | u32 xtal_freq; | ||
| 48 | |||
| 49 | #define MXL_DUAL_AGC 0 | ||
| 50 | #define MXL_SINGLE_AGC 1 | ||
| 51 | u8 agc_mode; | ||
| 52 | |||
| 53 | #define MXL_TF_DEFAULT 0 | ||
| 54 | #define MXL_TF_OFF 1 | ||
| 55 | #define MXL_TF_C 2 | ||
| 56 | #define MXL_TF_C_H 3 | ||
| 57 | #define MXL_TF_D 4 | ||
| 58 | #define MXL_TF_D_L 5 | ||
| 59 | #define MXL_TF_E 6 | ||
| 60 | #define MXL_TF_F 7 | ||
| 61 | #define MXL_TF_E_2 8 | ||
| 62 | #define MXL_TF_E_NA 9 | ||
| 63 | #define MXL_TF_G 10 | ||
| 64 | u8 tracking_filter; | ||
| 65 | |||
| 66 | #define MXL_RSSI_DISABLE 0 | ||
| 67 | #define MXL_RSSI_ENABLE 1 | ||
| 68 | u8 rssi_enable; | ||
| 69 | |||
| 70 | #define MXL_CAP_SEL_DISABLE 0 | ||
| 71 | #define MXL_CAP_SEL_ENABLE 1 | ||
| 72 | u8 cap_select; | ||
| 73 | |||
| 74 | #define MXL_DIV_OUT_1 0 | ||
| 75 | #define MXL_DIV_OUT_4 1 | ||
| 76 | u8 div_out; | ||
| 77 | |||
| 78 | #define MXL_CLOCK_OUT_DISABLE 0 | ||
| 79 | #define MXL_CLOCK_OUT_ENABLE 1 | ||
| 80 | u8 clock_out; | ||
| 81 | |||
| 82 | #define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200 | ||
| 83 | #define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300 | ||
| 84 | u32 output_load; | ||
| 85 | |||
| 86 | #define MXL5005S_TOP_5P5 55 | ||
| 87 | #define MXL5005S_TOP_7P2 72 | ||
| 88 | #define MXL5005S_TOP_9P2 92 | ||
| 89 | #define MXL5005S_TOP_11P0 110 | ||
| 90 | #define MXL5005S_TOP_12P9 129 | ||
| 91 | #define MXL5005S_TOP_14P7 147 | ||
| 92 | #define MXL5005S_TOP_16P8 168 | ||
| 93 | #define MXL5005S_TOP_19P4 194 | ||
| 94 | #define MXL5005S_TOP_21P2 212 | ||
| 95 | #define MXL5005S_TOP_23P2 232 | ||
| 96 | #define MXL5005S_TOP_25P2 252 | ||
| 97 | #define MXL5005S_TOP_27P1 271 | ||
| 98 | #define MXL5005S_TOP_29P2 292 | ||
| 99 | #define MXL5005S_TOP_31P7 317 | ||
| 100 | #define MXL5005S_TOP_34P9 349 | ||
| 101 | u32 top; | ||
| 102 | |||
| 103 | #define MXL_ANALOG_MODE 0 | ||
| 104 | #define MXL_DIGITAL_MODE 1 | ||
| 105 | u8 mod_mode; | ||
| 106 | |||
| 107 | #define MXL_ZERO_IF 0 | ||
| 108 | #define MXL_LOW_IF 1 | ||
| 109 | u8 if_mode; | ||
| 110 | |||
| 111 | /* Some boards need to override the built-in logic for determining | ||
| 112 | the gain when in QAM mode (the HVR-1600 is one such case) */ | ||
| 113 | u8 qam_gain; | ||
| 114 | |||
| 115 | /* Stuff I don't know what to do with */ | ||
| 116 | u8 AgcMasterByte; | ||
| 117 | }; | ||
| 118 | |||
| 119 | #if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ | ||
| 120 | (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) | ||
| 121 | extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, | ||
| 122 | struct i2c_adapter *i2c, | ||
| 123 | struct mxl5005s_config *config); | ||
| 124 | #else | ||
| 125 | static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, | ||
| 126 | struct i2c_adapter *i2c, | ||
| 127 | struct mxl5005s_config *config) | ||
| 128 | { | ||
| 129 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 130 | return NULL; | ||
| 131 | } | ||
| 132 | #endif /* CONFIG_DVB_TUNER_MXL5005S */ | ||
| 133 | |||
| 134 | #endif /* __MXL5005S_H */ | ||
| 135 | |||
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c new file mode 100644 index 00000000000..7eb1bf75cd0 --- /dev/null +++ b/drivers/media/common/tuners/mxl5007t.c | |||
| @@ -0,0 +1,883 @@ | |||
| 1 | /* | ||
| 2 | * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/i2c.h> | ||
| 22 | #include <linux/types.h> | ||
| 23 | #include <linux/videodev2.h> | ||
| 24 | #include "tuner-i2c.h" | ||
| 25 | #include "mxl5007t.h" | ||
| 26 | |||
| 27 | static DEFINE_MUTEX(mxl5007t_list_mutex); | ||
| 28 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 29 | |||
| 30 | static int mxl5007t_debug; | ||
| 31 | module_param_named(debug, mxl5007t_debug, int, 0644); | ||
| 32 | MODULE_PARM_DESC(debug, "set debug level"); | ||
| 33 | |||
| 34 | /* ------------------------------------------------------------------------- */ | ||
| 35 | |||
| 36 | #define mxl_printk(kern, fmt, arg...) \ | ||
| 37 | printk(kern "%s: " fmt "\n", __func__, ##arg) | ||
| 38 | |||
| 39 | #define mxl_err(fmt, arg...) \ | ||
| 40 | mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) | ||
| 41 | |||
| 42 | #define mxl_warn(fmt, arg...) \ | ||
| 43 | mxl_printk(KERN_WARNING, fmt, ##arg) | ||
| 44 | |||
| 45 | #define mxl_info(fmt, arg...) \ | ||
| 46 | mxl_printk(KERN_INFO, fmt, ##arg) | ||
| 47 | |||
| 48 | #define mxl_debug(fmt, arg...) \ | ||
| 49 | ({ \ | ||
| 50 | if (mxl5007t_debug) \ | ||
| 51 | mxl_printk(KERN_DEBUG, fmt, ##arg); \ | ||
| 52 | }) | ||
| 53 | |||
| 54 | #define mxl_fail(ret) \ | ||
| 55 | ({ \ | ||
| 56 | int __ret; \ | ||
| 57 | __ret = (ret < 0); \ | ||
| 58 | if (__ret) \ | ||
| 59 | mxl_printk(KERN_ERR, "error %d on line %d", \ | ||
| 60 | ret, __LINE__); \ | ||
| 61 | __ret; \ | ||
| 62 | }) | ||
| 63 | |||
| 64 | /* ------------------------------------------------------------------------- */ | ||
| 65 | |||
| 66 | #define MHz 1000000 | ||
| 67 | |||
| 68 | enum mxl5007t_mode { | ||
| 69 | MxL_MODE_ISDBT = 0, | ||
| 70 | MxL_MODE_DVBT = 1, | ||
| 71 | MxL_MODE_ATSC = 2, | ||
| 72 | MxL_MODE_CABLE = 0x10, | ||
| 73 | }; | ||
| 74 | |||
| 75 | enum mxl5007t_chip_version { | ||
| 76 | MxL_UNKNOWN_ID = 0x00, | ||
| 77 | MxL_5007_V1_F1 = 0x11, | ||
| 78 | MxL_5007_V1_F2 = 0x12, | ||
| 79 | MxL_5007_V4 = 0x14, | ||
| 80 | MxL_5007_V2_100_F1 = 0x21, | ||
| 81 | MxL_5007_V2_100_F2 = 0x22, | ||
| 82 | MxL_5007_V2_200_F1 = 0x23, | ||
| 83 | MxL_5007_V2_200_F2 = 0x24, | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct reg_pair_t { | ||
| 87 | u8 reg; | ||
| 88 | u8 val; | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* ------------------------------------------------------------------------- */ | ||
| 92 | |||
| 93 | static struct reg_pair_t init_tab[] = { | ||
| 94 | { 0x02, 0x06 }, | ||
| 95 | { 0x03, 0x48 }, | ||
| 96 | { 0x05, 0x04 }, | ||
| 97 | { 0x06, 0x10 }, | ||
| 98 | { 0x2e, 0x15 }, /* OVERRIDE */ | ||
| 99 | { 0x30, 0x10 }, /* OVERRIDE */ | ||
| 100 | { 0x45, 0x58 }, /* OVERRIDE */ | ||
| 101 | { 0x48, 0x19 }, /* OVERRIDE */ | ||
| 102 | { 0x52, 0x03 }, /* OVERRIDE */ | ||
| 103 | { 0x53, 0x44 }, /* OVERRIDE */ | ||
| 104 | { 0x6a, 0x4b }, /* OVERRIDE */ | ||
| 105 | { 0x76, 0x00 }, /* OVERRIDE */ | ||
| 106 | { 0x78, 0x18 }, /* OVERRIDE */ | ||
| 107 | { 0x7a, 0x17 }, /* OVERRIDE */ | ||
| 108 | { 0x85, 0x06 }, /* OVERRIDE */ | ||
| 109 | { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ | ||
| 110 | { 0, 0 } | ||
| 111 | }; | ||
| 112 | |||
| 113 | static struct reg_pair_t init_tab_cable[] = { | ||
| 114 | { 0x02, 0x06 }, | ||
| 115 | { 0x03, 0x48 }, | ||
| 116 | { 0x05, 0x04 }, | ||
| 117 | { 0x06, 0x10 }, | ||
| 118 | { 0x09, 0x3f }, | ||
| 119 | { 0x0a, 0x3f }, | ||
| 120 | { 0x0b, 0x3f }, | ||
| 121 | { 0x2e, 0x15 }, /* OVERRIDE */ | ||
| 122 | { 0x30, 0x10 }, /* OVERRIDE */ | ||
| 123 | { 0x45, 0x58 }, /* OVERRIDE */ | ||
| 124 | { 0x48, 0x19 }, /* OVERRIDE */ | ||
| 125 | { 0x52, 0x03 }, /* OVERRIDE */ | ||
| 126 | { 0x53, 0x44 }, /* OVERRIDE */ | ||
| 127 | { 0x6a, 0x4b }, /* OVERRIDE */ | ||
| 128 | { 0x76, 0x00 }, /* OVERRIDE */ | ||
| 129 | { 0x78, 0x18 }, /* OVERRIDE */ | ||
| 130 | { 0x7a, 0x17 }, /* OVERRIDE */ | ||
| 131 | { 0x85, 0x06 }, /* OVERRIDE */ | ||
| 132 | { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ | ||
| 133 | { 0, 0 } | ||
| 134 | }; | ||
| 135 | |||
| 136 | /* ------------------------------------------------------------------------- */ | ||
| 137 | |||
| 138 | static struct reg_pair_t reg_pair_rftune[] = { | ||
| 139 | { 0x0f, 0x00 }, /* abort tune */ | ||
| 140 | { 0x0c, 0x15 }, | ||
| 141 | { 0x0d, 0x40 }, | ||
| 142 | { 0x0e, 0x0e }, | ||
| 143 | { 0x1f, 0x87 }, /* OVERRIDE */ | ||
| 144 | { 0x20, 0x1f }, /* OVERRIDE */ | ||
| 145 | { 0x21, 0x87 }, /* OVERRIDE */ | ||
| 146 | { 0x22, 0x1f }, /* OVERRIDE */ | ||
| 147 | { 0x80, 0x01 }, /* freq dependent */ | ||
| 148 | { 0x0f, 0x01 }, /* start tune */ | ||
| 149 | { 0, 0 } | ||
| 150 | }; | ||
| 151 | |||
| 152 | /* ------------------------------------------------------------------------- */ | ||
| 153 | |||
| 154 | struct mxl5007t_state { | ||
| 155 | struct list_head hybrid_tuner_instance_list; | ||
| 156 | struct tuner_i2c_props i2c_props; | ||
| 157 | |||
| 158 | struct mutex lock; | ||
| 159 | |||
| 160 | struct mxl5007t_config *config; | ||
| 161 | |||
| 162 | enum mxl5007t_chip_version chip_id; | ||
| 163 | |||
| 164 | struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; | ||
| 165 | struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; | ||
| 166 | struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; | ||
| 167 | |||
| 168 | u32 frequency; | ||
| 169 | u32 bandwidth; | ||
| 170 | }; | ||
| 171 | |||
| 172 | /* ------------------------------------------------------------------------- */ | ||
| 173 | |||
| 174 | /* called by _init and _rftun to manipulate the register arrays */ | ||
| 175 | |||
| 176 | static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) | ||
| 177 | { | ||
| 178 | unsigned int i = 0; | ||
| 179 | |||
| 180 | while (reg_pair[i].reg || reg_pair[i].val) { | ||
| 181 | if (reg_pair[i].reg == reg) { | ||
| 182 | reg_pair[i].val &= ~mask; | ||
| 183 | reg_pair[i].val |= val; | ||
| 184 | } | ||
| 185 | i++; | ||
| 186 | |||
| 187 | } | ||
| 188 | return; | ||
| 189 | } | ||
| 190 | |||
| 191 | static void copy_reg_bits(struct reg_pair_t *reg_pair1, | ||
| 192 | struct reg_pair_t *reg_pair2) | ||
| 193 | { | ||
| 194 | unsigned int i, j; | ||
| 195 | |||
| 196 | i = j = 0; | ||
| 197 | |||
| 198 | while (reg_pair1[i].reg || reg_pair1[i].val) { | ||
| 199 | while (reg_pair2[j].reg || reg_pair2[j].val) { | ||
| 200 | if (reg_pair1[i].reg != reg_pair2[j].reg) { | ||
| 201 | j++; | ||
| 202 | continue; | ||
| 203 | } | ||
| 204 | reg_pair2[j].val = reg_pair1[i].val; | ||
| 205 | break; | ||
| 206 | } | ||
| 207 | i++; | ||
| 208 | } | ||
| 209 | return; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* ------------------------------------------------------------------------- */ | ||
| 213 | |||
| 214 | static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, | ||
| 215 | enum mxl5007t_mode mode, | ||
| 216 | s32 if_diff_out_level) | ||
| 217 | { | ||
| 218 | switch (mode) { | ||
| 219 | case MxL_MODE_ATSC: | ||
| 220 | set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); | ||
| 221 | break; | ||
| 222 | case MxL_MODE_DVBT: | ||
| 223 | set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); | ||
| 224 | break; | ||
| 225 | case MxL_MODE_ISDBT: | ||
| 226 | set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); | ||
| 227 | break; | ||
| 228 | case MxL_MODE_CABLE: | ||
| 229 | set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); | ||
| 230 | set_reg_bits(state->tab_init_cable, 0x0a, 0xff, | ||
| 231 | 8 - if_diff_out_level); | ||
| 232 | set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); | ||
| 233 | break; | ||
| 234 | default: | ||
| 235 | mxl_fail(-EINVAL); | ||
| 236 | } | ||
| 237 | return; | ||
| 238 | } | ||
| 239 | |||
| 240 | static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, | ||
| 241 | enum mxl5007t_if_freq if_freq, | ||
| 242 | int invert_if) | ||
| 243 | { | ||
| 244 | u8 val; | ||
| 245 | |||
| 246 | switch (if_freq) { | ||
| 247 | case MxL_IF_4_MHZ: | ||
| 248 | val = 0x00; | ||
| 249 | break; | ||
| 250 | case MxL_IF_4_5_MHZ: | ||
| 251 | val = 0x02; | ||
| 252 | break; | ||
| 253 | case MxL_IF_4_57_MHZ: | ||
| 254 | val = 0x03; | ||
| 255 | break; | ||
| 256 | case MxL_IF_5_MHZ: | ||
| 257 | val = 0x04; | ||
| 258 | break; | ||
| 259 | case MxL_IF_5_38_MHZ: | ||
| 260 | val = 0x05; | ||
| 261 | break; | ||
| 262 | case MxL_IF_6_MHZ: | ||
| 263 | val = 0x06; | ||
| 264 | break; | ||
| 265 | case MxL_IF_6_28_MHZ: | ||
| 266 | val = 0x07; | ||
| 267 | break; | ||
| 268 | case MxL_IF_9_1915_MHZ: | ||
| 269 | val = 0x08; | ||
| 270 | break; | ||
| 271 | case MxL_IF_35_25_MHZ: | ||
| 272 | val = 0x09; | ||
| 273 | break; | ||
| 274 | case MxL_IF_36_15_MHZ: | ||
| 275 | val = 0x0a; | ||
| 276 | break; | ||
| 277 | case MxL_IF_44_MHZ: | ||
| 278 | val = 0x0b; | ||
| 279 | break; | ||
| 280 | default: | ||
| 281 | mxl_fail(-EINVAL); | ||
| 282 | return; | ||
| 283 | } | ||
| 284 | set_reg_bits(state->tab_init, 0x02, 0x0f, val); | ||
| 285 | |||
| 286 | /* set inverted IF or normal IF */ | ||
| 287 | set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); | ||
| 288 | |||
| 289 | return; | ||
| 290 | } | ||
| 291 | |||
| 292 | static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, | ||
| 293 | enum mxl5007t_xtal_freq xtal_freq) | ||
| 294 | { | ||
| 295 | switch (xtal_freq) { | ||
| 296 | case MxL_XTAL_16_MHZ: | ||
| 297 | /* select xtal freq & ref freq */ | ||
| 298 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); | ||
| 299 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); | ||
| 300 | break; | ||
| 301 | case MxL_XTAL_20_MHZ: | ||
| 302 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); | ||
| 303 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); | ||
| 304 | break; | ||
| 305 | case MxL_XTAL_20_25_MHZ: | ||
| 306 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); | ||
| 307 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); | ||
| 308 | break; | ||
| 309 | case MxL_XTAL_20_48_MHZ: | ||
| 310 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); | ||
| 311 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); | ||
| 312 | break; | ||
| 313 | case MxL_XTAL_24_MHZ: | ||
| 314 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); | ||
| 315 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); | ||
| 316 | break; | ||
| 317 | case MxL_XTAL_25_MHZ: | ||
| 318 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); | ||
| 319 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); | ||
| 320 | break; | ||
| 321 | case MxL_XTAL_25_14_MHZ: | ||
| 322 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); | ||
| 323 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); | ||
| 324 | break; | ||
| 325 | case MxL_XTAL_27_MHZ: | ||
| 326 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); | ||
| 327 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); | ||
| 328 | break; | ||
| 329 | case MxL_XTAL_28_8_MHZ: | ||
| 330 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); | ||
| 331 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); | ||
| 332 | break; | ||
| 333 | case MxL_XTAL_32_MHZ: | ||
| 334 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); | ||
| 335 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); | ||
| 336 | break; | ||
| 337 | case MxL_XTAL_40_MHZ: | ||
| 338 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); | ||
| 339 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); | ||
| 340 | break; | ||
| 341 | case MxL_XTAL_44_MHZ: | ||
| 342 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); | ||
| 343 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); | ||
| 344 | break; | ||
| 345 | case MxL_XTAL_48_MHZ: | ||
| 346 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); | ||
| 347 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); | ||
| 348 | break; | ||
| 349 | case MxL_XTAL_49_3811_MHZ: | ||
| 350 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); | ||
| 351 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); | ||
| 352 | break; | ||
| 353 | default: | ||
| 354 | mxl_fail(-EINVAL); | ||
| 355 | return; | ||
| 356 | } | ||
| 357 | |||
| 358 | return; | ||
| 359 | } | ||
| 360 | |||
| 361 | static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, | ||
| 362 | enum mxl5007t_mode mode) | ||
| 363 | { | ||
| 364 | struct mxl5007t_config *cfg = state->config; | ||
| 365 | |||
| 366 | memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); | ||
| 367 | memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); | ||
| 368 | |||
| 369 | mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); | ||
| 370 | mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); | ||
| 371 | mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); | ||
| 372 | |||
| 373 | set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); | ||
| 374 | set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); | ||
| 375 | set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); | ||
| 376 | |||
| 377 | if (mode >= MxL_MODE_CABLE) { | ||
| 378 | copy_reg_bits(state->tab_init, state->tab_init_cable); | ||
| 379 | return state->tab_init_cable; | ||
| 380 | } else | ||
| 381 | return state->tab_init; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* ------------------------------------------------------------------------- */ | ||
| 385 | |||
| 386 | enum mxl5007t_bw_mhz { | ||
| 387 | MxL_BW_6MHz = 6, | ||
| 388 | MxL_BW_7MHz = 7, | ||
| 389 | MxL_BW_8MHz = 8, | ||
| 390 | }; | ||
| 391 | |||
| 392 | static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, | ||
| 393 | enum mxl5007t_bw_mhz bw) | ||
| 394 | { | ||
| 395 | u8 val; | ||
| 396 | |||
| 397 | switch (bw) { | ||
| 398 | case MxL_BW_6MHz: | ||
| 399 | val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, | ||
| 400 | * and DIG_MODEINDEX_CSF */ | ||
| 401 | break; | ||
| 402 | case MxL_BW_7MHz: | ||
| 403 | val = 0x2a; | ||
| 404 | break; | ||
| 405 | case MxL_BW_8MHz: | ||
| 406 | val = 0x3f; | ||
| 407 | break; | ||
| 408 | default: | ||
| 409 | mxl_fail(-EINVAL); | ||
| 410 | return; | ||
| 411 | } | ||
| 412 | set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); | ||
| 413 | |||
| 414 | return; | ||
| 415 | } | ||
| 416 | |||
| 417 | static struct | ||
| 418 | reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, | ||
| 419 | u32 rf_freq, enum mxl5007t_bw_mhz bw) | ||
| 420 | { | ||
| 421 | u32 dig_rf_freq = 0; | ||
| 422 | u32 temp; | ||
| 423 | u32 frac_divider = 1000000; | ||
| 424 | unsigned int i; | ||
| 425 | |||
| 426 | memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); | ||
| 427 | |||
| 428 | mxl5007t_set_bw_bits(state, bw); | ||
| 429 | |||
| 430 | /* Convert RF frequency into 16 bits => | ||
| 431 | * 10 bit integer (MHz) + 6 bit fraction */ | ||
| 432 | dig_rf_freq = rf_freq / MHz; | ||
| 433 | |||
| 434 | temp = rf_freq % MHz; | ||
| 435 | |||
| 436 | for (i = 0; i < 6; i++) { | ||
| 437 | dig_rf_freq <<= 1; | ||
| 438 | frac_divider /= 2; | ||
| 439 | if (temp > frac_divider) { | ||
| 440 | temp -= frac_divider; | ||
| 441 | dig_rf_freq++; | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | /* add to have shift center point by 7.8124 kHz */ | ||
| 446 | if (temp > 7812) | ||
| 447 | dig_rf_freq++; | ||
| 448 | |||
| 449 | set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); | ||
| 450 | set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); | ||
| 451 | |||
| 452 | if (rf_freq >= 333000000) | ||
| 453 | set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); | ||
| 454 | |||
| 455 | return state->tab_rftune; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* ------------------------------------------------------------------------- */ | ||
| 459 | |||
| 460 | static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) | ||
| 461 | { | ||
| 462 | u8 buf[] = { reg, val }; | ||
| 463 | struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, | ||
| 464 | .buf = buf, .len = 2 }; | ||
| 465 | int ret; | ||
| 466 | |||
| 467 | ret = i2c_transfer(state->i2c_props.adap, &msg, 1); | ||
| 468 | if (ret != 1) { | ||
| 469 | mxl_err("failed!"); | ||
| 470 | return -EREMOTEIO; | ||
| 471 | } | ||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | static int mxl5007t_write_regs(struct mxl5007t_state *state, | ||
| 476 | struct reg_pair_t *reg_pair) | ||
| 477 | { | ||
| 478 | unsigned int i = 0; | ||
| 479 | int ret = 0; | ||
| 480 | |||
| 481 | while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { | ||
| 482 | ret = mxl5007t_write_reg(state, | ||
| 483 | reg_pair[i].reg, reg_pair[i].val); | ||
| 484 | i++; | ||
| 485 | } | ||
| 486 | return ret; | ||
| 487 | } | ||
| 488 | |||
| 489 | static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) | ||
| 490 | { | ||
| 491 | struct i2c_msg msg[] = { | ||
| 492 | { .addr = state->i2c_props.addr, .flags = 0, | ||
| 493 | .buf = ®, .len = 1 }, | ||
| 494 | { .addr = state->i2c_props.addr, .flags = I2C_M_RD, | ||
| 495 | .buf = val, .len = 1 }, | ||
| 496 | }; | ||
| 497 | int ret; | ||
| 498 | |||
| 499 | ret = i2c_transfer(state->i2c_props.adap, msg, 2); | ||
| 500 | if (ret != 2) { | ||
| 501 | mxl_err("failed!"); | ||
| 502 | return -EREMOTEIO; | ||
| 503 | } | ||
| 504 | return 0; | ||
| 505 | } | ||
| 506 | |||
| 507 | static int mxl5007t_soft_reset(struct mxl5007t_state *state) | ||
| 508 | { | ||
| 509 | u8 d = 0xff; | ||
| 510 | struct i2c_msg msg = { | ||
| 511 | .addr = state->i2c_props.addr, .flags = 0, | ||
| 512 | .buf = &d, .len = 1 | ||
| 513 | }; | ||
| 514 | int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); | ||
| 515 | |||
| 516 | if (ret != 1) { | ||
| 517 | mxl_err("failed!"); | ||
| 518 | return -EREMOTEIO; | ||
| 519 | } | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int mxl5007t_tuner_init(struct mxl5007t_state *state, | ||
| 524 | enum mxl5007t_mode mode) | ||
| 525 | { | ||
| 526 | struct reg_pair_t *init_regs; | ||
| 527 | int ret; | ||
| 528 | |||
| 529 | ret = mxl5007t_soft_reset(state); | ||
| 530 | if (mxl_fail(ret)) | ||
| 531 | goto fail; | ||
| 532 | |||
| 533 | /* calculate initialization reg array */ | ||
| 534 | init_regs = mxl5007t_calc_init_regs(state, mode); | ||
| 535 | |||
| 536 | ret = mxl5007t_write_regs(state, init_regs); | ||
| 537 | if (mxl_fail(ret)) | ||
| 538 | goto fail; | ||
| 539 | mdelay(1); | ||
| 540 | fail: | ||
| 541 | return ret; | ||
| 542 | } | ||
| 543 | |||
| 544 | static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, | ||
| 545 | enum mxl5007t_bw_mhz bw) | ||
| 546 | { | ||
| 547 | struct reg_pair_t *rf_tune_regs; | ||
| 548 | int ret; | ||
| 549 | |||
| 550 | /* calculate channel change reg array */ | ||
| 551 | rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); | ||
| 552 | |||
| 553 | ret = mxl5007t_write_regs(state, rf_tune_regs); | ||
| 554 | if (mxl_fail(ret)) | ||
| 555 | goto fail; | ||
| 556 | msleep(3); | ||
| 557 | fail: | ||
| 558 | return ret; | ||
| 559 | } | ||
| 560 | |||
| 561 | /* ------------------------------------------------------------------------- */ | ||
| 562 | |||
| 563 | static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, | ||
| 564 | int *rf_locked, int *ref_locked) | ||
| 565 | { | ||
| 566 | u8 d; | ||
| 567 | int ret; | ||
| 568 | |||
| 569 | *rf_locked = 0; | ||
| 570 | *ref_locked = 0; | ||
| 571 | |||
| 572 | ret = mxl5007t_read_reg(state, 0xd8, &d); | ||
| 573 | if (mxl_fail(ret)) | ||
| 574 | goto fail; | ||
| 575 | |||
| 576 | if ((d & 0x0c) == 0x0c) | ||
| 577 | *rf_locked = 1; | ||
| 578 | |||
| 579 | if ((d & 0x03) == 0x03) | ||
| 580 | *ref_locked = 1; | ||
| 581 | fail: | ||
| 582 | return ret; | ||
| 583 | } | ||
| 584 | |||
| 585 | /* ------------------------------------------------------------------------- */ | ||
| 586 | |||
| 587 | static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 588 | { | ||
| 589 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 590 | int rf_locked, ref_locked, ret; | ||
| 591 | |||
| 592 | *status = 0; | ||
| 593 | |||
| 594 | if (fe->ops.i2c_gate_ctrl) | ||
| 595 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 596 | |||
| 597 | ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); | ||
| 598 | if (mxl_fail(ret)) | ||
| 599 | goto fail; | ||
| 600 | mxl_debug("%s%s", rf_locked ? "rf locked " : "", | ||
| 601 | ref_locked ? "ref locked" : ""); | ||
| 602 | |||
| 603 | if ((rf_locked) || (ref_locked)) | ||
| 604 | *status |= TUNER_STATUS_LOCKED; | ||
| 605 | fail: | ||
| 606 | if (fe->ops.i2c_gate_ctrl) | ||
| 607 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 608 | |||
| 609 | return ret; | ||
| 610 | } | ||
| 611 | |||
| 612 | /* ------------------------------------------------------------------------- */ | ||
| 613 | |||
| 614 | static int mxl5007t_set_params(struct dvb_frontend *fe, | ||
| 615 | struct dvb_frontend_parameters *params) | ||
| 616 | { | ||
| 617 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 618 | enum mxl5007t_bw_mhz bw; | ||
| 619 | enum mxl5007t_mode mode; | ||
| 620 | int ret; | ||
| 621 | u32 freq = params->frequency; | ||
| 622 | |||
| 623 | if (fe->ops.info.type == FE_ATSC) { | ||
| 624 | switch (params->u.vsb.modulation) { | ||
| 625 | case VSB_8: | ||
| 626 | case VSB_16: | ||
| 627 | mode = MxL_MODE_ATSC; | ||
| 628 | break; | ||
| 629 | case QAM_64: | ||
| 630 | case QAM_256: | ||
| 631 | mode = MxL_MODE_CABLE; | ||
| 632 | break; | ||
| 633 | default: | ||
| 634 | mxl_err("modulation not set!"); | ||
| 635 | return -EINVAL; | ||
| 636 | } | ||
| 637 | bw = MxL_BW_6MHz; | ||
| 638 | } else if (fe->ops.info.type == FE_OFDM) { | ||
| 639 | switch (params->u.ofdm.bandwidth) { | ||
| 640 | case BANDWIDTH_6_MHZ: | ||
| 641 | bw = MxL_BW_6MHz; | ||
| 642 | break; | ||
| 643 | case BANDWIDTH_7_MHZ: | ||
| 644 | bw = MxL_BW_7MHz; | ||
| 645 | break; | ||
| 646 | case BANDWIDTH_8_MHZ: | ||
| 647 | bw = MxL_BW_8MHz; | ||
| 648 | break; | ||
| 649 | default: | ||
| 650 | mxl_err("bandwidth not set!"); | ||
| 651 | return -EINVAL; | ||
| 652 | } | ||
| 653 | mode = MxL_MODE_DVBT; | ||
| 654 | } else { | ||
| 655 | mxl_err("modulation type not supported!"); | ||
| 656 | return -EINVAL; | ||
| 657 | } | ||
| 658 | |||
| 659 | if (fe->ops.i2c_gate_ctrl) | ||
| 660 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 661 | |||
| 662 | mutex_lock(&state->lock); | ||
| 663 | |||
| 664 | ret = mxl5007t_tuner_init(state, mode); | ||
| 665 | if (mxl_fail(ret)) | ||
| 666 | goto fail; | ||
| 667 | |||
| 668 | ret = mxl5007t_tuner_rf_tune(state, freq, bw); | ||
| 669 | if (mxl_fail(ret)) | ||
| 670 | goto fail; | ||
| 671 | |||
| 672 | state->frequency = freq; | ||
| 673 | state->bandwidth = (fe->ops.info.type == FE_OFDM) ? | ||
| 674 | params->u.ofdm.bandwidth : 0; | ||
| 675 | fail: | ||
| 676 | mutex_unlock(&state->lock); | ||
| 677 | |||
| 678 | if (fe->ops.i2c_gate_ctrl) | ||
| 679 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 680 | |||
| 681 | return ret; | ||
| 682 | } | ||
| 683 | |||
| 684 | /* ------------------------------------------------------------------------- */ | ||
| 685 | |||
| 686 | static int mxl5007t_init(struct dvb_frontend *fe) | ||
| 687 | { | ||
| 688 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 689 | int ret; | ||
| 690 | |||
| 691 | if (fe->ops.i2c_gate_ctrl) | ||
| 692 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 693 | |||
| 694 | /* wake from standby */ | ||
| 695 | ret = mxl5007t_write_reg(state, 0x01, 0x01); | ||
| 696 | mxl_fail(ret); | ||
| 697 | |||
| 698 | if (fe->ops.i2c_gate_ctrl) | ||
| 699 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 700 | |||
| 701 | return ret; | ||
| 702 | } | ||
| 703 | |||
| 704 | static int mxl5007t_sleep(struct dvb_frontend *fe) | ||
| 705 | { | ||
| 706 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 707 | int ret; | ||
| 708 | |||
| 709 | if (fe->ops.i2c_gate_ctrl) | ||
| 710 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 711 | |||
| 712 | /* enter standby mode */ | ||
| 713 | ret = mxl5007t_write_reg(state, 0x01, 0x00); | ||
| 714 | mxl_fail(ret); | ||
| 715 | ret = mxl5007t_write_reg(state, 0x0f, 0x00); | ||
| 716 | mxl_fail(ret); | ||
| 717 | |||
| 718 | if (fe->ops.i2c_gate_ctrl) | ||
| 719 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 720 | |||
| 721 | return ret; | ||
| 722 | } | ||
| 723 | |||
| 724 | /* ------------------------------------------------------------------------- */ | ||
| 725 | |||
| 726 | static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 727 | { | ||
| 728 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 729 | *frequency = state->frequency; | ||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | |||
| 733 | static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 734 | { | ||
| 735 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 736 | *bandwidth = state->bandwidth; | ||
| 737 | return 0; | ||
| 738 | } | ||
| 739 | |||
| 740 | static int mxl5007t_release(struct dvb_frontend *fe) | ||
| 741 | { | ||
| 742 | struct mxl5007t_state *state = fe->tuner_priv; | ||
| 743 | |||
| 744 | mutex_lock(&mxl5007t_list_mutex); | ||
| 745 | |||
| 746 | if (state) | ||
| 747 | hybrid_tuner_release_state(state); | ||
| 748 | |||
| 749 | mutex_unlock(&mxl5007t_list_mutex); | ||
| 750 | |||
| 751 | fe->tuner_priv = NULL; | ||
| 752 | |||
| 753 | return 0; | ||
| 754 | } | ||
| 755 | |||
| 756 | /* ------------------------------------------------------------------------- */ | ||
| 757 | |||
| 758 | static struct dvb_tuner_ops mxl5007t_tuner_ops = { | ||
| 759 | .info = { | ||
| 760 | .name = "MaxLinear MxL5007T", | ||
| 761 | }, | ||
| 762 | .init = mxl5007t_init, | ||
| 763 | .sleep = mxl5007t_sleep, | ||
| 764 | .set_params = mxl5007t_set_params, | ||
| 765 | .get_status = mxl5007t_get_status, | ||
| 766 | .get_frequency = mxl5007t_get_frequency, | ||
| 767 | .get_bandwidth = mxl5007t_get_bandwidth, | ||
| 768 | .release = mxl5007t_release, | ||
| 769 | }; | ||
| 770 | |||
| 771 | static int mxl5007t_get_chip_id(struct mxl5007t_state *state) | ||
| 772 | { | ||
| 773 | char *name; | ||
| 774 | int ret; | ||
| 775 | u8 id; | ||
| 776 | |||
| 777 | ret = mxl5007t_read_reg(state, 0xd9, &id); | ||
| 778 | if (mxl_fail(ret)) | ||
| 779 | goto fail; | ||
| 780 | |||
| 781 | switch (id) { | ||
| 782 | case MxL_5007_V1_F1: | ||
| 783 | name = "MxL5007.v1.f1"; | ||
| 784 | break; | ||
| 785 | case MxL_5007_V1_F2: | ||
| 786 | name = "MxL5007.v1.f2"; | ||
| 787 | break; | ||
| 788 | case MxL_5007_V2_100_F1: | ||
| 789 | name = "MxL5007.v2.100.f1"; | ||
| 790 | break; | ||
| 791 | case MxL_5007_V2_100_F2: | ||
| 792 | name = "MxL5007.v2.100.f2"; | ||
| 793 | break; | ||
| 794 | case MxL_5007_V2_200_F1: | ||
| 795 | name = "MxL5007.v2.200.f1"; | ||
| 796 | break; | ||
| 797 | case MxL_5007_V2_200_F2: | ||
| 798 | name = "MxL5007.v2.200.f2"; | ||
| 799 | break; | ||
| 800 | case MxL_5007_V4: | ||
| 801 | name = "MxL5007T.v4"; | ||
| 802 | break; | ||
| 803 | default: | ||
| 804 | name = "MxL5007T"; | ||
| 805 | printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); | ||
| 806 | id = MxL_UNKNOWN_ID; | ||
| 807 | } | ||
| 808 | state->chip_id = id; | ||
| 809 | mxl_info("%s detected @ %d-%04x", name, | ||
| 810 | i2c_adapter_id(state->i2c_props.adap), | ||
| 811 | state->i2c_props.addr); | ||
| 812 | return 0; | ||
| 813 | fail: | ||
| 814 | mxl_warn("unable to identify device @ %d-%04x", | ||
| 815 | i2c_adapter_id(state->i2c_props.adap), | ||
| 816 | state->i2c_props.addr); | ||
| 817 | |||
| 818 | state->chip_id = MxL_UNKNOWN_ID; | ||
| 819 | return ret; | ||
| 820 | } | ||
| 821 | |||
| 822 | struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, | ||
| 823 | struct i2c_adapter *i2c, u8 addr, | ||
| 824 | struct mxl5007t_config *cfg) | ||
| 825 | { | ||
| 826 | struct mxl5007t_state *state = NULL; | ||
| 827 | int instance, ret; | ||
| 828 | |||
| 829 | mutex_lock(&mxl5007t_list_mutex); | ||
| 830 | instance = hybrid_tuner_request_state(struct mxl5007t_state, state, | ||
| 831 | hybrid_tuner_instance_list, | ||
| 832 | i2c, addr, "mxl5007t"); | ||
| 833 | switch (instance) { | ||
| 834 | case 0: | ||
| 835 | goto fail; | ||
| 836 | case 1: | ||
| 837 | /* new tuner instance */ | ||
| 838 | state->config = cfg; | ||
| 839 | |||
| 840 | mutex_init(&state->lock); | ||
| 841 | |||
| 842 | if (fe->ops.i2c_gate_ctrl) | ||
| 843 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 844 | |||
| 845 | ret = mxl5007t_get_chip_id(state); | ||
| 846 | |||
| 847 | if (fe->ops.i2c_gate_ctrl) | ||
| 848 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 849 | |||
| 850 | /* check return value of mxl5007t_get_chip_id */ | ||
| 851 | if (mxl_fail(ret)) | ||
| 852 | goto fail; | ||
| 853 | break; | ||
| 854 | default: | ||
| 855 | /* existing tuner instance */ | ||
| 856 | break; | ||
| 857 | } | ||
| 858 | fe->tuner_priv = state; | ||
| 859 | mutex_unlock(&mxl5007t_list_mutex); | ||
| 860 | |||
| 861 | memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, | ||
| 862 | sizeof(struct dvb_tuner_ops)); | ||
| 863 | |||
| 864 | return fe; | ||
| 865 | fail: | ||
| 866 | mutex_unlock(&mxl5007t_list_mutex); | ||
| 867 | |||
| 868 | mxl5007t_release(fe); | ||
| 869 | return NULL; | ||
| 870 | } | ||
| 871 | EXPORT_SYMBOL_GPL(mxl5007t_attach); | ||
| 872 | MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); | ||
| 873 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
| 874 | MODULE_LICENSE("GPL"); | ||
| 875 | MODULE_VERSION("0.2"); | ||
| 876 | |||
| 877 | /* | ||
| 878 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 879 | * --------------------------------------------------------------------------- | ||
| 880 | * Local variables: | ||
| 881 | * c-basic-offset: 8 | ||
| 882 | * End: | ||
| 883 | */ | ||
diff --git a/drivers/media/common/tuners/mxl5007t.h b/drivers/media/common/tuners/mxl5007t.h new file mode 100644 index 00000000000..aa3eea0b526 --- /dev/null +++ b/drivers/media/common/tuners/mxl5007t.h | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | /* | ||
| 2 | * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __MXL5007T_H__ | ||
| 22 | #define __MXL5007T_H__ | ||
| 23 | |||
| 24 | #include "dvb_frontend.h" | ||
| 25 | |||
| 26 | /* ------------------------------------------------------------------------- */ | ||
| 27 | |||
| 28 | enum mxl5007t_if_freq { | ||
| 29 | MxL_IF_4_MHZ, /* 4000000 */ | ||
| 30 | MxL_IF_4_5_MHZ, /* 4500000 */ | ||
| 31 | MxL_IF_4_57_MHZ, /* 4570000 */ | ||
| 32 | MxL_IF_5_MHZ, /* 5000000 */ | ||
| 33 | MxL_IF_5_38_MHZ, /* 5380000 */ | ||
| 34 | MxL_IF_6_MHZ, /* 6000000 */ | ||
| 35 | MxL_IF_6_28_MHZ, /* 6280000 */ | ||
| 36 | MxL_IF_9_1915_MHZ, /* 9191500 */ | ||
| 37 | MxL_IF_35_25_MHZ, /* 35250000 */ | ||
| 38 | MxL_IF_36_15_MHZ, /* 36150000 */ | ||
| 39 | MxL_IF_44_MHZ, /* 44000000 */ | ||
| 40 | }; | ||
| 41 | |||
| 42 | enum mxl5007t_xtal_freq { | ||
| 43 | MxL_XTAL_16_MHZ, /* 16000000 */ | ||
| 44 | MxL_XTAL_20_MHZ, /* 20000000 */ | ||
| 45 | MxL_XTAL_20_25_MHZ, /* 20250000 */ | ||
| 46 | MxL_XTAL_20_48_MHZ, /* 20480000 */ | ||
| 47 | MxL_XTAL_24_MHZ, /* 24000000 */ | ||
| 48 | MxL_XTAL_25_MHZ, /* 25000000 */ | ||
| 49 | MxL_XTAL_25_14_MHZ, /* 25140000 */ | ||
| 50 | MxL_XTAL_27_MHZ, /* 27000000 */ | ||
| 51 | MxL_XTAL_28_8_MHZ, /* 28800000 */ | ||
| 52 | MxL_XTAL_32_MHZ, /* 32000000 */ | ||
| 53 | MxL_XTAL_40_MHZ, /* 40000000 */ | ||
| 54 | MxL_XTAL_44_MHZ, /* 44000000 */ | ||
| 55 | MxL_XTAL_48_MHZ, /* 48000000 */ | ||
| 56 | MxL_XTAL_49_3811_MHZ, /* 49381100 */ | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum mxl5007t_clkout_amp { | ||
| 60 | MxL_CLKOUT_AMP_0_94V = 0, | ||
| 61 | MxL_CLKOUT_AMP_0_53V = 1, | ||
| 62 | MxL_CLKOUT_AMP_0_37V = 2, | ||
| 63 | MxL_CLKOUT_AMP_0_28V = 3, | ||
| 64 | MxL_CLKOUT_AMP_0_23V = 4, | ||
| 65 | MxL_CLKOUT_AMP_0_20V = 5, | ||
| 66 | MxL_CLKOUT_AMP_0_17V = 6, | ||
| 67 | MxL_CLKOUT_AMP_0_15V = 7, | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct mxl5007t_config { | ||
| 71 | s32 if_diff_out_level; | ||
| 72 | enum mxl5007t_clkout_amp clk_out_amp; | ||
| 73 | enum mxl5007t_xtal_freq xtal_freq_hz; | ||
| 74 | enum mxl5007t_if_freq if_freq_hz; | ||
| 75 | unsigned int invert_if:1; | ||
| 76 | unsigned int loop_thru_enable:1; | ||
| 77 | unsigned int clk_out_enable:1; | ||
| 78 | }; | ||
| 79 | |||
| 80 | #if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) | ||
| 81 | extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, | ||
| 82 | struct i2c_adapter *i2c, u8 addr, | ||
| 83 | struct mxl5007t_config *cfg); | ||
| 84 | #else | ||
| 85 | static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, | ||
| 86 | struct i2c_adapter *i2c, | ||
| 87 | u8 addr, | ||
| 88 | struct mxl5007t_config *cfg) | ||
| 89 | { | ||
| 90 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 91 | return NULL; | ||
| 92 | } | ||
| 93 | #endif | ||
| 94 | |||
| 95 | #endif /* __MXL5007T_H__ */ | ||
| 96 | |||
| 97 | /* | ||
| 98 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 99 | * --------------------------------------------------------------------------- | ||
| 100 | * Local variables: | ||
| 101 | * c-basic-offset: 8 | ||
| 102 | * End: | ||
| 103 | */ | ||
| 104 | |||
diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c new file mode 100644 index 00000000000..9f5dba244cb --- /dev/null +++ b/drivers/media/common/tuners/qt1010.c | |||
| @@ -0,0 +1,483 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Quantek QT1010 silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> | ||
| 5 | * Aapo Tahkola <aet@rasterburn.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 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 | #include "qt1010.h" | ||
| 22 | #include "qt1010_priv.h" | ||
| 23 | |||
| 24 | static int debug; | ||
| 25 | module_param(debug, int, 0644); | ||
| 26 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 27 | |||
| 28 | #define dprintk(args...) \ | ||
| 29 | do { \ | ||
| 30 | if (debug) printk(KERN_DEBUG "QT1010: " args); \ | ||
| 31 | } while (0) | ||
| 32 | |||
| 33 | /* read single register */ | ||
| 34 | static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) | ||
| 35 | { | ||
| 36 | struct i2c_msg msg[2] = { | ||
| 37 | { .addr = priv->cfg->i2c_address, | ||
| 38 | .flags = 0, .buf = ®, .len = 1 }, | ||
| 39 | { .addr = priv->cfg->i2c_address, | ||
| 40 | .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
| 41 | }; | ||
| 42 | |||
| 43 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
| 44 | printk(KERN_WARNING "qt1010 I2C read failed\n"); | ||
| 45 | return -EREMOTEIO; | ||
| 46 | } | ||
| 47 | return 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | /* write single register */ | ||
| 51 | static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) | ||
| 52 | { | ||
| 53 | u8 buf[2] = { reg, val }; | ||
| 54 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, | ||
| 55 | .flags = 0, .buf = buf, .len = 2 }; | ||
| 56 | |||
| 57 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
| 58 | printk(KERN_WARNING "qt1010 I2C write failed\n"); | ||
| 59 | return -EREMOTEIO; | ||
| 60 | } | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* dump all registers */ | ||
| 65 | static void qt1010_dump_regs(struct qt1010_priv *priv) | ||
| 66 | { | ||
| 67 | u8 reg, val; | ||
| 68 | |||
| 69 | for (reg = 0; ; reg++) { | ||
| 70 | if (reg % 16 == 0) { | ||
| 71 | if (reg) | ||
| 72 | printk(KERN_CONT "\n"); | ||
| 73 | printk(KERN_DEBUG "%02x:", reg); | ||
| 74 | } | ||
| 75 | if (qt1010_readreg(priv, reg, &val) == 0) | ||
| 76 | printk(KERN_CONT " %02x", val); | ||
| 77 | else | ||
| 78 | printk(KERN_CONT " --"); | ||
| 79 | if (reg == 0x2f) | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | printk(KERN_CONT "\n"); | ||
| 83 | } | ||
| 84 | |||
| 85 | static int qt1010_set_params(struct dvb_frontend *fe, | ||
| 86 | struct dvb_frontend_parameters *params) | ||
| 87 | { | ||
| 88 | struct qt1010_priv *priv; | ||
| 89 | int err; | ||
| 90 | u32 freq, div, mod1, mod2; | ||
| 91 | u8 i, tmpval, reg05; | ||
| 92 | qt1010_i2c_oper_t rd[48] = { | ||
| 93 | { QT1010_WR, 0x01, 0x80 }, | ||
| 94 | { QT1010_WR, 0x02, 0x3f }, | ||
| 95 | { QT1010_WR, 0x05, 0xff }, /* 02 c write */ | ||
| 96 | { QT1010_WR, 0x06, 0x44 }, | ||
| 97 | { QT1010_WR, 0x07, 0xff }, /* 04 c write */ | ||
| 98 | { QT1010_WR, 0x08, 0x08 }, | ||
| 99 | { QT1010_WR, 0x09, 0xff }, /* 06 c write */ | ||
| 100 | { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ | ||
| 101 | { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ | ||
| 102 | { QT1010_WR, 0x0c, 0xe1 }, | ||
| 103 | { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ | ||
| 104 | { QT1010_WR, 0x1b, 0x00 }, | ||
| 105 | { QT1010_WR, 0x1c, 0x89 }, | ||
| 106 | { QT1010_WR, 0x11, 0xff }, /* 13 c write */ | ||
| 107 | { QT1010_WR, 0x12, 0xff }, /* 14 c write */ | ||
| 108 | { QT1010_WR, 0x22, 0xff }, /* 15 c write */ | ||
| 109 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 110 | { QT1010_WR, 0x1e, 0xd0 }, | ||
| 111 | { QT1010_RD, 0x22, 0xff }, /* 16 c read */ | ||
| 112 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 113 | { QT1010_RD, 0x05, 0xff }, /* 20 c read */ | ||
| 114 | { QT1010_RD, 0x22, 0xff }, /* 21 c read */ | ||
| 115 | { QT1010_WR, 0x23, 0xd0 }, | ||
| 116 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 117 | { QT1010_WR, 0x1e, 0xe0 }, | ||
| 118 | { QT1010_RD, 0x23, 0xff }, /* 25 c read */ | ||
| 119 | { QT1010_RD, 0x23, 0xff }, /* 26 c read */ | ||
| 120 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 121 | { QT1010_WR, 0x24, 0xd0 }, | ||
| 122 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 123 | { QT1010_WR, 0x1e, 0xf0 }, | ||
| 124 | { QT1010_RD, 0x24, 0xff }, /* 31 c read */ | ||
| 125 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 126 | { QT1010_WR, 0x14, 0x7f }, | ||
| 127 | { QT1010_WR, 0x15, 0x7f }, | ||
| 128 | { QT1010_WR, 0x05, 0xff }, /* 35 c write */ | ||
| 129 | { QT1010_WR, 0x06, 0x00 }, | ||
| 130 | { QT1010_WR, 0x15, 0x1f }, | ||
| 131 | { QT1010_WR, 0x16, 0xff }, | ||
| 132 | { QT1010_WR, 0x18, 0xff }, | ||
| 133 | { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ | ||
| 134 | { QT1010_WR, 0x20, 0xff }, /* 41 c write */ | ||
| 135 | { QT1010_WR, 0x21, 0x53 }, | ||
| 136 | { QT1010_WR, 0x25, 0xff }, /* 43 c write */ | ||
| 137 | { QT1010_WR, 0x26, 0x15 }, | ||
| 138 | { QT1010_WR, 0x00, 0xff }, /* 45 c write */ | ||
| 139 | { QT1010_WR, 0x02, 0x00 }, | ||
| 140 | { QT1010_WR, 0x01, 0x00 } | ||
| 141 | }; | ||
| 142 | |||
| 143 | #define FREQ1 32000000 /* 32 MHz */ | ||
| 144 | #define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ | ||
| 145 | |||
| 146 | priv = fe->tuner_priv; | ||
| 147 | freq = params->frequency; | ||
| 148 | div = (freq + QT1010_OFFSET) / QT1010_STEP; | ||
| 149 | freq = (div * QT1010_STEP) - QT1010_OFFSET; | ||
| 150 | mod1 = (freq + QT1010_OFFSET) % FREQ1; | ||
| 151 | mod2 = (freq + QT1010_OFFSET) % FREQ2; | ||
| 152 | priv->bandwidth = | ||
| 153 | (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
| 154 | priv->frequency = freq; | ||
| 155 | |||
| 156 | if (fe->ops.i2c_gate_ctrl) | ||
| 157 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 158 | |||
| 159 | /* reg 05 base value */ | ||
| 160 | if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ | ||
| 161 | else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ | ||
| 162 | else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ | ||
| 163 | else reg05 = 0x74; | ||
| 164 | |||
| 165 | /* 0x5 */ | ||
| 166 | rd[2].val = reg05; | ||
| 167 | |||
| 168 | /* 07 - set frequency: 32 MHz scale */ | ||
| 169 | rd[4].val = (freq + QT1010_OFFSET) / FREQ1; | ||
| 170 | |||
| 171 | /* 09 - changes every 8/24 MHz */ | ||
| 172 | if (mod1 < 8000000) rd[6].val = 0x1d; | ||
| 173 | else rd[6].val = 0x1c; | ||
| 174 | |||
| 175 | /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ | ||
| 176 | if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ | ||
| 177 | else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ | ||
| 178 | else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ | ||
| 179 | else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ | ||
| 180 | else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ | ||
| 181 | else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ | ||
| 182 | else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ | ||
| 183 | else rd[7].val = 0x0a; /* +28 MHz */ | ||
| 184 | |||
| 185 | /* 0b - changes every 2/2 MHz */ | ||
| 186 | if (mod2 < 2000000) rd[8].val = 0x45; | ||
| 187 | else rd[8].val = 0x44; | ||
| 188 | |||
| 189 | /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ | ||
| 190 | tmpval = 0x78; /* byte, overflows intentionally */ | ||
| 191 | rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); | ||
| 192 | |||
| 193 | /* 11 */ | ||
| 194 | rd[13].val = 0xfd; /* TODO: correct value calculation */ | ||
| 195 | |||
| 196 | /* 12 */ | ||
| 197 | rd[14].val = 0x91; /* TODO: correct value calculation */ | ||
| 198 | |||
| 199 | /* 22 */ | ||
| 200 | if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ | ||
| 201 | else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ | ||
| 202 | else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ | ||
| 203 | else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ | ||
| 204 | else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ | ||
| 205 | else rd[15].val = 0xd0; | ||
| 206 | |||
| 207 | /* 05 */ | ||
| 208 | rd[35].val = (reg05 & 0xf0); | ||
| 209 | |||
| 210 | /* 1f */ | ||
| 211 | if (mod1 < 8000000) tmpval = 0x00; | ||
| 212 | else if (mod1 < 12000000) tmpval = 0x01; | ||
| 213 | else if (mod1 < 16000000) tmpval = 0x02; | ||
| 214 | else if (mod1 < 24000000) tmpval = 0x03; | ||
| 215 | else if (mod1 < 28000000) tmpval = 0x04; | ||
| 216 | else tmpval = 0x05; | ||
| 217 | rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); | ||
| 218 | |||
| 219 | /* 20 */ | ||
| 220 | if (mod1 < 8000000) tmpval = 0x00; | ||
| 221 | else if (mod1 < 12000000) tmpval = 0x01; | ||
| 222 | else if (mod1 < 20000000) tmpval = 0x02; | ||
| 223 | else if (mod1 < 24000000) tmpval = 0x03; | ||
| 224 | else if (mod1 < 28000000) tmpval = 0x04; | ||
| 225 | else tmpval = 0x05; | ||
| 226 | rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); | ||
| 227 | |||
| 228 | /* 25 */ | ||
| 229 | rd[43].val = priv->reg25_init_val; | ||
| 230 | |||
| 231 | /* 00 */ | ||
| 232 | rd[45].val = 0x92; /* TODO: correct value calculation */ | ||
| 233 | |||
| 234 | dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \ | ||
| 235 | "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \ | ||
| 236 | "20:%02x 25:%02x 00:%02x", \ | ||
| 237 | freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ | ||
| 238 | rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ | ||
| 239 | rd[40].val, rd[41].val, rd[43].val, rd[45].val); | ||
| 240 | |||
| 241 | for (i = 0; i < ARRAY_SIZE(rd); i++) { | ||
| 242 | if (rd[i].oper == QT1010_WR) { | ||
| 243 | err = qt1010_writereg(priv, rd[i].reg, rd[i].val); | ||
| 244 | } else { /* read is required to proper locking */ | ||
| 245 | err = qt1010_readreg(priv, rd[i].reg, &tmpval); | ||
| 246 | } | ||
| 247 | if (err) return err; | ||
| 248 | } | ||
| 249 | |||
| 250 | if (debug) | ||
| 251 | qt1010_dump_regs(priv); | ||
| 252 | |||
| 253 | if (fe->ops.i2c_gate_ctrl) | ||
| 254 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int qt1010_init_meas1(struct qt1010_priv *priv, | ||
| 260 | u8 oper, u8 reg, u8 reg_init_val, u8 *retval) | ||
| 261 | { | ||
| 262 | u8 i, val1, val2; | ||
| 263 | int err; | ||
| 264 | |||
| 265 | qt1010_i2c_oper_t i2c_data[] = { | ||
| 266 | { QT1010_WR, reg, reg_init_val }, | ||
| 267 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 268 | { QT1010_WR, 0x1e, oper }, | ||
| 269 | { QT1010_RD, reg, 0xff } | ||
| 270 | }; | ||
| 271 | |||
| 272 | for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { | ||
| 273 | if (i2c_data[i].oper == QT1010_WR) { | ||
| 274 | err = qt1010_writereg(priv, i2c_data[i].reg, | ||
| 275 | i2c_data[i].val); | ||
| 276 | } else { | ||
| 277 | err = qt1010_readreg(priv, i2c_data[i].reg, &val2); | ||
| 278 | } | ||
| 279 | if (err) return err; | ||
| 280 | } | ||
| 281 | |||
| 282 | do { | ||
| 283 | val1 = val2; | ||
| 284 | err = qt1010_readreg(priv, reg, &val2); | ||
| 285 | if (err) return err; | ||
| 286 | dprintk("compare reg:%02x %02x %02x", reg, val1, val2); | ||
| 287 | } while (val1 != val2); | ||
| 288 | *retval = val1; | ||
| 289 | |||
| 290 | return qt1010_writereg(priv, 0x1e, 0x00); | ||
| 291 | } | ||
| 292 | |||
| 293 | static u8 qt1010_init_meas2(struct qt1010_priv *priv, | ||
| 294 | u8 reg_init_val, u8 *retval) | ||
| 295 | { | ||
| 296 | u8 i, val; | ||
| 297 | int err; | ||
| 298 | qt1010_i2c_oper_t i2c_data[] = { | ||
| 299 | { QT1010_WR, 0x07, reg_init_val }, | ||
| 300 | { QT1010_WR, 0x22, 0xd0 }, | ||
| 301 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 302 | { QT1010_WR, 0x1e, 0xd0 }, | ||
| 303 | { QT1010_RD, 0x22, 0xff }, | ||
| 304 | { QT1010_WR, 0x1e, 0x00 }, | ||
| 305 | { QT1010_WR, 0x22, 0xff } | ||
| 306 | }; | ||
| 307 | for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { | ||
| 308 | if (i2c_data[i].oper == QT1010_WR) { | ||
| 309 | err = qt1010_writereg(priv, i2c_data[i].reg, | ||
| 310 | i2c_data[i].val); | ||
| 311 | } else { | ||
| 312 | err = qt1010_readreg(priv, i2c_data[i].reg, &val); | ||
| 313 | } | ||
| 314 | if (err) return err; | ||
| 315 | } | ||
| 316 | *retval = val; | ||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | static int qt1010_init(struct dvb_frontend *fe) | ||
| 321 | { | ||
| 322 | struct qt1010_priv *priv = fe->tuner_priv; | ||
| 323 | struct dvb_frontend_parameters params; | ||
| 324 | int err = 0; | ||
| 325 | u8 i, tmpval, *valptr = NULL; | ||
| 326 | |||
| 327 | qt1010_i2c_oper_t i2c_data[] = { | ||
| 328 | { QT1010_WR, 0x01, 0x80 }, | ||
| 329 | { QT1010_WR, 0x0d, 0x84 }, | ||
| 330 | { QT1010_WR, 0x0e, 0xb7 }, | ||
| 331 | { QT1010_WR, 0x2a, 0x23 }, | ||
| 332 | { QT1010_WR, 0x2c, 0xdc }, | ||
| 333 | { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ | ||
| 334 | { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ | ||
| 335 | { QT1010_WR, 0x2b, 0x70 }, | ||
| 336 | { QT1010_WR, 0x2a, 0x23 }, | ||
| 337 | { QT1010_M1, 0x26, 0x08 }, | ||
| 338 | { QT1010_M1, 0x82, 0xff }, | ||
| 339 | { QT1010_WR, 0x05, 0x14 }, | ||
| 340 | { QT1010_WR, 0x06, 0x44 }, | ||
| 341 | { QT1010_WR, 0x07, 0x28 }, | ||
| 342 | { QT1010_WR, 0x08, 0x0b }, | ||
| 343 | { QT1010_WR, 0x11, 0xfd }, | ||
| 344 | { QT1010_M1, 0x22, 0x0d }, | ||
| 345 | { QT1010_M1, 0xd0, 0xff }, | ||
| 346 | { QT1010_WR, 0x06, 0x40 }, | ||
| 347 | { QT1010_WR, 0x16, 0xf0 }, | ||
| 348 | { QT1010_WR, 0x02, 0x38 }, | ||
| 349 | { QT1010_WR, 0x03, 0x18 }, | ||
| 350 | { QT1010_WR, 0x20, 0xe0 }, | ||
| 351 | { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ | ||
| 352 | { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ | ||
| 353 | { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ | ||
| 354 | { QT1010_WR, 0x03, 0x19 }, | ||
| 355 | { QT1010_WR, 0x02, 0x3f }, | ||
| 356 | { QT1010_WR, 0x21, 0x53 }, | ||
| 357 | { QT1010_RD, 0x21, 0xff }, | ||
| 358 | { QT1010_WR, 0x11, 0xfd }, | ||
| 359 | { QT1010_WR, 0x05, 0x34 }, | ||
| 360 | { QT1010_WR, 0x06, 0x44 }, | ||
| 361 | { QT1010_WR, 0x08, 0x08 } | ||
| 362 | }; | ||
| 363 | |||
| 364 | if (fe->ops.i2c_gate_ctrl) | ||
| 365 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 366 | |||
| 367 | for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { | ||
| 368 | switch (i2c_data[i].oper) { | ||
| 369 | case QT1010_WR: | ||
| 370 | err = qt1010_writereg(priv, i2c_data[i].reg, | ||
| 371 | i2c_data[i].val); | ||
| 372 | break; | ||
| 373 | case QT1010_RD: | ||
| 374 | if (i2c_data[i].val == 0x20) | ||
| 375 | valptr = &priv->reg20_init_val; | ||
| 376 | else | ||
| 377 | valptr = &tmpval; | ||
| 378 | err = qt1010_readreg(priv, i2c_data[i].reg, valptr); | ||
| 379 | break; | ||
| 380 | case QT1010_M1: | ||
| 381 | if (i2c_data[i].val == 0x25) | ||
| 382 | valptr = &priv->reg25_init_val; | ||
| 383 | else if (i2c_data[i].val == 0x1f) | ||
| 384 | valptr = &priv->reg1f_init_val; | ||
| 385 | else | ||
| 386 | valptr = &tmpval; | ||
| 387 | err = qt1010_init_meas1(priv, i2c_data[i+1].reg, | ||
| 388 | i2c_data[i].reg, | ||
| 389 | i2c_data[i].val, valptr); | ||
| 390 | i++; | ||
| 391 | break; | ||
| 392 | } | ||
| 393 | if (err) return err; | ||
| 394 | } | ||
| 395 | |||
| 396 | for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ | ||
| 397 | if ((err = qt1010_init_meas2(priv, i, &tmpval))) | ||
| 398 | return err; | ||
| 399 | |||
| 400 | params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */ | ||
| 401 | /* MSI Megasky 580 GL861 533000000 */ | ||
| 402 | return qt1010_set_params(fe, ¶ms); | ||
| 403 | } | ||
| 404 | |||
| 405 | static int qt1010_release(struct dvb_frontend *fe) | ||
| 406 | { | ||
| 407 | kfree(fe->tuner_priv); | ||
| 408 | fe->tuner_priv = NULL; | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 413 | { | ||
| 414 | struct qt1010_priv *priv = fe->tuner_priv; | ||
| 415 | *frequency = priv->frequency; | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 420 | { | ||
| 421 | struct qt1010_priv *priv = fe->tuner_priv; | ||
| 422 | *bandwidth = priv->bandwidth; | ||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | static const struct dvb_tuner_ops qt1010_tuner_ops = { | ||
| 427 | .info = { | ||
| 428 | .name = "Quantek QT1010", | ||
| 429 | .frequency_min = QT1010_MIN_FREQ, | ||
| 430 | .frequency_max = QT1010_MAX_FREQ, | ||
| 431 | .frequency_step = QT1010_STEP, | ||
| 432 | }, | ||
| 433 | |||
| 434 | .release = qt1010_release, | ||
| 435 | .init = qt1010_init, | ||
| 436 | /* TODO: implement sleep */ | ||
| 437 | |||
| 438 | .set_params = qt1010_set_params, | ||
| 439 | .get_frequency = qt1010_get_frequency, | ||
| 440 | .get_bandwidth = qt1010_get_bandwidth | ||
| 441 | }; | ||
| 442 | |||
| 443 | struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, | ||
| 444 | struct i2c_adapter *i2c, | ||
| 445 | struct qt1010_config *cfg) | ||
| 446 | { | ||
| 447 | struct qt1010_priv *priv = NULL; | ||
| 448 | u8 id; | ||
| 449 | |||
| 450 | priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); | ||
| 451 | if (priv == NULL) | ||
| 452 | return NULL; | ||
| 453 | |||
| 454 | priv->cfg = cfg; | ||
| 455 | priv->i2c = i2c; | ||
| 456 | |||
| 457 | if (fe->ops.i2c_gate_ctrl) | ||
| 458 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
| 459 | |||
| 460 | |||
| 461 | /* Try to detect tuner chip. Probably this is not correct register. */ | ||
| 462 | if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { | ||
| 463 | kfree(priv); | ||
| 464 | return NULL; | ||
| 465 | } | ||
| 466 | |||
| 467 | if (fe->ops.i2c_gate_ctrl) | ||
| 468 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
| 469 | |||
| 470 | printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); | ||
| 471 | memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, | ||
| 472 | sizeof(struct dvb_tuner_ops)); | ||
| 473 | |||
| 474 | fe->tuner_priv = priv; | ||
| 475 | return fe; | ||
| 476 | } | ||
| 477 | EXPORT_SYMBOL(qt1010_attach); | ||
| 478 | |||
| 479 | MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); | ||
| 480 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
| 481 | MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>"); | ||
| 482 | MODULE_VERSION("0.1"); | ||
| 483 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/qt1010.h b/drivers/media/common/tuners/qt1010.h new file mode 100644 index 00000000000..807fb7b6146 --- /dev/null +++ b/drivers/media/common/tuners/qt1010.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Quantek QT1010 silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> | ||
| 5 | * Aapo Tahkola <aet@rasterburn.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 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 | #ifndef QT1010_H | ||
| 23 | #define QT1010_H | ||
| 24 | |||
| 25 | #include "dvb_frontend.h" | ||
| 26 | |||
| 27 | struct qt1010_config { | ||
| 28 | u8 i2c_address; | ||
| 29 | }; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Attach a qt1010 tuner to the supplied frontend structure. | ||
| 33 | * | ||
| 34 | * @param fe frontend to attach to | ||
| 35 | * @param i2c i2c adapter to use | ||
| 36 | * @param cfg tuner hw based configuration | ||
| 37 | * @return fe pointer on success, NULL on failure | ||
| 38 | */ | ||
| 39 | #if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) | ||
| 40 | extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, | ||
| 41 | struct i2c_adapter *i2c, | ||
| 42 | struct qt1010_config *cfg); | ||
| 43 | #else | ||
| 44 | static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, | ||
| 45 | struct i2c_adapter *i2c, | ||
| 46 | struct qt1010_config *cfg) | ||
| 47 | { | ||
| 48 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 49 | return NULL; | ||
| 50 | } | ||
| 51 | #endif // CONFIG_MEDIA_TUNER_QT1010 | ||
| 52 | |||
| 53 | #endif | ||
diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h new file mode 100644 index 00000000000..090cf475f09 --- /dev/null +++ b/drivers/media/common/tuners/qt1010_priv.h | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Quantek QT1010 silicon tuner | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> | ||
| 5 | * Aapo Tahkola <aet@rasterburn.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 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 | #ifndef QT1010_PRIV_H | ||
| 23 | #define QT1010_PRIV_H | ||
| 24 | |||
| 25 | /* | ||
| 26 | reg def meaning | ||
| 27 | === === ======= | ||
| 28 | 00 00 ? | ||
| 29 | 01 a0 ? operation start/stop; start=80, stop=00 | ||
| 30 | 02 00 ? | ||
| 31 | 03 19 ? | ||
| 32 | 04 00 ? | ||
| 33 | 05 00 ? maybe band selection | ||
| 34 | 06 00 ? | ||
| 35 | 07 2b set frequency: 32 MHz scale, n*32 MHz | ||
| 36 | 08 0b ? | ||
| 37 | 09 10 ? changes every 8/24 MHz; values 1d/1c | ||
| 38 | 0a 08 set frequency: 4 MHz scale, n*4 MHz | ||
| 39 | 0b 41 ? changes every 2/2 MHz; values 45/45 | ||
| 40 | 0c e1 ? | ||
| 41 | 0d 94 ? | ||
| 42 | 0e b6 ? | ||
| 43 | 0f 2c ? | ||
| 44 | 10 10 ? | ||
| 45 | 11 f1 ? maybe device specified adjustment | ||
| 46 | 12 11 ? maybe device specified adjustment | ||
| 47 | 13 3f ? | ||
| 48 | 14 1f ? | ||
| 49 | 15 3f ? | ||
| 50 | 16 ff ? | ||
| 51 | 17 ff ? | ||
| 52 | 18 f7 ? | ||
| 53 | 19 80 ? | ||
| 54 | 1a d0 set frequency: 125 kHz scale, n*125 kHz | ||
| 55 | 1b 00 ? | ||
| 56 | 1c 89 ? | ||
| 57 | 1d 00 ? | ||
| 58 | 1e 00 ? looks like operation register; write cmd here, read result from 1f-26 | ||
| 59 | 1f 20 ? chip initialization | ||
| 60 | 20 e0 ? chip initialization | ||
| 61 | 21 20 ? | ||
| 62 | 22 d0 ? | ||
| 63 | 23 d0 ? | ||
| 64 | 24 d0 ? | ||
| 65 | 25 40 ? chip initialization | ||
| 66 | 26 08 ? | ||
| 67 | 27 29 ? | ||
| 68 | 28 55 ? | ||
| 69 | 29 39 ? | ||
| 70 | 2a 13 ? | ||
| 71 | 2b 01 ? | ||
| 72 | 2c ea ? | ||
| 73 | 2d 00 ? | ||
| 74 | 2e 00 ? not used? | ||
| 75 | 2f 00 ? not used? | ||
| 76 | */ | ||
| 77 | |||
| 78 | #define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, | ||
| 79 | hw could be more precise but we don't | ||
| 80 | know how to use */ | ||
| 81 | #define QT1010_MIN_FREQ 48000000 /* 48 MHz */ | ||
| 82 | #define QT1010_MAX_FREQ 860000000 /* 860 MHz */ | ||
| 83 | #define QT1010_OFFSET 1246000000 /* 1246 MHz */ | ||
| 84 | |||
| 85 | #define QT1010_WR 0 | ||
| 86 | #define QT1010_RD 1 | ||
| 87 | #define QT1010_M1 3 | ||
| 88 | |||
| 89 | typedef struct { | ||
| 90 | u8 oper, reg, val; | ||
| 91 | } qt1010_i2c_oper_t; | ||
| 92 | |||
| 93 | struct qt1010_priv { | ||
| 94 | struct qt1010_config *cfg; | ||
| 95 | struct i2c_adapter *i2c; | ||
| 96 | |||
| 97 | u8 reg1f_init_val; | ||
| 98 | u8 reg20_init_val; | ||
| 99 | u8 reg25_init_val; | ||
| 100 | |||
| 101 | u32 frequency; | ||
| 102 | u32 bandwidth; | ||
| 103 | }; | ||
| 104 | |||
| 105 | #endif | ||
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c new file mode 100644 index 00000000000..1f1db20d46b --- /dev/null +++ b/drivers/media/common/tuners/tda18212.c | |||
| @@ -0,0 +1,265 @@ | |||
| 1 | /* | ||
| 2 | * NXP TDA18212HN silicon tuner driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along | ||
| 17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "tda18212_priv.h" | ||
| 22 | |||
| 23 | static int debug; | ||
| 24 | module_param(debug, int, 0644); | ||
| 25 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 26 | |||
| 27 | /* write multiple registers */ | ||
| 28 | static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, | ||
| 29 | int len) | ||
| 30 | { | ||
| 31 | int ret; | ||
| 32 | u8 buf[len+1]; | ||
| 33 | struct i2c_msg msg[1] = { | ||
| 34 | { | ||
| 35 | .addr = priv->cfg->i2c_address, | ||
| 36 | .flags = 0, | ||
| 37 | .len = sizeof(buf), | ||
| 38 | .buf = buf, | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | |||
| 42 | buf[0] = reg; | ||
| 43 | memcpy(&buf[1], val, len); | ||
| 44 | |||
| 45 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
| 46 | if (ret == 1) { | ||
| 47 | ret = 0; | ||
| 48 | } else { | ||
| 49 | warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
| 50 | ret = -EREMOTEIO; | ||
| 51 | } | ||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* read multiple registers */ | ||
| 56 | static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, | ||
| 57 | int len) | ||
| 58 | { | ||
| 59 | int ret; | ||
| 60 | u8 buf[len]; | ||
| 61 | struct i2c_msg msg[2] = { | ||
| 62 | { | ||
| 63 | .addr = priv->cfg->i2c_address, | ||
| 64 | .flags = 0, | ||
| 65 | .len = 1, | ||
| 66 | .buf = ®, | ||
| 67 | }, { | ||
| 68 | .addr = priv->cfg->i2c_address, | ||
| 69 | .flags = I2C_M_RD, | ||
| 70 | .len = sizeof(buf), | ||
| 71 | .buf = buf, | ||
| 72 | } | ||
| 73 | }; | ||
| 74 | |||
| 75 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
| 76 | if (ret == 2) { | ||
| 77 | memcpy(val, buf, len); | ||
| 78 | ret = 0; | ||
| 79 | } else { | ||
| 80 | warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
| 81 | ret = -EREMOTEIO; | ||
| 82 | } | ||
| 83 | |||
| 84 | return ret; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* write single register */ | ||
| 88 | static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) | ||
| 89 | { | ||
| 90 | return tda18212_wr_regs(priv, reg, &val, 1); | ||
| 91 | } | ||
| 92 | |||
| 93 | /* read single register */ | ||
| 94 | static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) | ||
| 95 | { | ||
| 96 | return tda18212_rd_regs(priv, reg, val, 1); | ||
| 97 | } | ||
| 98 | |||
| 99 | #if 0 /* keep, useful when developing driver */ | ||
| 100 | static void tda18212_dump_regs(struct tda18212_priv *priv) | ||
| 101 | { | ||
| 102 | int i; | ||
| 103 | u8 buf[256]; | ||
| 104 | |||
| 105 | #define TDA18212_RD_LEN 32 | ||
| 106 | for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) | ||
| 107 | tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); | ||
| 108 | |||
| 109 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, | ||
| 110 | sizeof(buf), true); | ||
| 111 | |||
| 112 | return; | ||
| 113 | } | ||
| 114 | #endif | ||
| 115 | |||
| 116 | static int tda18212_set_params(struct dvb_frontend *fe, | ||
| 117 | struct dvb_frontend_parameters *p) | ||
| 118 | { | ||
| 119 | struct tda18212_priv *priv = fe->tuner_priv; | ||
| 120 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 121 | int ret, i; | ||
| 122 | u32 if_khz; | ||
| 123 | u8 buf[9]; | ||
| 124 | static const u8 bw_params[][3] = { | ||
| 125 | /* 0f 13 23 */ | ||
| 126 | { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */ | ||
| 127 | { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */ | ||
| 128 | { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */ | ||
| 129 | { 0x92, 0x53, 0x03 }, /* DVB-C */ | ||
| 130 | }; | ||
| 131 | |||
| 132 | dbg("%s: delsys=%d RF=%d BW=%d", __func__, | ||
| 133 | c->delivery_system, c->frequency, c->bandwidth_hz); | ||
| 134 | |||
| 135 | if (fe->ops.i2c_gate_ctrl) | ||
| 136 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
| 137 | |||
| 138 | switch (c->delivery_system) { | ||
| 139 | case SYS_DVBT: | ||
| 140 | switch (c->bandwidth_hz) { | ||
| 141 | case 6000000: | ||
| 142 | if_khz = priv->cfg->if_dvbt_6; | ||
| 143 | i = 0; | ||
| 144 | break; | ||
| 145 | case 7000000: | ||
| 146 | if_khz = priv->cfg->if_dvbt_7; | ||
| 147 | i = 1; | ||
| 148 | break; | ||
| 149 | case 8000000: | ||
| 150 | if_khz = priv->cfg->if_dvbt_8; | ||
| 151 | i = 2; | ||
| 152 | break; | ||
| 153 | default: | ||
| 154 | ret = -EINVAL; | ||
| 155 | goto error; | ||
| 156 | } | ||
| 157 | break; | ||
| 158 | case SYS_DVBC_ANNEX_AC: | ||
| 159 | if_khz = priv->cfg->if_dvbc; | ||
| 160 | i = 3; | ||
| 161 | break; | ||
| 162 | default: | ||
| 163 | ret = -EINVAL; | ||
| 164 | goto error; | ||
| 165 | } | ||
| 166 | |||
| 167 | ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); | ||
| 168 | if (ret) | ||
| 169 | goto error; | ||
| 170 | |||
| 171 | ret = tda18212_wr_reg(priv, 0x06, 0x00); | ||
| 172 | if (ret) | ||
| 173 | goto error; | ||
| 174 | |||
| 175 | ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); | ||
| 176 | if (ret) | ||
| 177 | goto error; | ||
| 178 | |||
| 179 | buf[0] = 0x02; | ||
| 180 | buf[1] = bw_params[i][1]; | ||
| 181 | buf[2] = 0x03; /* default value */ | ||
| 182 | buf[3] = if_khz / 50; | ||
| 183 | buf[4] = ((c->frequency / 1000) >> 16) & 0xff; | ||
| 184 | buf[5] = ((c->frequency / 1000) >> 8) & 0xff; | ||
| 185 | buf[6] = ((c->frequency / 1000) >> 0) & 0xff; | ||
| 186 | buf[7] = 0xc1; | ||
| 187 | buf[8] = 0x01; | ||
| 188 | ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); | ||
| 189 | if (ret) | ||
| 190 | goto error; | ||
| 191 | |||
| 192 | exit: | ||
| 193 | if (fe->ops.i2c_gate_ctrl) | ||
| 194 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
| 195 | |||
| 196 | return ret; | ||
| 197 | |||
| 198 | error: | ||
| 199 | dbg("%s: failed:%d", __func__, ret); | ||
| 200 | goto exit; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int tda18212_release(struct dvb_frontend *fe) | ||
| 204 | { | ||
| 205 | kfree(fe->tuner_priv); | ||
| 206 | fe->tuner_priv = NULL; | ||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static const struct dvb_tuner_ops tda18212_tuner_ops = { | ||
| 211 | .info = { | ||
| 212 | .name = "NXP TDA18212", | ||
| 213 | |||
| 214 | .frequency_min = 48000000, | ||
| 215 | .frequency_max = 864000000, | ||
| 216 | .frequency_step = 1000, | ||
| 217 | }, | ||
| 218 | |||
| 219 | .release = tda18212_release, | ||
| 220 | |||
| 221 | .set_params = tda18212_set_params, | ||
| 222 | }; | ||
| 223 | |||
| 224 | struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
| 225 | struct i2c_adapter *i2c, struct tda18212_config *cfg) | ||
| 226 | { | ||
| 227 | struct tda18212_priv *priv = NULL; | ||
| 228 | int ret; | ||
| 229 | u8 val; | ||
| 230 | |||
| 231 | priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); | ||
| 232 | if (priv == NULL) | ||
| 233 | return NULL; | ||
| 234 | |||
| 235 | priv->cfg = cfg; | ||
| 236 | priv->i2c = i2c; | ||
| 237 | fe->tuner_priv = priv; | ||
| 238 | |||
| 239 | if (fe->ops.i2c_gate_ctrl) | ||
| 240 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
| 241 | |||
| 242 | /* check if the tuner is there */ | ||
| 243 | ret = tda18212_rd_reg(priv, 0x00, &val); | ||
| 244 | |||
| 245 | if (fe->ops.i2c_gate_ctrl) | ||
| 246 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
| 247 | |||
| 248 | dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); | ||
| 249 | if (ret || val != 0xc7) { | ||
| 250 | kfree(priv); | ||
| 251 | return NULL; | ||
| 252 | } | ||
| 253 | |||
| 254 | info("NXP TDA18212HN successfully identified."); | ||
| 255 | |||
| 256 | memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, | ||
| 257 | sizeof(struct dvb_tuner_ops)); | ||
| 258 | |||
| 259 | return fe; | ||
| 260 | } | ||
| 261 | EXPORT_SYMBOL(tda18212_attach); | ||
| 262 | |||
| 263 | MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); | ||
| 264 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
| 265 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h new file mode 100644 index 00000000000..83b497f59e1 --- /dev/null +++ b/drivers/media/common/tuners/tda18212.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* | ||
| 2 | * NXP TDA18212HN silicon tuner driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along | ||
| 17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef TDA18212_H | ||
| 22 | #define TDA18212_H | ||
| 23 | |||
| 24 | #include "dvb_frontend.h" | ||
| 25 | |||
| 26 | struct tda18212_config { | ||
| 27 | u8 i2c_address; | ||
| 28 | |||
| 29 | u16 if_dvbt_6; | ||
| 30 | u16 if_dvbt_7; | ||
| 31 | u16 if_dvbt_8; | ||
| 32 | u16 if_dvbc; | ||
| 33 | }; | ||
| 34 | |||
| 35 | #if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ | ||
| 36 | (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) | ||
| 37 | extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
| 38 | struct i2c_adapter *i2c, struct tda18212_config *cfg); | ||
| 39 | #else | ||
| 40 | static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
| 41 | struct i2c_adapter *i2c, struct tda18212_config *cfg) | ||
| 42 | { | ||
| 43 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #endif | ||
diff --git a/drivers/media/common/tuners/tda18212_priv.h b/drivers/media/common/tuners/tda18212_priv.h new file mode 100644 index 00000000000..9adff9356b7 --- /dev/null +++ b/drivers/media/common/tuners/tda18212_priv.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * NXP TDA18212HN silicon tuner driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along | ||
| 17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef TDA18212_PRIV_H | ||
| 22 | #define TDA18212_PRIV_H | ||
| 23 | |||
| 24 | #include "tda18212.h" | ||
| 25 | |||
| 26 | #define LOG_PREFIX "tda18212" | ||
| 27 | |||
| 28 | #undef dbg | ||
| 29 | #define dbg(f, arg...) \ | ||
| 30 | if (debug) \ | ||
| 31 | printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
| 32 | #undef err | ||
| 33 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
| 34 | #undef info | ||
| 35 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
| 36 | #undef warn | ||
| 37 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
| 38 | |||
| 39 | struct tda18212_priv { | ||
| 40 | struct tda18212_config *cfg; | ||
| 41 | struct i2c_adapter *i2c; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #endif | ||
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c new file mode 100644 index 00000000000..aacfe2387e2 --- /dev/null +++ b/drivers/media/common/tuners/tda18218.c | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | /* | ||
| 2 | * NXP TDA18218HN silicon tuner driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "tda18218.h" | ||
| 22 | #include "tda18218_priv.h" | ||
| 23 | |||
| 24 | static int debug; | ||
| 25 | module_param(debug, int, 0644); | ||
| 26 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 27 | |||
| 28 | /* write multiple registers */ | ||
| 29 | static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) | ||
| 30 | { | ||
| 31 | int ret = 0; | ||
| 32 | u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; | ||
| 33 | struct i2c_msg msg[1] = { | ||
| 34 | { | ||
| 35 | .addr = priv->cfg->i2c_address, | ||
| 36 | .flags = 0, | ||
| 37 | .buf = buf, | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | msg_len_max = priv->cfg->i2c_wr_max - 1; | ||
| 42 | quotient = len / msg_len_max; | ||
| 43 | remainder = len % msg_len_max; | ||
| 44 | msg_len = msg_len_max; | ||
| 45 | for (i = 0; (i <= quotient && remainder); i++) { | ||
| 46 | if (i == quotient) /* set len of the last msg */ | ||
| 47 | msg_len = remainder; | ||
| 48 | |||
| 49 | msg[0].len = msg_len + 1; | ||
| 50 | buf[0] = reg + i * msg_len_max; | ||
| 51 | memcpy(&buf[1], &val[i * msg_len_max], msg_len); | ||
| 52 | |||
| 53 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
| 54 | if (ret != 1) | ||
| 55 | break; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (ret == 1) { | ||
| 59 | ret = 0; | ||
| 60 | } else { | ||
| 61 | warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
| 62 | ret = -EREMOTEIO; | ||
| 63 | } | ||
| 64 | |||
| 65 | return ret; | ||
| 66 | } | ||
| 67 | |||
| 68 | /* read multiple registers */ | ||
| 69 | static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) | ||
| 70 | { | ||
| 71 | int ret; | ||
| 72 | u8 buf[reg+len]; /* we must start read always from reg 0x00 */ | ||
| 73 | struct i2c_msg msg[2] = { | ||
| 74 | { | ||
| 75 | .addr = priv->cfg->i2c_address, | ||
| 76 | .flags = 0, | ||
| 77 | .len = 1, | ||
| 78 | .buf = "\x00", | ||
| 79 | }, { | ||
| 80 | .addr = priv->cfg->i2c_address, | ||
| 81 | .flags = I2C_M_RD, | ||
| 82 | .len = sizeof(buf), | ||
| 83 | .buf = buf, | ||
| 84 | } | ||
| 85 | }; | ||
| 86 | |||
| 87 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
| 88 | if (ret == 2) { | ||
| 89 | memcpy(val, &buf[reg], len); | ||
| 90 | ret = 0; | ||
| 91 | } else { | ||
| 92 | warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
| 93 | ret = -EREMOTEIO; | ||
| 94 | } | ||
| 95 | |||
| 96 | return ret; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* write single register */ | ||
| 100 | static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) | ||
| 101 | { | ||
| 102 | return tda18218_wr_regs(priv, reg, &val, 1); | ||
| 103 | } | ||
| 104 | |||
| 105 | /* read single register */ | ||
| 106 | |||
| 107 | static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) | ||
| 108 | { | ||
| 109 | return tda18218_rd_regs(priv, reg, val, 1); | ||
| 110 | } | ||
| 111 | |||
| 112 | static int tda18218_set_params(struct dvb_frontend *fe, | ||
| 113 | struct dvb_frontend_parameters *params) | ||
| 114 | { | ||
| 115 | struct tda18218_priv *priv = fe->tuner_priv; | ||
| 116 | int ret; | ||
| 117 | u8 buf[3], i, BP_Filter, LP_Fc; | ||
| 118 | u32 LO_Frac; | ||
| 119 | /* TODO: find out correct AGC algorithm */ | ||
| 120 | u8 agc[][2] = { | ||
| 121 | { R20_AGC11, 0x60 }, | ||
| 122 | { R23_AGC21, 0x02 }, | ||
| 123 | { R20_AGC11, 0xa0 }, | ||
| 124 | { R23_AGC21, 0x09 }, | ||
| 125 | { R20_AGC11, 0xe0 }, | ||
| 126 | { R23_AGC21, 0x0c }, | ||
| 127 | { R20_AGC11, 0x40 }, | ||
| 128 | { R23_AGC21, 0x01 }, | ||
| 129 | { R20_AGC11, 0x80 }, | ||
| 130 | { R23_AGC21, 0x08 }, | ||
| 131 | { R20_AGC11, 0xc0 }, | ||
| 132 | { R23_AGC21, 0x0b }, | ||
| 133 | { R24_AGC22, 0x1c }, | ||
| 134 | { R24_AGC22, 0x0c }, | ||
| 135 | }; | ||
| 136 | |||
| 137 | if (fe->ops.i2c_gate_ctrl) | ||
| 138 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
| 139 | |||
| 140 | /* low-pass filter cut-off frequency */ | ||
| 141 | switch (params->u.ofdm.bandwidth) { | ||
| 142 | case BANDWIDTH_6_MHZ: | ||
| 143 | LP_Fc = 0; | ||
| 144 | LO_Frac = params->frequency + 4000000; | ||
| 145 | break; | ||
| 146 | case BANDWIDTH_7_MHZ: | ||
| 147 | LP_Fc = 1; | ||
| 148 | LO_Frac = params->frequency + 3500000; | ||
| 149 | break; | ||
| 150 | case BANDWIDTH_8_MHZ: | ||
| 151 | default: | ||
| 152 | LP_Fc = 2; | ||
| 153 | LO_Frac = params->frequency + 4000000; | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* band-pass filter */ | ||
| 158 | if (LO_Frac < 188000000) | ||
| 159 | BP_Filter = 3; | ||
| 160 | else if (LO_Frac < 253000000) | ||
| 161 | BP_Filter = 4; | ||
| 162 | else if (LO_Frac < 343000000) | ||
| 163 | BP_Filter = 5; | ||
| 164 | else | ||
| 165 | BP_Filter = 6; | ||
| 166 | |||
| 167 | buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ | ||
| 168 | buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ | ||
| 169 | buf[2] = priv->regs[R1C_AGC2B]; | ||
| 170 | ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); | ||
| 171 | if (ret) | ||
| 172 | goto error; | ||
| 173 | |||
| 174 | buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ | ||
| 175 | buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ | ||
| 176 | buf[2] = (LO_Frac / 1000) << 4 | | ||
| 177 | (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ | ||
| 178 | ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); | ||
| 179 | if (ret) | ||
| 180 | goto error; | ||
| 181 | |||
| 182 | buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ | ||
| 183 | ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); | ||
| 184 | if (ret) | ||
| 185 | goto error; | ||
| 186 | |||
| 187 | buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ | ||
| 188 | ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); | ||
| 189 | if (ret) | ||
| 190 | goto error; | ||
| 191 | |||
| 192 | /* trigger AGC */ | ||
| 193 | for (i = 0; i < ARRAY_SIZE(agc); i++) { | ||
| 194 | ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); | ||
| 195 | if (ret) | ||
| 196 | goto error; | ||
| 197 | } | ||
| 198 | |||
| 199 | error: | ||
| 200 | if (fe->ops.i2c_gate_ctrl) | ||
| 201 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
| 202 | |||
| 203 | if (ret) | ||
| 204 | dbg("%s: failed ret:%d", __func__, ret); | ||
| 205 | |||
| 206 | return ret; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int tda18218_sleep(struct dvb_frontend *fe) | ||
| 210 | { | ||
| 211 | struct tda18218_priv *priv = fe->tuner_priv; | ||
| 212 | int ret; | ||
| 213 | |||
| 214 | if (fe->ops.i2c_gate_ctrl) | ||
| 215 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
| 216 | |||
| 217 | /* standby */ | ||
| 218 | ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); | ||
| 219 | |||
| 220 | if (fe->ops.i2c_gate_ctrl) | ||
| 221 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
| 222 | |||
| 223 | if (ret) | ||
| 224 | dbg("%s: failed ret:%d", __func__, ret); | ||
| 225 | |||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | static int tda18218_init(struct dvb_frontend *fe) | ||
| 230 | { | ||
| 231 | struct tda18218_priv *priv = fe->tuner_priv; | ||
| 232 | int ret; | ||
| 233 | |||
| 234 | /* TODO: calibrations */ | ||
| 235 | |||
| 236 | if (fe->ops.i2c_gate_ctrl) | ||
| 237 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
| 238 | |||
| 239 | ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); | ||
| 240 | |||
| 241 | if (fe->ops.i2c_gate_ctrl) | ||
| 242 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
| 243 | |||
| 244 | if (ret) | ||
| 245 | dbg("%s: failed ret:%d", __func__, ret); | ||
| 246 | |||
| 247 | return ret; | ||
| 248 | } | ||
| 249 | |||
| 250 | static int tda18218_release(struct dvb_frontend *fe) | ||
| 251 | { | ||
| 252 | kfree(fe->tuner_priv); | ||
| 253 | fe->tuner_priv = NULL; | ||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | static const struct dvb_tuner_ops tda18218_tuner_ops = { | ||
| 258 | .info = { | ||
| 259 | .name = "NXP TDA18218", | ||
| 260 | |||
| 261 | .frequency_min = 174000000, | ||
| 262 | .frequency_max = 864000000, | ||
| 263 | .frequency_step = 1000, | ||
| 264 | }, | ||
| 265 | |||
| 266 | .release = tda18218_release, | ||
| 267 | .init = tda18218_init, | ||
| 268 | .sleep = tda18218_sleep, | ||
| 269 | |||
| 270 | .set_params = tda18218_set_params, | ||
| 271 | }; | ||
| 272 | |||
| 273 | struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
| 274 | struct i2c_adapter *i2c, struct tda18218_config *cfg) | ||
| 275 | { | ||
| 276 | struct tda18218_priv *priv = NULL; | ||
| 277 | u8 val; | ||
| 278 | int ret; | ||
| 279 | /* chip default registers values */ | ||
| 280 | static u8 def_regs[] = { | ||
| 281 | 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, | ||
| 282 | 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, | ||
| 283 | 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, | ||
| 284 | 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, | ||
| 285 | 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, | ||
| 286 | 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 | ||
| 287 | }; | ||
| 288 | |||
| 289 | priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); | ||
| 290 | if (priv == NULL) | ||
| 291 | return NULL; | ||
| 292 | |||
| 293 | priv->cfg = cfg; | ||
| 294 | priv->i2c = i2c; | ||
| 295 | fe->tuner_priv = priv; | ||
| 296 | |||
| 297 | if (fe->ops.i2c_gate_ctrl) | ||
| 298 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
| 299 | |||
| 300 | /* check if the tuner is there */ | ||
| 301 | ret = tda18218_rd_reg(priv, R00_ID, &val); | ||
| 302 | dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); | ||
| 303 | if (ret || val != def_regs[R00_ID]) { | ||
| 304 | kfree(priv); | ||
| 305 | return NULL; | ||
| 306 | } | ||
| 307 | |||
| 308 | info("NXP TDA18218HN successfully identified."); | ||
| 309 | |||
| 310 | memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, | ||
| 311 | sizeof(struct dvb_tuner_ops)); | ||
| 312 | memcpy(priv->regs, def_regs, sizeof(def_regs)); | ||
| 313 | |||
| 314 | /* loop-through enabled chip default register values */ | ||
| 315 | if (priv->cfg->loop_through) { | ||
| 316 | priv->regs[R17_PD1] = 0xb0; | ||
| 317 | priv->regs[R18_PD2] = 0x59; | ||
| 318 | } | ||
| 319 | |||
| 320 | /* standby */ | ||
| 321 | ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); | ||
| 322 | if (ret) | ||
| 323 | dbg("%s: failed ret:%d", __func__, ret); | ||
| 324 | |||
| 325 | if (fe->ops.i2c_gate_ctrl) | ||
| 326 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
| 327 | |||
| 328 | return fe; | ||
| 329 | } | ||
| 330 | EXPORT_SYMBOL(tda18218_attach); | ||
| 331 | |||
| 332 | MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); | ||
| 333 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
| 334 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/common/tuners/tda18218.h new file mode 100644 index 00000000000..b4180d18002 --- /dev/null +++ b/drivers/media/common/tuners/tda18218.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * NXP TDA18218HN silicon tuner driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef TDA18218_H | ||
| 22 | #define TDA18218_H | ||
| 23 | |||
| 24 | #include "dvb_frontend.h" | ||
| 25 | |||
| 26 | struct tda18218_config { | ||
| 27 | u8 i2c_address; | ||
| 28 | u8 i2c_wr_max; | ||
| 29 | u8 loop_through:1; | ||
| 30 | }; | ||
| 31 | |||
| 32 | #if defined(CONFIG_MEDIA_TUNER_TDA18218) || \ | ||
| 33 | (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE)) | ||
| 34 | extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
| 35 | struct i2c_adapter *i2c, struct tda18218_config *cfg); | ||
| 36 | #else | ||
| 37 | static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
| 38 | struct i2c_adapter *i2c, struct tda18218_config *cfg) | ||
| 39 | { | ||
| 40 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 41 | return NULL; | ||
| 42 | } | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #endif | ||
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h new file mode 100644 index 00000000000..904e5365c78 --- /dev/null +++ b/drivers/media/common/tuners/tda18218_priv.h | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /* | ||
| 2 | * NXP TDA18218HN silicon tuner driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef TDA18218_PRIV_H | ||
| 22 | #define TDA18218_PRIV_H | ||
| 23 | |||
| 24 | #define LOG_PREFIX "tda18218" | ||
| 25 | |||
| 26 | #undef dbg | ||
| 27 | #define dbg(f, arg...) \ | ||
| 28 | if (debug) \ | ||
| 29 | printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg) | ||
| 30 | #undef err | ||
| 31 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
| 32 | #undef info | ||
| 33 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
| 34 | #undef warn | ||
| 35 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
| 36 | |||
| 37 | #define R00_ID 0x00 /* ID byte */ | ||
| 38 | #define R01_R1 0x01 /* Read byte 1 */ | ||
| 39 | #define R02_R2 0x02 /* Read byte 2 */ | ||
| 40 | #define R03_R3 0x03 /* Read byte 3 */ | ||
| 41 | #define R04_R4 0x04 /* Read byte 4 */ | ||
| 42 | #define R05_R5 0x05 /* Read byte 5 */ | ||
| 43 | #define R06_R6 0x06 /* Read byte 6 */ | ||
| 44 | #define R07_MD1 0x07 /* Main divider byte 1 */ | ||
| 45 | #define R08_PSM1 0x08 /* PSM byte 1 */ | ||
| 46 | #define R09_MD2 0x09 /* Main divider byte 2 */ | ||
| 47 | #define R0A_MD3 0x0a /* Main divider byte 1 */ | ||
| 48 | #define R0B_MD4 0x0b /* Main divider byte 4 */ | ||
| 49 | #define R0C_MD5 0x0c /* Main divider byte 5 */ | ||
| 50 | #define R0D_MD6 0x0d /* Main divider byte 6 */ | ||
| 51 | #define R0E_MD7 0x0e /* Main divider byte 7 */ | ||
| 52 | #define R0F_MD8 0x0f /* Main divider byte 8 */ | ||
| 53 | #define R10_CD1 0x10 /* Call divider byte 1 */ | ||
| 54 | #define R11_CD2 0x11 /* Call divider byte 2 */ | ||
| 55 | #define R12_CD3 0x12 /* Call divider byte 3 */ | ||
| 56 | #define R13_CD4 0x13 /* Call divider byte 4 */ | ||
| 57 | #define R14_CD5 0x14 /* Call divider byte 5 */ | ||
| 58 | #define R15_CD6 0x15 /* Call divider byte 6 */ | ||
| 59 | #define R16_CD7 0x16 /* Call divider byte 7 */ | ||
| 60 | #define R17_PD1 0x17 /* Power-down byte 1 */ | ||
| 61 | #define R18_PD2 0x18 /* Power-down byte 2 */ | ||
| 62 | #define R19_XTOUT 0x19 /* XTOUT byte */ | ||
| 63 | #define R1A_IF1 0x1a /* IF byte 1 */ | ||
| 64 | #define R1B_IF2 0x1b /* IF byte 2 */ | ||
| 65 | #define R1C_AGC2B 0x1c /* AGC2b byte */ | ||
| 66 | #define R1D_PSM2 0x1d /* PSM byte 2 */ | ||
| 67 | #define R1E_PSM3 0x1e /* PSM byte 3 */ | ||
| 68 | #define R1F_PSM4 0x1f /* PSM byte 4 */ | ||
| 69 | #define R20_AGC11 0x20 /* AGC1 byte 1 */ | ||
| 70 | #define R21_AGC12 0x21 /* AGC1 byte 2 */ | ||
| 71 | #define R22_AGC13 0x22 /* AGC1 byte 3 */ | ||
| 72 | #define R23_AGC21 0x23 /* AGC2 byte 1 */ | ||
| 73 | #define R24_AGC22 0x24 /* AGC2 byte 2 */ | ||
| 74 | #define R25_AAGC 0x25 /* Analog AGC byte */ | ||
| 75 | #define R26_RC 0x26 /* RC byte */ | ||
| 76 | #define R27_RSSI 0x27 /* RSSI byte */ | ||
| 77 | #define R28_IRCAL1 0x28 /* IR CAL byte 1 */ | ||
| 78 | #define R29_IRCAL2 0x29 /* IR CAL byte 2 */ | ||
| 79 | #define R2A_IRCAL3 0x2a /* IR CAL byte 3 */ | ||
| 80 | #define R2B_IRCAL4 0x2b /* IR CAL byte 4 */ | ||
| 81 | #define R2C_RFCAL1 0x2c /* RF CAL byte 1 */ | ||
| 82 | #define R2D_RFCAL2 0x2d /* RF CAL byte 2 */ | ||
| 83 | #define R2E_RFCAL3 0x2e /* RF CAL byte 3 */ | ||
| 84 | #define R2F_RFCAL4 0x2f /* RF CAL byte 4 */ | ||
| 85 | #define R30_RFCAL5 0x30 /* RF CAL byte 5 */ | ||
| 86 | #define R31_RFCAL6 0x31 /* RF CAL byte 6 */ | ||
| 87 | #define R32_RFCAL7 0x32 /* RF CAL byte 7 */ | ||
| 88 | #define R33_RFCAL8 0x33 /* RF CAL byte 8 */ | ||
| 89 | #define R34_RFCAL9 0x34 /* RF CAL byte 9 */ | ||
| 90 | #define R35_RFCAL10 0x35 /* RF CAL byte 10 */ | ||
| 91 | #define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */ | ||
| 92 | #define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */ | ||
| 93 | #define R38_MARGIN 0x38 /* Margin byte */ | ||
| 94 | #define R39_FMAX1 0x39 /* Fmax byte 1 */ | ||
| 95 | #define R3A_FMAX2 0x3a /* Fmax byte 2 */ | ||
| 96 | |||
| 97 | #define TDA18218_NUM_REGS 59 | ||
| 98 | |||
| 99 | struct tda18218_priv { | ||
| 100 | struct tda18218_config *cfg; | ||
| 101 | struct i2c_adapter *i2c; | ||
| 102 | |||
| 103 | u8 regs[TDA18218_NUM_REGS]; | ||
| 104 | }; | ||
| 105 | |||
| 106 | #endif | ||
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c new file mode 100644 index 00000000000..aae40e52af5 --- /dev/null +++ b/drivers/media/common/tuners/tda18271-common.c | |||
| @@ -0,0 +1,685 @@ | |||
| 1 | /* | ||
| 2 | tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
| 3 | |||
| 4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "tda18271-priv.h" | ||
| 22 | |||
| 23 | static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
| 24 | { | ||
| 25 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 26 | enum tda18271_i2c_gate gate; | ||
| 27 | int ret = 0; | ||
| 28 | |||
| 29 | switch (priv->gate) { | ||
| 30 | case TDA18271_GATE_DIGITAL: | ||
| 31 | case TDA18271_GATE_ANALOG: | ||
| 32 | gate = priv->gate; | ||
| 33 | break; | ||
| 34 | case TDA18271_GATE_AUTO: | ||
| 35 | default: | ||
| 36 | switch (priv->mode) { | ||
| 37 | case TDA18271_DIGITAL: | ||
| 38 | gate = TDA18271_GATE_DIGITAL; | ||
| 39 | break; | ||
| 40 | case TDA18271_ANALOG: | ||
| 41 | default: | ||
| 42 | gate = TDA18271_GATE_ANALOG; | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | switch (gate) { | ||
| 48 | case TDA18271_GATE_ANALOG: | ||
| 49 | if (fe->ops.analog_ops.i2c_gate_ctrl) | ||
| 50 | ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); | ||
| 51 | break; | ||
| 52 | case TDA18271_GATE_DIGITAL: | ||
| 53 | if (fe->ops.i2c_gate_ctrl) | ||
| 54 | ret = fe->ops.i2c_gate_ctrl(fe, enable); | ||
| 55 | break; | ||
| 56 | default: | ||
| 57 | ret = -EINVAL; | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | |||
| 61 | return ret; | ||
| 62 | }; | ||
| 63 | |||
| 64 | /*---------------------------------------------------------------------*/ | ||
| 65 | |||
| 66 | static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) | ||
| 67 | { | ||
| 68 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 69 | unsigned char *regs = priv->tda18271_regs; | ||
| 70 | |||
| 71 | tda_reg("=== TDA18271 REG DUMP ===\n"); | ||
| 72 | tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); | ||
| 73 | tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); | ||
| 74 | tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); | ||
| 75 | tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); | ||
| 76 | tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); | ||
| 77 | tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); | ||
| 78 | tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); | ||
| 79 | tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); | ||
| 80 | tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); | ||
| 81 | tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); | ||
| 82 | tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); | ||
| 83 | tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); | ||
| 84 | tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); | ||
| 85 | tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); | ||
| 86 | tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); | ||
| 87 | tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); | ||
| 88 | |||
| 89 | /* only dump extended regs if DBG_ADV is set */ | ||
| 90 | if (!(tda18271_debug & DBG_ADV)) | ||
| 91 | return; | ||
| 92 | |||
| 93 | /* W indicates write-only registers. | ||
| 94 | * Register dump for write-only registers shows last value written. */ | ||
| 95 | |||
| 96 | tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); | ||
| 97 | tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); | ||
| 98 | tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); | ||
| 99 | tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); | ||
| 100 | tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); | ||
| 101 | tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); | ||
| 102 | tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); | ||
| 103 | tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); | ||
| 104 | tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); | ||
| 105 | tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); | ||
| 106 | tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); | ||
| 107 | tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); | ||
| 108 | tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); | ||
| 109 | tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); | ||
| 110 | tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); | ||
| 111 | tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); | ||
| 112 | tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); | ||
| 113 | tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); | ||
| 114 | tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); | ||
| 115 | tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); | ||
| 116 | tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); | ||
| 117 | tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); | ||
| 118 | tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); | ||
| 119 | } | ||
| 120 | |||
| 121 | int tda18271_read_regs(struct dvb_frontend *fe) | ||
| 122 | { | ||
| 123 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 124 | unsigned char *regs = priv->tda18271_regs; | ||
| 125 | unsigned char buf = 0x00; | ||
| 126 | int ret; | ||
| 127 | struct i2c_msg msg[] = { | ||
| 128 | { .addr = priv->i2c_props.addr, .flags = 0, | ||
| 129 | .buf = &buf, .len = 1 }, | ||
| 130 | { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, | ||
| 131 | .buf = regs, .len = 16 } | ||
| 132 | }; | ||
| 133 | |||
| 134 | tda18271_i2c_gate_ctrl(fe, 1); | ||
| 135 | |||
| 136 | /* read all registers */ | ||
| 137 | ret = i2c_transfer(priv->i2c_props.adap, msg, 2); | ||
| 138 | |||
| 139 | tda18271_i2c_gate_ctrl(fe, 0); | ||
| 140 | |||
| 141 | if (ret != 2) | ||
| 142 | tda_err("ERROR: i2c_transfer returned: %d\n", ret); | ||
| 143 | |||
| 144 | if (tda18271_debug & DBG_REG) | ||
| 145 | tda18271_dump_regs(fe, 0); | ||
| 146 | |||
| 147 | return (ret == 2 ? 0 : ret); | ||
| 148 | } | ||
| 149 | |||
| 150 | int tda18271_read_extended(struct dvb_frontend *fe) | ||
| 151 | { | ||
| 152 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 153 | unsigned char *regs = priv->tda18271_regs; | ||
| 154 | unsigned char regdump[TDA18271_NUM_REGS]; | ||
| 155 | unsigned char buf = 0x00; | ||
| 156 | int ret, i; | ||
| 157 | struct i2c_msg msg[] = { | ||
| 158 | { .addr = priv->i2c_props.addr, .flags = 0, | ||
| 159 | .buf = &buf, .len = 1 }, | ||
| 160 | { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, | ||
| 161 | .buf = regdump, .len = TDA18271_NUM_REGS } | ||
| 162 | }; | ||
| 163 | |||
| 164 | tda18271_i2c_gate_ctrl(fe, 1); | ||
| 165 | |||
| 166 | /* read all registers */ | ||
| 167 | ret = i2c_transfer(priv->i2c_props.adap, msg, 2); | ||
| 168 | |||
| 169 | tda18271_i2c_gate_ctrl(fe, 0); | ||
| 170 | |||
| 171 | if (ret != 2) | ||
| 172 | tda_err("ERROR: i2c_transfer returned: %d\n", ret); | ||
| 173 | |||
| 174 | for (i = 0; i < TDA18271_NUM_REGS; i++) { | ||
| 175 | /* don't update write-only registers */ | ||
| 176 | if ((i != R_EB9) && | ||
| 177 | (i != R_EB16) && | ||
| 178 | (i != R_EB17) && | ||
| 179 | (i != R_EB19) && | ||
| 180 | (i != R_EB20)) | ||
| 181 | regs[i] = regdump[i]; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (tda18271_debug & DBG_REG) | ||
| 185 | tda18271_dump_regs(fe, 1); | ||
| 186 | |||
| 187 | return (ret == 2 ? 0 : ret); | ||
| 188 | } | ||
| 189 | |||
| 190 | int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) | ||
| 191 | { | ||
| 192 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 193 | unsigned char *regs = priv->tda18271_regs; | ||
| 194 | unsigned char buf[TDA18271_NUM_REGS + 1]; | ||
| 195 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0, | ||
| 196 | .buf = buf }; | ||
| 197 | int i, ret = 1, max; | ||
| 198 | |||
| 199 | BUG_ON((len == 0) || (idx + len > sizeof(buf))); | ||
| 200 | |||
| 201 | |||
| 202 | switch (priv->small_i2c) { | ||
| 203 | case TDA18271_03_BYTE_CHUNK_INIT: | ||
| 204 | max = 3; | ||
| 205 | break; | ||
| 206 | case TDA18271_08_BYTE_CHUNK_INIT: | ||
| 207 | max = 8; | ||
| 208 | break; | ||
| 209 | case TDA18271_16_BYTE_CHUNK_INIT: | ||
| 210 | max = 16; | ||
| 211 | break; | ||
| 212 | case TDA18271_39_BYTE_CHUNK_INIT: | ||
| 213 | default: | ||
| 214 | max = 39; | ||
| 215 | } | ||
| 216 | |||
| 217 | tda18271_i2c_gate_ctrl(fe, 1); | ||
| 218 | while (len) { | ||
| 219 | if (max > len) | ||
| 220 | max = len; | ||
| 221 | |||
| 222 | buf[0] = idx; | ||
| 223 | for (i = 1; i <= max; i++) | ||
| 224 | buf[i] = regs[idx - 1 + i]; | ||
| 225 | |||
| 226 | msg.len = max + 1; | ||
| 227 | |||
| 228 | /* write registers */ | ||
| 229 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
| 230 | if (ret != 1) | ||
| 231 | break; | ||
| 232 | |||
| 233 | idx += max; | ||
| 234 | len -= max; | ||
| 235 | } | ||
| 236 | tda18271_i2c_gate_ctrl(fe, 0); | ||
| 237 | |||
| 238 | if (ret != 1) | ||
| 239 | tda_err("ERROR: idx = 0x%x, len = %d, " | ||
| 240 | "i2c_transfer returned: %d\n", idx, max, ret); | ||
| 241 | |||
| 242 | return (ret == 1 ? 0 : ret); | ||
| 243 | } | ||
| 244 | |||
| 245 | /*---------------------------------------------------------------------*/ | ||
| 246 | |||
| 247 | int tda18271_charge_pump_source(struct dvb_frontend *fe, | ||
| 248 | enum tda18271_pll pll, int force) | ||
| 249 | { | ||
| 250 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 251 | unsigned char *regs = priv->tda18271_regs; | ||
| 252 | |||
| 253 | int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4; | ||
| 254 | |||
| 255 | regs[r_cp] &= ~0x20; | ||
| 256 | regs[r_cp] |= ((force & 1) << 5); | ||
| 257 | |||
| 258 | return tda18271_write_regs(fe, r_cp, 1); | ||
| 259 | } | ||
| 260 | |||
| 261 | int tda18271_init_regs(struct dvb_frontend *fe) | ||
| 262 | { | ||
| 263 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 264 | unsigned char *regs = priv->tda18271_regs; | ||
| 265 | |||
| 266 | tda_dbg("initializing registers for device @ %d-%04x\n", | ||
| 267 | i2c_adapter_id(priv->i2c_props.adap), | ||
| 268 | priv->i2c_props.addr); | ||
| 269 | |||
| 270 | /* initialize registers */ | ||
| 271 | switch (priv->id) { | ||
| 272 | case TDA18271HDC1: | ||
| 273 | regs[R_ID] = 0x83; | ||
| 274 | break; | ||
| 275 | case TDA18271HDC2: | ||
| 276 | regs[R_ID] = 0x84; | ||
| 277 | break; | ||
| 278 | }; | ||
| 279 | |||
| 280 | regs[R_TM] = 0x08; | ||
| 281 | regs[R_PL] = 0x80; | ||
| 282 | regs[R_EP1] = 0xc6; | ||
| 283 | regs[R_EP2] = 0xdf; | ||
| 284 | regs[R_EP3] = 0x16; | ||
| 285 | regs[R_EP4] = 0x60; | ||
| 286 | regs[R_EP5] = 0x80; | ||
| 287 | regs[R_CPD] = 0x80; | ||
| 288 | regs[R_CD1] = 0x00; | ||
| 289 | regs[R_CD2] = 0x00; | ||
| 290 | regs[R_CD3] = 0x00; | ||
| 291 | regs[R_MPD] = 0x00; | ||
| 292 | regs[R_MD1] = 0x00; | ||
| 293 | regs[R_MD2] = 0x00; | ||
| 294 | regs[R_MD3] = 0x00; | ||
| 295 | |||
| 296 | switch (priv->id) { | ||
| 297 | case TDA18271HDC1: | ||
| 298 | regs[R_EB1] = 0xff; | ||
| 299 | break; | ||
| 300 | case TDA18271HDC2: | ||
| 301 | regs[R_EB1] = 0xfc; | ||
| 302 | break; | ||
| 303 | }; | ||
| 304 | |||
| 305 | regs[R_EB2] = 0x01; | ||
| 306 | regs[R_EB3] = 0x84; | ||
| 307 | regs[R_EB4] = 0x41; | ||
| 308 | regs[R_EB5] = 0x01; | ||
| 309 | regs[R_EB6] = 0x84; | ||
| 310 | regs[R_EB7] = 0x40; | ||
| 311 | regs[R_EB8] = 0x07; | ||
| 312 | regs[R_EB9] = 0x00; | ||
| 313 | regs[R_EB10] = 0x00; | ||
| 314 | regs[R_EB11] = 0x96; | ||
| 315 | |||
| 316 | switch (priv->id) { | ||
| 317 | case TDA18271HDC1: | ||
| 318 | regs[R_EB12] = 0x0f; | ||
| 319 | break; | ||
| 320 | case TDA18271HDC2: | ||
| 321 | regs[R_EB12] = 0x33; | ||
| 322 | break; | ||
| 323 | }; | ||
| 324 | |||
| 325 | regs[R_EB13] = 0xc1; | ||
| 326 | regs[R_EB14] = 0x00; | ||
| 327 | regs[R_EB15] = 0x8f; | ||
| 328 | regs[R_EB16] = 0x00; | ||
| 329 | regs[R_EB17] = 0x00; | ||
| 330 | |||
| 331 | switch (priv->id) { | ||
| 332 | case TDA18271HDC1: | ||
| 333 | regs[R_EB18] = 0x00; | ||
| 334 | break; | ||
| 335 | case TDA18271HDC2: | ||
| 336 | regs[R_EB18] = 0x8c; | ||
| 337 | break; | ||
| 338 | }; | ||
| 339 | |||
| 340 | regs[R_EB19] = 0x00; | ||
| 341 | regs[R_EB20] = 0x20; | ||
| 342 | |||
| 343 | switch (priv->id) { | ||
| 344 | case TDA18271HDC1: | ||
| 345 | regs[R_EB21] = 0x33; | ||
| 346 | break; | ||
| 347 | case TDA18271HDC2: | ||
| 348 | regs[R_EB21] = 0xb3; | ||
| 349 | break; | ||
| 350 | }; | ||
| 351 | |||
| 352 | regs[R_EB22] = 0x48; | ||
| 353 | regs[R_EB23] = 0xb0; | ||
| 354 | |||
| 355 | tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); | ||
| 356 | |||
| 357 | /* setup agc1 gain */ | ||
| 358 | regs[R_EB17] = 0x00; | ||
| 359 | tda18271_write_regs(fe, R_EB17, 1); | ||
| 360 | regs[R_EB17] = 0x03; | ||
| 361 | tda18271_write_regs(fe, R_EB17, 1); | ||
| 362 | regs[R_EB17] = 0x43; | ||
| 363 | tda18271_write_regs(fe, R_EB17, 1); | ||
| 364 | regs[R_EB17] = 0x4c; | ||
| 365 | tda18271_write_regs(fe, R_EB17, 1); | ||
| 366 | |||
| 367 | /* setup agc2 gain */ | ||
| 368 | if ((priv->id) == TDA18271HDC1) { | ||
| 369 | regs[R_EB20] = 0xa0; | ||
| 370 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 371 | regs[R_EB20] = 0xa7; | ||
| 372 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 373 | regs[R_EB20] = 0xe7; | ||
| 374 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 375 | regs[R_EB20] = 0xec; | ||
| 376 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 377 | } | ||
| 378 | |||
| 379 | /* image rejection calibration */ | ||
| 380 | |||
| 381 | /* low-band */ | ||
| 382 | regs[R_EP3] = 0x1f; | ||
| 383 | regs[R_EP4] = 0x66; | ||
| 384 | regs[R_EP5] = 0x81; | ||
| 385 | regs[R_CPD] = 0xcc; | ||
| 386 | regs[R_CD1] = 0x6c; | ||
| 387 | regs[R_CD2] = 0x00; | ||
| 388 | regs[R_CD3] = 0x00; | ||
| 389 | regs[R_MPD] = 0xcd; | ||
| 390 | regs[R_MD1] = 0x77; | ||
| 391 | regs[R_MD2] = 0x08; | ||
| 392 | regs[R_MD3] = 0x00; | ||
| 393 | |||
| 394 | tda18271_write_regs(fe, R_EP3, 11); | ||
| 395 | |||
| 396 | if ((priv->id) == TDA18271HDC2) { | ||
| 397 | /* main pll cp source on */ | ||
| 398 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); | ||
| 399 | msleep(1); | ||
| 400 | |||
| 401 | /* main pll cp source off */ | ||
| 402 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); | ||
| 403 | } | ||
| 404 | |||
| 405 | msleep(5); /* pll locking */ | ||
| 406 | |||
| 407 | /* launch detector */ | ||
| 408 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 409 | msleep(5); /* wanted low measurement */ | ||
| 410 | |||
| 411 | regs[R_EP5] = 0x85; | ||
| 412 | regs[R_CPD] = 0xcb; | ||
| 413 | regs[R_CD1] = 0x66; | ||
| 414 | regs[R_CD2] = 0x70; | ||
| 415 | |||
| 416 | tda18271_write_regs(fe, R_EP3, 7); | ||
| 417 | msleep(5); /* pll locking */ | ||
| 418 | |||
| 419 | /* launch optimization algorithm */ | ||
| 420 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 421 | msleep(30); /* image low optimization completion */ | ||
| 422 | |||
| 423 | /* mid-band */ | ||
| 424 | regs[R_EP5] = 0x82; | ||
| 425 | regs[R_CPD] = 0xa8; | ||
| 426 | regs[R_CD2] = 0x00; | ||
| 427 | regs[R_MPD] = 0xa9; | ||
| 428 | regs[R_MD1] = 0x73; | ||
| 429 | regs[R_MD2] = 0x1a; | ||
| 430 | |||
| 431 | tda18271_write_regs(fe, R_EP3, 11); | ||
| 432 | msleep(5); /* pll locking */ | ||
| 433 | |||
| 434 | /* launch detector */ | ||
| 435 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 436 | msleep(5); /* wanted mid measurement */ | ||
| 437 | |||
| 438 | regs[R_EP5] = 0x86; | ||
| 439 | regs[R_CPD] = 0xa8; | ||
| 440 | regs[R_CD1] = 0x66; | ||
| 441 | regs[R_CD2] = 0xa0; | ||
| 442 | |||
| 443 | tda18271_write_regs(fe, R_EP3, 7); | ||
| 444 | msleep(5); /* pll locking */ | ||
| 445 | |||
| 446 | /* launch optimization algorithm */ | ||
| 447 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 448 | msleep(30); /* image mid optimization completion */ | ||
| 449 | |||
| 450 | /* high-band */ | ||
| 451 | regs[R_EP5] = 0x83; | ||
| 452 | regs[R_CPD] = 0x98; | ||
| 453 | regs[R_CD1] = 0x65; | ||
| 454 | regs[R_CD2] = 0x00; | ||
| 455 | regs[R_MPD] = 0x99; | ||
| 456 | regs[R_MD1] = 0x71; | ||
| 457 | regs[R_MD2] = 0xcd; | ||
| 458 | |||
| 459 | tda18271_write_regs(fe, R_EP3, 11); | ||
| 460 | msleep(5); /* pll locking */ | ||
| 461 | |||
| 462 | /* launch detector */ | ||
| 463 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 464 | msleep(5); /* wanted high measurement */ | ||
| 465 | |||
| 466 | regs[R_EP5] = 0x87; | ||
| 467 | regs[R_CD1] = 0x65; | ||
| 468 | regs[R_CD2] = 0x50; | ||
| 469 | |||
| 470 | tda18271_write_regs(fe, R_EP3, 7); | ||
| 471 | msleep(5); /* pll locking */ | ||
| 472 | |||
| 473 | /* launch optimization algorithm */ | ||
| 474 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 475 | msleep(30); /* image high optimization completion */ | ||
| 476 | |||
| 477 | /* return to normal mode */ | ||
| 478 | regs[R_EP4] = 0x64; | ||
| 479 | tda18271_write_regs(fe, R_EP4, 1); | ||
| 480 | |||
| 481 | /* synchronize */ | ||
| 482 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 483 | |||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | /*---------------------------------------------------------------------*/ | ||
| 488 | |||
| 489 | /* | ||
| 490 | * Standby modes, EP3 [7:5] | ||
| 491 | * | ||
| 492 | * | SM || SM_LT || SM_XT || mode description | ||
| 493 | * |=====\\=======\\=======\\=================================== | ||
| 494 | * | 0 || 0 || 0 || normal mode | ||
| 495 | * |-----||-------||-------||----------------------------------- | ||
| 496 | * | || || || standby mode w/ slave tuner output | ||
| 497 | * | 1 || 0 || 0 || & loop thru & xtal oscillator on | ||
| 498 | * |-----||-------||-------||----------------------------------- | ||
| 499 | * | 1 || 1 || 0 || standby mode w/ xtal oscillator on | ||
| 500 | * |-----||-------||-------||----------------------------------- | ||
| 501 | * | 1 || 1 || 1 || power off | ||
| 502 | * | ||
| 503 | */ | ||
| 504 | |||
| 505 | int tda18271_set_standby_mode(struct dvb_frontend *fe, | ||
| 506 | int sm, int sm_lt, int sm_xt) | ||
| 507 | { | ||
| 508 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 509 | unsigned char *regs = priv->tda18271_regs; | ||
| 510 | |||
| 511 | if (tda18271_debug & DBG_ADV) | ||
| 512 | tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); | ||
| 513 | |||
| 514 | regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ | ||
| 515 | regs[R_EP3] |= (sm ? (1 << 7) : 0) | | ||
| 516 | (sm_lt ? (1 << 6) : 0) | | ||
| 517 | (sm_xt ? (1 << 5) : 0); | ||
| 518 | |||
| 519 | return tda18271_write_regs(fe, R_EP3, 1); | ||
| 520 | } | ||
| 521 | |||
| 522 | /*---------------------------------------------------------------------*/ | ||
| 523 | |||
| 524 | int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) | ||
| 525 | { | ||
| 526 | /* sets main post divider & divider bytes, but does not write them */ | ||
| 527 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 528 | unsigned char *regs = priv->tda18271_regs; | ||
| 529 | u8 d, pd; | ||
| 530 | u32 div; | ||
| 531 | |||
| 532 | int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); | ||
| 533 | if (tda_fail(ret)) | ||
| 534 | goto fail; | ||
| 535 | |||
| 536 | regs[R_MPD] = (0x7f & pd); | ||
| 537 | |||
| 538 | div = ((d * (freq / 1000)) << 7) / 125; | ||
| 539 | |||
| 540 | regs[R_MD1] = 0x7f & (div >> 16); | ||
| 541 | regs[R_MD2] = 0xff & (div >> 8); | ||
| 542 | regs[R_MD3] = 0xff & div; | ||
| 543 | fail: | ||
| 544 | return ret; | ||
| 545 | } | ||
| 546 | |||
| 547 | int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) | ||
| 548 | { | ||
| 549 | /* sets cal post divider & divider bytes, but does not write them */ | ||
| 550 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 551 | unsigned char *regs = priv->tda18271_regs; | ||
| 552 | u8 d, pd; | ||
| 553 | u32 div; | ||
| 554 | |||
| 555 | int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); | ||
| 556 | if (tda_fail(ret)) | ||
| 557 | goto fail; | ||
| 558 | |||
| 559 | regs[R_CPD] = pd; | ||
| 560 | |||
| 561 | div = ((d * (freq / 1000)) << 7) / 125; | ||
| 562 | |||
| 563 | regs[R_CD1] = 0x7f & (div >> 16); | ||
| 564 | regs[R_CD2] = 0xff & (div >> 8); | ||
| 565 | regs[R_CD3] = 0xff & div; | ||
| 566 | fail: | ||
| 567 | return ret; | ||
| 568 | } | ||
| 569 | |||
| 570 | /*---------------------------------------------------------------------*/ | ||
| 571 | |||
| 572 | int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) | ||
| 573 | { | ||
| 574 | /* sets bp filter bits, but does not write them */ | ||
| 575 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 576 | unsigned char *regs = priv->tda18271_regs; | ||
| 577 | u8 val; | ||
| 578 | |||
| 579 | int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); | ||
| 580 | if (tda_fail(ret)) | ||
| 581 | goto fail; | ||
| 582 | |||
| 583 | regs[R_EP1] &= ~0x07; /* clear bp filter bits */ | ||
| 584 | regs[R_EP1] |= (0x07 & val); | ||
| 585 | fail: | ||
| 586 | return ret; | ||
| 587 | } | ||
| 588 | |||
| 589 | int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) | ||
| 590 | { | ||
| 591 | /* sets K & M bits, but does not write them */ | ||
| 592 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 593 | unsigned char *regs = priv->tda18271_regs; | ||
| 594 | u8 val; | ||
| 595 | |||
| 596 | int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); | ||
| 597 | if (tda_fail(ret)) | ||
| 598 | goto fail; | ||
| 599 | |||
| 600 | regs[R_EB13] &= ~0x7c; /* clear k & m bits */ | ||
| 601 | regs[R_EB13] |= (0x7c & val); | ||
| 602 | fail: | ||
| 603 | return ret; | ||
| 604 | } | ||
| 605 | |||
| 606 | int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) | ||
| 607 | { | ||
| 608 | /* sets rf band bits, but does not write them */ | ||
| 609 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 610 | unsigned char *regs = priv->tda18271_regs; | ||
| 611 | u8 val; | ||
| 612 | |||
| 613 | int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); | ||
| 614 | if (tda_fail(ret)) | ||
| 615 | goto fail; | ||
| 616 | |||
| 617 | regs[R_EP2] &= ~0xe0; /* clear rf band bits */ | ||
| 618 | regs[R_EP2] |= (0xe0 & (val << 5)); | ||
| 619 | fail: | ||
| 620 | return ret; | ||
| 621 | } | ||
| 622 | |||
| 623 | int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) | ||
| 624 | { | ||
| 625 | /* sets gain taper bits, but does not write them */ | ||
| 626 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 627 | unsigned char *regs = priv->tda18271_regs; | ||
| 628 | u8 val; | ||
| 629 | |||
| 630 | int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); | ||
| 631 | if (tda_fail(ret)) | ||
| 632 | goto fail; | ||
| 633 | |||
| 634 | regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ | ||
| 635 | regs[R_EP2] |= (0x1f & val); | ||
| 636 | fail: | ||
| 637 | return ret; | ||
| 638 | } | ||
| 639 | |||
| 640 | int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) | ||
| 641 | { | ||
| 642 | /* sets IR Meas bits, but does not write them */ | ||
| 643 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 644 | unsigned char *regs = priv->tda18271_regs; | ||
| 645 | u8 val; | ||
| 646 | |||
| 647 | int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); | ||
| 648 | if (tda_fail(ret)) | ||
| 649 | goto fail; | ||
| 650 | |||
| 651 | regs[R_EP5] &= ~0x07; | ||
| 652 | regs[R_EP5] |= (0x07 & val); | ||
| 653 | fail: | ||
| 654 | return ret; | ||
| 655 | } | ||
| 656 | |||
| 657 | int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) | ||
| 658 | { | ||
| 659 | /* sets rf cal byte (RFC_Cprog), but does not write it */ | ||
| 660 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 661 | unsigned char *regs = priv->tda18271_regs; | ||
| 662 | u8 val; | ||
| 663 | |||
| 664 | int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); | ||
| 665 | /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range | ||
| 666 | * for frequencies above 61.1 MHz. In these cases, the internal RF | ||
| 667 | * tracking filters calibration mechanism is used. | ||
| 668 | * | ||
| 669 | * There is no need to warn the user about this. | ||
| 670 | */ | ||
| 671 | if (ret < 0) | ||
| 672 | goto fail; | ||
| 673 | |||
| 674 | regs[R_EB14] = val; | ||
| 675 | fail: | ||
| 676 | return ret; | ||
| 677 | } | ||
| 678 | |||
| 679 | /* | ||
| 680 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 681 | * --------------------------------------------------------------------------- | ||
| 682 | * Local variables: | ||
| 683 | * c-basic-offset: 8 | ||
| 684 | * End: | ||
| 685 | */ | ||
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c new file mode 100644 index 00000000000..57022e88e33 --- /dev/null +++ b/drivers/media/common/tuners/tda18271-fe.c | |||
| @@ -0,0 +1,1346 @@ | |||
| 1 | /* | ||
| 2 | tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
| 3 | |||
| 4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/videodev2.h> | ||
| 23 | #include "tda18271-priv.h" | ||
| 24 | |||
| 25 | int tda18271_debug; | ||
| 26 | module_param_named(debug, tda18271_debug, int, 0644); | ||
| 27 | MODULE_PARM_DESC(debug, "set debug level " | ||
| 28 | "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); | ||
| 29 | |||
| 30 | static int tda18271_cal_on_startup = -1; | ||
| 31 | module_param_named(cal, tda18271_cal_on_startup, int, 0644); | ||
| 32 | MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); | ||
| 33 | |||
| 34 | static DEFINE_MUTEX(tda18271_list_mutex); | ||
| 35 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 36 | |||
| 37 | /*---------------------------------------------------------------------*/ | ||
| 38 | |||
| 39 | static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) | ||
| 40 | { | ||
| 41 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 42 | |||
| 43 | int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, | ||
| 44 | priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, | ||
| 45 | priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); | ||
| 46 | |||
| 47 | if (tda_fail(ret)) | ||
| 48 | goto fail; | ||
| 49 | |||
| 50 | tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", | ||
| 51 | standby ? "standby" : "active", | ||
| 52 | priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", | ||
| 53 | priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); | ||
| 54 | fail: | ||
| 55 | return ret; | ||
| 56 | } | ||
| 57 | |||
| 58 | /*---------------------------------------------------------------------*/ | ||
| 59 | |||
| 60 | static inline int charge_pump_source(struct dvb_frontend *fe, int force) | ||
| 61 | { | ||
| 62 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 63 | return tda18271_charge_pump_source(fe, | ||
| 64 | (priv->role == TDA18271_SLAVE) ? | ||
| 65 | TDA18271_CAL_PLL : | ||
| 66 | TDA18271_MAIN_PLL, force); | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline void tda18271_set_if_notch(struct dvb_frontend *fe) | ||
| 70 | { | ||
| 71 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 72 | unsigned char *regs = priv->tda18271_regs; | ||
| 73 | |||
| 74 | switch (priv->mode) { | ||
| 75 | case TDA18271_ANALOG: | ||
| 76 | regs[R_MPD] &= ~0x80; /* IF notch = 0 */ | ||
| 77 | break; | ||
| 78 | case TDA18271_DIGITAL: | ||
| 79 | regs[R_MPD] |= 0x80; /* IF notch = 1 */ | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | static int tda18271_channel_configuration(struct dvb_frontend *fe, | ||
| 85 | struct tda18271_std_map_item *map, | ||
| 86 | u32 freq, u32 bw) | ||
| 87 | { | ||
| 88 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 89 | unsigned char *regs = priv->tda18271_regs; | ||
| 90 | int ret; | ||
| 91 | u32 N; | ||
| 92 | |||
| 93 | /* update TV broadcast parameters */ | ||
| 94 | |||
| 95 | /* set standard */ | ||
| 96 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
| 97 | regs[R_EP3] |= (map->agc_mode << 3) | map->std; | ||
| 98 | |||
| 99 | if (priv->id == TDA18271HDC2) { | ||
| 100 | /* set rfagc to high speed mode */ | ||
| 101 | regs[R_EP3] &= ~0x04; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* set cal mode to normal */ | ||
| 105 | regs[R_EP4] &= ~0x03; | ||
| 106 | |||
| 107 | /* update IF output level */ | ||
| 108 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
| 109 | regs[R_EP4] |= (map->if_lvl << 2); | ||
| 110 | |||
| 111 | /* update FM_RFn */ | ||
| 112 | regs[R_EP4] &= ~0x80; | ||
| 113 | regs[R_EP4] |= map->fm_rfn << 7; | ||
| 114 | |||
| 115 | /* update rf top / if top */ | ||
| 116 | regs[R_EB22] = 0x00; | ||
| 117 | regs[R_EB22] |= map->rfagc_top; | ||
| 118 | ret = tda18271_write_regs(fe, R_EB22, 1); | ||
| 119 | if (tda_fail(ret)) | ||
| 120 | goto fail; | ||
| 121 | |||
| 122 | /* --------------------------------------------------------------- */ | ||
| 123 | |||
| 124 | /* disable Power Level Indicator */ | ||
| 125 | regs[R_EP1] |= 0x40; | ||
| 126 | |||
| 127 | /* make sure thermometer is off */ | ||
| 128 | regs[R_TM] &= ~0x10; | ||
| 129 | |||
| 130 | /* frequency dependent parameters */ | ||
| 131 | |||
| 132 | tda18271_calc_ir_measure(fe, &freq); | ||
| 133 | |||
| 134 | tda18271_calc_bp_filter(fe, &freq); | ||
| 135 | |||
| 136 | tda18271_calc_rf_band(fe, &freq); | ||
| 137 | |||
| 138 | tda18271_calc_gain_taper(fe, &freq); | ||
| 139 | |||
| 140 | /* --------------------------------------------------------------- */ | ||
| 141 | |||
| 142 | /* dual tuner and agc1 extra configuration */ | ||
| 143 | |||
| 144 | switch (priv->role) { | ||
| 145 | case TDA18271_MASTER: | ||
| 146 | regs[R_EB1] |= 0x04; /* main vco */ | ||
| 147 | break; | ||
| 148 | case TDA18271_SLAVE: | ||
| 149 | regs[R_EB1] &= ~0x04; /* cal vco */ | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* agc1 always active */ | ||
| 154 | regs[R_EB1] &= ~0x02; | ||
| 155 | |||
| 156 | /* agc1 has priority on agc2 */ | ||
| 157 | regs[R_EB1] &= ~0x01; | ||
| 158 | |||
| 159 | ret = tda18271_write_regs(fe, R_EB1, 1); | ||
| 160 | if (tda_fail(ret)) | ||
| 161 | goto fail; | ||
| 162 | |||
| 163 | /* --------------------------------------------------------------- */ | ||
| 164 | |||
| 165 | N = map->if_freq * 1000 + freq; | ||
| 166 | |||
| 167 | switch (priv->role) { | ||
| 168 | case TDA18271_MASTER: | ||
| 169 | tda18271_calc_main_pll(fe, N); | ||
| 170 | tda18271_set_if_notch(fe); | ||
| 171 | tda18271_write_regs(fe, R_MPD, 4); | ||
| 172 | break; | ||
| 173 | case TDA18271_SLAVE: | ||
| 174 | tda18271_calc_cal_pll(fe, N); | ||
| 175 | tda18271_write_regs(fe, R_CPD, 4); | ||
| 176 | |||
| 177 | regs[R_MPD] = regs[R_CPD] & 0x7f; | ||
| 178 | tda18271_set_if_notch(fe); | ||
| 179 | tda18271_write_regs(fe, R_MPD, 1); | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | |||
| 183 | ret = tda18271_write_regs(fe, R_TM, 7); | ||
| 184 | if (tda_fail(ret)) | ||
| 185 | goto fail; | ||
| 186 | |||
| 187 | /* force charge pump source */ | ||
| 188 | charge_pump_source(fe, 1); | ||
| 189 | |||
| 190 | msleep(1); | ||
| 191 | |||
| 192 | /* return pll to normal operation */ | ||
| 193 | charge_pump_source(fe, 0); | ||
| 194 | |||
| 195 | msleep(20); | ||
| 196 | |||
| 197 | if (priv->id == TDA18271HDC2) { | ||
| 198 | /* set rfagc to normal speed mode */ | ||
| 199 | if (map->fm_rfn) | ||
| 200 | regs[R_EP3] &= ~0x04; | ||
| 201 | else | ||
| 202 | regs[R_EP3] |= 0x04; | ||
| 203 | ret = tda18271_write_regs(fe, R_EP3, 1); | ||
| 204 | } | ||
| 205 | fail: | ||
| 206 | return ret; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int tda18271_read_thermometer(struct dvb_frontend *fe) | ||
| 210 | { | ||
| 211 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 212 | unsigned char *regs = priv->tda18271_regs; | ||
| 213 | int tm; | ||
| 214 | |||
| 215 | /* switch thermometer on */ | ||
| 216 | regs[R_TM] |= 0x10; | ||
| 217 | tda18271_write_regs(fe, R_TM, 1); | ||
| 218 | |||
| 219 | /* read thermometer info */ | ||
| 220 | tda18271_read_regs(fe); | ||
| 221 | |||
| 222 | if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || | ||
| 223 | (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { | ||
| 224 | |||
| 225 | if ((regs[R_TM] & 0x20) == 0x20) | ||
| 226 | regs[R_TM] &= ~0x20; | ||
| 227 | else | ||
| 228 | regs[R_TM] |= 0x20; | ||
| 229 | |||
| 230 | tda18271_write_regs(fe, R_TM, 1); | ||
| 231 | |||
| 232 | msleep(10); /* temperature sensing */ | ||
| 233 | |||
| 234 | /* read thermometer info */ | ||
| 235 | tda18271_read_regs(fe); | ||
| 236 | } | ||
| 237 | |||
| 238 | tm = tda18271_lookup_thermometer(fe); | ||
| 239 | |||
| 240 | /* switch thermometer off */ | ||
| 241 | regs[R_TM] &= ~0x10; | ||
| 242 | tda18271_write_regs(fe, R_TM, 1); | ||
| 243 | |||
| 244 | /* set CAL mode to normal */ | ||
| 245 | regs[R_EP4] &= ~0x03; | ||
| 246 | tda18271_write_regs(fe, R_EP4, 1); | ||
| 247 | |||
| 248 | return tm; | ||
| 249 | } | ||
| 250 | |||
| 251 | /* ------------------------------------------------------------------ */ | ||
| 252 | |||
| 253 | static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, | ||
| 254 | u32 freq) | ||
| 255 | { | ||
| 256 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 257 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
| 258 | unsigned char *regs = priv->tda18271_regs; | ||
| 259 | int i, ret; | ||
| 260 | u8 tm_current, dc_over_dt, rf_tab; | ||
| 261 | s32 rfcal_comp, approx; | ||
| 262 | |||
| 263 | /* power up */ | ||
| 264 | ret = tda18271_set_standby_mode(fe, 0, 0, 0); | ||
| 265 | if (tda_fail(ret)) | ||
| 266 | goto fail; | ||
| 267 | |||
| 268 | /* read die current temperature */ | ||
| 269 | tm_current = tda18271_read_thermometer(fe); | ||
| 270 | |||
| 271 | /* frequency dependent parameters */ | ||
| 272 | |||
| 273 | tda18271_calc_rf_cal(fe, &freq); | ||
| 274 | rf_tab = regs[R_EB14]; | ||
| 275 | |||
| 276 | i = tda18271_lookup_rf_band(fe, &freq, NULL); | ||
| 277 | if (tda_fail(i)) | ||
| 278 | return i; | ||
| 279 | |||
| 280 | if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { | ||
| 281 | approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) + | ||
| 282 | map[i].rf_b1 + rf_tab; | ||
| 283 | } else { | ||
| 284 | approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) + | ||
| 285 | map[i].rf_b2 + rf_tab; | ||
| 286 | } | ||
| 287 | |||
| 288 | if (approx < 0) | ||
| 289 | approx = 0; | ||
| 290 | if (approx > 255) | ||
| 291 | approx = 255; | ||
| 292 | |||
| 293 | tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); | ||
| 294 | |||
| 295 | /* calculate temperature compensation */ | ||
| 296 | rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; | ||
| 297 | |||
| 298 | regs[R_EB14] = (unsigned char)(approx + rfcal_comp); | ||
| 299 | ret = tda18271_write_regs(fe, R_EB14, 1); | ||
| 300 | fail: | ||
| 301 | return ret; | ||
| 302 | } | ||
| 303 | |||
| 304 | static int tda18271_por(struct dvb_frontend *fe) | ||
| 305 | { | ||
| 306 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 307 | unsigned char *regs = priv->tda18271_regs; | ||
| 308 | int ret; | ||
| 309 | |||
| 310 | /* power up detector 1 */ | ||
| 311 | regs[R_EB12] &= ~0x20; | ||
| 312 | ret = tda18271_write_regs(fe, R_EB12, 1); | ||
| 313 | if (tda_fail(ret)) | ||
| 314 | goto fail; | ||
| 315 | |||
| 316 | regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ | ||
| 317 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
| 318 | ret = tda18271_write_regs(fe, R_EB18, 1); | ||
| 319 | if (tda_fail(ret)) | ||
| 320 | goto fail; | ||
| 321 | |||
| 322 | regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ | ||
| 323 | |||
| 324 | /* POR mode */ | ||
| 325 | ret = tda18271_set_standby_mode(fe, 1, 0, 0); | ||
| 326 | if (tda_fail(ret)) | ||
| 327 | goto fail; | ||
| 328 | |||
| 329 | /* disable 1.5 MHz low pass filter */ | ||
| 330 | regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ | ||
| 331 | regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ | ||
| 332 | ret = tda18271_write_regs(fe, R_EB21, 3); | ||
| 333 | fail: | ||
| 334 | return ret; | ||
| 335 | } | ||
| 336 | |||
| 337 | static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) | ||
| 338 | { | ||
| 339 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 340 | unsigned char *regs = priv->tda18271_regs; | ||
| 341 | u32 N; | ||
| 342 | |||
| 343 | /* set CAL mode to normal */ | ||
| 344 | regs[R_EP4] &= ~0x03; | ||
| 345 | tda18271_write_regs(fe, R_EP4, 1); | ||
| 346 | |||
| 347 | /* switch off agc1 */ | ||
| 348 | regs[R_EP3] |= 0x40; /* sm_lt = 1 */ | ||
| 349 | |||
| 350 | regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ | ||
| 351 | tda18271_write_regs(fe, R_EB18, 1); | ||
| 352 | |||
| 353 | /* frequency dependent parameters */ | ||
| 354 | |||
| 355 | tda18271_calc_bp_filter(fe, &freq); | ||
| 356 | tda18271_calc_gain_taper(fe, &freq); | ||
| 357 | tda18271_calc_rf_band(fe, &freq); | ||
| 358 | tda18271_calc_km(fe, &freq); | ||
| 359 | |||
| 360 | tda18271_write_regs(fe, R_EP1, 3); | ||
| 361 | tda18271_write_regs(fe, R_EB13, 1); | ||
| 362 | |||
| 363 | /* main pll charge pump source */ | ||
| 364 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); | ||
| 365 | |||
| 366 | /* cal pll charge pump source */ | ||
| 367 | tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); | ||
| 368 | |||
| 369 | /* force dcdc converter to 0 V */ | ||
| 370 | regs[R_EB14] = 0x00; | ||
| 371 | tda18271_write_regs(fe, R_EB14, 1); | ||
| 372 | |||
| 373 | /* disable plls lock */ | ||
| 374 | regs[R_EB20] &= ~0x20; | ||
| 375 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 376 | |||
| 377 | /* set CAL mode to RF tracking filter calibration */ | ||
| 378 | regs[R_EP4] |= 0x03; | ||
| 379 | tda18271_write_regs(fe, R_EP4, 2); | ||
| 380 | |||
| 381 | /* --------------------------------------------------------------- */ | ||
| 382 | |||
| 383 | /* set the internal calibration signal */ | ||
| 384 | N = freq; | ||
| 385 | |||
| 386 | tda18271_calc_cal_pll(fe, N); | ||
| 387 | tda18271_write_regs(fe, R_CPD, 4); | ||
| 388 | |||
| 389 | /* downconvert internal calibration */ | ||
| 390 | N += 1000000; | ||
| 391 | |||
| 392 | tda18271_calc_main_pll(fe, N); | ||
| 393 | tda18271_write_regs(fe, R_MPD, 4); | ||
| 394 | |||
| 395 | msleep(5); | ||
| 396 | |||
| 397 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 398 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 399 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 400 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 401 | |||
| 402 | /* --------------------------------------------------------------- */ | ||
| 403 | |||
| 404 | /* normal operation for the main pll */ | ||
| 405 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); | ||
| 406 | |||
| 407 | /* normal operation for the cal pll */ | ||
| 408 | tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); | ||
| 409 | |||
| 410 | msleep(10); /* plls locking */ | ||
| 411 | |||
| 412 | /* launch the rf tracking filters calibration */ | ||
| 413 | regs[R_EB20] |= 0x20; | ||
| 414 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 415 | |||
| 416 | msleep(60); /* calibration */ | ||
| 417 | |||
| 418 | /* --------------------------------------------------------------- */ | ||
| 419 | |||
| 420 | /* set CAL mode to normal */ | ||
| 421 | regs[R_EP4] &= ~0x03; | ||
| 422 | |||
| 423 | /* switch on agc1 */ | ||
| 424 | regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ | ||
| 425 | |||
| 426 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
| 427 | tda18271_write_regs(fe, R_EB18, 1); | ||
| 428 | |||
| 429 | tda18271_write_regs(fe, R_EP3, 2); | ||
| 430 | |||
| 431 | /* synchronization */ | ||
| 432 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 433 | |||
| 434 | /* get calibration result */ | ||
| 435 | tda18271_read_extended(fe); | ||
| 436 | |||
| 437 | return regs[R_EB14]; | ||
| 438 | } | ||
| 439 | |||
| 440 | static int tda18271_powerscan(struct dvb_frontend *fe, | ||
| 441 | u32 *freq_in, u32 *freq_out) | ||
| 442 | { | ||
| 443 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 444 | unsigned char *regs = priv->tda18271_regs; | ||
| 445 | int sgn, bcal, count, wait, ret; | ||
| 446 | u8 cid_target; | ||
| 447 | u16 count_limit; | ||
| 448 | u32 freq; | ||
| 449 | |||
| 450 | freq = *freq_in; | ||
| 451 | |||
| 452 | tda18271_calc_rf_band(fe, &freq); | ||
| 453 | tda18271_calc_rf_cal(fe, &freq); | ||
| 454 | tda18271_calc_gain_taper(fe, &freq); | ||
| 455 | tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); | ||
| 456 | |||
| 457 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 458 | tda18271_write_regs(fe, R_EB14, 1); | ||
| 459 | |||
| 460 | /* downconvert frequency */ | ||
| 461 | freq += 1000000; | ||
| 462 | |||
| 463 | tda18271_calc_main_pll(fe, freq); | ||
| 464 | tda18271_write_regs(fe, R_MPD, 4); | ||
| 465 | |||
| 466 | msleep(5); /* pll locking */ | ||
| 467 | |||
| 468 | /* detection mode */ | ||
| 469 | regs[R_EP4] &= ~0x03; | ||
| 470 | regs[R_EP4] |= 0x01; | ||
| 471 | tda18271_write_regs(fe, R_EP4, 1); | ||
| 472 | |||
| 473 | /* launch power detection measurement */ | ||
| 474 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 475 | |||
| 476 | /* read power detection info, stored in EB10 */ | ||
| 477 | ret = tda18271_read_extended(fe); | ||
| 478 | if (tda_fail(ret)) | ||
| 479 | return ret; | ||
| 480 | |||
| 481 | /* algorithm initialization */ | ||
| 482 | sgn = 1; | ||
| 483 | *freq_out = *freq_in; | ||
| 484 | bcal = 0; | ||
| 485 | count = 0; | ||
| 486 | wait = false; | ||
| 487 | |||
| 488 | while ((regs[R_EB10] & 0x3f) < cid_target) { | ||
| 489 | /* downconvert updated freq to 1 MHz */ | ||
| 490 | freq = *freq_in + (sgn * count) + 1000000; | ||
| 491 | |||
| 492 | tda18271_calc_main_pll(fe, freq); | ||
| 493 | tda18271_write_regs(fe, R_MPD, 4); | ||
| 494 | |||
| 495 | if (wait) { | ||
| 496 | msleep(5); /* pll locking */ | ||
| 497 | wait = false; | ||
| 498 | } else | ||
| 499 | udelay(100); /* pll locking */ | ||
| 500 | |||
| 501 | /* launch power detection measurement */ | ||
| 502 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 503 | |||
| 504 | /* read power detection info, stored in EB10 */ | ||
| 505 | ret = tda18271_read_extended(fe); | ||
| 506 | if (tda_fail(ret)) | ||
| 507 | return ret; | ||
| 508 | |||
| 509 | count += 200; | ||
| 510 | |||
| 511 | if (count <= count_limit) | ||
| 512 | continue; | ||
| 513 | |||
| 514 | if (sgn <= 0) | ||
| 515 | break; | ||
| 516 | |||
| 517 | sgn = -1 * sgn; | ||
| 518 | count = 200; | ||
| 519 | wait = true; | ||
| 520 | } | ||
| 521 | |||
| 522 | if ((regs[R_EB10] & 0x3f) >= cid_target) { | ||
| 523 | bcal = 1; | ||
| 524 | *freq_out = freq - 1000000; | ||
| 525 | } else | ||
| 526 | bcal = 0; | ||
| 527 | |||
| 528 | tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", | ||
| 529 | bcal, *freq_in, *freq_out, freq); | ||
| 530 | |||
| 531 | return bcal; | ||
| 532 | } | ||
| 533 | |||
| 534 | static int tda18271_powerscan_init(struct dvb_frontend *fe) | ||
| 535 | { | ||
| 536 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 537 | unsigned char *regs = priv->tda18271_regs; | ||
| 538 | int ret; | ||
| 539 | |||
| 540 | /* set standard to digital */ | ||
| 541 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
| 542 | regs[R_EP3] |= 0x12; | ||
| 543 | |||
| 544 | /* set cal mode to normal */ | ||
| 545 | regs[R_EP4] &= ~0x03; | ||
| 546 | |||
| 547 | /* update IF output level */ | ||
| 548 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
| 549 | |||
| 550 | ret = tda18271_write_regs(fe, R_EP3, 2); | ||
| 551 | if (tda_fail(ret)) | ||
| 552 | goto fail; | ||
| 553 | |||
| 554 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
| 555 | ret = tda18271_write_regs(fe, R_EB18, 1); | ||
| 556 | if (tda_fail(ret)) | ||
| 557 | goto fail; | ||
| 558 | |||
| 559 | regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ | ||
| 560 | |||
| 561 | /* 1.5 MHz low pass filter */ | ||
| 562 | regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ | ||
| 563 | regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ | ||
| 564 | |||
| 565 | ret = tda18271_write_regs(fe, R_EB21, 3); | ||
| 566 | fail: | ||
| 567 | return ret; | ||
| 568 | } | ||
| 569 | |||
| 570 | static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) | ||
| 571 | { | ||
| 572 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 573 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
| 574 | unsigned char *regs = priv->tda18271_regs; | ||
| 575 | int bcal, rf, i; | ||
| 576 | s32 divisor, dividend; | ||
| 577 | #define RF1 0 | ||
| 578 | #define RF2 1 | ||
| 579 | #define RF3 2 | ||
| 580 | u32 rf_default[3]; | ||
| 581 | u32 rf_freq[3]; | ||
| 582 | s32 prog_cal[3]; | ||
| 583 | s32 prog_tab[3]; | ||
| 584 | |||
| 585 | i = tda18271_lookup_rf_band(fe, &freq, NULL); | ||
| 586 | |||
| 587 | if (tda_fail(i)) | ||
| 588 | return i; | ||
| 589 | |||
| 590 | rf_default[RF1] = 1000 * map[i].rf1_def; | ||
| 591 | rf_default[RF2] = 1000 * map[i].rf2_def; | ||
| 592 | rf_default[RF3] = 1000 * map[i].rf3_def; | ||
| 593 | |||
| 594 | for (rf = RF1; rf <= RF3; rf++) { | ||
| 595 | if (0 == rf_default[rf]) | ||
| 596 | return 0; | ||
| 597 | tda_cal("freq = %d, rf = %d\n", freq, rf); | ||
| 598 | |||
| 599 | /* look for optimized calibration frequency */ | ||
| 600 | bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); | ||
| 601 | if (tda_fail(bcal)) | ||
| 602 | return bcal; | ||
| 603 | |||
| 604 | tda18271_calc_rf_cal(fe, &rf_freq[rf]); | ||
| 605 | prog_tab[rf] = (s32)regs[R_EB14]; | ||
| 606 | |||
| 607 | if (1 == bcal) | ||
| 608 | prog_cal[rf] = | ||
| 609 | (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); | ||
| 610 | else | ||
| 611 | prog_cal[rf] = prog_tab[rf]; | ||
| 612 | |||
| 613 | switch (rf) { | ||
| 614 | case RF1: | ||
| 615 | map[i].rf_a1 = 0; | ||
| 616 | map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); | ||
| 617 | map[i].rf1 = rf_freq[RF1] / 1000; | ||
| 618 | break; | ||
| 619 | case RF2: | ||
| 620 | dividend = (prog_cal[RF2] - prog_tab[RF2] - | ||
| 621 | prog_cal[RF1] + prog_tab[RF1]); | ||
| 622 | divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; | ||
| 623 | map[i].rf_a1 = (dividend / divisor); | ||
| 624 | map[i].rf2 = rf_freq[RF2] / 1000; | ||
| 625 | break; | ||
| 626 | case RF3: | ||
| 627 | dividend = (prog_cal[RF3] - prog_tab[RF3] - | ||
| 628 | prog_cal[RF2] + prog_tab[RF2]); | ||
| 629 | divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; | ||
| 630 | map[i].rf_a2 = (dividend / divisor); | ||
| 631 | map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); | ||
| 632 | map[i].rf3 = rf_freq[RF3] / 1000; | ||
| 633 | break; | ||
| 634 | default: | ||
| 635 | BUG(); | ||
| 636 | } | ||
| 637 | } | ||
| 638 | |||
| 639 | return 0; | ||
| 640 | } | ||
| 641 | |||
| 642 | static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) | ||
| 643 | { | ||
| 644 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 645 | unsigned int i; | ||
| 646 | int ret; | ||
| 647 | |||
| 648 | tda_info("tda18271: performing RF tracking filter calibration\n"); | ||
| 649 | |||
| 650 | /* wait for die temperature stabilization */ | ||
| 651 | msleep(200); | ||
| 652 | |||
| 653 | ret = tda18271_powerscan_init(fe); | ||
| 654 | if (tda_fail(ret)) | ||
| 655 | goto fail; | ||
| 656 | |||
| 657 | /* rf band calibration */ | ||
| 658 | for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) { | ||
| 659 | ret = | ||
| 660 | tda18271_rf_tracking_filters_init(fe, 1000 * | ||
| 661 | priv->rf_cal_state[i].rfmax); | ||
| 662 | if (tda_fail(ret)) | ||
| 663 | goto fail; | ||
| 664 | } | ||
| 665 | |||
| 666 | priv->tm_rfcal = tda18271_read_thermometer(fe); | ||
| 667 | fail: | ||
| 668 | return ret; | ||
| 669 | } | ||
| 670 | |||
| 671 | /* ------------------------------------------------------------------ */ | ||
| 672 | |||
| 673 | static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) | ||
| 674 | { | ||
| 675 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 676 | unsigned char *regs = priv->tda18271_regs; | ||
| 677 | int ret; | ||
| 678 | |||
| 679 | /* test RF_CAL_OK to see if we need init */ | ||
| 680 | if ((regs[R_EP1] & 0x10) == 0) | ||
| 681 | priv->cal_initialized = false; | ||
| 682 | |||
| 683 | if (priv->cal_initialized) | ||
| 684 | return 0; | ||
| 685 | |||
| 686 | ret = tda18271_calc_rf_filter_curve(fe); | ||
| 687 | if (tda_fail(ret)) | ||
| 688 | goto fail; | ||
| 689 | |||
| 690 | ret = tda18271_por(fe); | ||
| 691 | if (tda_fail(ret)) | ||
| 692 | goto fail; | ||
| 693 | |||
| 694 | tda_info("tda18271: RF tracking filter calibration complete\n"); | ||
| 695 | |||
| 696 | priv->cal_initialized = true; | ||
| 697 | goto end; | ||
| 698 | fail: | ||
| 699 | tda_info("tda18271: RF tracking filter calibration failed!\n"); | ||
| 700 | end: | ||
| 701 | return ret; | ||
| 702 | } | ||
| 703 | |||
| 704 | static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, | ||
| 705 | u32 freq, u32 bw) | ||
| 706 | { | ||
| 707 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 708 | unsigned char *regs = priv->tda18271_regs; | ||
| 709 | int ret; | ||
| 710 | u32 N = 0; | ||
| 711 | |||
| 712 | /* calculate bp filter */ | ||
| 713 | tda18271_calc_bp_filter(fe, &freq); | ||
| 714 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 715 | |||
| 716 | regs[R_EB4] &= 0x07; | ||
| 717 | regs[R_EB4] |= 0x60; | ||
| 718 | tda18271_write_regs(fe, R_EB4, 1); | ||
| 719 | |||
| 720 | regs[R_EB7] = 0x60; | ||
| 721 | tda18271_write_regs(fe, R_EB7, 1); | ||
| 722 | |||
| 723 | regs[R_EB14] = 0x00; | ||
| 724 | tda18271_write_regs(fe, R_EB14, 1); | ||
| 725 | |||
| 726 | regs[R_EB20] = 0xcc; | ||
| 727 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 728 | |||
| 729 | /* set cal mode to RF tracking filter calibration */ | ||
| 730 | regs[R_EP4] |= 0x03; | ||
| 731 | |||
| 732 | /* calculate cal pll */ | ||
| 733 | |||
| 734 | switch (priv->mode) { | ||
| 735 | case TDA18271_ANALOG: | ||
| 736 | N = freq - 1250000; | ||
| 737 | break; | ||
| 738 | case TDA18271_DIGITAL: | ||
| 739 | N = freq + bw / 2; | ||
| 740 | break; | ||
| 741 | } | ||
| 742 | |||
| 743 | tda18271_calc_cal_pll(fe, N); | ||
| 744 | |||
| 745 | /* calculate main pll */ | ||
| 746 | |||
| 747 | switch (priv->mode) { | ||
| 748 | case TDA18271_ANALOG: | ||
| 749 | N = freq - 250000; | ||
| 750 | break; | ||
| 751 | case TDA18271_DIGITAL: | ||
| 752 | N = freq + bw / 2 + 1000000; | ||
| 753 | break; | ||
| 754 | } | ||
| 755 | |||
| 756 | tda18271_calc_main_pll(fe, N); | ||
| 757 | |||
| 758 | ret = tda18271_write_regs(fe, R_EP3, 11); | ||
| 759 | if (tda_fail(ret)) | ||
| 760 | return ret; | ||
| 761 | |||
| 762 | msleep(5); /* RF tracking filter calibration initialization */ | ||
| 763 | |||
| 764 | /* search for K,M,CO for RF calibration */ | ||
| 765 | tda18271_calc_km(fe, &freq); | ||
| 766 | tda18271_write_regs(fe, R_EB13, 1); | ||
| 767 | |||
| 768 | /* search for rf band */ | ||
| 769 | tda18271_calc_rf_band(fe, &freq); | ||
| 770 | |||
| 771 | /* search for gain taper */ | ||
| 772 | tda18271_calc_gain_taper(fe, &freq); | ||
| 773 | |||
| 774 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 775 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 776 | tda18271_write_regs(fe, R_EP2, 1); | ||
| 777 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 778 | |||
| 779 | regs[R_EB4] &= 0x07; | ||
| 780 | regs[R_EB4] |= 0x40; | ||
| 781 | tda18271_write_regs(fe, R_EB4, 1); | ||
| 782 | |||
| 783 | regs[R_EB7] = 0x40; | ||
| 784 | tda18271_write_regs(fe, R_EB7, 1); | ||
| 785 | msleep(10); /* pll locking */ | ||
| 786 | |||
| 787 | regs[R_EB20] = 0xec; | ||
| 788 | tda18271_write_regs(fe, R_EB20, 1); | ||
| 789 | msleep(60); /* RF tracking filter calibration completion */ | ||
| 790 | |||
| 791 | regs[R_EP4] &= ~0x03; /* set cal mode to normal */ | ||
| 792 | tda18271_write_regs(fe, R_EP4, 1); | ||
| 793 | |||
| 794 | tda18271_write_regs(fe, R_EP1, 1); | ||
| 795 | |||
| 796 | /* RF tracking filter correction for VHF_Low band */ | ||
| 797 | if (0 == tda18271_calc_rf_cal(fe, &freq)) | ||
| 798 | tda18271_write_regs(fe, R_EB14, 1); | ||
| 799 | |||
| 800 | return 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | /* ------------------------------------------------------------------ */ | ||
| 804 | |||
| 805 | static int tda18271_ir_cal_init(struct dvb_frontend *fe) | ||
| 806 | { | ||
| 807 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 808 | unsigned char *regs = priv->tda18271_regs; | ||
| 809 | int ret; | ||
| 810 | |||
| 811 | ret = tda18271_read_regs(fe); | ||
| 812 | if (tda_fail(ret)) | ||
| 813 | goto fail; | ||
| 814 | |||
| 815 | /* test IR_CAL_OK to see if we need init */ | ||
| 816 | if ((regs[R_EP1] & 0x08) == 0) | ||
| 817 | ret = tda18271_init_regs(fe); | ||
| 818 | fail: | ||
| 819 | return ret; | ||
| 820 | } | ||
| 821 | |||
| 822 | static int tda18271_init(struct dvb_frontend *fe) | ||
| 823 | { | ||
| 824 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 825 | int ret; | ||
| 826 | |||
| 827 | mutex_lock(&priv->lock); | ||
| 828 | |||
| 829 | /* full power up */ | ||
| 830 | ret = tda18271_set_standby_mode(fe, 0, 0, 0); | ||
| 831 | if (tda_fail(ret)) | ||
| 832 | goto fail; | ||
| 833 | |||
| 834 | /* initialization */ | ||
| 835 | ret = tda18271_ir_cal_init(fe); | ||
| 836 | if (tda_fail(ret)) | ||
| 837 | goto fail; | ||
| 838 | |||
| 839 | if (priv->id == TDA18271HDC2) | ||
| 840 | tda18271c2_rf_cal_init(fe); | ||
| 841 | fail: | ||
| 842 | mutex_unlock(&priv->lock); | ||
| 843 | |||
| 844 | return ret; | ||
| 845 | } | ||
| 846 | |||
| 847 | static int tda18271_sleep(struct dvb_frontend *fe) | ||
| 848 | { | ||
| 849 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 850 | int ret; | ||
| 851 | |||
| 852 | mutex_lock(&priv->lock); | ||
| 853 | |||
| 854 | /* enter standby mode, with required output features enabled */ | ||
| 855 | ret = tda18271_toggle_output(fe, 1); | ||
| 856 | |||
| 857 | mutex_unlock(&priv->lock); | ||
| 858 | |||
| 859 | return ret; | ||
| 860 | } | ||
| 861 | |||
| 862 | /* ------------------------------------------------------------------ */ | ||
| 863 | |||
| 864 | static int tda18271_agc(struct dvb_frontend *fe) | ||
| 865 | { | ||
| 866 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 867 | int ret = 0; | ||
| 868 | |||
| 869 | switch (priv->config) { | ||
| 870 | case 0: | ||
| 871 | /* no external agc configuration required */ | ||
| 872 | if (tda18271_debug & DBG_ADV) | ||
| 873 | tda_dbg("no agc configuration provided\n"); | ||
| 874 | break; | ||
| 875 | case 3: | ||
| 876 | /* switch with GPIO of saa713x */ | ||
| 877 | tda_dbg("invoking callback\n"); | ||
| 878 | if (fe->callback) | ||
| 879 | ret = fe->callback(priv->i2c_props.adap->algo_data, | ||
| 880 | DVB_FRONTEND_COMPONENT_TUNER, | ||
| 881 | TDA18271_CALLBACK_CMD_AGC_ENABLE, | ||
| 882 | priv->mode); | ||
| 883 | break; | ||
| 884 | case 1: | ||
| 885 | case 2: | ||
| 886 | default: | ||
| 887 | /* n/a - currently not supported */ | ||
| 888 | tda_err("unsupported configuration: %d\n", priv->config); | ||
| 889 | ret = -EINVAL; | ||
| 890 | break; | ||
| 891 | } | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | static int tda18271_tune(struct dvb_frontend *fe, | ||
| 896 | struct tda18271_std_map_item *map, u32 freq, u32 bw) | ||
| 897 | { | ||
| 898 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 899 | int ret; | ||
| 900 | |||
| 901 | tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", | ||
| 902 | freq, map->if_freq, bw, map->agc_mode, map->std); | ||
| 903 | |||
| 904 | ret = tda18271_agc(fe); | ||
| 905 | if (tda_fail(ret)) | ||
| 906 | tda_warn("failed to configure agc\n"); | ||
| 907 | |||
| 908 | ret = tda18271_init(fe); | ||
| 909 | if (tda_fail(ret)) | ||
| 910 | goto fail; | ||
| 911 | |||
| 912 | mutex_lock(&priv->lock); | ||
| 913 | |||
| 914 | switch (priv->id) { | ||
| 915 | case TDA18271HDC1: | ||
| 916 | tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); | ||
| 917 | break; | ||
| 918 | case TDA18271HDC2: | ||
| 919 | tda18271c2_rf_tracking_filters_correction(fe, freq); | ||
| 920 | break; | ||
| 921 | } | ||
| 922 | ret = tda18271_channel_configuration(fe, map, freq, bw); | ||
| 923 | |||
| 924 | mutex_unlock(&priv->lock); | ||
| 925 | fail: | ||
| 926 | return ret; | ||
| 927 | } | ||
| 928 | |||
| 929 | /* ------------------------------------------------------------------ */ | ||
| 930 | |||
| 931 | static int tda18271_set_params(struct dvb_frontend *fe, | ||
| 932 | struct dvb_frontend_parameters *params) | ||
| 933 | { | ||
| 934 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 935 | struct tda18271_std_map *std_map = &priv->std; | ||
| 936 | struct tda18271_std_map_item *map; | ||
| 937 | int ret; | ||
| 938 | u32 bw, freq = params->frequency; | ||
| 939 | |||
| 940 | priv->mode = TDA18271_DIGITAL; | ||
| 941 | |||
| 942 | if (fe->ops.info.type == FE_ATSC) { | ||
| 943 | switch (params->u.vsb.modulation) { | ||
| 944 | case VSB_8: | ||
| 945 | case VSB_16: | ||
| 946 | map = &std_map->atsc_6; | ||
| 947 | break; | ||
| 948 | case QAM_64: | ||
| 949 | case QAM_256: | ||
| 950 | map = &std_map->qam_6; | ||
| 951 | break; | ||
| 952 | default: | ||
| 953 | tda_warn("modulation not set!\n"); | ||
| 954 | return -EINVAL; | ||
| 955 | } | ||
| 956 | #if 0 | ||
| 957 | /* userspace request is already center adjusted */ | ||
| 958 | freq += 1750000; /* Adjust to center (+1.75MHZ) */ | ||
| 959 | #endif | ||
| 960 | bw = 6000000; | ||
| 961 | } else if (fe->ops.info.type == FE_OFDM) { | ||
| 962 | switch (params->u.ofdm.bandwidth) { | ||
| 963 | case BANDWIDTH_6_MHZ: | ||
| 964 | bw = 6000000; | ||
| 965 | map = &std_map->dvbt_6; | ||
| 966 | break; | ||
| 967 | case BANDWIDTH_7_MHZ: | ||
| 968 | bw = 7000000; | ||
| 969 | map = &std_map->dvbt_7; | ||
| 970 | break; | ||
| 971 | case BANDWIDTH_8_MHZ: | ||
| 972 | bw = 8000000; | ||
| 973 | map = &std_map->dvbt_8; | ||
| 974 | break; | ||
| 975 | default: | ||
| 976 | tda_warn("bandwidth not set!\n"); | ||
| 977 | return -EINVAL; | ||
| 978 | } | ||
| 979 | } else if (fe->ops.info.type == FE_QAM) { | ||
| 980 | /* DVB-C */ | ||
| 981 | map = &std_map->qam_8; | ||
| 982 | bw = 8000000; | ||
| 983 | } else { | ||
| 984 | tda_warn("modulation type not supported!\n"); | ||
| 985 | return -EINVAL; | ||
| 986 | } | ||
| 987 | |||
| 988 | /* When tuning digital, the analog demod must be tri-stated */ | ||
| 989 | if (fe->ops.analog_ops.standby) | ||
| 990 | fe->ops.analog_ops.standby(fe); | ||
| 991 | |||
| 992 | ret = tda18271_tune(fe, map, freq, bw); | ||
| 993 | |||
| 994 | if (tda_fail(ret)) | ||
| 995 | goto fail; | ||
| 996 | |||
| 997 | priv->frequency = freq; | ||
| 998 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? | ||
| 999 | params->u.ofdm.bandwidth : 0; | ||
| 1000 | fail: | ||
| 1001 | return ret; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static int tda18271_set_analog_params(struct dvb_frontend *fe, | ||
| 1005 | struct analog_parameters *params) | ||
| 1006 | { | ||
| 1007 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1008 | struct tda18271_std_map *std_map = &priv->std; | ||
| 1009 | struct tda18271_std_map_item *map; | ||
| 1010 | char *mode; | ||
| 1011 | int ret; | ||
| 1012 | u32 freq = params->frequency * 125 * | ||
| 1013 | ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2; | ||
| 1014 | |||
| 1015 | priv->mode = TDA18271_ANALOG; | ||
| 1016 | |||
| 1017 | if (params->mode == V4L2_TUNER_RADIO) { | ||
| 1018 | map = &std_map->fm_radio; | ||
| 1019 | mode = "fm"; | ||
| 1020 | } else if (params->std & V4L2_STD_MN) { | ||
| 1021 | map = &std_map->atv_mn; | ||
| 1022 | mode = "MN"; | ||
| 1023 | } else if (params->std & V4L2_STD_B) { | ||
| 1024 | map = &std_map->atv_b; | ||
| 1025 | mode = "B"; | ||
| 1026 | } else if (params->std & V4L2_STD_GH) { | ||
| 1027 | map = &std_map->atv_gh; | ||
| 1028 | mode = "GH"; | ||
| 1029 | } else if (params->std & V4L2_STD_PAL_I) { | ||
| 1030 | map = &std_map->atv_i; | ||
| 1031 | mode = "I"; | ||
| 1032 | } else if (params->std & V4L2_STD_DK) { | ||
| 1033 | map = &std_map->atv_dk; | ||
| 1034 | mode = "DK"; | ||
| 1035 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
| 1036 | map = &std_map->atv_l; | ||
| 1037 | mode = "L"; | ||
| 1038 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
| 1039 | map = &std_map->atv_lc; | ||
| 1040 | mode = "L'"; | ||
| 1041 | } else { | ||
| 1042 | map = &std_map->atv_i; | ||
| 1043 | mode = "xx"; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | tda_dbg("setting tda18271 to system %s\n", mode); | ||
| 1047 | |||
| 1048 | ret = tda18271_tune(fe, map, freq, 0); | ||
| 1049 | |||
| 1050 | if (tda_fail(ret)) | ||
| 1051 | goto fail; | ||
| 1052 | |||
| 1053 | priv->frequency = freq; | ||
| 1054 | priv->bandwidth = 0; | ||
| 1055 | fail: | ||
| 1056 | return ret; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | static int tda18271_release(struct dvb_frontend *fe) | ||
| 1060 | { | ||
| 1061 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1062 | |||
| 1063 | mutex_lock(&tda18271_list_mutex); | ||
| 1064 | |||
| 1065 | if (priv) | ||
| 1066 | hybrid_tuner_release_state(priv); | ||
| 1067 | |||
| 1068 | mutex_unlock(&tda18271_list_mutex); | ||
| 1069 | |||
| 1070 | fe->tuner_priv = NULL; | ||
| 1071 | |||
| 1072 | return 0; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 1076 | { | ||
| 1077 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1078 | *frequency = priv->frequency; | ||
| 1079 | return 0; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 1083 | { | ||
| 1084 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1085 | *bandwidth = priv->bandwidth; | ||
| 1086 | return 0; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | /* ------------------------------------------------------------------ */ | ||
| 1090 | |||
| 1091 | #define tda18271_update_std(std_cfg, name) do { \ | ||
| 1092 | if (map->std_cfg.if_freq + \ | ||
| 1093 | map->std_cfg.agc_mode + map->std_cfg.std + \ | ||
| 1094 | map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ | ||
| 1095 | tda_dbg("Using custom std config for %s\n", name); \ | ||
| 1096 | memcpy(&std->std_cfg, &map->std_cfg, \ | ||
| 1097 | sizeof(struct tda18271_std_map_item)); \ | ||
| 1098 | } } while (0) | ||
| 1099 | |||
| 1100 | #define tda18271_dump_std_item(std_cfg, name) do { \ | ||
| 1101 | tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ | ||
| 1102 | "if_lvl = %d, rfagc_top = 0x%02x\n", \ | ||
| 1103 | name, std->std_cfg.if_freq, \ | ||
| 1104 | std->std_cfg.agc_mode, std->std_cfg.std, \ | ||
| 1105 | std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ | ||
| 1106 | } while (0) | ||
| 1107 | |||
| 1108 | static int tda18271_dump_std_map(struct dvb_frontend *fe) | ||
| 1109 | { | ||
| 1110 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1111 | struct tda18271_std_map *std = &priv->std; | ||
| 1112 | |||
| 1113 | tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); | ||
| 1114 | tda18271_dump_std_item(fm_radio, " fm "); | ||
| 1115 | tda18271_dump_std_item(atv_b, "atv b "); | ||
| 1116 | tda18271_dump_std_item(atv_dk, "atv dk"); | ||
| 1117 | tda18271_dump_std_item(atv_gh, "atv gh"); | ||
| 1118 | tda18271_dump_std_item(atv_i, "atv i "); | ||
| 1119 | tda18271_dump_std_item(atv_l, "atv l "); | ||
| 1120 | tda18271_dump_std_item(atv_lc, "atv l'"); | ||
| 1121 | tda18271_dump_std_item(atv_mn, "atv mn"); | ||
| 1122 | tda18271_dump_std_item(atsc_6, "atsc 6"); | ||
| 1123 | tda18271_dump_std_item(dvbt_6, "dvbt 6"); | ||
| 1124 | tda18271_dump_std_item(dvbt_7, "dvbt 7"); | ||
| 1125 | tda18271_dump_std_item(dvbt_8, "dvbt 8"); | ||
| 1126 | tda18271_dump_std_item(qam_6, "qam 6 "); | ||
| 1127 | tda18271_dump_std_item(qam_8, "qam 8 "); | ||
| 1128 | |||
| 1129 | return 0; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | static int tda18271_update_std_map(struct dvb_frontend *fe, | ||
| 1133 | struct tda18271_std_map *map) | ||
| 1134 | { | ||
| 1135 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1136 | struct tda18271_std_map *std = &priv->std; | ||
| 1137 | |||
| 1138 | if (!map) | ||
| 1139 | return -EINVAL; | ||
| 1140 | |||
| 1141 | tda18271_update_std(fm_radio, "fm"); | ||
| 1142 | tda18271_update_std(atv_b, "atv b"); | ||
| 1143 | tda18271_update_std(atv_dk, "atv dk"); | ||
| 1144 | tda18271_update_std(atv_gh, "atv gh"); | ||
| 1145 | tda18271_update_std(atv_i, "atv i"); | ||
| 1146 | tda18271_update_std(atv_l, "atv l"); | ||
| 1147 | tda18271_update_std(atv_lc, "atv l'"); | ||
| 1148 | tda18271_update_std(atv_mn, "atv mn"); | ||
| 1149 | tda18271_update_std(atsc_6, "atsc 6"); | ||
| 1150 | tda18271_update_std(dvbt_6, "dvbt 6"); | ||
| 1151 | tda18271_update_std(dvbt_7, "dvbt 7"); | ||
| 1152 | tda18271_update_std(dvbt_8, "dvbt 8"); | ||
| 1153 | tda18271_update_std(qam_6, "qam 6"); | ||
| 1154 | tda18271_update_std(qam_8, "qam 8"); | ||
| 1155 | |||
| 1156 | return 0; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | static int tda18271_get_id(struct dvb_frontend *fe) | ||
| 1160 | { | ||
| 1161 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1162 | unsigned char *regs = priv->tda18271_regs; | ||
| 1163 | char *name; | ||
| 1164 | |||
| 1165 | mutex_lock(&priv->lock); | ||
| 1166 | tda18271_read_regs(fe); | ||
| 1167 | mutex_unlock(&priv->lock); | ||
| 1168 | |||
| 1169 | switch (regs[R_ID] & 0x7f) { | ||
| 1170 | case 3: | ||
| 1171 | name = "TDA18271HD/C1"; | ||
| 1172 | priv->id = TDA18271HDC1; | ||
| 1173 | break; | ||
| 1174 | case 4: | ||
| 1175 | name = "TDA18271HD/C2"; | ||
| 1176 | priv->id = TDA18271HDC2; | ||
| 1177 | break; | ||
| 1178 | default: | ||
| 1179 | tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n", | ||
| 1180 | regs[R_ID], i2c_adapter_id(priv->i2c_props.adap), | ||
| 1181 | priv->i2c_props.addr); | ||
| 1182 | return -EINVAL; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | tda_info("%s detected @ %d-%04x\n", name, | ||
| 1186 | i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); | ||
| 1187 | |||
| 1188 | return 0; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | static int tda18271_setup_configuration(struct dvb_frontend *fe, | ||
| 1192 | struct tda18271_config *cfg) | ||
| 1193 | { | ||
| 1194 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1195 | |||
| 1196 | priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; | ||
| 1197 | priv->role = (cfg) ? cfg->role : TDA18271_MASTER; | ||
| 1198 | priv->config = (cfg) ? cfg->config : 0; | ||
| 1199 | priv->small_i2c = (cfg) ? | ||
| 1200 | cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT; | ||
| 1201 | priv->output_opt = (cfg) ? | ||
| 1202 | cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; | ||
| 1203 | |||
| 1204 | return 0; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg) | ||
| 1208 | { | ||
| 1209 | /* tda18271_cal_on_startup == -1 when cal module option is unset */ | ||
| 1210 | return ((tda18271_cal_on_startup == -1) ? | ||
| 1211 | /* honor configuration setting */ | ||
| 1212 | ((cfg) && (cfg->rf_cal_on_startup)) : | ||
| 1213 | /* module option overrides configuration setting */ | ||
| 1214 | (tda18271_cal_on_startup)) ? 1 : 0; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
| 1218 | { | ||
| 1219 | struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg; | ||
| 1220 | |||
| 1221 | tda18271_setup_configuration(fe, cfg); | ||
| 1222 | |||
| 1223 | if (tda18271_need_cal_on_startup(cfg)) | ||
| 1224 | tda18271_init(fe); | ||
| 1225 | |||
| 1226 | /* override default std map with values in config struct */ | ||
| 1227 | if ((cfg) && (cfg->std_map)) | ||
| 1228 | tda18271_update_std_map(fe, cfg->std_map); | ||
| 1229 | |||
| 1230 | return 0; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | static struct dvb_tuner_ops tda18271_tuner_ops = { | ||
| 1234 | .info = { | ||
| 1235 | .name = "NXP TDA18271HD", | ||
| 1236 | .frequency_min = 45000000, | ||
| 1237 | .frequency_max = 864000000, | ||
| 1238 | .frequency_step = 62500 | ||
| 1239 | }, | ||
| 1240 | .init = tda18271_init, | ||
| 1241 | .sleep = tda18271_sleep, | ||
| 1242 | .set_params = tda18271_set_params, | ||
| 1243 | .set_analog_params = tda18271_set_analog_params, | ||
| 1244 | .release = tda18271_release, | ||
| 1245 | .set_config = tda18271_set_config, | ||
| 1246 | .get_frequency = tda18271_get_frequency, | ||
| 1247 | .get_bandwidth = tda18271_get_bandwidth, | ||
| 1248 | }; | ||
| 1249 | |||
| 1250 | struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
| 1251 | struct i2c_adapter *i2c, | ||
| 1252 | struct tda18271_config *cfg) | ||
| 1253 | { | ||
| 1254 | struct tda18271_priv *priv = NULL; | ||
| 1255 | int instance, ret; | ||
| 1256 | |||
| 1257 | mutex_lock(&tda18271_list_mutex); | ||
| 1258 | |||
| 1259 | instance = hybrid_tuner_request_state(struct tda18271_priv, priv, | ||
| 1260 | hybrid_tuner_instance_list, | ||
| 1261 | i2c, addr, "tda18271"); | ||
| 1262 | switch (instance) { | ||
| 1263 | case 0: | ||
| 1264 | goto fail; | ||
| 1265 | case 1: | ||
| 1266 | /* new tuner instance */ | ||
| 1267 | fe->tuner_priv = priv; | ||
| 1268 | |||
| 1269 | tda18271_setup_configuration(fe, cfg); | ||
| 1270 | |||
| 1271 | priv->cal_initialized = false; | ||
| 1272 | mutex_init(&priv->lock); | ||
| 1273 | |||
| 1274 | ret = tda18271_get_id(fe); | ||
| 1275 | if (tda_fail(ret)) | ||
| 1276 | goto fail; | ||
| 1277 | |||
| 1278 | ret = tda18271_assign_map_layout(fe); | ||
| 1279 | if (tda_fail(ret)) | ||
| 1280 | goto fail; | ||
| 1281 | |||
| 1282 | mutex_lock(&priv->lock); | ||
| 1283 | tda18271_init_regs(fe); | ||
| 1284 | |||
| 1285 | if ((tda18271_need_cal_on_startup(cfg)) && | ||
| 1286 | (priv->id == TDA18271HDC2)) | ||
| 1287 | tda18271c2_rf_cal_init(fe); | ||
| 1288 | |||
| 1289 | mutex_unlock(&priv->lock); | ||
| 1290 | break; | ||
| 1291 | default: | ||
| 1292 | /* existing tuner instance */ | ||
| 1293 | fe->tuner_priv = priv; | ||
| 1294 | |||
| 1295 | /* allow dvb driver to override configuration settings */ | ||
| 1296 | if (cfg) { | ||
| 1297 | if (cfg->gate != TDA18271_GATE_ANALOG) | ||
| 1298 | priv->gate = cfg->gate; | ||
| 1299 | if (cfg->role) | ||
| 1300 | priv->role = cfg->role; | ||
| 1301 | if (cfg->config) | ||
| 1302 | priv->config = cfg->config; | ||
| 1303 | if (cfg->small_i2c) | ||
| 1304 | priv->small_i2c = cfg->small_i2c; | ||
| 1305 | if (cfg->output_opt) | ||
| 1306 | priv->output_opt = cfg->output_opt; | ||
| 1307 | if (cfg->std_map) | ||
| 1308 | tda18271_update_std_map(fe, cfg->std_map); | ||
| 1309 | } | ||
| 1310 | if (tda18271_need_cal_on_startup(cfg)) | ||
| 1311 | tda18271_init(fe); | ||
| 1312 | break; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | /* override default std map with values in config struct */ | ||
| 1316 | if ((cfg) && (cfg->std_map)) | ||
| 1317 | tda18271_update_std_map(fe, cfg->std_map); | ||
| 1318 | |||
| 1319 | mutex_unlock(&tda18271_list_mutex); | ||
| 1320 | |||
| 1321 | memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, | ||
| 1322 | sizeof(struct dvb_tuner_ops)); | ||
| 1323 | |||
| 1324 | if (tda18271_debug & (DBG_MAP | DBG_ADV)) | ||
| 1325 | tda18271_dump_std_map(fe); | ||
| 1326 | |||
| 1327 | return fe; | ||
| 1328 | fail: | ||
| 1329 | mutex_unlock(&tda18271_list_mutex); | ||
| 1330 | |||
| 1331 | tda18271_release(fe); | ||
| 1332 | return NULL; | ||
| 1333 | } | ||
| 1334 | EXPORT_SYMBOL_GPL(tda18271_attach); | ||
| 1335 | MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); | ||
| 1336 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
| 1337 | MODULE_LICENSE("GPL"); | ||
| 1338 | MODULE_VERSION("0.4"); | ||
| 1339 | |||
| 1340 | /* | ||
| 1341 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 1342 | * --------------------------------------------------------------------------- | ||
| 1343 | * Local variables: | ||
| 1344 | * c-basic-offset: 8 | ||
| 1345 | * End: | ||
| 1346 | */ | ||
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c new file mode 100644 index 00000000000..3d5b6ab7e33 --- /dev/null +++ b/drivers/media/common/tuners/tda18271-maps.c | |||
| @@ -0,0 +1,1313 @@ | |||
| 1 | /* | ||
| 2 | tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
| 3 | |||
| 4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "tda18271-priv.h" | ||
| 22 | |||
| 23 | struct tda18271_pll_map { | ||
| 24 | u32 lomax; | ||
| 25 | u8 pd; /* post div */ | ||
| 26 | u8 d; /* div */ | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct tda18271_map { | ||
| 30 | u32 rfmax; | ||
| 31 | u8 val; | ||
| 32 | }; | ||
| 33 | |||
| 34 | /*---------------------------------------------------------------------*/ | ||
| 35 | |||
| 36 | static struct tda18271_pll_map tda18271c1_main_pll[] = { | ||
| 37 | { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, | ||
| 38 | { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, | ||
| 39 | { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, | ||
| 40 | { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, | ||
| 41 | { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, | ||
| 42 | { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, | ||
| 43 | { .lomax = 54000, .pd = 0x59, .d = 0x90 }, | ||
| 44 | { .lomax = 61000, .pd = 0x58, .d = 0x80 }, | ||
| 45 | { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, | ||
| 46 | { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, | ||
| 47 | { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, | ||
| 48 | { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, | ||
| 49 | { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, | ||
| 50 | { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, | ||
| 51 | { .lomax = 109000, .pd = 0x49, .d = 0x48 }, | ||
| 52 | { .lomax = 123000, .pd = 0x48, .d = 0x40 }, | ||
| 53 | { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, | ||
| 54 | { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, | ||
| 55 | { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, | ||
| 56 | { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, | ||
| 57 | { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, | ||
| 58 | { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, | ||
| 59 | { .lomax = 219000, .pd = 0x39, .d = 0x24 }, | ||
| 60 | { .lomax = 246000, .pd = 0x38, .d = 0x20 }, | ||
| 61 | { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, | ||
| 62 | { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, | ||
| 63 | { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, | ||
| 64 | { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, | ||
| 65 | { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, | ||
| 66 | { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, | ||
| 67 | { .lomax = 438000, .pd = 0x29, .d = 0x12 }, | ||
| 68 | { .lomax = 493000, .pd = 0x28, .d = 0x10 }, | ||
| 69 | { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, | ||
| 70 | { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, | ||
| 71 | { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, | ||
| 72 | { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, | ||
| 73 | { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, | ||
| 74 | { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, | ||
| 75 | { .lomax = 877000, .pd = 0x19, .d = 0x09 }, | ||
| 76 | { .lomax = 987000, .pd = 0x18, .d = 0x08 }, | ||
| 77 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
| 78 | }; | ||
| 79 | |||
| 80 | static struct tda18271_pll_map tda18271c2_main_pll[] = { | ||
| 81 | { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, | ||
| 82 | { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, | ||
| 83 | { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, | ||
| 84 | { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, | ||
| 85 | { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, | ||
| 86 | { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, | ||
| 87 | { .lomax = 55188, .pd = 0x51, .d = 0x90 }, | ||
| 88 | { .lomax = 62125, .pd = 0x50, .d = 0x80 }, | ||
| 89 | { .lomax = 66250, .pd = 0x47, .d = 0x78 }, | ||
| 90 | { .lomax = 71000, .pd = 0x46, .d = 0x70 }, | ||
| 91 | { .lomax = 76375, .pd = 0x45, .d = 0x68 }, | ||
| 92 | { .lomax = 82750, .pd = 0x44, .d = 0x60 }, | ||
| 93 | { .lomax = 90250, .pd = 0x43, .d = 0x58 }, | ||
| 94 | { .lomax = 99375, .pd = 0x42, .d = 0x50 }, | ||
| 95 | { .lomax = 110375, .pd = 0x41, .d = 0x48 }, | ||
| 96 | { .lomax = 124250, .pd = 0x40, .d = 0x40 }, | ||
| 97 | { .lomax = 132500, .pd = 0x37, .d = 0x3c }, | ||
| 98 | { .lomax = 142000, .pd = 0x36, .d = 0x38 }, | ||
| 99 | { .lomax = 152750, .pd = 0x35, .d = 0x34 }, | ||
| 100 | { .lomax = 165500, .pd = 0x34, .d = 0x30 }, | ||
| 101 | { .lomax = 180500, .pd = 0x33, .d = 0x2c }, | ||
| 102 | { .lomax = 198750, .pd = 0x32, .d = 0x28 }, | ||
| 103 | { .lomax = 220750, .pd = 0x31, .d = 0x24 }, | ||
| 104 | { .lomax = 248500, .pd = 0x30, .d = 0x20 }, | ||
| 105 | { .lomax = 265000, .pd = 0x27, .d = 0x1e }, | ||
| 106 | { .lomax = 284000, .pd = 0x26, .d = 0x1c }, | ||
| 107 | { .lomax = 305500, .pd = 0x25, .d = 0x1a }, | ||
| 108 | { .lomax = 331000, .pd = 0x24, .d = 0x18 }, | ||
| 109 | { .lomax = 361000, .pd = 0x23, .d = 0x16 }, | ||
| 110 | { .lomax = 397500, .pd = 0x22, .d = 0x14 }, | ||
| 111 | { .lomax = 441500, .pd = 0x21, .d = 0x12 }, | ||
| 112 | { .lomax = 497000, .pd = 0x20, .d = 0x10 }, | ||
| 113 | { .lomax = 530000, .pd = 0x17, .d = 0x0f }, | ||
| 114 | { .lomax = 568000, .pd = 0x16, .d = 0x0e }, | ||
| 115 | { .lomax = 611000, .pd = 0x15, .d = 0x0d }, | ||
| 116 | { .lomax = 662000, .pd = 0x14, .d = 0x0c }, | ||
| 117 | { .lomax = 722000, .pd = 0x13, .d = 0x0b }, | ||
| 118 | { .lomax = 795000, .pd = 0x12, .d = 0x0a }, | ||
| 119 | { .lomax = 883000, .pd = 0x11, .d = 0x09 }, | ||
| 120 | { .lomax = 994000, .pd = 0x10, .d = 0x08 }, | ||
| 121 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
| 122 | }; | ||
| 123 | |||
| 124 | static struct tda18271_pll_map tda18271c1_cal_pll[] = { | ||
| 125 | { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, | ||
| 126 | { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, | ||
| 127 | { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, | ||
| 128 | { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, | ||
| 129 | { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, | ||
| 130 | { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, | ||
| 131 | { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, | ||
| 132 | { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, | ||
| 133 | { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, | ||
| 134 | { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, | ||
| 135 | { .lomax = 88000, .pd = 0xca, .d = 0x50 }, | ||
| 136 | { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, | ||
| 137 | { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, | ||
| 138 | { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, | ||
| 139 | { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, | ||
| 140 | { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, | ||
| 141 | { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, | ||
| 142 | { .lomax = 176000, .pd = 0xba, .d = 0x28 }, | ||
| 143 | { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, | ||
| 144 | { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, | ||
| 145 | { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, | ||
| 146 | { .lomax = 271000, .pd = 0xad, .d = 0x1a }, | ||
| 147 | { .lomax = 294000, .pd = 0xac, .d = 0x18 }, | ||
| 148 | { .lomax = 321000, .pd = 0xab, .d = 0x16 }, | ||
| 149 | { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, | ||
| 150 | { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, | ||
| 151 | { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, | ||
| 152 | { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, | ||
| 153 | { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, | ||
| 154 | { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, | ||
| 155 | { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, | ||
| 156 | { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, | ||
| 157 | { .lomax = 785000, .pd = 0x99, .d = 0x09 }, | ||
| 158 | { .lomax = 883000, .pd = 0x98, .d = 0x08 }, | ||
| 159 | { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, | ||
| 160 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
| 161 | }; | ||
| 162 | |||
| 163 | static struct tda18271_pll_map tda18271c2_cal_pll[] = { | ||
| 164 | { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, | ||
| 165 | { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, | ||
| 166 | { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, | ||
| 167 | { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, | ||
| 168 | { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, | ||
| 169 | { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, | ||
| 170 | { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, | ||
| 171 | { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, | ||
| 172 | { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, | ||
| 173 | { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, | ||
| 174 | { .lomax = 87875, .pd = 0xca, .d = 0x50 }, | ||
| 175 | { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, | ||
| 176 | { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, | ||
| 177 | { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, | ||
| 178 | { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, | ||
| 179 | { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, | ||
| 180 | { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, | ||
| 181 | { .lomax = 175750, .pd = 0xba, .d = 0x28 }, | ||
| 182 | { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, | ||
| 183 | { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, | ||
| 184 | { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, | ||
| 185 | { .lomax = 270500, .pd = 0xad, .d = 0x1a }, | ||
| 186 | { .lomax = 293000, .pd = 0xac, .d = 0x18 }, | ||
| 187 | { .lomax = 319500, .pd = 0xab, .d = 0x16 }, | ||
| 188 | { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, | ||
| 189 | { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, | ||
| 190 | { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, | ||
| 191 | { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, | ||
| 192 | { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, | ||
| 193 | { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, | ||
| 194 | { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, | ||
| 195 | { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, | ||
| 196 | { .lomax = 781000, .pd = 0x99, .d = 0x09 }, | ||
| 197 | { .lomax = 879000, .pd = 0x98, .d = 0x08 }, | ||
| 198 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
| 199 | }; | ||
| 200 | |||
| 201 | static struct tda18271_map tda18271_bp_filter[] = { | ||
| 202 | { .rfmax = 62000, .val = 0x00 }, | ||
| 203 | { .rfmax = 84000, .val = 0x01 }, | ||
| 204 | { .rfmax = 100000, .val = 0x02 }, | ||
| 205 | { .rfmax = 140000, .val = 0x03 }, | ||
| 206 | { .rfmax = 170000, .val = 0x04 }, | ||
| 207 | { .rfmax = 180000, .val = 0x05 }, | ||
| 208 | { .rfmax = 865000, .val = 0x06 }, | ||
| 209 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 210 | }; | ||
| 211 | |||
| 212 | static struct tda18271_map tda18271c1_km[] = { | ||
| 213 | { .rfmax = 61100, .val = 0x74 }, | ||
| 214 | { .rfmax = 350000, .val = 0x40 }, | ||
| 215 | { .rfmax = 720000, .val = 0x30 }, | ||
| 216 | { .rfmax = 865000, .val = 0x40 }, | ||
| 217 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 218 | }; | ||
| 219 | |||
| 220 | static struct tda18271_map tda18271c2_km[] = { | ||
| 221 | { .rfmax = 47900, .val = 0x38 }, | ||
| 222 | { .rfmax = 61100, .val = 0x44 }, | ||
| 223 | { .rfmax = 350000, .val = 0x30 }, | ||
| 224 | { .rfmax = 720000, .val = 0x24 }, | ||
| 225 | { .rfmax = 865000, .val = 0x3c }, | ||
| 226 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 227 | }; | ||
| 228 | |||
| 229 | static struct tda18271_map tda18271_rf_band[] = { | ||
| 230 | { .rfmax = 47900, .val = 0x00 }, | ||
| 231 | { .rfmax = 61100, .val = 0x01 }, | ||
| 232 | { .rfmax = 152600, .val = 0x02 }, | ||
| 233 | { .rfmax = 164700, .val = 0x03 }, | ||
| 234 | { .rfmax = 203500, .val = 0x04 }, | ||
| 235 | { .rfmax = 457800, .val = 0x05 }, | ||
| 236 | { .rfmax = 865000, .val = 0x06 }, | ||
| 237 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct tda18271_map tda18271_gain_taper[] = { | ||
| 241 | { .rfmax = 45400, .val = 0x1f }, | ||
| 242 | { .rfmax = 45800, .val = 0x1e }, | ||
| 243 | { .rfmax = 46200, .val = 0x1d }, | ||
| 244 | { .rfmax = 46700, .val = 0x1c }, | ||
| 245 | { .rfmax = 47100, .val = 0x1b }, | ||
| 246 | { .rfmax = 47500, .val = 0x1a }, | ||
| 247 | { .rfmax = 47900, .val = 0x19 }, | ||
| 248 | { .rfmax = 49600, .val = 0x17 }, | ||
| 249 | { .rfmax = 51200, .val = 0x16 }, | ||
| 250 | { .rfmax = 52900, .val = 0x15 }, | ||
| 251 | { .rfmax = 54500, .val = 0x14 }, | ||
| 252 | { .rfmax = 56200, .val = 0x13 }, | ||
| 253 | { .rfmax = 57800, .val = 0x12 }, | ||
| 254 | { .rfmax = 59500, .val = 0x11 }, | ||
| 255 | { .rfmax = 61100, .val = 0x10 }, | ||
| 256 | { .rfmax = 67600, .val = 0x0d }, | ||
| 257 | { .rfmax = 74200, .val = 0x0c }, | ||
| 258 | { .rfmax = 80700, .val = 0x0b }, | ||
| 259 | { .rfmax = 87200, .val = 0x0a }, | ||
| 260 | { .rfmax = 93800, .val = 0x09 }, | ||
| 261 | { .rfmax = 100300, .val = 0x08 }, | ||
| 262 | { .rfmax = 106900, .val = 0x07 }, | ||
| 263 | { .rfmax = 113400, .val = 0x06 }, | ||
| 264 | { .rfmax = 119900, .val = 0x05 }, | ||
| 265 | { .rfmax = 126500, .val = 0x04 }, | ||
| 266 | { .rfmax = 133000, .val = 0x03 }, | ||
| 267 | { .rfmax = 139500, .val = 0x02 }, | ||
| 268 | { .rfmax = 146100, .val = 0x01 }, | ||
| 269 | { .rfmax = 152600, .val = 0x00 }, | ||
| 270 | { .rfmax = 154300, .val = 0x1f }, | ||
| 271 | { .rfmax = 156100, .val = 0x1e }, | ||
| 272 | { .rfmax = 157800, .val = 0x1d }, | ||
| 273 | { .rfmax = 159500, .val = 0x1c }, | ||
| 274 | { .rfmax = 161200, .val = 0x1b }, | ||
| 275 | { .rfmax = 163000, .val = 0x1a }, | ||
| 276 | { .rfmax = 164700, .val = 0x19 }, | ||
| 277 | { .rfmax = 170200, .val = 0x17 }, | ||
| 278 | { .rfmax = 175800, .val = 0x16 }, | ||
| 279 | { .rfmax = 181300, .val = 0x15 }, | ||
| 280 | { .rfmax = 186900, .val = 0x14 }, | ||
| 281 | { .rfmax = 192400, .val = 0x13 }, | ||
| 282 | { .rfmax = 198000, .val = 0x12 }, | ||
| 283 | { .rfmax = 203500, .val = 0x11 }, | ||
| 284 | { .rfmax = 216200, .val = 0x14 }, | ||
| 285 | { .rfmax = 228900, .val = 0x13 }, | ||
| 286 | { .rfmax = 241600, .val = 0x12 }, | ||
| 287 | { .rfmax = 254400, .val = 0x11 }, | ||
| 288 | { .rfmax = 267100, .val = 0x10 }, | ||
| 289 | { .rfmax = 279800, .val = 0x0f }, | ||
| 290 | { .rfmax = 292500, .val = 0x0e }, | ||
| 291 | { .rfmax = 305200, .val = 0x0d }, | ||
| 292 | { .rfmax = 317900, .val = 0x0c }, | ||
| 293 | { .rfmax = 330700, .val = 0x0b }, | ||
| 294 | { .rfmax = 343400, .val = 0x0a }, | ||
| 295 | { .rfmax = 356100, .val = 0x09 }, | ||
| 296 | { .rfmax = 368800, .val = 0x08 }, | ||
| 297 | { .rfmax = 381500, .val = 0x07 }, | ||
| 298 | { .rfmax = 394200, .val = 0x06 }, | ||
| 299 | { .rfmax = 406900, .val = 0x05 }, | ||
| 300 | { .rfmax = 419700, .val = 0x04 }, | ||
| 301 | { .rfmax = 432400, .val = 0x03 }, | ||
| 302 | { .rfmax = 445100, .val = 0x02 }, | ||
| 303 | { .rfmax = 457800, .val = 0x01 }, | ||
| 304 | { .rfmax = 476300, .val = 0x19 }, | ||
| 305 | { .rfmax = 494800, .val = 0x18 }, | ||
| 306 | { .rfmax = 513300, .val = 0x17 }, | ||
| 307 | { .rfmax = 531800, .val = 0x16 }, | ||
| 308 | { .rfmax = 550300, .val = 0x15 }, | ||
| 309 | { .rfmax = 568900, .val = 0x14 }, | ||
| 310 | { .rfmax = 587400, .val = 0x13 }, | ||
| 311 | { .rfmax = 605900, .val = 0x12 }, | ||
| 312 | { .rfmax = 624400, .val = 0x11 }, | ||
| 313 | { .rfmax = 642900, .val = 0x10 }, | ||
| 314 | { .rfmax = 661400, .val = 0x0f }, | ||
| 315 | { .rfmax = 679900, .val = 0x0e }, | ||
| 316 | { .rfmax = 698400, .val = 0x0d }, | ||
| 317 | { .rfmax = 716900, .val = 0x0c }, | ||
| 318 | { .rfmax = 735400, .val = 0x0b }, | ||
| 319 | { .rfmax = 753900, .val = 0x0a }, | ||
| 320 | { .rfmax = 772500, .val = 0x09 }, | ||
| 321 | { .rfmax = 791000, .val = 0x08 }, | ||
| 322 | { .rfmax = 809500, .val = 0x07 }, | ||
| 323 | { .rfmax = 828000, .val = 0x06 }, | ||
| 324 | { .rfmax = 846500, .val = 0x05 }, | ||
| 325 | { .rfmax = 865000, .val = 0x04 }, | ||
| 326 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 327 | }; | ||
| 328 | |||
| 329 | static struct tda18271_map tda18271c1_rf_cal[] = { | ||
| 330 | { .rfmax = 41000, .val = 0x1e }, | ||
| 331 | { .rfmax = 43000, .val = 0x30 }, | ||
| 332 | { .rfmax = 45000, .val = 0x43 }, | ||
| 333 | { .rfmax = 46000, .val = 0x4d }, | ||
| 334 | { .rfmax = 47000, .val = 0x54 }, | ||
| 335 | { .rfmax = 47900, .val = 0x64 }, | ||
| 336 | { .rfmax = 49100, .val = 0x20 }, | ||
| 337 | { .rfmax = 50000, .val = 0x22 }, | ||
| 338 | { .rfmax = 51000, .val = 0x2a }, | ||
| 339 | { .rfmax = 53000, .val = 0x32 }, | ||
| 340 | { .rfmax = 55000, .val = 0x35 }, | ||
| 341 | { .rfmax = 56000, .val = 0x3c }, | ||
| 342 | { .rfmax = 57000, .val = 0x3f }, | ||
| 343 | { .rfmax = 58000, .val = 0x48 }, | ||
| 344 | { .rfmax = 59000, .val = 0x4d }, | ||
| 345 | { .rfmax = 60000, .val = 0x58 }, | ||
| 346 | { .rfmax = 61100, .val = 0x5f }, | ||
| 347 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 348 | }; | ||
| 349 | |||
| 350 | static struct tda18271_map tda18271c2_rf_cal[] = { | ||
| 351 | { .rfmax = 41000, .val = 0x0f }, | ||
| 352 | { .rfmax = 43000, .val = 0x1c }, | ||
| 353 | { .rfmax = 45000, .val = 0x2f }, | ||
| 354 | { .rfmax = 46000, .val = 0x39 }, | ||
| 355 | { .rfmax = 47000, .val = 0x40 }, | ||
| 356 | { .rfmax = 47900, .val = 0x50 }, | ||
| 357 | { .rfmax = 49100, .val = 0x16 }, | ||
| 358 | { .rfmax = 50000, .val = 0x18 }, | ||
| 359 | { .rfmax = 51000, .val = 0x20 }, | ||
| 360 | { .rfmax = 53000, .val = 0x28 }, | ||
| 361 | { .rfmax = 55000, .val = 0x2b }, | ||
| 362 | { .rfmax = 56000, .val = 0x32 }, | ||
| 363 | { .rfmax = 57000, .val = 0x35 }, | ||
| 364 | { .rfmax = 58000, .val = 0x3e }, | ||
| 365 | { .rfmax = 59000, .val = 0x43 }, | ||
| 366 | { .rfmax = 60000, .val = 0x4e }, | ||
| 367 | { .rfmax = 61100, .val = 0x55 }, | ||
| 368 | { .rfmax = 63000, .val = 0x0f }, | ||
| 369 | { .rfmax = 64000, .val = 0x11 }, | ||
| 370 | { .rfmax = 65000, .val = 0x12 }, | ||
| 371 | { .rfmax = 66000, .val = 0x15 }, | ||
| 372 | { .rfmax = 67000, .val = 0x16 }, | ||
| 373 | { .rfmax = 68000, .val = 0x17 }, | ||
| 374 | { .rfmax = 70000, .val = 0x19 }, | ||
| 375 | { .rfmax = 71000, .val = 0x1c }, | ||
| 376 | { .rfmax = 72000, .val = 0x1d }, | ||
| 377 | { .rfmax = 73000, .val = 0x1f }, | ||
| 378 | { .rfmax = 74000, .val = 0x20 }, | ||
| 379 | { .rfmax = 75000, .val = 0x21 }, | ||
| 380 | { .rfmax = 76000, .val = 0x24 }, | ||
| 381 | { .rfmax = 77000, .val = 0x25 }, | ||
| 382 | { .rfmax = 78000, .val = 0x27 }, | ||
| 383 | { .rfmax = 80000, .val = 0x28 }, | ||
| 384 | { .rfmax = 81000, .val = 0x29 }, | ||
| 385 | { .rfmax = 82000, .val = 0x2d }, | ||
| 386 | { .rfmax = 83000, .val = 0x2e }, | ||
| 387 | { .rfmax = 84000, .val = 0x2f }, | ||
| 388 | { .rfmax = 85000, .val = 0x31 }, | ||
| 389 | { .rfmax = 86000, .val = 0x33 }, | ||
| 390 | { .rfmax = 87000, .val = 0x34 }, | ||
| 391 | { .rfmax = 88000, .val = 0x35 }, | ||
| 392 | { .rfmax = 89000, .val = 0x37 }, | ||
| 393 | { .rfmax = 90000, .val = 0x38 }, | ||
| 394 | { .rfmax = 91000, .val = 0x39 }, | ||
| 395 | { .rfmax = 93000, .val = 0x3c }, | ||
| 396 | { .rfmax = 94000, .val = 0x3e }, | ||
| 397 | { .rfmax = 95000, .val = 0x3f }, | ||
| 398 | { .rfmax = 96000, .val = 0x40 }, | ||
| 399 | { .rfmax = 97000, .val = 0x42 }, | ||
| 400 | { .rfmax = 99000, .val = 0x45 }, | ||
| 401 | { .rfmax = 100000, .val = 0x46 }, | ||
| 402 | { .rfmax = 102000, .val = 0x48 }, | ||
| 403 | { .rfmax = 103000, .val = 0x4a }, | ||
| 404 | { .rfmax = 105000, .val = 0x4d }, | ||
| 405 | { .rfmax = 106000, .val = 0x4e }, | ||
| 406 | { .rfmax = 107000, .val = 0x50 }, | ||
| 407 | { .rfmax = 108000, .val = 0x51 }, | ||
| 408 | { .rfmax = 110000, .val = 0x54 }, | ||
| 409 | { .rfmax = 111000, .val = 0x56 }, | ||
| 410 | { .rfmax = 112000, .val = 0x57 }, | ||
| 411 | { .rfmax = 113000, .val = 0x58 }, | ||
| 412 | { .rfmax = 114000, .val = 0x59 }, | ||
| 413 | { .rfmax = 115000, .val = 0x5c }, | ||
| 414 | { .rfmax = 116000, .val = 0x5d }, | ||
| 415 | { .rfmax = 117000, .val = 0x5f }, | ||
| 416 | { .rfmax = 119000, .val = 0x60 }, | ||
| 417 | { .rfmax = 120000, .val = 0x64 }, | ||
| 418 | { .rfmax = 121000, .val = 0x65 }, | ||
| 419 | { .rfmax = 122000, .val = 0x66 }, | ||
| 420 | { .rfmax = 123000, .val = 0x68 }, | ||
| 421 | { .rfmax = 124000, .val = 0x69 }, | ||
| 422 | { .rfmax = 125000, .val = 0x6c }, | ||
| 423 | { .rfmax = 126000, .val = 0x6d }, | ||
| 424 | { .rfmax = 127000, .val = 0x6e }, | ||
| 425 | { .rfmax = 128000, .val = 0x70 }, | ||
| 426 | { .rfmax = 129000, .val = 0x71 }, | ||
| 427 | { .rfmax = 130000, .val = 0x75 }, | ||
| 428 | { .rfmax = 131000, .val = 0x77 }, | ||
| 429 | { .rfmax = 132000, .val = 0x78 }, | ||
| 430 | { .rfmax = 133000, .val = 0x7b }, | ||
| 431 | { .rfmax = 134000, .val = 0x7e }, | ||
| 432 | { .rfmax = 135000, .val = 0x81 }, | ||
| 433 | { .rfmax = 136000, .val = 0x82 }, | ||
| 434 | { .rfmax = 137000, .val = 0x87 }, | ||
| 435 | { .rfmax = 138000, .val = 0x88 }, | ||
| 436 | { .rfmax = 139000, .val = 0x8d }, | ||
| 437 | { .rfmax = 140000, .val = 0x8e }, | ||
| 438 | { .rfmax = 141000, .val = 0x91 }, | ||
| 439 | { .rfmax = 142000, .val = 0x95 }, | ||
| 440 | { .rfmax = 143000, .val = 0x9a }, | ||
| 441 | { .rfmax = 144000, .val = 0x9d }, | ||
| 442 | { .rfmax = 145000, .val = 0xa1 }, | ||
| 443 | { .rfmax = 146000, .val = 0xa2 }, | ||
| 444 | { .rfmax = 147000, .val = 0xa4 }, | ||
| 445 | { .rfmax = 148000, .val = 0xa9 }, | ||
| 446 | { .rfmax = 149000, .val = 0xae }, | ||
| 447 | { .rfmax = 150000, .val = 0xb0 }, | ||
| 448 | { .rfmax = 151000, .val = 0xb1 }, | ||
| 449 | { .rfmax = 152000, .val = 0xb7 }, | ||
| 450 | { .rfmax = 152600, .val = 0xbd }, | ||
| 451 | { .rfmax = 154000, .val = 0x20 }, | ||
| 452 | { .rfmax = 155000, .val = 0x22 }, | ||
| 453 | { .rfmax = 156000, .val = 0x24 }, | ||
| 454 | { .rfmax = 157000, .val = 0x25 }, | ||
| 455 | { .rfmax = 158000, .val = 0x27 }, | ||
| 456 | { .rfmax = 159000, .val = 0x29 }, | ||
| 457 | { .rfmax = 160000, .val = 0x2c }, | ||
| 458 | { .rfmax = 161000, .val = 0x2d }, | ||
| 459 | { .rfmax = 163000, .val = 0x2e }, | ||
| 460 | { .rfmax = 164000, .val = 0x2f }, | ||
| 461 | { .rfmax = 164700, .val = 0x30 }, | ||
| 462 | { .rfmax = 166000, .val = 0x11 }, | ||
| 463 | { .rfmax = 167000, .val = 0x12 }, | ||
| 464 | { .rfmax = 168000, .val = 0x13 }, | ||
| 465 | { .rfmax = 169000, .val = 0x14 }, | ||
| 466 | { .rfmax = 170000, .val = 0x15 }, | ||
| 467 | { .rfmax = 172000, .val = 0x16 }, | ||
| 468 | { .rfmax = 173000, .val = 0x17 }, | ||
| 469 | { .rfmax = 174000, .val = 0x18 }, | ||
| 470 | { .rfmax = 175000, .val = 0x1a }, | ||
| 471 | { .rfmax = 176000, .val = 0x1b }, | ||
| 472 | { .rfmax = 178000, .val = 0x1d }, | ||
| 473 | { .rfmax = 179000, .val = 0x1e }, | ||
| 474 | { .rfmax = 180000, .val = 0x1f }, | ||
| 475 | { .rfmax = 181000, .val = 0x20 }, | ||
| 476 | { .rfmax = 182000, .val = 0x21 }, | ||
| 477 | { .rfmax = 183000, .val = 0x22 }, | ||
| 478 | { .rfmax = 184000, .val = 0x24 }, | ||
| 479 | { .rfmax = 185000, .val = 0x25 }, | ||
| 480 | { .rfmax = 186000, .val = 0x26 }, | ||
| 481 | { .rfmax = 187000, .val = 0x27 }, | ||
| 482 | { .rfmax = 188000, .val = 0x29 }, | ||
| 483 | { .rfmax = 189000, .val = 0x2a }, | ||
| 484 | { .rfmax = 190000, .val = 0x2c }, | ||
| 485 | { .rfmax = 191000, .val = 0x2d }, | ||
| 486 | { .rfmax = 192000, .val = 0x2e }, | ||
| 487 | { .rfmax = 193000, .val = 0x2f }, | ||
| 488 | { .rfmax = 194000, .val = 0x30 }, | ||
| 489 | { .rfmax = 195000, .val = 0x33 }, | ||
| 490 | { .rfmax = 196000, .val = 0x35 }, | ||
| 491 | { .rfmax = 198000, .val = 0x36 }, | ||
| 492 | { .rfmax = 200000, .val = 0x38 }, | ||
| 493 | { .rfmax = 201000, .val = 0x3c }, | ||
| 494 | { .rfmax = 202000, .val = 0x3d }, | ||
| 495 | { .rfmax = 203500, .val = 0x3e }, | ||
| 496 | { .rfmax = 206000, .val = 0x0e }, | ||
| 497 | { .rfmax = 208000, .val = 0x0f }, | ||
| 498 | { .rfmax = 212000, .val = 0x10 }, | ||
| 499 | { .rfmax = 216000, .val = 0x11 }, | ||
| 500 | { .rfmax = 217000, .val = 0x12 }, | ||
| 501 | { .rfmax = 218000, .val = 0x13 }, | ||
| 502 | { .rfmax = 220000, .val = 0x14 }, | ||
| 503 | { .rfmax = 222000, .val = 0x15 }, | ||
| 504 | { .rfmax = 225000, .val = 0x16 }, | ||
| 505 | { .rfmax = 228000, .val = 0x17 }, | ||
| 506 | { .rfmax = 231000, .val = 0x18 }, | ||
| 507 | { .rfmax = 234000, .val = 0x19 }, | ||
| 508 | { .rfmax = 235000, .val = 0x1a }, | ||
| 509 | { .rfmax = 236000, .val = 0x1b }, | ||
| 510 | { .rfmax = 237000, .val = 0x1c }, | ||
| 511 | { .rfmax = 240000, .val = 0x1d }, | ||
| 512 | { .rfmax = 242000, .val = 0x1e }, | ||
| 513 | { .rfmax = 244000, .val = 0x1f }, | ||
| 514 | { .rfmax = 247000, .val = 0x20 }, | ||
| 515 | { .rfmax = 249000, .val = 0x21 }, | ||
| 516 | { .rfmax = 252000, .val = 0x22 }, | ||
| 517 | { .rfmax = 253000, .val = 0x23 }, | ||
| 518 | { .rfmax = 254000, .val = 0x24 }, | ||
| 519 | { .rfmax = 256000, .val = 0x25 }, | ||
| 520 | { .rfmax = 259000, .val = 0x26 }, | ||
| 521 | { .rfmax = 262000, .val = 0x27 }, | ||
| 522 | { .rfmax = 264000, .val = 0x28 }, | ||
| 523 | { .rfmax = 267000, .val = 0x29 }, | ||
| 524 | { .rfmax = 269000, .val = 0x2a }, | ||
| 525 | { .rfmax = 271000, .val = 0x2b }, | ||
| 526 | { .rfmax = 273000, .val = 0x2c }, | ||
| 527 | { .rfmax = 275000, .val = 0x2d }, | ||
| 528 | { .rfmax = 277000, .val = 0x2e }, | ||
| 529 | { .rfmax = 279000, .val = 0x2f }, | ||
| 530 | { .rfmax = 282000, .val = 0x30 }, | ||
| 531 | { .rfmax = 284000, .val = 0x31 }, | ||
| 532 | { .rfmax = 286000, .val = 0x32 }, | ||
| 533 | { .rfmax = 287000, .val = 0x33 }, | ||
| 534 | { .rfmax = 290000, .val = 0x34 }, | ||
| 535 | { .rfmax = 293000, .val = 0x35 }, | ||
| 536 | { .rfmax = 295000, .val = 0x36 }, | ||
| 537 | { .rfmax = 297000, .val = 0x37 }, | ||
| 538 | { .rfmax = 300000, .val = 0x38 }, | ||
| 539 | { .rfmax = 303000, .val = 0x39 }, | ||
| 540 | { .rfmax = 305000, .val = 0x3a }, | ||
| 541 | { .rfmax = 306000, .val = 0x3b }, | ||
| 542 | { .rfmax = 307000, .val = 0x3c }, | ||
| 543 | { .rfmax = 310000, .val = 0x3d }, | ||
| 544 | { .rfmax = 312000, .val = 0x3e }, | ||
| 545 | { .rfmax = 315000, .val = 0x3f }, | ||
| 546 | { .rfmax = 318000, .val = 0x40 }, | ||
| 547 | { .rfmax = 320000, .val = 0x41 }, | ||
| 548 | { .rfmax = 323000, .val = 0x42 }, | ||
| 549 | { .rfmax = 324000, .val = 0x43 }, | ||
| 550 | { .rfmax = 325000, .val = 0x44 }, | ||
| 551 | { .rfmax = 327000, .val = 0x45 }, | ||
| 552 | { .rfmax = 331000, .val = 0x46 }, | ||
| 553 | { .rfmax = 334000, .val = 0x47 }, | ||
| 554 | { .rfmax = 337000, .val = 0x48 }, | ||
| 555 | { .rfmax = 339000, .val = 0x49 }, | ||
| 556 | { .rfmax = 340000, .val = 0x4a }, | ||
| 557 | { .rfmax = 341000, .val = 0x4b }, | ||
| 558 | { .rfmax = 343000, .val = 0x4c }, | ||
| 559 | { .rfmax = 345000, .val = 0x4d }, | ||
| 560 | { .rfmax = 349000, .val = 0x4e }, | ||
| 561 | { .rfmax = 352000, .val = 0x4f }, | ||
| 562 | { .rfmax = 353000, .val = 0x50 }, | ||
| 563 | { .rfmax = 355000, .val = 0x51 }, | ||
| 564 | { .rfmax = 357000, .val = 0x52 }, | ||
| 565 | { .rfmax = 359000, .val = 0x53 }, | ||
| 566 | { .rfmax = 361000, .val = 0x54 }, | ||
| 567 | { .rfmax = 362000, .val = 0x55 }, | ||
| 568 | { .rfmax = 364000, .val = 0x56 }, | ||
| 569 | { .rfmax = 368000, .val = 0x57 }, | ||
| 570 | { .rfmax = 370000, .val = 0x58 }, | ||
| 571 | { .rfmax = 372000, .val = 0x59 }, | ||
| 572 | { .rfmax = 375000, .val = 0x5a }, | ||
| 573 | { .rfmax = 376000, .val = 0x5b }, | ||
| 574 | { .rfmax = 377000, .val = 0x5c }, | ||
| 575 | { .rfmax = 379000, .val = 0x5d }, | ||
| 576 | { .rfmax = 382000, .val = 0x5e }, | ||
| 577 | { .rfmax = 384000, .val = 0x5f }, | ||
| 578 | { .rfmax = 385000, .val = 0x60 }, | ||
| 579 | { .rfmax = 386000, .val = 0x61 }, | ||
| 580 | { .rfmax = 388000, .val = 0x62 }, | ||
| 581 | { .rfmax = 390000, .val = 0x63 }, | ||
| 582 | { .rfmax = 393000, .val = 0x64 }, | ||
| 583 | { .rfmax = 394000, .val = 0x65 }, | ||
| 584 | { .rfmax = 396000, .val = 0x66 }, | ||
| 585 | { .rfmax = 397000, .val = 0x67 }, | ||
| 586 | { .rfmax = 398000, .val = 0x68 }, | ||
| 587 | { .rfmax = 400000, .val = 0x69 }, | ||
| 588 | { .rfmax = 402000, .val = 0x6a }, | ||
| 589 | { .rfmax = 403000, .val = 0x6b }, | ||
| 590 | { .rfmax = 407000, .val = 0x6c }, | ||
| 591 | { .rfmax = 408000, .val = 0x6d }, | ||
| 592 | { .rfmax = 409000, .val = 0x6e }, | ||
| 593 | { .rfmax = 410000, .val = 0x6f }, | ||
| 594 | { .rfmax = 411000, .val = 0x70 }, | ||
| 595 | { .rfmax = 412000, .val = 0x71 }, | ||
| 596 | { .rfmax = 413000, .val = 0x72 }, | ||
| 597 | { .rfmax = 414000, .val = 0x73 }, | ||
| 598 | { .rfmax = 417000, .val = 0x74 }, | ||
| 599 | { .rfmax = 418000, .val = 0x75 }, | ||
| 600 | { .rfmax = 420000, .val = 0x76 }, | ||
| 601 | { .rfmax = 422000, .val = 0x77 }, | ||
| 602 | { .rfmax = 423000, .val = 0x78 }, | ||
| 603 | { .rfmax = 424000, .val = 0x79 }, | ||
| 604 | { .rfmax = 427000, .val = 0x7a }, | ||
| 605 | { .rfmax = 428000, .val = 0x7b }, | ||
| 606 | { .rfmax = 429000, .val = 0x7d }, | ||
| 607 | { .rfmax = 432000, .val = 0x7f }, | ||
| 608 | { .rfmax = 434000, .val = 0x80 }, | ||
| 609 | { .rfmax = 435000, .val = 0x81 }, | ||
| 610 | { .rfmax = 436000, .val = 0x83 }, | ||
| 611 | { .rfmax = 437000, .val = 0x84 }, | ||
| 612 | { .rfmax = 438000, .val = 0x85 }, | ||
| 613 | { .rfmax = 439000, .val = 0x86 }, | ||
| 614 | { .rfmax = 440000, .val = 0x87 }, | ||
| 615 | { .rfmax = 441000, .val = 0x88 }, | ||
| 616 | { .rfmax = 442000, .val = 0x89 }, | ||
| 617 | { .rfmax = 445000, .val = 0x8a }, | ||
| 618 | { .rfmax = 446000, .val = 0x8b }, | ||
| 619 | { .rfmax = 447000, .val = 0x8c }, | ||
| 620 | { .rfmax = 448000, .val = 0x8e }, | ||
| 621 | { .rfmax = 449000, .val = 0x8f }, | ||
| 622 | { .rfmax = 450000, .val = 0x90 }, | ||
| 623 | { .rfmax = 452000, .val = 0x91 }, | ||
| 624 | { .rfmax = 453000, .val = 0x93 }, | ||
| 625 | { .rfmax = 454000, .val = 0x94 }, | ||
| 626 | { .rfmax = 456000, .val = 0x96 }, | ||
| 627 | { .rfmax = 457800, .val = 0x98 }, | ||
| 628 | { .rfmax = 461000, .val = 0x11 }, | ||
| 629 | { .rfmax = 468000, .val = 0x12 }, | ||
| 630 | { .rfmax = 472000, .val = 0x13 }, | ||
| 631 | { .rfmax = 473000, .val = 0x14 }, | ||
| 632 | { .rfmax = 474000, .val = 0x15 }, | ||
| 633 | { .rfmax = 481000, .val = 0x16 }, | ||
| 634 | { .rfmax = 486000, .val = 0x17 }, | ||
| 635 | { .rfmax = 491000, .val = 0x18 }, | ||
| 636 | { .rfmax = 498000, .val = 0x19 }, | ||
| 637 | { .rfmax = 499000, .val = 0x1a }, | ||
| 638 | { .rfmax = 501000, .val = 0x1b }, | ||
| 639 | { .rfmax = 506000, .val = 0x1c }, | ||
| 640 | { .rfmax = 511000, .val = 0x1d }, | ||
| 641 | { .rfmax = 516000, .val = 0x1e }, | ||
| 642 | { .rfmax = 520000, .val = 0x1f }, | ||
| 643 | { .rfmax = 521000, .val = 0x20 }, | ||
| 644 | { .rfmax = 525000, .val = 0x21 }, | ||
| 645 | { .rfmax = 529000, .val = 0x22 }, | ||
| 646 | { .rfmax = 533000, .val = 0x23 }, | ||
| 647 | { .rfmax = 539000, .val = 0x24 }, | ||
| 648 | { .rfmax = 541000, .val = 0x25 }, | ||
| 649 | { .rfmax = 547000, .val = 0x26 }, | ||
| 650 | { .rfmax = 549000, .val = 0x27 }, | ||
| 651 | { .rfmax = 551000, .val = 0x28 }, | ||
| 652 | { .rfmax = 556000, .val = 0x29 }, | ||
| 653 | { .rfmax = 561000, .val = 0x2a }, | ||
| 654 | { .rfmax = 563000, .val = 0x2b }, | ||
| 655 | { .rfmax = 565000, .val = 0x2c }, | ||
| 656 | { .rfmax = 569000, .val = 0x2d }, | ||
| 657 | { .rfmax = 571000, .val = 0x2e }, | ||
| 658 | { .rfmax = 577000, .val = 0x2f }, | ||
| 659 | { .rfmax = 580000, .val = 0x30 }, | ||
| 660 | { .rfmax = 582000, .val = 0x31 }, | ||
| 661 | { .rfmax = 584000, .val = 0x32 }, | ||
| 662 | { .rfmax = 588000, .val = 0x33 }, | ||
| 663 | { .rfmax = 591000, .val = 0x34 }, | ||
| 664 | { .rfmax = 596000, .val = 0x35 }, | ||
| 665 | { .rfmax = 598000, .val = 0x36 }, | ||
| 666 | { .rfmax = 603000, .val = 0x37 }, | ||
| 667 | { .rfmax = 604000, .val = 0x38 }, | ||
| 668 | { .rfmax = 606000, .val = 0x39 }, | ||
| 669 | { .rfmax = 612000, .val = 0x3a }, | ||
| 670 | { .rfmax = 615000, .val = 0x3b }, | ||
| 671 | { .rfmax = 617000, .val = 0x3c }, | ||
| 672 | { .rfmax = 621000, .val = 0x3d }, | ||
| 673 | { .rfmax = 622000, .val = 0x3e }, | ||
| 674 | { .rfmax = 625000, .val = 0x3f }, | ||
| 675 | { .rfmax = 632000, .val = 0x40 }, | ||
| 676 | { .rfmax = 633000, .val = 0x41 }, | ||
| 677 | { .rfmax = 634000, .val = 0x42 }, | ||
| 678 | { .rfmax = 642000, .val = 0x43 }, | ||
| 679 | { .rfmax = 643000, .val = 0x44 }, | ||
| 680 | { .rfmax = 647000, .val = 0x45 }, | ||
| 681 | { .rfmax = 650000, .val = 0x46 }, | ||
| 682 | { .rfmax = 652000, .val = 0x47 }, | ||
| 683 | { .rfmax = 657000, .val = 0x48 }, | ||
| 684 | { .rfmax = 661000, .val = 0x49 }, | ||
| 685 | { .rfmax = 662000, .val = 0x4a }, | ||
| 686 | { .rfmax = 665000, .val = 0x4b }, | ||
| 687 | { .rfmax = 667000, .val = 0x4c }, | ||
| 688 | { .rfmax = 670000, .val = 0x4d }, | ||
| 689 | { .rfmax = 673000, .val = 0x4e }, | ||
| 690 | { .rfmax = 676000, .val = 0x4f }, | ||
| 691 | { .rfmax = 677000, .val = 0x50 }, | ||
| 692 | { .rfmax = 681000, .val = 0x51 }, | ||
| 693 | { .rfmax = 683000, .val = 0x52 }, | ||
| 694 | { .rfmax = 686000, .val = 0x53 }, | ||
| 695 | { .rfmax = 688000, .val = 0x54 }, | ||
| 696 | { .rfmax = 689000, .val = 0x55 }, | ||
| 697 | { .rfmax = 691000, .val = 0x56 }, | ||
| 698 | { .rfmax = 695000, .val = 0x57 }, | ||
| 699 | { .rfmax = 698000, .val = 0x58 }, | ||
| 700 | { .rfmax = 703000, .val = 0x59 }, | ||
| 701 | { .rfmax = 704000, .val = 0x5a }, | ||
| 702 | { .rfmax = 705000, .val = 0x5b }, | ||
| 703 | { .rfmax = 707000, .val = 0x5c }, | ||
| 704 | { .rfmax = 710000, .val = 0x5d }, | ||
| 705 | { .rfmax = 712000, .val = 0x5e }, | ||
| 706 | { .rfmax = 717000, .val = 0x5f }, | ||
| 707 | { .rfmax = 718000, .val = 0x60 }, | ||
| 708 | { .rfmax = 721000, .val = 0x61 }, | ||
| 709 | { .rfmax = 722000, .val = 0x62 }, | ||
| 710 | { .rfmax = 723000, .val = 0x63 }, | ||
| 711 | { .rfmax = 725000, .val = 0x64 }, | ||
| 712 | { .rfmax = 727000, .val = 0x65 }, | ||
| 713 | { .rfmax = 730000, .val = 0x66 }, | ||
| 714 | { .rfmax = 732000, .val = 0x67 }, | ||
| 715 | { .rfmax = 735000, .val = 0x68 }, | ||
| 716 | { .rfmax = 740000, .val = 0x69 }, | ||
| 717 | { .rfmax = 741000, .val = 0x6a }, | ||
| 718 | { .rfmax = 742000, .val = 0x6b }, | ||
| 719 | { .rfmax = 743000, .val = 0x6c }, | ||
| 720 | { .rfmax = 745000, .val = 0x6d }, | ||
| 721 | { .rfmax = 747000, .val = 0x6e }, | ||
| 722 | { .rfmax = 748000, .val = 0x6f }, | ||
| 723 | { .rfmax = 750000, .val = 0x70 }, | ||
| 724 | { .rfmax = 752000, .val = 0x71 }, | ||
| 725 | { .rfmax = 754000, .val = 0x72 }, | ||
| 726 | { .rfmax = 757000, .val = 0x73 }, | ||
| 727 | { .rfmax = 758000, .val = 0x74 }, | ||
| 728 | { .rfmax = 760000, .val = 0x75 }, | ||
| 729 | { .rfmax = 763000, .val = 0x76 }, | ||
| 730 | { .rfmax = 764000, .val = 0x77 }, | ||
| 731 | { .rfmax = 766000, .val = 0x78 }, | ||
| 732 | { .rfmax = 767000, .val = 0x79 }, | ||
| 733 | { .rfmax = 768000, .val = 0x7a }, | ||
| 734 | { .rfmax = 773000, .val = 0x7b }, | ||
| 735 | { .rfmax = 774000, .val = 0x7c }, | ||
| 736 | { .rfmax = 776000, .val = 0x7d }, | ||
| 737 | { .rfmax = 777000, .val = 0x7e }, | ||
| 738 | { .rfmax = 778000, .val = 0x7f }, | ||
| 739 | { .rfmax = 779000, .val = 0x80 }, | ||
| 740 | { .rfmax = 781000, .val = 0x81 }, | ||
| 741 | { .rfmax = 783000, .val = 0x82 }, | ||
| 742 | { .rfmax = 784000, .val = 0x83 }, | ||
| 743 | { .rfmax = 785000, .val = 0x84 }, | ||
| 744 | { .rfmax = 786000, .val = 0x85 }, | ||
| 745 | { .rfmax = 793000, .val = 0x86 }, | ||
| 746 | { .rfmax = 794000, .val = 0x87 }, | ||
| 747 | { .rfmax = 795000, .val = 0x88 }, | ||
| 748 | { .rfmax = 797000, .val = 0x89 }, | ||
| 749 | { .rfmax = 799000, .val = 0x8a }, | ||
| 750 | { .rfmax = 801000, .val = 0x8b }, | ||
| 751 | { .rfmax = 802000, .val = 0x8c }, | ||
| 752 | { .rfmax = 803000, .val = 0x8d }, | ||
| 753 | { .rfmax = 804000, .val = 0x8e }, | ||
| 754 | { .rfmax = 810000, .val = 0x90 }, | ||
| 755 | { .rfmax = 811000, .val = 0x91 }, | ||
| 756 | { .rfmax = 812000, .val = 0x92 }, | ||
| 757 | { .rfmax = 814000, .val = 0x93 }, | ||
| 758 | { .rfmax = 816000, .val = 0x94 }, | ||
| 759 | { .rfmax = 817000, .val = 0x96 }, | ||
| 760 | { .rfmax = 818000, .val = 0x97 }, | ||
| 761 | { .rfmax = 820000, .val = 0x98 }, | ||
| 762 | { .rfmax = 821000, .val = 0x99 }, | ||
| 763 | { .rfmax = 822000, .val = 0x9a }, | ||
| 764 | { .rfmax = 828000, .val = 0x9b }, | ||
| 765 | { .rfmax = 829000, .val = 0x9d }, | ||
| 766 | { .rfmax = 830000, .val = 0x9f }, | ||
| 767 | { .rfmax = 831000, .val = 0xa0 }, | ||
| 768 | { .rfmax = 833000, .val = 0xa1 }, | ||
| 769 | { .rfmax = 835000, .val = 0xa2 }, | ||
| 770 | { .rfmax = 836000, .val = 0xa3 }, | ||
| 771 | { .rfmax = 837000, .val = 0xa4 }, | ||
| 772 | { .rfmax = 838000, .val = 0xa6 }, | ||
| 773 | { .rfmax = 840000, .val = 0xa8 }, | ||
| 774 | { .rfmax = 842000, .val = 0xa9 }, | ||
| 775 | { .rfmax = 845000, .val = 0xaa }, | ||
| 776 | { .rfmax = 846000, .val = 0xab }, | ||
| 777 | { .rfmax = 847000, .val = 0xad }, | ||
| 778 | { .rfmax = 848000, .val = 0xae }, | ||
| 779 | { .rfmax = 852000, .val = 0xaf }, | ||
| 780 | { .rfmax = 853000, .val = 0xb0 }, | ||
| 781 | { .rfmax = 858000, .val = 0xb1 }, | ||
| 782 | { .rfmax = 860000, .val = 0xb2 }, | ||
| 783 | { .rfmax = 861000, .val = 0xb3 }, | ||
| 784 | { .rfmax = 862000, .val = 0xb4 }, | ||
| 785 | { .rfmax = 863000, .val = 0xb6 }, | ||
| 786 | { .rfmax = 864000, .val = 0xb8 }, | ||
| 787 | { .rfmax = 865000, .val = 0xb9 }, | ||
| 788 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 789 | }; | ||
| 790 | |||
| 791 | static struct tda18271_map tda18271_ir_measure[] = { | ||
| 792 | { .rfmax = 30000, .val = 4 }, | ||
| 793 | { .rfmax = 200000, .val = 5 }, | ||
| 794 | { .rfmax = 600000, .val = 6 }, | ||
| 795 | { .rfmax = 865000, .val = 7 }, | ||
| 796 | { .rfmax = 0, .val = 0 }, /* end */ | ||
| 797 | }; | ||
| 798 | |||
| 799 | static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { | ||
| 800 | { .rfmax = 47900, .val = 0x00 }, | ||
| 801 | { .rfmax = 55000, .val = 0x00 }, | ||
| 802 | { .rfmax = 61100, .val = 0x0a }, | ||
| 803 | { .rfmax = 64000, .val = 0x0a }, | ||
| 804 | { .rfmax = 82000, .val = 0x14 }, | ||
| 805 | { .rfmax = 84000, .val = 0x19 }, | ||
| 806 | { .rfmax = 119000, .val = 0x1c }, | ||
| 807 | { .rfmax = 124000, .val = 0x20 }, | ||
| 808 | { .rfmax = 129000, .val = 0x2a }, | ||
| 809 | { .rfmax = 134000, .val = 0x32 }, | ||
| 810 | { .rfmax = 139000, .val = 0x39 }, | ||
| 811 | { .rfmax = 144000, .val = 0x3e }, | ||
| 812 | { .rfmax = 149000, .val = 0x3f }, | ||
| 813 | { .rfmax = 152600, .val = 0x40 }, | ||
| 814 | { .rfmax = 154000, .val = 0x40 }, | ||
| 815 | { .rfmax = 164700, .val = 0x41 }, | ||
| 816 | { .rfmax = 203500, .val = 0x32 }, | ||
| 817 | { .rfmax = 353000, .val = 0x19 }, | ||
| 818 | { .rfmax = 356000, .val = 0x1a }, | ||
| 819 | { .rfmax = 359000, .val = 0x1b }, | ||
| 820 | { .rfmax = 363000, .val = 0x1c }, | ||
| 821 | { .rfmax = 366000, .val = 0x1d }, | ||
| 822 | { .rfmax = 369000, .val = 0x1e }, | ||
| 823 | { .rfmax = 373000, .val = 0x1f }, | ||
| 824 | { .rfmax = 376000, .val = 0x20 }, | ||
| 825 | { .rfmax = 379000, .val = 0x21 }, | ||
| 826 | { .rfmax = 383000, .val = 0x22 }, | ||
| 827 | { .rfmax = 386000, .val = 0x23 }, | ||
| 828 | { .rfmax = 389000, .val = 0x24 }, | ||
| 829 | { .rfmax = 393000, .val = 0x25 }, | ||
| 830 | { .rfmax = 396000, .val = 0x26 }, | ||
| 831 | { .rfmax = 399000, .val = 0x27 }, | ||
| 832 | { .rfmax = 402000, .val = 0x28 }, | ||
| 833 | { .rfmax = 404000, .val = 0x29 }, | ||
| 834 | { .rfmax = 407000, .val = 0x2a }, | ||
| 835 | { .rfmax = 409000, .val = 0x2b }, | ||
| 836 | { .rfmax = 412000, .val = 0x2c }, | ||
| 837 | { .rfmax = 414000, .val = 0x2d }, | ||
| 838 | { .rfmax = 417000, .val = 0x2e }, | ||
| 839 | { .rfmax = 419000, .val = 0x2f }, | ||
| 840 | { .rfmax = 422000, .val = 0x30 }, | ||
| 841 | { .rfmax = 424000, .val = 0x31 }, | ||
| 842 | { .rfmax = 427000, .val = 0x32 }, | ||
| 843 | { .rfmax = 429000, .val = 0x33 }, | ||
| 844 | { .rfmax = 432000, .val = 0x34 }, | ||
| 845 | { .rfmax = 434000, .val = 0x35 }, | ||
| 846 | { .rfmax = 437000, .val = 0x36 }, | ||
| 847 | { .rfmax = 439000, .val = 0x37 }, | ||
| 848 | { .rfmax = 442000, .val = 0x38 }, | ||
| 849 | { .rfmax = 444000, .val = 0x39 }, | ||
| 850 | { .rfmax = 447000, .val = 0x3a }, | ||
| 851 | { .rfmax = 449000, .val = 0x3b }, | ||
| 852 | { .rfmax = 457800, .val = 0x3c }, | ||
| 853 | { .rfmax = 465000, .val = 0x0f }, | ||
| 854 | { .rfmax = 477000, .val = 0x12 }, | ||
| 855 | { .rfmax = 483000, .val = 0x14 }, | ||
| 856 | { .rfmax = 502000, .val = 0x19 }, | ||
| 857 | { .rfmax = 508000, .val = 0x1b }, | ||
| 858 | { .rfmax = 519000, .val = 0x1c }, | ||
| 859 | { .rfmax = 522000, .val = 0x1d }, | ||
| 860 | { .rfmax = 524000, .val = 0x1e }, | ||
| 861 | { .rfmax = 534000, .val = 0x1f }, | ||
| 862 | { .rfmax = 549000, .val = 0x20 }, | ||
| 863 | { .rfmax = 554000, .val = 0x22 }, | ||
| 864 | { .rfmax = 584000, .val = 0x24 }, | ||
| 865 | { .rfmax = 589000, .val = 0x26 }, | ||
| 866 | { .rfmax = 658000, .val = 0x27 }, | ||
| 867 | { .rfmax = 664000, .val = 0x2c }, | ||
| 868 | { .rfmax = 669000, .val = 0x2d }, | ||
| 869 | { .rfmax = 699000, .val = 0x2e }, | ||
| 870 | { .rfmax = 704000, .val = 0x30 }, | ||
| 871 | { .rfmax = 709000, .val = 0x31 }, | ||
| 872 | { .rfmax = 714000, .val = 0x32 }, | ||
| 873 | { .rfmax = 724000, .val = 0x33 }, | ||
| 874 | { .rfmax = 729000, .val = 0x36 }, | ||
| 875 | { .rfmax = 739000, .val = 0x38 }, | ||
| 876 | { .rfmax = 744000, .val = 0x39 }, | ||
| 877 | { .rfmax = 749000, .val = 0x3b }, | ||
| 878 | { .rfmax = 754000, .val = 0x3c }, | ||
| 879 | { .rfmax = 759000, .val = 0x3d }, | ||
| 880 | { .rfmax = 764000, .val = 0x3e }, | ||
| 881 | { .rfmax = 769000, .val = 0x3f }, | ||
| 882 | { .rfmax = 774000, .val = 0x40 }, | ||
| 883 | { .rfmax = 779000, .val = 0x41 }, | ||
| 884 | { .rfmax = 784000, .val = 0x43 }, | ||
| 885 | { .rfmax = 789000, .val = 0x46 }, | ||
| 886 | { .rfmax = 794000, .val = 0x48 }, | ||
| 887 | { .rfmax = 799000, .val = 0x4b }, | ||
| 888 | { .rfmax = 804000, .val = 0x4f }, | ||
| 889 | { .rfmax = 809000, .val = 0x54 }, | ||
| 890 | { .rfmax = 814000, .val = 0x59 }, | ||
| 891 | { .rfmax = 819000, .val = 0x5d }, | ||
| 892 | { .rfmax = 824000, .val = 0x61 }, | ||
| 893 | { .rfmax = 829000, .val = 0x68 }, | ||
| 894 | { .rfmax = 834000, .val = 0x6e }, | ||
| 895 | { .rfmax = 839000, .val = 0x75 }, | ||
| 896 | { .rfmax = 844000, .val = 0x7e }, | ||
| 897 | { .rfmax = 849000, .val = 0x82 }, | ||
| 898 | { .rfmax = 854000, .val = 0x84 }, | ||
| 899 | { .rfmax = 859000, .val = 0x8f }, | ||
| 900 | { .rfmax = 865000, .val = 0x9a }, | ||
| 901 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
| 902 | }; | ||
| 903 | |||
| 904 | /*---------------------------------------------------------------------*/ | ||
| 905 | |||
| 906 | struct tda18271_thermo_map { | ||
| 907 | u8 d; | ||
| 908 | u8 r0; | ||
| 909 | u8 r1; | ||
| 910 | }; | ||
| 911 | |||
| 912 | static struct tda18271_thermo_map tda18271_thermometer[] = { | ||
| 913 | { .d = 0x00, .r0 = 60, .r1 = 92 }, | ||
| 914 | { .d = 0x01, .r0 = 62, .r1 = 94 }, | ||
| 915 | { .d = 0x02, .r0 = 66, .r1 = 98 }, | ||
| 916 | { .d = 0x03, .r0 = 64, .r1 = 96 }, | ||
| 917 | { .d = 0x04, .r0 = 74, .r1 = 106 }, | ||
| 918 | { .d = 0x05, .r0 = 72, .r1 = 104 }, | ||
| 919 | { .d = 0x06, .r0 = 68, .r1 = 100 }, | ||
| 920 | { .d = 0x07, .r0 = 70, .r1 = 102 }, | ||
| 921 | { .d = 0x08, .r0 = 90, .r1 = 122 }, | ||
| 922 | { .d = 0x09, .r0 = 88, .r1 = 120 }, | ||
| 923 | { .d = 0x0a, .r0 = 84, .r1 = 116 }, | ||
| 924 | { .d = 0x0b, .r0 = 86, .r1 = 118 }, | ||
| 925 | { .d = 0x0c, .r0 = 76, .r1 = 108 }, | ||
| 926 | { .d = 0x0d, .r0 = 78, .r1 = 110 }, | ||
| 927 | { .d = 0x0e, .r0 = 82, .r1 = 114 }, | ||
| 928 | { .d = 0x0f, .r0 = 80, .r1 = 112 }, | ||
| 929 | { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ | ||
| 930 | }; | ||
| 931 | |||
| 932 | int tda18271_lookup_thermometer(struct dvb_frontend *fe) | ||
| 933 | { | ||
| 934 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 935 | unsigned char *regs = priv->tda18271_regs; | ||
| 936 | int val, i = 0; | ||
| 937 | |||
| 938 | while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { | ||
| 939 | if (tda18271_thermometer[i + 1].d == 0) | ||
| 940 | break; | ||
| 941 | i++; | ||
| 942 | } | ||
| 943 | |||
| 944 | if ((regs[R_TM] & 0x20) == 0x20) | ||
| 945 | val = tda18271_thermometer[i].r1; | ||
| 946 | else | ||
| 947 | val = tda18271_thermometer[i].r0; | ||
| 948 | |||
| 949 | tda_map("(%d) tm = %d\n", i, val); | ||
| 950 | |||
| 951 | return val; | ||
| 952 | } | ||
| 953 | |||
| 954 | /*---------------------------------------------------------------------*/ | ||
| 955 | |||
| 956 | struct tda18271_cid_target_map { | ||
| 957 | u32 rfmax; | ||
| 958 | u8 target; | ||
| 959 | u16 limit; | ||
| 960 | }; | ||
| 961 | |||
| 962 | static struct tda18271_cid_target_map tda18271_cid_target[] = { | ||
| 963 | { .rfmax = 46000, .target = 0x04, .limit = 1800 }, | ||
| 964 | { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, | ||
| 965 | { .rfmax = 70100, .target = 0x01, .limit = 4000 }, | ||
| 966 | { .rfmax = 136800, .target = 0x18, .limit = 4000 }, | ||
| 967 | { .rfmax = 156700, .target = 0x18, .limit = 4000 }, | ||
| 968 | { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, | ||
| 969 | { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, | ||
| 970 | { .rfmax = 345000, .target = 0x18, .limit = 4000 }, | ||
| 971 | { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, | ||
| 972 | { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, | ||
| 973 | { .rfmax = 697500, .target = 0x32, .limit = 4000 }, | ||
| 974 | { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, | ||
| 975 | { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ | ||
| 976 | }; | ||
| 977 | |||
| 978 | int tda18271_lookup_cid_target(struct dvb_frontend *fe, | ||
| 979 | u32 *freq, u8 *cid_target, u16 *count_limit) | ||
| 980 | { | ||
| 981 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 982 | int i = 0; | ||
| 983 | |||
| 984 | while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { | ||
| 985 | if (tda18271_cid_target[i + 1].rfmax == 0) | ||
| 986 | break; | ||
| 987 | i++; | ||
| 988 | } | ||
| 989 | *cid_target = tda18271_cid_target[i].target; | ||
| 990 | *count_limit = tda18271_cid_target[i].limit; | ||
| 991 | |||
| 992 | tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, | ||
| 993 | tda18271_cid_target[i].target, tda18271_cid_target[i].limit); | ||
| 994 | |||
| 995 | return 0; | ||
| 996 | } | ||
| 997 | |||
| 998 | /*---------------------------------------------------------------------*/ | ||
| 999 | |||
| 1000 | static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { | ||
| 1001 | { .rfmax = 47900, .rfband = 0x00, | ||
| 1002 | .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, | ||
| 1003 | { .rfmax = 61100, .rfband = 0x01, | ||
| 1004 | .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, | ||
| 1005 | { .rfmax = 152600, .rfband = 0x02, | ||
| 1006 | .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, | ||
| 1007 | { .rfmax = 164700, .rfband = 0x03, | ||
| 1008 | .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, | ||
| 1009 | { .rfmax = 203500, .rfband = 0x04, | ||
| 1010 | .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, | ||
| 1011 | { .rfmax = 457800, .rfband = 0x05, | ||
| 1012 | .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, | ||
| 1013 | { .rfmax = 865000, .rfband = 0x06, | ||
| 1014 | .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, | ||
| 1015 | { .rfmax = 0, .rfband = 0x00, | ||
| 1016 | .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ | ||
| 1017 | }; | ||
| 1018 | |||
| 1019 | int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) | ||
| 1020 | { | ||
| 1021 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1022 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
| 1023 | int i = 0; | ||
| 1024 | |||
| 1025 | while ((map[i].rfmax * 1000) < *freq) { | ||
| 1026 | if (tda18271_debug & DBG_ADV) | ||
| 1027 | tda_map("(%d) rfmax = %d < freq = %d, " | ||
| 1028 | "rf1_def = %d, rf2_def = %d, rf3_def = %d, " | ||
| 1029 | "rf1 = %d, rf2 = %d, rf3 = %d, " | ||
| 1030 | "rf_a1 = %d, rf_a2 = %d, " | ||
| 1031 | "rf_b1 = %d, rf_b2 = %d\n", | ||
| 1032 | i, map[i].rfmax * 1000, *freq, | ||
| 1033 | map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, | ||
| 1034 | map[i].rf1, map[i].rf2, map[i].rf3, | ||
| 1035 | map[i].rf_a1, map[i].rf_a2, | ||
| 1036 | map[i].rf_b1, map[i].rf_b2); | ||
| 1037 | if (map[i].rfmax == 0) | ||
| 1038 | return -EINVAL; | ||
| 1039 | i++; | ||
| 1040 | } | ||
| 1041 | if (rf_band) | ||
| 1042 | *rf_band = map[i].rfband; | ||
| 1043 | |||
| 1044 | tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); | ||
| 1045 | |||
| 1046 | return i; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /*---------------------------------------------------------------------*/ | ||
| 1050 | |||
| 1051 | struct tda18271_map_layout { | ||
| 1052 | struct tda18271_pll_map *main_pll; | ||
| 1053 | struct tda18271_pll_map *cal_pll; | ||
| 1054 | |||
| 1055 | struct tda18271_map *rf_cal; | ||
| 1056 | struct tda18271_map *rf_cal_kmco; | ||
| 1057 | struct tda18271_map *rf_cal_dc_over_dt; | ||
| 1058 | |||
| 1059 | struct tda18271_map *bp_filter; | ||
| 1060 | struct tda18271_map *rf_band; | ||
| 1061 | struct tda18271_map *gain_taper; | ||
| 1062 | struct tda18271_map *ir_measure; | ||
| 1063 | }; | ||
| 1064 | |||
| 1065 | /*---------------------------------------------------------------------*/ | ||
| 1066 | |||
| 1067 | int tda18271_lookup_pll_map(struct dvb_frontend *fe, | ||
| 1068 | enum tda18271_map_type map_type, | ||
| 1069 | u32 *freq, u8 *post_div, u8 *div) | ||
| 1070 | { | ||
| 1071 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1072 | struct tda18271_pll_map *map = NULL; | ||
| 1073 | unsigned int i = 0; | ||
| 1074 | char *map_name; | ||
| 1075 | int ret = 0; | ||
| 1076 | |||
| 1077 | BUG_ON(!priv->maps); | ||
| 1078 | |||
| 1079 | switch (map_type) { | ||
| 1080 | case MAIN_PLL: | ||
| 1081 | map = priv->maps->main_pll; | ||
| 1082 | map_name = "main_pll"; | ||
| 1083 | break; | ||
| 1084 | case CAL_PLL: | ||
| 1085 | map = priv->maps->cal_pll; | ||
| 1086 | map_name = "cal_pll"; | ||
| 1087 | break; | ||
| 1088 | default: | ||
| 1089 | /* we should never get here */ | ||
| 1090 | map_name = "undefined"; | ||
| 1091 | break; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | if (!map) { | ||
| 1095 | tda_warn("%s map is not set!\n", map_name); | ||
| 1096 | ret = -EINVAL; | ||
| 1097 | goto fail; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | while ((map[i].lomax * 1000) < *freq) { | ||
| 1101 | if (map[i + 1].lomax == 0) { | ||
| 1102 | tda_map("%s: frequency (%d) out of range\n", | ||
| 1103 | map_name, *freq); | ||
| 1104 | ret = -ERANGE; | ||
| 1105 | break; | ||
| 1106 | } | ||
| 1107 | i++; | ||
| 1108 | } | ||
| 1109 | *post_div = map[i].pd; | ||
| 1110 | *div = map[i].d; | ||
| 1111 | |||
| 1112 | tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", | ||
| 1113 | i, map_name, *post_div, *div); | ||
| 1114 | fail: | ||
| 1115 | return ret; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | int tda18271_lookup_map(struct dvb_frontend *fe, | ||
| 1119 | enum tda18271_map_type map_type, | ||
| 1120 | u32 *freq, u8 *val) | ||
| 1121 | { | ||
| 1122 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1123 | struct tda18271_map *map = NULL; | ||
| 1124 | unsigned int i = 0; | ||
| 1125 | char *map_name; | ||
| 1126 | int ret = 0; | ||
| 1127 | |||
| 1128 | BUG_ON(!priv->maps); | ||
| 1129 | |||
| 1130 | switch (map_type) { | ||
| 1131 | case BP_FILTER: | ||
| 1132 | map = priv->maps->bp_filter; | ||
| 1133 | map_name = "bp_filter"; | ||
| 1134 | break; | ||
| 1135 | case RF_CAL_KMCO: | ||
| 1136 | map = priv->maps->rf_cal_kmco; | ||
| 1137 | map_name = "km"; | ||
| 1138 | break; | ||
| 1139 | case RF_BAND: | ||
| 1140 | map = priv->maps->rf_band; | ||
| 1141 | map_name = "rf_band"; | ||
| 1142 | break; | ||
| 1143 | case GAIN_TAPER: | ||
| 1144 | map = priv->maps->gain_taper; | ||
| 1145 | map_name = "gain_taper"; | ||
| 1146 | break; | ||
| 1147 | case RF_CAL: | ||
| 1148 | map = priv->maps->rf_cal; | ||
| 1149 | map_name = "rf_cal"; | ||
| 1150 | break; | ||
| 1151 | case IR_MEASURE: | ||
| 1152 | map = priv->maps->ir_measure; | ||
| 1153 | map_name = "ir_measure"; | ||
| 1154 | break; | ||
| 1155 | case RF_CAL_DC_OVER_DT: | ||
| 1156 | map = priv->maps->rf_cal_dc_over_dt; | ||
| 1157 | map_name = "rf_cal_dc_over_dt"; | ||
| 1158 | break; | ||
| 1159 | default: | ||
| 1160 | /* we should never get here */ | ||
| 1161 | map_name = "undefined"; | ||
| 1162 | break; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | if (!map) { | ||
| 1166 | tda_warn("%s map is not set!\n", map_name); | ||
| 1167 | ret = -EINVAL; | ||
| 1168 | goto fail; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | while ((map[i].rfmax * 1000) < *freq) { | ||
| 1172 | if (map[i + 1].rfmax == 0) { | ||
| 1173 | tda_map("%s: frequency (%d) out of range\n", | ||
| 1174 | map_name, *freq); | ||
| 1175 | ret = -ERANGE; | ||
| 1176 | break; | ||
| 1177 | } | ||
| 1178 | i++; | ||
| 1179 | } | ||
| 1180 | *val = map[i].val; | ||
| 1181 | |||
| 1182 | tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); | ||
| 1183 | fail: | ||
| 1184 | return ret; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | /*---------------------------------------------------------------------*/ | ||
| 1188 | |||
| 1189 | static struct tda18271_std_map tda18271c1_std_map = { | ||
| 1190 | .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, | ||
| 1191 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ | ||
| 1192 | .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
| 1193 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
| 1194 | .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
| 1195 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
| 1196 | .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
| 1197 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
| 1198 | .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
| 1199 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
| 1200 | .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
| 1201 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
| 1202 | .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
| 1203 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
| 1204 | .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5, | ||
| 1205 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ | ||
| 1206 | .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
| 1207 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
| 1208 | .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
| 1209 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
| 1210 | .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
| 1211 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
| 1212 | .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6, | ||
| 1213 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ | ||
| 1214 | .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
| 1215 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
| 1216 | .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, | ||
| 1217 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ | ||
| 1218 | }; | ||
| 1219 | |||
| 1220 | static struct tda18271_std_map tda18271c2_std_map = { | ||
| 1221 | .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, | ||
| 1222 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ | ||
| 1223 | .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, | ||
| 1224 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ | ||
| 1225 | .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
| 1226 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
| 1227 | .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
| 1228 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
| 1229 | .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
| 1230 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
| 1231 | .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
| 1232 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
| 1233 | .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
| 1234 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
| 1235 | .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4, | ||
| 1236 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */ | ||
| 1237 | .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
| 1238 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
| 1239 | .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
| 1240 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
| 1241 | .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
| 1242 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
| 1243 | .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
| 1244 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
| 1245 | .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
| 1246 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
| 1247 | .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, | ||
| 1248 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ | ||
| 1249 | }; | ||
| 1250 | |||
| 1251 | /*---------------------------------------------------------------------*/ | ||
| 1252 | |||
| 1253 | static struct tda18271_map_layout tda18271c1_map_layout = { | ||
| 1254 | .main_pll = tda18271c1_main_pll, | ||
| 1255 | .cal_pll = tda18271c1_cal_pll, | ||
| 1256 | |||
| 1257 | .rf_cal = tda18271c1_rf_cal, | ||
| 1258 | .rf_cal_kmco = tda18271c1_km, | ||
| 1259 | |||
| 1260 | .bp_filter = tda18271_bp_filter, | ||
| 1261 | .rf_band = tda18271_rf_band, | ||
| 1262 | .gain_taper = tda18271_gain_taper, | ||
| 1263 | .ir_measure = tda18271_ir_measure, | ||
| 1264 | }; | ||
| 1265 | |||
| 1266 | static struct tda18271_map_layout tda18271c2_map_layout = { | ||
| 1267 | .main_pll = tda18271c2_main_pll, | ||
| 1268 | .cal_pll = tda18271c2_cal_pll, | ||
| 1269 | |||
| 1270 | .rf_cal = tda18271c2_rf_cal, | ||
| 1271 | .rf_cal_kmco = tda18271c2_km, | ||
| 1272 | |||
| 1273 | .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, | ||
| 1274 | |||
| 1275 | .bp_filter = tda18271_bp_filter, | ||
| 1276 | .rf_band = tda18271_rf_band, | ||
| 1277 | .gain_taper = tda18271_gain_taper, | ||
| 1278 | .ir_measure = tda18271_ir_measure, | ||
| 1279 | }; | ||
| 1280 | |||
| 1281 | int tda18271_assign_map_layout(struct dvb_frontend *fe) | ||
| 1282 | { | ||
| 1283 | struct tda18271_priv *priv = fe->tuner_priv; | ||
| 1284 | int ret = 0; | ||
| 1285 | |||
| 1286 | switch (priv->id) { | ||
| 1287 | case TDA18271HDC1: | ||
| 1288 | priv->maps = &tda18271c1_map_layout; | ||
| 1289 | memcpy(&priv->std, &tda18271c1_std_map, | ||
| 1290 | sizeof(struct tda18271_std_map)); | ||
| 1291 | break; | ||
| 1292 | case TDA18271HDC2: | ||
| 1293 | priv->maps = &tda18271c2_map_layout; | ||
| 1294 | memcpy(&priv->std, &tda18271c2_std_map, | ||
| 1295 | sizeof(struct tda18271_std_map)); | ||
| 1296 | break; | ||
| 1297 | default: | ||
| 1298 | ret = -EINVAL; | ||
| 1299 | break; | ||
| 1300 | } | ||
| 1301 | memcpy(priv->rf_cal_state, &tda18271_rf_band_template, | ||
| 1302 | sizeof(tda18271_rf_band_template)); | ||
| 1303 | |||
| 1304 | return ret; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | /* | ||
| 1308 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 1309 | * --------------------------------------------------------------------------- | ||
| 1310 | * Local variables: | ||
| 1311 | * c-basic-offset: 8 | ||
| 1312 | * End: | ||
| 1313 | */ | ||
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h new file mode 100644 index 00000000000..9589ab0576d --- /dev/null +++ b/drivers/media/common/tuners/tda18271-priv.h | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | /* | ||
| 2 | tda18271-priv.h - private header for the NXP TDA18271 silicon tuner | ||
| 3 | |||
| 4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __TDA18271_PRIV_H__ | ||
| 22 | #define __TDA18271_PRIV_H__ | ||
| 23 | |||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | #include <linux/mutex.h> | ||
| 27 | #include "tuner-i2c.h" | ||
| 28 | #include "tda18271.h" | ||
| 29 | |||
| 30 | #define R_ID 0x00 /* ID byte */ | ||
| 31 | #define R_TM 0x01 /* Thermo byte */ | ||
| 32 | #define R_PL 0x02 /* Power level byte */ | ||
| 33 | #define R_EP1 0x03 /* Easy Prog byte 1 */ | ||
| 34 | #define R_EP2 0x04 /* Easy Prog byte 2 */ | ||
| 35 | #define R_EP3 0x05 /* Easy Prog byte 3 */ | ||
| 36 | #define R_EP4 0x06 /* Easy Prog byte 4 */ | ||
| 37 | #define R_EP5 0x07 /* Easy Prog byte 5 */ | ||
| 38 | #define R_CPD 0x08 /* Cal Post-Divider byte */ | ||
| 39 | #define R_CD1 0x09 /* Cal Divider byte 1 */ | ||
| 40 | #define R_CD2 0x0a /* Cal Divider byte 2 */ | ||
| 41 | #define R_CD3 0x0b /* Cal Divider byte 3 */ | ||
| 42 | #define R_MPD 0x0c /* Main Post-Divider byte */ | ||
| 43 | #define R_MD1 0x0d /* Main Divider byte 1 */ | ||
| 44 | #define R_MD2 0x0e /* Main Divider byte 2 */ | ||
| 45 | #define R_MD3 0x0f /* Main Divider byte 3 */ | ||
| 46 | #define R_EB1 0x10 /* Extended byte 1 */ | ||
| 47 | #define R_EB2 0x11 /* Extended byte 2 */ | ||
| 48 | #define R_EB3 0x12 /* Extended byte 3 */ | ||
| 49 | #define R_EB4 0x13 /* Extended byte 4 */ | ||
| 50 | #define R_EB5 0x14 /* Extended byte 5 */ | ||
| 51 | #define R_EB6 0x15 /* Extended byte 6 */ | ||
| 52 | #define R_EB7 0x16 /* Extended byte 7 */ | ||
| 53 | #define R_EB8 0x17 /* Extended byte 8 */ | ||
| 54 | #define R_EB9 0x18 /* Extended byte 9 */ | ||
| 55 | #define R_EB10 0x19 /* Extended byte 10 */ | ||
| 56 | #define R_EB11 0x1a /* Extended byte 11 */ | ||
| 57 | #define R_EB12 0x1b /* Extended byte 12 */ | ||
| 58 | #define R_EB13 0x1c /* Extended byte 13 */ | ||
| 59 | #define R_EB14 0x1d /* Extended byte 14 */ | ||
| 60 | #define R_EB15 0x1e /* Extended byte 15 */ | ||
| 61 | #define R_EB16 0x1f /* Extended byte 16 */ | ||
| 62 | #define R_EB17 0x20 /* Extended byte 17 */ | ||
| 63 | #define R_EB18 0x21 /* Extended byte 18 */ | ||
| 64 | #define R_EB19 0x22 /* Extended byte 19 */ | ||
| 65 | #define R_EB20 0x23 /* Extended byte 20 */ | ||
| 66 | #define R_EB21 0x24 /* Extended byte 21 */ | ||
| 67 | #define R_EB22 0x25 /* Extended byte 22 */ | ||
| 68 | #define R_EB23 0x26 /* Extended byte 23 */ | ||
| 69 | |||
| 70 | #define TDA18271_NUM_REGS 39 | ||
| 71 | |||
| 72 | /*---------------------------------------------------------------------*/ | ||
| 73 | |||
| 74 | struct tda18271_rf_tracking_filter_cal { | ||
| 75 | u32 rfmax; | ||
| 76 | u8 rfband; | ||
| 77 | u32 rf1_def; | ||
| 78 | u32 rf2_def; | ||
| 79 | u32 rf3_def; | ||
| 80 | u32 rf1; | ||
| 81 | u32 rf2; | ||
| 82 | u32 rf3; | ||
| 83 | s32 rf_a1; | ||
| 84 | s32 rf_b1; | ||
| 85 | s32 rf_a2; | ||
| 86 | s32 rf_b2; | ||
| 87 | }; | ||
| 88 | |||
| 89 | enum tda18271_pll { | ||
| 90 | TDA18271_MAIN_PLL, | ||
| 91 | TDA18271_CAL_PLL, | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct tda18271_map_layout; | ||
| 95 | |||
| 96 | enum tda18271_ver { | ||
| 97 | TDA18271HDC1, | ||
| 98 | TDA18271HDC2, | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct tda18271_priv { | ||
| 102 | unsigned char tda18271_regs[TDA18271_NUM_REGS]; | ||
| 103 | |||
| 104 | struct list_head hybrid_tuner_instance_list; | ||
| 105 | struct tuner_i2c_props i2c_props; | ||
| 106 | |||
| 107 | enum tda18271_mode mode; | ||
| 108 | enum tda18271_role role; | ||
| 109 | enum tda18271_i2c_gate gate; | ||
| 110 | enum tda18271_ver id; | ||
| 111 | enum tda18271_output_options output_opt; | ||
| 112 | enum tda18271_small_i2c small_i2c; | ||
| 113 | |||
| 114 | unsigned int config; /* interface to saa713x / tda829x */ | ||
| 115 | unsigned int cal_initialized:1; | ||
| 116 | |||
| 117 | u8 tm_rfcal; | ||
| 118 | |||
| 119 | struct tda18271_map_layout *maps; | ||
| 120 | struct tda18271_std_map std; | ||
| 121 | struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; | ||
| 122 | |||
| 123 | struct mutex lock; | ||
| 124 | |||
| 125 | u32 frequency; | ||
| 126 | u32 bandwidth; | ||
| 127 | }; | ||
| 128 | |||
| 129 | /*---------------------------------------------------------------------*/ | ||
| 130 | |||
| 131 | extern int tda18271_debug; | ||
| 132 | |||
| 133 | #define DBG_INFO 1 | ||
| 134 | #define DBG_MAP 2 | ||
| 135 | #define DBG_REG 4 | ||
| 136 | #define DBG_ADV 8 | ||
| 137 | #define DBG_CAL 16 | ||
| 138 | |||
| 139 | #define tda_printk(st, kern, fmt, arg...) do {\ | ||
| 140 | if (st) { \ | ||
| 141 | struct tda18271_priv *state = st; \ | ||
| 142 | printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \ | ||
| 143 | i2c_adapter_id(state->i2c_props.adap), \ | ||
| 144 | state->i2c_props.addr, \ | ||
| 145 | (state->role == TDA18271_MASTER) \ | ||
| 146 | ? "M" : "S", ##arg); \ | ||
| 147 | } else \ | ||
| 148 | printk(kern "%s: " fmt, __func__, ##arg); \ | ||
| 149 | } while (0) | ||
| 150 | |||
| 151 | #define tda_dprintk(st, lvl, fmt, arg...) do {\ | ||
| 152 | if (tda18271_debug & lvl) \ | ||
| 153 | tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0) | ||
| 154 | |||
| 155 | #define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) | ||
| 156 | #define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) | ||
| 157 | #define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) | ||
| 158 | #define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) | ||
| 159 | #define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) | ||
| 160 | #define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) | ||
| 161 | #define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) | ||
| 162 | |||
| 163 | #define tda_fail(ret) \ | ||
| 164 | ({ \ | ||
| 165 | int __ret; \ | ||
| 166 | __ret = (ret < 0); \ | ||
| 167 | if (__ret) \ | ||
| 168 | tda_printk(priv, KERN_ERR, \ | ||
| 169 | "error %d on line %d\n", ret, __LINE__); \ | ||
| 170 | __ret; \ | ||
| 171 | }) | ||
| 172 | |||
| 173 | /*---------------------------------------------------------------------*/ | ||
| 174 | |||
| 175 | enum tda18271_map_type { | ||
| 176 | /* tda18271_pll_map */ | ||
| 177 | MAIN_PLL, | ||
| 178 | CAL_PLL, | ||
| 179 | /* tda18271_map */ | ||
| 180 | RF_CAL, | ||
| 181 | RF_CAL_KMCO, | ||
| 182 | RF_CAL_DC_OVER_DT, | ||
| 183 | BP_FILTER, | ||
| 184 | RF_BAND, | ||
| 185 | GAIN_TAPER, | ||
| 186 | IR_MEASURE, | ||
| 187 | }; | ||
| 188 | |||
| 189 | extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, | ||
| 190 | enum tda18271_map_type map_type, | ||
| 191 | u32 *freq, u8 *post_div, u8 *div); | ||
| 192 | extern int tda18271_lookup_map(struct dvb_frontend *fe, | ||
| 193 | enum tda18271_map_type map_type, | ||
| 194 | u32 *freq, u8 *val); | ||
| 195 | |||
| 196 | extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); | ||
| 197 | |||
| 198 | extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, | ||
| 199 | u32 *freq, u8 *rf_band); | ||
| 200 | |||
| 201 | extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, | ||
| 202 | u32 *freq, u8 *cid_target, | ||
| 203 | u16 *count_limit); | ||
| 204 | |||
| 205 | extern int tda18271_assign_map_layout(struct dvb_frontend *fe); | ||
| 206 | |||
| 207 | /*---------------------------------------------------------------------*/ | ||
| 208 | |||
| 209 | extern int tda18271_read_regs(struct dvb_frontend *fe); | ||
| 210 | extern int tda18271_read_extended(struct dvb_frontend *fe); | ||
| 211 | extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); | ||
| 212 | extern int tda18271_init_regs(struct dvb_frontend *fe); | ||
| 213 | |||
| 214 | extern int tda18271_charge_pump_source(struct dvb_frontend *fe, | ||
| 215 | enum tda18271_pll pll, int force); | ||
| 216 | extern int tda18271_set_standby_mode(struct dvb_frontend *fe, | ||
| 217 | int sm, int sm_lt, int sm_xt); | ||
| 218 | |||
| 219 | extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); | ||
| 220 | extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); | ||
| 221 | |||
| 222 | extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); | ||
| 223 | extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); | ||
| 224 | extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); | ||
| 225 | extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); | ||
| 226 | extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); | ||
| 227 | extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); | ||
| 228 | |||
| 229 | #endif /* __TDA18271_PRIV_H__ */ | ||
| 230 | |||
| 231 | /* | ||
| 232 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 233 | * --------------------------------------------------------------------------- | ||
| 234 | * Local variables: | ||
| 235 | * c-basic-offset: 8 | ||
| 236 | * End: | ||
| 237 | */ | ||
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h new file mode 100644 index 00000000000..50cfa8cebb9 --- /dev/null +++ b/drivers/media/common/tuners/tda18271.h | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | /* | ||
| 2 | tda18271.h - header for the Philips / NXP TDA18271 silicon tuner | ||
| 3 | |||
| 4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __TDA18271_H__ | ||
| 22 | #define __TDA18271_H__ | ||
| 23 | |||
| 24 | #include <linux/i2c.h> | ||
| 25 | #include "dvb_frontend.h" | ||
| 26 | |||
| 27 | struct tda18271_std_map_item { | ||
| 28 | u16 if_freq; | ||
| 29 | |||
| 30 | /* EP3[4:3] */ | ||
| 31 | unsigned int agc_mode:2; | ||
| 32 | /* EP3[2:0] */ | ||
| 33 | unsigned int std:3; | ||
| 34 | /* EP4[7] */ | ||
| 35 | unsigned int fm_rfn:1; | ||
| 36 | /* EP4[4:2] */ | ||
| 37 | unsigned int if_lvl:3; | ||
| 38 | /* EB22[6:0] */ | ||
| 39 | unsigned int rfagc_top:7; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct tda18271_std_map { | ||
| 43 | struct tda18271_std_map_item fm_radio; | ||
| 44 | struct tda18271_std_map_item atv_b; | ||
| 45 | struct tda18271_std_map_item atv_dk; | ||
| 46 | struct tda18271_std_map_item atv_gh; | ||
| 47 | struct tda18271_std_map_item atv_i; | ||
| 48 | struct tda18271_std_map_item atv_l; | ||
| 49 | struct tda18271_std_map_item atv_lc; | ||
| 50 | struct tda18271_std_map_item atv_mn; | ||
| 51 | struct tda18271_std_map_item atsc_6; | ||
| 52 | struct tda18271_std_map_item dvbt_6; | ||
| 53 | struct tda18271_std_map_item dvbt_7; | ||
| 54 | struct tda18271_std_map_item dvbt_8; | ||
| 55 | struct tda18271_std_map_item qam_6; | ||
| 56 | struct tda18271_std_map_item qam_8; | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum tda18271_role { | ||
| 60 | TDA18271_MASTER = 0, | ||
| 61 | TDA18271_SLAVE, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum tda18271_i2c_gate { | ||
| 65 | TDA18271_GATE_AUTO = 0, | ||
| 66 | TDA18271_GATE_ANALOG, | ||
| 67 | TDA18271_GATE_DIGITAL, | ||
| 68 | }; | ||
| 69 | |||
| 70 | enum tda18271_output_options { | ||
| 71 | /* slave tuner output & loop thru & xtal oscillator always on */ | ||
| 72 | TDA18271_OUTPUT_LT_XT_ON = 0, | ||
| 73 | |||
| 74 | /* slave tuner output loop thru off */ | ||
| 75 | TDA18271_OUTPUT_LT_OFF = 1, | ||
| 76 | |||
| 77 | /* xtal oscillator off */ | ||
| 78 | TDA18271_OUTPUT_XT_OFF = 2, | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum tda18271_small_i2c { | ||
| 82 | TDA18271_39_BYTE_CHUNK_INIT = 0, | ||
| 83 | TDA18271_16_BYTE_CHUNK_INIT = 16, | ||
| 84 | TDA18271_08_BYTE_CHUNK_INIT = 8, | ||
| 85 | TDA18271_03_BYTE_CHUNK_INIT = 3, | ||
| 86 | }; | ||
| 87 | |||
| 88 | struct tda18271_config { | ||
| 89 | /* override default if freq / std settings (optional) */ | ||
| 90 | struct tda18271_std_map *std_map; | ||
| 91 | |||
| 92 | /* master / slave tuner: master uses main pll, slave uses cal pll */ | ||
| 93 | enum tda18271_role role; | ||
| 94 | |||
| 95 | /* use i2c gate provided by analog or digital demod */ | ||
| 96 | enum tda18271_i2c_gate gate; | ||
| 97 | |||
| 98 | /* output options that can be disabled */ | ||
| 99 | enum tda18271_output_options output_opt; | ||
| 100 | |||
| 101 | /* some i2c providers can't write all 39 registers at once */ | ||
| 102 | enum tda18271_small_i2c small_i2c; | ||
| 103 | |||
| 104 | /* force rf tracking filter calibration on startup */ | ||
| 105 | unsigned int rf_cal_on_startup:1; | ||
| 106 | |||
| 107 | /* interface to saa713x / tda829x */ | ||
| 108 | unsigned int config; | ||
| 109 | }; | ||
| 110 | |||
| 111 | #define TDA18271_CALLBACK_CMD_AGC_ENABLE 0 | ||
| 112 | |||
| 113 | enum tda18271_mode { | ||
| 114 | TDA18271_ANALOG = 0, | ||
| 115 | TDA18271_DIGITAL, | ||
| 116 | }; | ||
| 117 | |||
| 118 | #if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) | ||
| 119 | extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
| 120 | struct i2c_adapter *i2c, | ||
| 121 | struct tda18271_config *cfg); | ||
| 122 | #else | ||
| 123 | static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, | ||
| 124 | u8 addr, | ||
| 125 | struct i2c_adapter *i2c, | ||
| 126 | struct tda18271_config *cfg) | ||
| 127 | { | ||
| 128 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 129 | return NULL; | ||
| 130 | } | ||
| 131 | #endif | ||
| 132 | |||
| 133 | #endif /* __TDA18271_H__ */ | ||
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c new file mode 100644 index 00000000000..b21b6ea68b2 --- /dev/null +++ b/drivers/media/common/tuners/tda827x.c | |||
| @@ -0,0 +1,913 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * (c) 2005 Hartmut Hackmann | ||
| 4 | * (c) 2007 Michael Krufky | ||
| 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 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <asm/types.h> | ||
| 24 | #include <linux/dvb/frontend.h> | ||
| 25 | #include <linux/videodev2.h> | ||
| 26 | |||
| 27 | #include "tda827x.h" | ||
| 28 | |||
| 29 | static int debug; | ||
| 30 | module_param(debug, int, 0644); | ||
| 31 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
| 32 | |||
| 33 | #define dprintk(args...) \ | ||
| 34 | do { \ | ||
| 35 | if (debug) printk(KERN_DEBUG "tda827x: " args); \ | ||
| 36 | } while (0) | ||
| 37 | |||
| 38 | struct tda827x_priv { | ||
| 39 | int i2c_addr; | ||
| 40 | struct i2c_adapter *i2c_adap; | ||
| 41 | struct tda827x_config *cfg; | ||
| 42 | |||
| 43 | unsigned int sgIF; | ||
| 44 | unsigned char lpsel; | ||
| 45 | |||
| 46 | u32 frequency; | ||
| 47 | u32 bandwidth; | ||
| 48 | }; | ||
| 49 | |||
| 50 | static void tda827x_set_std(struct dvb_frontend *fe, | ||
| 51 | struct analog_parameters *params) | ||
| 52 | { | ||
| 53 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 54 | char *mode; | ||
| 55 | |||
| 56 | priv->lpsel = 0; | ||
| 57 | if (params->std & V4L2_STD_MN) { | ||
| 58 | priv->sgIF = 92; | ||
| 59 | priv->lpsel = 1; | ||
| 60 | mode = "MN"; | ||
| 61 | } else if (params->std & V4L2_STD_B) { | ||
| 62 | priv->sgIF = 108; | ||
| 63 | mode = "B"; | ||
| 64 | } else if (params->std & V4L2_STD_GH) { | ||
| 65 | priv->sgIF = 124; | ||
| 66 | mode = "GH"; | ||
| 67 | } else if (params->std & V4L2_STD_PAL_I) { | ||
| 68 | priv->sgIF = 124; | ||
| 69 | mode = "I"; | ||
| 70 | } else if (params->std & V4L2_STD_DK) { | ||
| 71 | priv->sgIF = 124; | ||
| 72 | mode = "DK"; | ||
| 73 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
| 74 | priv->sgIF = 124; | ||
| 75 | mode = "L"; | ||
| 76 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
| 77 | priv->sgIF = 20; | ||
| 78 | mode = "LC"; | ||
| 79 | } else { | ||
| 80 | priv->sgIF = 124; | ||
| 81 | mode = "xx"; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (params->mode == V4L2_TUNER_RADIO) { | ||
| 85 | priv->sgIF = 88; /* if frequency is 5.5 MHz */ | ||
| 86 | dprintk("setting tda827x to radio FM\n"); | ||
| 87 | } else | ||
| 88 | dprintk("setting tda827x to system %s\n", mode); | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | /* ------------------------------------------------------------------ */ | ||
| 93 | |||
| 94 | struct tda827x_data { | ||
| 95 | u32 lomax; | ||
| 96 | u8 spd; | ||
| 97 | u8 bs; | ||
| 98 | u8 bp; | ||
| 99 | u8 cp; | ||
| 100 | u8 gc3; | ||
| 101 | u8 div1p5; | ||
| 102 | }; | ||
| 103 | |||
| 104 | static const struct tda827x_data tda827x_table[] = { | ||
| 105 | { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
| 106 | { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
| 107 | { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
| 108 | { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
| 109 | { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 110 | { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 111 | { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 112 | { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
| 113 | { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
| 114 | { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 115 | { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 116 | { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
| 117 | { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 118 | { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 119 | { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
| 120 | { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
| 121 | { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 122 | { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 123 | { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 124 | { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 125 | { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
| 126 | { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
| 127 | { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
| 128 | { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
| 129 | { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
| 130 | { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
| 131 | { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
| 132 | { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
| 133 | { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} | ||
| 134 | }; | ||
| 135 | |||
| 136 | static int tuner_transfer(struct dvb_frontend *fe, | ||
| 137 | struct i2c_msg *msg, | ||
| 138 | const int size) | ||
| 139 | { | ||
| 140 | int rc; | ||
| 141 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 142 | |||
| 143 | if (fe->ops.i2c_gate_ctrl) | ||
| 144 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 145 | rc = i2c_transfer(priv->i2c_adap, msg, size); | ||
| 146 | if (fe->ops.i2c_gate_ctrl) | ||
| 147 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 148 | |||
| 149 | if (rc >= 0 && rc != size) | ||
| 150 | return -EIO; | ||
| 151 | |||
| 152 | return rc; | ||
| 153 | } | ||
| 154 | |||
| 155 | static int tda827xo_set_params(struct dvb_frontend *fe, | ||
| 156 | struct dvb_frontend_parameters *params) | ||
| 157 | { | ||
| 158 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 159 | u8 buf[14]; | ||
| 160 | int rc; | ||
| 161 | |||
| 162 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
| 163 | .buf = buf, .len = sizeof(buf) }; | ||
| 164 | int i, tuner_freq, if_freq; | ||
| 165 | u32 N; | ||
| 166 | |||
| 167 | dprintk("%s:\n", __func__); | ||
| 168 | switch (params->u.ofdm.bandwidth) { | ||
| 169 | case BANDWIDTH_6_MHZ: | ||
| 170 | if_freq = 4000000; | ||
| 171 | break; | ||
| 172 | case BANDWIDTH_7_MHZ: | ||
| 173 | if_freq = 4500000; | ||
| 174 | break; | ||
| 175 | default: /* 8 MHz or Auto */ | ||
| 176 | if_freq = 5000000; | ||
| 177 | break; | ||
| 178 | } | ||
| 179 | tuner_freq = params->frequency + if_freq; | ||
| 180 | |||
| 181 | i = 0; | ||
| 182 | while (tda827x_table[i].lomax < tuner_freq) { | ||
| 183 | if (tda827x_table[i + 1].lomax == 0) | ||
| 184 | break; | ||
| 185 | i++; | ||
| 186 | } | ||
| 187 | |||
| 188 | N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); | ||
| 189 | buf[0] = 0; | ||
| 190 | buf[1] = (N>>8) | 0x40; | ||
| 191 | buf[2] = N & 0xff; | ||
| 192 | buf[3] = 0; | ||
| 193 | buf[4] = 0x52; | ||
| 194 | buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + | ||
| 195 | (tda827x_table[i].bs << 3) + | ||
| 196 | tda827x_table[i].bp; | ||
| 197 | buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; | ||
| 198 | buf[7] = 0xbf; | ||
| 199 | buf[8] = 0x2a; | ||
| 200 | buf[9] = 0x05; | ||
| 201 | buf[10] = 0xff; | ||
| 202 | buf[11] = 0x00; | ||
| 203 | buf[12] = 0x00; | ||
| 204 | buf[13] = 0x40; | ||
| 205 | |||
| 206 | msg.len = 14; | ||
| 207 | rc = tuner_transfer(fe, &msg, 1); | ||
| 208 | if (rc < 0) | ||
| 209 | goto err; | ||
| 210 | |||
| 211 | msleep(500); | ||
| 212 | /* correct CP value */ | ||
| 213 | buf[0] = 0x30; | ||
| 214 | buf[1] = 0x50 + tda827x_table[i].cp; | ||
| 215 | msg.len = 2; | ||
| 216 | |||
| 217 | rc = tuner_transfer(fe, &msg, 1); | ||
| 218 | if (rc < 0) | ||
| 219 | goto err; | ||
| 220 | |||
| 221 | priv->frequency = params->frequency; | ||
| 222 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | |||
| 226 | err: | ||
| 227 | printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", | ||
| 228 | __func__, priv->i2c_addr << 1); | ||
| 229 | return rc; | ||
| 230 | } | ||
| 231 | |||
| 232 | static int tda827xo_sleep(struct dvb_frontend *fe) | ||
| 233 | { | ||
| 234 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 235 | static u8 buf[] = { 0x30, 0xd0 }; | ||
| 236 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
| 237 | .buf = buf, .len = sizeof(buf) }; | ||
| 238 | |||
| 239 | dprintk("%s:\n", __func__); | ||
| 240 | tuner_transfer(fe, &msg, 1); | ||
| 241 | |||
| 242 | if (priv->cfg && priv->cfg->sleep) | ||
| 243 | priv->cfg->sleep(fe); | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | /* ------------------------------------------------------------------ */ | ||
| 249 | |||
| 250 | static int tda827xo_set_analog_params(struct dvb_frontend *fe, | ||
| 251 | struct analog_parameters *params) | ||
| 252 | { | ||
| 253 | unsigned char tuner_reg[8]; | ||
| 254 | unsigned char reg2[2]; | ||
| 255 | u32 N; | ||
| 256 | int i; | ||
| 257 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 258 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; | ||
| 259 | unsigned int freq = params->frequency; | ||
| 260 | |||
| 261 | tda827x_set_std(fe, params); | ||
| 262 | |||
| 263 | if (params->mode == V4L2_TUNER_RADIO) | ||
| 264 | freq = freq / 1000; | ||
| 265 | |||
| 266 | N = freq + priv->sgIF; | ||
| 267 | |||
| 268 | i = 0; | ||
| 269 | while (tda827x_table[i].lomax < N * 62500) { | ||
| 270 | if (tda827x_table[i + 1].lomax == 0) | ||
| 271 | break; | ||
| 272 | i++; | ||
| 273 | } | ||
| 274 | |||
| 275 | N = N << tda827x_table[i].spd; | ||
| 276 | |||
| 277 | tuner_reg[0] = 0; | ||
| 278 | tuner_reg[1] = (unsigned char)(N>>8); | ||
| 279 | tuner_reg[2] = (unsigned char) N; | ||
| 280 | tuner_reg[3] = 0x40; | ||
| 281 | tuner_reg[4] = 0x52 + (priv->lpsel << 5); | ||
| 282 | tuner_reg[5] = (tda827x_table[i].spd << 6) + | ||
| 283 | (tda827x_table[i].div1p5 << 5) + | ||
| 284 | (tda827x_table[i].bs << 3) + tda827x_table[i].bp; | ||
| 285 | tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); | ||
| 286 | tuner_reg[7] = 0x8f; | ||
| 287 | |||
| 288 | msg.buf = tuner_reg; | ||
| 289 | msg.len = 8; | ||
| 290 | tuner_transfer(fe, &msg, 1); | ||
| 291 | |||
| 292 | msg.buf = reg2; | ||
| 293 | msg.len = 2; | ||
| 294 | reg2[0] = 0x80; | ||
| 295 | reg2[1] = 0; | ||
| 296 | tuner_transfer(fe, &msg, 1); | ||
| 297 | |||
| 298 | reg2[0] = 0x60; | ||
| 299 | reg2[1] = 0xbf; | ||
| 300 | tuner_transfer(fe, &msg, 1); | ||
| 301 | |||
| 302 | reg2[0] = 0x30; | ||
| 303 | reg2[1] = tuner_reg[4] + 0x80; | ||
| 304 | tuner_transfer(fe, &msg, 1); | ||
| 305 | |||
| 306 | msleep(1); | ||
| 307 | reg2[0] = 0x30; | ||
| 308 | reg2[1] = tuner_reg[4] + 4; | ||
| 309 | tuner_transfer(fe, &msg, 1); | ||
| 310 | |||
| 311 | msleep(1); | ||
| 312 | reg2[0] = 0x30; | ||
| 313 | reg2[1] = tuner_reg[4]; | ||
| 314 | tuner_transfer(fe, &msg, 1); | ||
| 315 | |||
| 316 | msleep(550); | ||
| 317 | reg2[0] = 0x30; | ||
| 318 | reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; | ||
| 319 | tuner_transfer(fe, &msg, 1); | ||
| 320 | |||
| 321 | reg2[0] = 0x60; | ||
| 322 | reg2[1] = 0x3f; | ||
| 323 | tuner_transfer(fe, &msg, 1); | ||
| 324 | |||
| 325 | reg2[0] = 0x80; | ||
| 326 | reg2[1] = 0x08; /* Vsync en */ | ||
| 327 | tuner_transfer(fe, &msg, 1); | ||
| 328 | |||
| 329 | priv->frequency = params->frequency; | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | static void tda827xo_agcf(struct dvb_frontend *fe) | ||
| 335 | { | ||
| 336 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 337 | unsigned char data[] = { 0x80, 0x0c }; | ||
| 338 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
| 339 | .buf = data, .len = 2}; | ||
| 340 | |||
| 341 | tuner_transfer(fe, &msg, 1); | ||
| 342 | } | ||
| 343 | |||
| 344 | /* ------------------------------------------------------------------ */ | ||
| 345 | |||
| 346 | struct tda827xa_data { | ||
| 347 | u32 lomax; | ||
| 348 | u8 svco; | ||
| 349 | u8 spd; | ||
| 350 | u8 scr; | ||
| 351 | u8 sbs; | ||
| 352 | u8 gc3; | ||
| 353 | }; | ||
| 354 | |||
| 355 | static struct tda827xa_data tda827xa_dvbt[] = { | ||
| 356 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
| 357 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
| 358 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
| 359 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
| 360 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 361 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 362 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 363 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 364 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 365 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
| 366 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
| 367 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
| 368 | { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
| 369 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 370 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 371 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 372 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 373 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
| 374 | { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 375 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
| 376 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
| 377 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
| 378 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
| 379 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
| 380 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
| 381 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
| 382 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
| 383 | }; | ||
| 384 | |||
| 385 | static struct tda827xa_data tda827xa_dvbc[] = { | ||
| 386 | { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
| 387 | { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
| 388 | { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
| 389 | { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
| 390 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
| 391 | { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
| 392 | { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
| 393 | { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
| 394 | { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
| 395 | { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
| 396 | { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, | ||
| 397 | { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, | ||
| 398 | { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, | ||
| 399 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, | ||
| 400 | { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, | ||
| 401 | { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, | ||
| 402 | { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, | ||
| 403 | { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
| 404 | { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, | ||
| 405 | { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
| 406 | { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, | ||
| 407 | { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
| 408 | { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, | ||
| 409 | { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
| 410 | { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
| 411 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, | ||
| 412 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
| 413 | }; | ||
| 414 | |||
| 415 | static struct tda827xa_data tda827xa_analog[] = { | ||
| 416 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
| 417 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
| 418 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
| 419 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
| 420 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 421 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 422 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 423 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 424 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
| 425 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
| 426 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, | ||
| 427 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, | ||
| 428 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
| 429 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, | ||
| 430 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, | ||
| 431 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 432 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
| 433 | { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
| 434 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
| 435 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
| 436 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
| 437 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
| 438 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
| 439 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
| 440 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
| 441 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
| 442 | }; | ||
| 443 | |||
| 444 | static int tda827xa_sleep(struct dvb_frontend *fe) | ||
| 445 | { | ||
| 446 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 447 | static u8 buf[] = { 0x30, 0x90 }; | ||
| 448 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
| 449 | .buf = buf, .len = sizeof(buf) }; | ||
| 450 | |||
| 451 | dprintk("%s:\n", __func__); | ||
| 452 | |||
| 453 | tuner_transfer(fe, &msg, 1); | ||
| 454 | |||
| 455 | if (priv->cfg && priv->cfg->sleep) | ||
| 456 | priv->cfg->sleep(fe); | ||
| 457 | |||
| 458 | return 0; | ||
| 459 | } | ||
| 460 | |||
| 461 | static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, | ||
| 462 | struct analog_parameters *params) | ||
| 463 | { | ||
| 464 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 465 | unsigned char buf[] = {0x22, 0x01}; | ||
| 466 | int arg; | ||
| 467 | int gp_func; | ||
| 468 | struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
| 469 | |||
| 470 | if (NULL == priv->cfg) { | ||
| 471 | dprintk("tda827x_config not defined, cannot set LNA gain!\n"); | ||
| 472 | return; | ||
| 473 | } | ||
| 474 | msg.addr = priv->cfg->switch_addr; | ||
| 475 | if (priv->cfg->config) { | ||
| 476 | if (high) | ||
| 477 | dprintk("setting LNA to high gain\n"); | ||
| 478 | else | ||
| 479 | dprintk("setting LNA to low gain\n"); | ||
| 480 | } | ||
| 481 | switch (priv->cfg->config) { | ||
| 482 | case 0: /* no LNA */ | ||
| 483 | break; | ||
| 484 | case 1: /* switch is GPIO 0 of tda8290 */ | ||
| 485 | case 2: | ||
| 486 | if (params == NULL) { | ||
| 487 | gp_func = 0; | ||
| 488 | arg = 0; | ||
| 489 | } else { | ||
| 490 | /* turn Vsync on */ | ||
| 491 | gp_func = 1; | ||
| 492 | if (params->std & V4L2_STD_MN) | ||
| 493 | arg = 1; | ||
| 494 | else | ||
| 495 | arg = 0; | ||
| 496 | } | ||
| 497 | if (fe->callback) | ||
| 498 | fe->callback(priv->i2c_adap->algo_data, | ||
| 499 | DVB_FRONTEND_COMPONENT_TUNER, | ||
| 500 | gp_func, arg); | ||
| 501 | buf[1] = high ? 0 : 1; | ||
| 502 | if (priv->cfg->config == 2) | ||
| 503 | buf[1] = high ? 1 : 0; | ||
| 504 | tuner_transfer(fe, &msg, 1); | ||
| 505 | break; | ||
| 506 | case 3: /* switch with GPIO of saa713x */ | ||
| 507 | if (fe->callback) | ||
| 508 | fe->callback(priv->i2c_adap->algo_data, | ||
| 509 | DVB_FRONTEND_COMPONENT_TUNER, 0, high); | ||
| 510 | break; | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | static int tda827xa_set_params(struct dvb_frontend *fe, | ||
| 515 | struct dvb_frontend_parameters *params) | ||
| 516 | { | ||
| 517 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 518 | struct tda827xa_data *frequency_map = tda827xa_dvbt; | ||
| 519 | u8 buf[11]; | ||
| 520 | |||
| 521 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
| 522 | .buf = buf, .len = sizeof(buf) }; | ||
| 523 | |||
| 524 | int i, tuner_freq, if_freq, rc; | ||
| 525 | u32 N; | ||
| 526 | |||
| 527 | dprintk("%s:\n", __func__); | ||
| 528 | |||
| 529 | tda827xa_lna_gain(fe, 1, NULL); | ||
| 530 | msleep(20); | ||
| 531 | |||
| 532 | switch (params->u.ofdm.bandwidth) { | ||
| 533 | case BANDWIDTH_6_MHZ: | ||
| 534 | if_freq = 4000000; | ||
| 535 | break; | ||
| 536 | case BANDWIDTH_7_MHZ: | ||
| 537 | if_freq = 4500000; | ||
| 538 | break; | ||
| 539 | default: /* 8 MHz or Auto */ | ||
| 540 | if_freq = 5000000; | ||
| 541 | break; | ||
| 542 | } | ||
| 543 | tuner_freq = params->frequency + if_freq; | ||
| 544 | |||
| 545 | if (fe->ops.info.type == FE_QAM) { | ||
| 546 | dprintk("%s select tda827xa_dvbc\n", __func__); | ||
| 547 | frequency_map = tda827xa_dvbc; | ||
| 548 | } | ||
| 549 | |||
| 550 | i = 0; | ||
| 551 | while (frequency_map[i].lomax < tuner_freq) { | ||
| 552 | if (frequency_map[i + 1].lomax == 0) | ||
| 553 | break; | ||
| 554 | i++; | ||
| 555 | } | ||
| 556 | |||
| 557 | N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; | ||
| 558 | buf[0] = 0; // subaddress | ||
| 559 | buf[1] = N >> 8; | ||
| 560 | buf[2] = N & 0xff; | ||
| 561 | buf[3] = 0; | ||
| 562 | buf[4] = 0x16; | ||
| 563 | buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + | ||
| 564 | frequency_map[i].sbs; | ||
| 565 | buf[6] = 0x4b + (frequency_map[i].gc3 << 4); | ||
| 566 | buf[7] = 0x1c; | ||
| 567 | buf[8] = 0x06; | ||
| 568 | buf[9] = 0x24; | ||
| 569 | buf[10] = 0x00; | ||
| 570 | msg.len = 11; | ||
| 571 | rc = tuner_transfer(fe, &msg, 1); | ||
| 572 | if (rc < 0) | ||
| 573 | goto err; | ||
| 574 | |||
| 575 | buf[0] = 0x90; | ||
| 576 | buf[1] = 0xff; | ||
| 577 | buf[2] = 0x60; | ||
| 578 | buf[3] = 0x00; | ||
| 579 | buf[4] = 0x59; // lpsel, for 6MHz + 2 | ||
| 580 | msg.len = 5; | ||
| 581 | rc = tuner_transfer(fe, &msg, 1); | ||
| 582 | if (rc < 0) | ||
| 583 | goto err; | ||
| 584 | |||
| 585 | buf[0] = 0xa0; | ||
| 586 | buf[1] = 0x40; | ||
| 587 | msg.len = 2; | ||
| 588 | rc = tuner_transfer(fe, &msg, 1); | ||
| 589 | if (rc < 0) | ||
| 590 | goto err; | ||
| 591 | |||
| 592 | msleep(11); | ||
| 593 | msg.flags = I2C_M_RD; | ||
| 594 | rc = tuner_transfer(fe, &msg, 1); | ||
| 595 | if (rc < 0) | ||
| 596 | goto err; | ||
| 597 | msg.flags = 0; | ||
| 598 | |||
| 599 | buf[1] >>= 4; | ||
| 600 | dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); | ||
| 601 | if ((buf[1]) < 2) { | ||
| 602 | tda827xa_lna_gain(fe, 0, NULL); | ||
| 603 | buf[0] = 0x60; | ||
| 604 | buf[1] = 0x0c; | ||
| 605 | rc = tuner_transfer(fe, &msg, 1); | ||
| 606 | if (rc < 0) | ||
| 607 | goto err; | ||
| 608 | } | ||
| 609 | |||
| 610 | buf[0] = 0xc0; | ||
| 611 | buf[1] = 0x99; // lpsel, for 6MHz + 2 | ||
| 612 | rc = tuner_transfer(fe, &msg, 1); | ||
| 613 | if (rc < 0) | ||
| 614 | goto err; | ||
| 615 | |||
| 616 | buf[0] = 0x60; | ||
| 617 | buf[1] = 0x3c; | ||
| 618 | rc = tuner_transfer(fe, &msg, 1); | ||
| 619 | if (rc < 0) | ||
| 620 | goto err; | ||
| 621 | |||
| 622 | /* correct CP value */ | ||
| 623 | buf[0] = 0x30; | ||
| 624 | buf[1] = 0x10 + frequency_map[i].scr; | ||
| 625 | rc = tuner_transfer(fe, &msg, 1); | ||
| 626 | if (rc < 0) | ||
| 627 | goto err; | ||
| 628 | |||
| 629 | msleep(163); | ||
| 630 | buf[0] = 0xc0; | ||
| 631 | buf[1] = 0x39; // lpsel, for 6MHz + 2 | ||
| 632 | rc = tuner_transfer(fe, &msg, 1); | ||
| 633 | if (rc < 0) | ||
| 634 | goto err; | ||
| 635 | |||
| 636 | msleep(3); | ||
| 637 | /* freeze AGC1 */ | ||
| 638 | buf[0] = 0x50; | ||
| 639 | buf[1] = 0x4f + (frequency_map[i].gc3 << 4); | ||
| 640 | rc = tuner_transfer(fe, &msg, 1); | ||
| 641 | if (rc < 0) | ||
| 642 | goto err; | ||
| 643 | |||
| 644 | priv->frequency = params->frequency; | ||
| 645 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
| 646 | |||
| 647 | |||
| 648 | return 0; | ||
| 649 | |||
| 650 | err: | ||
| 651 | printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", | ||
| 652 | __func__, priv->i2c_addr << 1); | ||
| 653 | return rc; | ||
| 654 | } | ||
| 655 | |||
| 656 | |||
| 657 | static int tda827xa_set_analog_params(struct dvb_frontend *fe, | ||
| 658 | struct analog_parameters *params) | ||
| 659 | { | ||
| 660 | unsigned char tuner_reg[11]; | ||
| 661 | u32 N; | ||
| 662 | int i; | ||
| 663 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 664 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
| 665 | .buf = tuner_reg, .len = sizeof(tuner_reg) }; | ||
| 666 | unsigned int freq = params->frequency; | ||
| 667 | |||
| 668 | tda827x_set_std(fe, params); | ||
| 669 | |||
| 670 | tda827xa_lna_gain(fe, 1, params); | ||
| 671 | msleep(10); | ||
| 672 | |||
| 673 | if (params->mode == V4L2_TUNER_RADIO) | ||
| 674 | freq = freq / 1000; | ||
| 675 | |||
| 676 | N = freq + priv->sgIF; | ||
| 677 | |||
| 678 | i = 0; | ||
| 679 | while (tda827xa_analog[i].lomax < N * 62500) { | ||
| 680 | if (tda827xa_analog[i + 1].lomax == 0) | ||
| 681 | break; | ||
| 682 | i++; | ||
| 683 | } | ||
| 684 | |||
| 685 | N = N << tda827xa_analog[i].spd; | ||
| 686 | |||
| 687 | tuner_reg[0] = 0; | ||
| 688 | tuner_reg[1] = (unsigned char)(N>>8); | ||
| 689 | tuner_reg[2] = (unsigned char) N; | ||
| 690 | tuner_reg[3] = 0; | ||
| 691 | tuner_reg[4] = 0x16; | ||
| 692 | tuner_reg[5] = (tda827xa_analog[i].spd << 5) + | ||
| 693 | (tda827xa_analog[i].svco << 3) + | ||
| 694 | tda827xa_analog[i].sbs; | ||
| 695 | tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); | ||
| 696 | tuner_reg[7] = 0x1c; | ||
| 697 | tuner_reg[8] = 4; | ||
| 698 | tuner_reg[9] = 0x20; | ||
| 699 | tuner_reg[10] = 0x00; | ||
| 700 | msg.len = 11; | ||
| 701 | tuner_transfer(fe, &msg, 1); | ||
| 702 | |||
| 703 | tuner_reg[0] = 0x90; | ||
| 704 | tuner_reg[1] = 0xff; | ||
| 705 | tuner_reg[2] = 0xe0; | ||
| 706 | tuner_reg[3] = 0; | ||
| 707 | tuner_reg[4] = 0x99 + (priv->lpsel << 1); | ||
| 708 | msg.len = 5; | ||
| 709 | tuner_transfer(fe, &msg, 1); | ||
| 710 | |||
| 711 | tuner_reg[0] = 0xa0; | ||
| 712 | tuner_reg[1] = 0xc0; | ||
| 713 | msg.len = 2; | ||
| 714 | tuner_transfer(fe, &msg, 1); | ||
| 715 | |||
| 716 | tuner_reg[0] = 0x30; | ||
| 717 | tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; | ||
| 718 | tuner_transfer(fe, &msg, 1); | ||
| 719 | |||
| 720 | msg.flags = I2C_M_RD; | ||
| 721 | tuner_transfer(fe, &msg, 1); | ||
| 722 | msg.flags = 0; | ||
| 723 | tuner_reg[1] >>= 4; | ||
| 724 | dprintk("AGC2 gain is: %d\n", tuner_reg[1]); | ||
| 725 | if (tuner_reg[1] < 1) | ||
| 726 | tda827xa_lna_gain(fe, 0, params); | ||
| 727 | |||
| 728 | msleep(100); | ||
| 729 | tuner_reg[0] = 0x60; | ||
| 730 | tuner_reg[1] = 0x3c; | ||
| 731 | tuner_transfer(fe, &msg, 1); | ||
| 732 | |||
| 733 | msleep(163); | ||
| 734 | tuner_reg[0] = 0x50; | ||
| 735 | tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); | ||
| 736 | tuner_transfer(fe, &msg, 1); | ||
| 737 | |||
| 738 | tuner_reg[0] = 0x80; | ||
| 739 | tuner_reg[1] = 0x28; | ||
| 740 | tuner_transfer(fe, &msg, 1); | ||
| 741 | |||
| 742 | tuner_reg[0] = 0xb0; | ||
| 743 | tuner_reg[1] = 0x01; | ||
| 744 | tuner_transfer(fe, &msg, 1); | ||
| 745 | |||
| 746 | tuner_reg[0] = 0xc0; | ||
| 747 | tuner_reg[1] = 0x19 + (priv->lpsel << 1); | ||
| 748 | tuner_transfer(fe, &msg, 1); | ||
| 749 | |||
| 750 | priv->frequency = params->frequency; | ||
| 751 | |||
| 752 | return 0; | ||
| 753 | } | ||
| 754 | |||
| 755 | static void tda827xa_agcf(struct dvb_frontend *fe) | ||
| 756 | { | ||
| 757 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 758 | unsigned char data[] = {0x80, 0x2c}; | ||
| 759 | struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, | ||
| 760 | .buf = data, .len = 2}; | ||
| 761 | tuner_transfer(fe, &msg, 1); | ||
| 762 | } | ||
| 763 | |||
| 764 | /* ------------------------------------------------------------------ */ | ||
| 765 | |||
| 766 | static int tda827x_release(struct dvb_frontend *fe) | ||
| 767 | { | ||
| 768 | kfree(fe->tuner_priv); | ||
| 769 | fe->tuner_priv = NULL; | ||
| 770 | return 0; | ||
| 771 | } | ||
| 772 | |||
| 773 | static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 774 | { | ||
| 775 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 776 | *frequency = priv->frequency; | ||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 781 | { | ||
| 782 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 783 | *bandwidth = priv->bandwidth; | ||
| 784 | return 0; | ||
| 785 | } | ||
| 786 | |||
| 787 | static int tda827x_init(struct dvb_frontend *fe) | ||
| 788 | { | ||
| 789 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 790 | dprintk("%s:\n", __func__); | ||
| 791 | if (priv->cfg && priv->cfg->init) | ||
| 792 | priv->cfg->init(fe); | ||
| 793 | |||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | static int tda827x_probe_version(struct dvb_frontend *fe); | ||
| 798 | |||
| 799 | static int tda827x_initial_init(struct dvb_frontend *fe) | ||
| 800 | { | ||
| 801 | int ret; | ||
| 802 | ret = tda827x_probe_version(fe); | ||
| 803 | if (ret) | ||
| 804 | return ret; | ||
| 805 | return fe->ops.tuner_ops.init(fe); | ||
| 806 | } | ||
| 807 | |||
| 808 | static int tda827x_initial_sleep(struct dvb_frontend *fe) | ||
| 809 | { | ||
| 810 | int ret; | ||
| 811 | ret = tda827x_probe_version(fe); | ||
| 812 | if (ret) | ||
| 813 | return ret; | ||
| 814 | return fe->ops.tuner_ops.sleep(fe); | ||
| 815 | } | ||
| 816 | |||
| 817 | static struct dvb_tuner_ops tda827xo_tuner_ops = { | ||
| 818 | .info = { | ||
| 819 | .name = "Philips TDA827X", | ||
| 820 | .frequency_min = 55000000, | ||
| 821 | .frequency_max = 860000000, | ||
| 822 | .frequency_step = 250000 | ||
| 823 | }, | ||
| 824 | .release = tda827x_release, | ||
| 825 | .init = tda827x_initial_init, | ||
| 826 | .sleep = tda827x_initial_sleep, | ||
| 827 | .set_params = tda827xo_set_params, | ||
| 828 | .set_analog_params = tda827xo_set_analog_params, | ||
| 829 | .get_frequency = tda827x_get_frequency, | ||
| 830 | .get_bandwidth = tda827x_get_bandwidth, | ||
| 831 | }; | ||
| 832 | |||
| 833 | static struct dvb_tuner_ops tda827xa_tuner_ops = { | ||
| 834 | .info = { | ||
| 835 | .name = "Philips TDA827XA", | ||
| 836 | .frequency_min = 44000000, | ||
| 837 | .frequency_max = 906000000, | ||
| 838 | .frequency_step = 62500 | ||
| 839 | }, | ||
| 840 | .release = tda827x_release, | ||
| 841 | .init = tda827x_init, | ||
| 842 | .sleep = tda827xa_sleep, | ||
| 843 | .set_params = tda827xa_set_params, | ||
| 844 | .set_analog_params = tda827xa_set_analog_params, | ||
| 845 | .get_frequency = tda827x_get_frequency, | ||
| 846 | .get_bandwidth = tda827x_get_bandwidth, | ||
| 847 | }; | ||
| 848 | |||
| 849 | static int tda827x_probe_version(struct dvb_frontend *fe) | ||
| 850 | { | ||
| 851 | u8 data; | ||
| 852 | int rc; | ||
| 853 | struct tda827x_priv *priv = fe->tuner_priv; | ||
| 854 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, | ||
| 855 | .buf = &data, .len = 1 }; | ||
| 856 | |||
| 857 | rc = tuner_transfer(fe, &msg, 1); | ||
| 858 | |||
| 859 | if (rc < 0) { | ||
| 860 | printk("%s: could not read from tuner at addr: 0x%02x\n", | ||
| 861 | __func__, msg.addr << 1); | ||
| 862 | return rc; | ||
| 863 | } | ||
| 864 | if ((data & 0x3c) == 0) { | ||
| 865 | dprintk("tda827x tuner found\n"); | ||
| 866 | fe->ops.tuner_ops.init = tda827x_init; | ||
| 867 | fe->ops.tuner_ops.sleep = tda827xo_sleep; | ||
| 868 | if (priv->cfg) | ||
| 869 | priv->cfg->agcf = tda827xo_agcf; | ||
| 870 | } else { | ||
| 871 | dprintk("tda827xa tuner found\n"); | ||
| 872 | memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
| 873 | if (priv->cfg) | ||
| 874 | priv->cfg->agcf = tda827xa_agcf; | ||
| 875 | } | ||
| 876 | return 0; | ||
| 877 | } | ||
| 878 | |||
| 879 | struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, | ||
| 880 | struct i2c_adapter *i2c, | ||
| 881 | struct tda827x_config *cfg) | ||
| 882 | { | ||
| 883 | struct tda827x_priv *priv = NULL; | ||
| 884 | |||
| 885 | dprintk("%s:\n", __func__); | ||
| 886 | priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); | ||
| 887 | if (priv == NULL) | ||
| 888 | return NULL; | ||
| 889 | |||
| 890 | priv->i2c_addr = addr; | ||
| 891 | priv->i2c_adap = i2c; | ||
| 892 | priv->cfg = cfg; | ||
| 893 | memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
| 894 | fe->tuner_priv = priv; | ||
| 895 | |||
| 896 | dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); | ||
| 897 | |||
| 898 | return fe; | ||
| 899 | } | ||
| 900 | EXPORT_SYMBOL_GPL(tda827x_attach); | ||
| 901 | |||
| 902 | MODULE_DESCRIPTION("DVB TDA827x driver"); | ||
| 903 | MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); | ||
| 904 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
| 905 | MODULE_LICENSE("GPL"); | ||
| 906 | |||
| 907 | /* | ||
| 908 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 909 | * --------------------------------------------------------------------------- | ||
| 910 | * Local variables: | ||
| 911 | * c-basic-offset: 8 | ||
| 912 | * End: | ||
| 913 | */ | ||
diff --git a/drivers/media/common/tuners/tda827x.h b/drivers/media/common/tuners/tda827x.h new file mode 100644 index 00000000000..7d72ce0a0c2 --- /dev/null +++ b/drivers/media/common/tuners/tda827x.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | DVB Driver for Philips tda827x / tda827xa Silicon tuners | ||
| 3 | |||
| 4 | (c) 2005 Hartmut Hackmann | ||
| 5 | (c) 2007 Michael Krufky | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2 of the License, or | ||
| 10 | (at your option) any later version. | ||
| 11 | |||
| 12 | This program is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | |||
| 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 | |||
| 24 | #ifndef __DVB_TDA827X_H__ | ||
| 25 | #define __DVB_TDA827X_H__ | ||
| 26 | |||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include "dvb_frontend.h" | ||
| 29 | |||
| 30 | struct tda827x_config | ||
| 31 | { | ||
| 32 | /* saa7134 - provided callbacks */ | ||
| 33 | int (*init) (struct dvb_frontend *fe); | ||
| 34 | int (*sleep) (struct dvb_frontend *fe); | ||
| 35 | |||
| 36 | /* interface to tda829x driver */ | ||
| 37 | unsigned int config; | ||
| 38 | int switch_addr; | ||
| 39 | |||
| 40 | void (*agcf)(struct dvb_frontend *fe); | ||
| 41 | }; | ||
| 42 | |||
| 43 | |||
| 44 | /** | ||
| 45 | * Attach a tda827x tuner to the supplied frontend structure. | ||
| 46 | * | ||
| 47 | * @param fe Frontend to attach to. | ||
| 48 | * @param addr i2c address of the tuner. | ||
| 49 | * @param i2c i2c adapter to use. | ||
| 50 | * @param cfg optional callback function pointers. | ||
| 51 | * @return FE pointer on success, NULL on failure. | ||
| 52 | */ | ||
| 53 | #if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) | ||
| 54 | extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, | ||
| 55 | struct i2c_adapter *i2c, | ||
| 56 | struct tda827x_config *cfg); | ||
| 57 | #else | ||
| 58 | static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, | ||
| 59 | int addr, | ||
| 60 | struct i2c_adapter *i2c, | ||
| 61 | struct tda827x_config *cfg) | ||
| 62 | { | ||
| 63 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 64 | return NULL; | ||
| 65 | } | ||
| 66 | #endif // CONFIG_MEDIA_TUNER_TDA827X | ||
| 67 | |||
| 68 | #endif // __DVB_TDA827X_H__ | ||
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c new file mode 100644 index 00000000000..8c4852114ee --- /dev/null +++ b/drivers/media/common/tuners/tda8290.c | |||
| @@ -0,0 +1,874 @@ | |||
| 1 | /* | ||
| 2 | |||
| 3 | i2c tv tuner chip device driver | ||
| 4 | controls the philips tda8290+75 tuner chip combo. | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | |||
| 20 | This "tda8290" module was split apart from the original "tuner" module. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/i2c.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/videodev2.h> | ||
| 27 | #include "tuner-i2c.h" | ||
| 28 | #include "tda8290.h" | ||
| 29 | #include "tda827x.h" | ||
| 30 | #include "tda18271.h" | ||
| 31 | |||
| 32 | static int debug; | ||
| 33 | module_param(debug, int, 0644); | ||
| 34 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 35 | |||
| 36 | static int deemphasis_50; | ||
| 37 | module_param(deemphasis_50, int, 0644); | ||
| 38 | MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); | ||
| 39 | |||
| 40 | /* ---------------------------------------------------------------------- */ | ||
| 41 | |||
| 42 | struct tda8290_priv { | ||
| 43 | struct tuner_i2c_props i2c_props; | ||
| 44 | |||
| 45 | unsigned char tda8290_easy_mode; | ||
| 46 | |||
| 47 | unsigned char tda827x_addr; | ||
| 48 | |||
| 49 | unsigned char ver; | ||
| 50 | #define TDA8290 1 | ||
| 51 | #define TDA8295 2 | ||
| 52 | #define TDA8275 4 | ||
| 53 | #define TDA8275A 8 | ||
| 54 | #define TDA18271 16 | ||
| 55 | |||
| 56 | struct tda827x_config cfg; | ||
| 57 | }; | ||
| 58 | |||
| 59 | /*---------------------------------------------------------------------*/ | ||
| 60 | |||
| 61 | static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) | ||
| 62 | { | ||
| 63 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 64 | |||
| 65 | unsigned char enable[2] = { 0x21, 0xC0 }; | ||
| 66 | unsigned char disable[2] = { 0x21, 0x00 }; | ||
| 67 | unsigned char *msg; | ||
| 68 | |||
| 69 | if (close) { | ||
| 70 | msg = enable; | ||
| 71 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
| 72 | /* let the bridge stabilize */ | ||
| 73 | msleep(20); | ||
| 74 | } else { | ||
| 75 | msg = disable; | ||
| 76 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
| 77 | } | ||
| 78 | |||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) | ||
| 83 | { | ||
| 84 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 85 | |||
| 86 | unsigned char enable[2] = { 0x45, 0xc1 }; | ||
| 87 | unsigned char disable[2] = { 0x46, 0x00 }; | ||
| 88 | unsigned char buf[3] = { 0x45, 0x01, 0x00 }; | ||
| 89 | unsigned char *msg; | ||
| 90 | |||
| 91 | if (close) { | ||
| 92 | msg = enable; | ||
| 93 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
| 94 | /* let the bridge stabilize */ | ||
| 95 | msleep(20); | ||
| 96 | } else { | ||
| 97 | msg = disable; | ||
| 98 | tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); | ||
| 99 | |||
| 100 | buf[2] = msg[1]; | ||
| 101 | buf[2] &= ~0x04; | ||
| 102 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); | ||
| 103 | msleep(5); | ||
| 104 | |||
| 105 | msg[1] |= 0x04; | ||
| 106 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
| 107 | } | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | /*---------------------------------------------------------------------*/ | ||
| 113 | |||
| 114 | static void set_audio(struct dvb_frontend *fe, | ||
| 115 | struct analog_parameters *params) | ||
| 116 | { | ||
| 117 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 118 | char* mode; | ||
| 119 | |||
| 120 | if (params->std & V4L2_STD_MN) { | ||
| 121 | priv->tda8290_easy_mode = 0x01; | ||
| 122 | mode = "MN"; | ||
| 123 | } else if (params->std & V4L2_STD_B) { | ||
| 124 | priv->tda8290_easy_mode = 0x02; | ||
| 125 | mode = "B"; | ||
| 126 | } else if (params->std & V4L2_STD_GH) { | ||
| 127 | priv->tda8290_easy_mode = 0x04; | ||
| 128 | mode = "GH"; | ||
| 129 | } else if (params->std & V4L2_STD_PAL_I) { | ||
| 130 | priv->tda8290_easy_mode = 0x08; | ||
| 131 | mode = "I"; | ||
| 132 | } else if (params->std & V4L2_STD_DK) { | ||
| 133 | priv->tda8290_easy_mode = 0x10; | ||
| 134 | mode = "DK"; | ||
| 135 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
| 136 | priv->tda8290_easy_mode = 0x20; | ||
| 137 | mode = "L"; | ||
| 138 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
| 139 | priv->tda8290_easy_mode = 0x40; | ||
| 140 | mode = "LC"; | ||
| 141 | } else { | ||
| 142 | priv->tda8290_easy_mode = 0x10; | ||
| 143 | mode = "xx"; | ||
| 144 | } | ||
| 145 | |||
| 146 | if (params->mode == V4L2_TUNER_RADIO) { | ||
| 147 | /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ | ||
| 148 | priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; | ||
| 149 | tuner_dbg("setting to radio FM\n"); | ||
| 150 | } else { | ||
| 151 | tuner_dbg("setting tda829x to system %s\n", mode); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | static struct { | ||
| 156 | unsigned char seq[2]; | ||
| 157 | } fm_mode[] = { | ||
| 158 | { { 0x01, 0x81} }, /* Put device into expert mode */ | ||
| 159 | { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ | ||
| 160 | { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ | ||
| 161 | { { 0x05, 0x04} }, /* ADC headroom */ | ||
| 162 | { { 0x06, 0x10} }, /* group delay flat */ | ||
| 163 | |||
| 164 | { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ | ||
| 165 | { { 0x08, 0x00} }, | ||
| 166 | { { 0x09, 0x80} }, | ||
| 167 | { { 0x0a, 0xda} }, | ||
| 168 | { { 0x0b, 0x4b} }, | ||
| 169 | { { 0x0c, 0x68} }, | ||
| 170 | |||
| 171 | { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ | ||
| 172 | { { 0x14, 0x00} }, /* disable auto mute if no video */ | ||
| 173 | }; | ||
| 174 | |||
| 175 | static void tda8290_set_params(struct dvb_frontend *fe, | ||
| 176 | struct analog_parameters *params) | ||
| 177 | { | ||
| 178 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 179 | |||
| 180 | unsigned char soft_reset[] = { 0x00, 0x00 }; | ||
| 181 | unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; | ||
| 182 | unsigned char expert_mode[] = { 0x01, 0x80 }; | ||
| 183 | unsigned char agc_out_on[] = { 0x02, 0x00 }; | ||
| 184 | unsigned char gainset_off[] = { 0x28, 0x14 }; | ||
| 185 | unsigned char if_agc_spd[] = { 0x0f, 0x88 }; | ||
| 186 | unsigned char adc_head_6[] = { 0x05, 0x04 }; | ||
| 187 | unsigned char adc_head_9[] = { 0x05, 0x02 }; | ||
| 188 | unsigned char adc_head_12[] = { 0x05, 0x01 }; | ||
| 189 | unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; | ||
| 190 | unsigned char pll_bw_low[] = { 0x0d, 0x27 }; | ||
| 191 | unsigned char gainset_2[] = { 0x28, 0x64 }; | ||
| 192 | unsigned char agc_rst_on[] = { 0x0e, 0x0b }; | ||
| 193 | unsigned char agc_rst_off[] = { 0x0e, 0x09 }; | ||
| 194 | unsigned char if_agc_set[] = { 0x0f, 0x81 }; | ||
| 195 | unsigned char addr_adc_sat = 0x1a; | ||
| 196 | unsigned char addr_agc_stat = 0x1d; | ||
| 197 | unsigned char addr_pll_stat = 0x1b; | ||
| 198 | unsigned char adc_sat, agc_stat, | ||
| 199 | pll_stat; | ||
| 200 | int i; | ||
| 201 | |||
| 202 | set_audio(fe, params); | ||
| 203 | |||
| 204 | if (priv->cfg.config) | ||
| 205 | tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); | ||
| 206 | tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); | ||
| 207 | tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); | ||
| 208 | tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); | ||
| 209 | msleep(1); | ||
| 210 | |||
| 211 | if (params->mode == V4L2_TUNER_RADIO) { | ||
| 212 | unsigned char deemphasis[] = { 0x13, 1 }; | ||
| 213 | |||
| 214 | /* FIXME: allow using a different deemphasis */ | ||
| 215 | |||
| 216 | if (deemphasis_50) | ||
| 217 | deemphasis[1] = 2; | ||
| 218 | |||
| 219 | for (i = 0; i < ARRAY_SIZE(fm_mode); i++) | ||
| 220 | tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); | ||
| 221 | |||
| 222 | tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); | ||
| 223 | } else { | ||
| 224 | expert_mode[1] = priv->tda8290_easy_mode + 0x80; | ||
| 225 | tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); | ||
| 226 | tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); | ||
| 227 | tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); | ||
| 228 | if (priv->tda8290_easy_mode & 0x60) | ||
| 229 | tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); | ||
| 230 | else | ||
| 231 | tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); | ||
| 232 | tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); | ||
| 233 | } | ||
| 234 | |||
| 235 | |||
| 236 | tda8290_i2c_bridge(fe, 1); | ||
| 237 | |||
| 238 | if (fe->ops.tuner_ops.set_analog_params) | ||
| 239 | fe->ops.tuner_ops.set_analog_params(fe, params); | ||
| 240 | |||
| 241 | for (i = 0; i < 3; i++) { | ||
| 242 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 243 | &addr_pll_stat, 1, &pll_stat, 1); | ||
| 244 | if (pll_stat & 0x80) { | ||
| 245 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 246 | &addr_adc_sat, 1, | ||
| 247 | &adc_sat, 1); | ||
| 248 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 249 | &addr_agc_stat, 1, | ||
| 250 | &agc_stat, 1); | ||
| 251 | tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); | ||
| 252 | break; | ||
| 253 | } else { | ||
| 254 | tuner_dbg("tda8290 not locked, no signal?\n"); | ||
| 255 | msleep(100); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | /* adjust headroom resp. gain */ | ||
| 259 | if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { | ||
| 260 | tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", | ||
| 261 | agc_stat, adc_sat, pll_stat & 0x80); | ||
| 262 | tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); | ||
| 263 | msleep(100); | ||
| 264 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 265 | &addr_agc_stat, 1, &agc_stat, 1); | ||
| 266 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 267 | &addr_pll_stat, 1, &pll_stat, 1); | ||
| 268 | if ((agc_stat > 115) || !(pll_stat & 0x80)) { | ||
| 269 | tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", | ||
| 270 | agc_stat, pll_stat & 0x80); | ||
| 271 | if (priv->cfg.agcf) | ||
| 272 | priv->cfg.agcf(fe); | ||
| 273 | msleep(100); | ||
| 274 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 275 | &addr_agc_stat, 1, | ||
| 276 | &agc_stat, 1); | ||
| 277 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 278 | &addr_pll_stat, 1, | ||
| 279 | &pll_stat, 1); | ||
| 280 | if((agc_stat > 115) || !(pll_stat & 0x80)) { | ||
| 281 | tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); | ||
| 282 | tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); | ||
| 283 | tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); | ||
| 284 | msleep(100); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | /* l/ l' deadlock? */ | ||
| 290 | if(priv->tda8290_easy_mode & 0x60) { | ||
| 291 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 292 | &addr_adc_sat, 1, | ||
| 293 | &adc_sat, 1); | ||
| 294 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 295 | &addr_pll_stat, 1, | ||
| 296 | &pll_stat, 1); | ||
| 297 | if ((adc_sat > 20) || !(pll_stat & 0x80)) { | ||
| 298 | tuner_dbg("trying to resolve SECAM L deadlock\n"); | ||
| 299 | tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); | ||
| 300 | msleep(40); | ||
| 301 | tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | tda8290_i2c_bridge(fe, 0); | ||
| 306 | tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); | ||
| 307 | } | ||
| 308 | |||
| 309 | /*---------------------------------------------------------------------*/ | ||
| 310 | |||
| 311 | static void tda8295_power(struct dvb_frontend *fe, int enable) | ||
| 312 | { | ||
| 313 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 314 | unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ | ||
| 315 | |||
| 316 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); | ||
| 317 | |||
| 318 | if (enable) | ||
| 319 | buf[1] = 0x01; | ||
| 320 | else | ||
| 321 | buf[1] = 0x03; | ||
| 322 | |||
| 323 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
| 324 | } | ||
| 325 | |||
| 326 | static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) | ||
| 327 | { | ||
| 328 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 329 | unsigned char buf[] = { 0x01, 0x00 }; | ||
| 330 | |||
| 331 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); | ||
| 332 | |||
| 333 | if (enable) | ||
| 334 | buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ | ||
| 335 | else | ||
| 336 | buf[1] = 0x00; /* reset active bit */ | ||
| 337 | |||
| 338 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
| 339 | } | ||
| 340 | |||
| 341 | static void tda8295_set_video_std(struct dvb_frontend *fe) | ||
| 342 | { | ||
| 343 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 344 | unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; | ||
| 345 | |||
| 346 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
| 347 | |||
| 348 | tda8295_set_easy_mode(fe, 1); | ||
| 349 | msleep(20); | ||
| 350 | tda8295_set_easy_mode(fe, 0); | ||
| 351 | } | ||
| 352 | |||
| 353 | /*---------------------------------------------------------------------*/ | ||
| 354 | |||
| 355 | static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) | ||
| 356 | { | ||
| 357 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 358 | unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ | ||
| 359 | |||
| 360 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); | ||
| 361 | |||
| 362 | if (enable) | ||
| 363 | buf[1] &= ~0x40; | ||
| 364 | else | ||
| 365 | buf[1] |= 0x40; | ||
| 366 | |||
| 367 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
| 368 | } | ||
| 369 | |||
| 370 | static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) | ||
| 371 | { | ||
| 372 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 373 | unsigned char set_gpio_cf[] = { 0x44, 0x00 }; | ||
| 374 | unsigned char set_gpio_val[] = { 0x46, 0x00 }; | ||
| 375 | |||
| 376 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 377 | &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); | ||
| 378 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 379 | &set_gpio_val[0], 1, &set_gpio_val[1], 1); | ||
| 380 | |||
| 381 | set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ | ||
| 382 | |||
| 383 | if (enable) { | ||
| 384 | set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ | ||
| 385 | set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ | ||
| 386 | } | ||
| 387 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); | ||
| 388 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); | ||
| 389 | } | ||
| 390 | |||
| 391 | static int tda8295_has_signal(struct dvb_frontend *fe) | ||
| 392 | { | ||
| 393 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 394 | |||
| 395 | unsigned char hvpll_stat = 0x26; | ||
| 396 | unsigned char ret; | ||
| 397 | |||
| 398 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); | ||
| 399 | return (ret & 0x01) ? 65535 : 0; | ||
| 400 | } | ||
| 401 | |||
| 402 | /*---------------------------------------------------------------------*/ | ||
| 403 | |||
| 404 | static void tda8295_set_params(struct dvb_frontend *fe, | ||
| 405 | struct analog_parameters *params) | ||
| 406 | { | ||
| 407 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 408 | |||
| 409 | unsigned char blanking_mode[] = { 0x1d, 0x00 }; | ||
| 410 | |||
| 411 | set_audio(fe, params); | ||
| 412 | |||
| 413 | tuner_dbg("%s: freq = %d\n", __func__, params->frequency); | ||
| 414 | |||
| 415 | tda8295_power(fe, 1); | ||
| 416 | tda8295_agc1_out(fe, 1); | ||
| 417 | |||
| 418 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 419 | &blanking_mode[0], 1, &blanking_mode[1], 1); | ||
| 420 | |||
| 421 | tda8295_set_video_std(fe); | ||
| 422 | |||
| 423 | blanking_mode[1] = 0x03; | ||
| 424 | tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); | ||
| 425 | msleep(20); | ||
| 426 | |||
| 427 | tda8295_i2c_bridge(fe, 1); | ||
| 428 | |||
| 429 | if (fe->ops.tuner_ops.set_analog_params) | ||
| 430 | fe->ops.tuner_ops.set_analog_params(fe, params); | ||
| 431 | |||
| 432 | if (priv->cfg.agcf) | ||
| 433 | priv->cfg.agcf(fe); | ||
| 434 | |||
| 435 | if (tda8295_has_signal(fe)) | ||
| 436 | tuner_dbg("tda8295 is locked\n"); | ||
| 437 | else | ||
| 438 | tuner_dbg("tda8295 not locked, no signal?\n"); | ||
| 439 | |||
| 440 | tda8295_i2c_bridge(fe, 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | /*---------------------------------------------------------------------*/ | ||
| 444 | |||
| 445 | static int tda8290_has_signal(struct dvb_frontend *fe) | ||
| 446 | { | ||
| 447 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 448 | |||
| 449 | unsigned char i2c_get_afc[1] = { 0x1B }; | ||
| 450 | unsigned char afc = 0; | ||
| 451 | |||
| 452 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
| 453 | i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); | ||
| 454 | return (afc & 0x80)? 65535:0; | ||
| 455 | } | ||
| 456 | |||
| 457 | /*---------------------------------------------------------------------*/ | ||
| 458 | |||
| 459 | static void tda8290_standby(struct dvb_frontend *fe) | ||
| 460 | { | ||
| 461 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 462 | |||
| 463 | unsigned char cb1[] = { 0x30, 0xD0 }; | ||
| 464 | unsigned char tda8290_standby[] = { 0x00, 0x02 }; | ||
| 465 | unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; | ||
| 466 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; | ||
| 467 | |||
| 468 | tda8290_i2c_bridge(fe, 1); | ||
| 469 | if (priv->ver & TDA8275A) | ||
| 470 | cb1[1] = 0x90; | ||
| 471 | i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
| 472 | tda8290_i2c_bridge(fe, 0); | ||
| 473 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); | ||
| 474 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); | ||
| 475 | } | ||
| 476 | |||
| 477 | static void tda8295_standby(struct dvb_frontend *fe) | ||
| 478 | { | ||
| 479 | tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ | ||
| 480 | |||
| 481 | tda8295_power(fe, 0); | ||
| 482 | } | ||
| 483 | |||
| 484 | static void tda8290_init_if(struct dvb_frontend *fe) | ||
| 485 | { | ||
| 486 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 487 | |||
| 488 | unsigned char set_VS[] = { 0x30, 0x6F }; | ||
| 489 | unsigned char set_GP00_CF[] = { 0x20, 0x01 }; | ||
| 490 | unsigned char set_GP01_CF[] = { 0x20, 0x0B }; | ||
| 491 | |||
| 492 | if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) | ||
| 493 | tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); | ||
| 494 | else | ||
| 495 | tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); | ||
| 496 | tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); | ||
| 497 | } | ||
| 498 | |||
| 499 | static void tda8295_init_if(struct dvb_frontend *fe) | ||
| 500 | { | ||
| 501 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 502 | |||
| 503 | static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; | ||
| 504 | static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; | ||
| 505 | static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; | ||
| 506 | static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; | ||
| 507 | static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; | ||
| 508 | static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; | ||
| 509 | static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; | ||
| 510 | |||
| 511 | tda8295_power(fe, 1); | ||
| 512 | |||
| 513 | tda8295_set_easy_mode(fe, 0); | ||
| 514 | tda8295_set_video_std(fe); | ||
| 515 | |||
| 516 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); | ||
| 517 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); | ||
| 518 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); | ||
| 519 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); | ||
| 520 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); | ||
| 521 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); | ||
| 522 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); | ||
| 523 | |||
| 524 | tda8295_agc1_out(fe, 0); | ||
| 525 | tda8295_agc2_out(fe, 0); | ||
| 526 | } | ||
| 527 | |||
| 528 | static void tda8290_init_tuner(struct dvb_frontend *fe) | ||
| 529 | { | ||
| 530 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 531 | unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, | ||
| 532 | 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; | ||
| 533 | unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, | ||
| 534 | 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; | ||
| 535 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, | ||
| 536 | .buf=tda8275_init, .len = 14}; | ||
| 537 | if (priv->ver & TDA8275A) | ||
| 538 | msg.buf = tda8275a_init; | ||
| 539 | |||
| 540 | tda8290_i2c_bridge(fe, 1); | ||
| 541 | i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
| 542 | tda8290_i2c_bridge(fe, 0); | ||
| 543 | } | ||
| 544 | |||
| 545 | /*---------------------------------------------------------------------*/ | ||
| 546 | |||
| 547 | static void tda829x_release(struct dvb_frontend *fe) | ||
| 548 | { | ||
| 549 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 550 | |||
| 551 | /* only try to release the tuner if we've | ||
| 552 | * attached it from within this module */ | ||
| 553 | if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) | ||
| 554 | if (fe->ops.tuner_ops.release) | ||
| 555 | fe->ops.tuner_ops.release(fe); | ||
| 556 | |||
| 557 | kfree(fe->analog_demod_priv); | ||
| 558 | fe->analog_demod_priv = NULL; | ||
| 559 | } | ||
| 560 | |||
| 561 | static struct tda18271_config tda829x_tda18271_config = { | ||
| 562 | .gate = TDA18271_GATE_ANALOG, | ||
| 563 | }; | ||
| 564 | |||
| 565 | static int tda829x_find_tuner(struct dvb_frontend *fe) | ||
| 566 | { | ||
| 567 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
| 568 | struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; | ||
| 569 | int i, ret, tuners_found; | ||
| 570 | u32 tuner_addrs; | ||
| 571 | u8 data; | ||
| 572 | struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; | ||
| 573 | |||
| 574 | if (!analog_ops->i2c_gate_ctrl) { | ||
| 575 | printk(KERN_ERR "tda8290: no gate control were provided!\n"); | ||
| 576 | |||
| 577 | return -EINVAL; | ||
| 578 | } | ||
| 579 | |||
| 580 | analog_ops->i2c_gate_ctrl(fe, 1); | ||
| 581 | |||
| 582 | /* probe for tuner chip */ | ||
| 583 | tuners_found = 0; | ||
| 584 | tuner_addrs = 0; | ||
| 585 | for (i = 0x60; i <= 0x63; i++) { | ||
| 586 | msg.addr = i; | ||
| 587 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
| 588 | if (ret == 1) { | ||
| 589 | tuners_found++; | ||
| 590 | tuner_addrs = (tuner_addrs << 8) + i; | ||
| 591 | } | ||
| 592 | } | ||
| 593 | /* if there is more than one tuner, we expect the right one is | ||
| 594 | behind the bridge and we choose the highest address that doesn't | ||
| 595 | give a response now | ||
| 596 | */ | ||
| 597 | |||
| 598 | analog_ops->i2c_gate_ctrl(fe, 0); | ||
| 599 | |||
| 600 | if (tuners_found > 1) | ||
| 601 | for (i = 0; i < tuners_found; i++) { | ||
| 602 | msg.addr = tuner_addrs & 0xff; | ||
| 603 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
| 604 | if (ret == 1) | ||
| 605 | tuner_addrs = tuner_addrs >> 8; | ||
| 606 | else | ||
| 607 | break; | ||
| 608 | } | ||
| 609 | |||
| 610 | if (tuner_addrs == 0) { | ||
| 611 | tuner_addrs = 0x60; | ||
| 612 | tuner_info("could not clearly identify tuner address, " | ||
| 613 | "defaulting to %x\n", tuner_addrs); | ||
| 614 | } else { | ||
| 615 | tuner_addrs = tuner_addrs & 0xff; | ||
| 616 | tuner_info("setting tuner address to %x\n", tuner_addrs); | ||
| 617 | } | ||
| 618 | priv->tda827x_addr = tuner_addrs; | ||
| 619 | msg.addr = tuner_addrs; | ||
| 620 | |||
| 621 | analog_ops->i2c_gate_ctrl(fe, 1); | ||
| 622 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
| 623 | |||
| 624 | if (ret != 1) { | ||
| 625 | tuner_warn("tuner access failed!\n"); | ||
| 626 | analog_ops->i2c_gate_ctrl(fe, 0); | ||
| 627 | return -EREMOTEIO; | ||
| 628 | } | ||
| 629 | |||
| 630 | if ((data == 0x83) || (data == 0x84)) { | ||
| 631 | priv->ver |= TDA18271; | ||
| 632 | tda829x_tda18271_config.config = priv->cfg.config; | ||
| 633 | dvb_attach(tda18271_attach, fe, priv->tda827x_addr, | ||
| 634 | priv->i2c_props.adap, &tda829x_tda18271_config); | ||
| 635 | } else { | ||
| 636 | if ((data & 0x3c) == 0) | ||
| 637 | priv->ver |= TDA8275; | ||
| 638 | else | ||
| 639 | priv->ver |= TDA8275A; | ||
| 640 | |||
| 641 | dvb_attach(tda827x_attach, fe, priv->tda827x_addr, | ||
| 642 | priv->i2c_props.adap, &priv->cfg); | ||
| 643 | priv->cfg.switch_addr = priv->i2c_props.addr; | ||
| 644 | } | ||
| 645 | if (fe->ops.tuner_ops.init) | ||
| 646 | fe->ops.tuner_ops.init(fe); | ||
| 647 | |||
| 648 | if (fe->ops.tuner_ops.sleep) | ||
| 649 | fe->ops.tuner_ops.sleep(fe); | ||
| 650 | |||
| 651 | analog_ops->i2c_gate_ctrl(fe, 0); | ||
| 652 | |||
| 653 | return 0; | ||
| 654 | } | ||
| 655 | |||
| 656 | static int tda8290_probe(struct tuner_i2c_props *i2c_props) | ||
| 657 | { | ||
| 658 | #define TDA8290_ID 0x89 | ||
| 659 | u8 reg = 0x1f, id; | ||
| 660 | struct i2c_msg msg_read[] = { | ||
| 661 | { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, | ||
| 662 | { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, | ||
| 663 | }; | ||
| 664 | |||
| 665 | /* detect tda8290 */ | ||
| 666 | if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { | ||
| 667 | printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", | ||
| 668 | __func__, reg); | ||
| 669 | return -ENODEV; | ||
| 670 | } | ||
| 671 | |||
| 672 | if (id == TDA8290_ID) { | ||
| 673 | if (debug) | ||
| 674 | printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", | ||
| 675 | __func__, i2c_adapter_id(i2c_props->adap), | ||
| 676 | i2c_props->addr); | ||
| 677 | return 0; | ||
| 678 | } | ||
| 679 | return -ENODEV; | ||
| 680 | } | ||
| 681 | |||
| 682 | static int tda8295_probe(struct tuner_i2c_props *i2c_props) | ||
| 683 | { | ||
| 684 | #define TDA8295_ID 0x8a | ||
| 685 | #define TDA8295C2_ID 0x8b | ||
| 686 | u8 reg = 0x2f, id; | ||
| 687 | struct i2c_msg msg_read[] = { | ||
| 688 | { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, | ||
| 689 | { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, | ||
| 690 | }; | ||
| 691 | |||
| 692 | /* detect tda8295 */ | ||
| 693 | if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { | ||
| 694 | printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", | ||
| 695 | __func__, reg); | ||
| 696 | return -ENODEV; | ||
| 697 | } | ||
| 698 | |||
| 699 | if ((id & 0xfe) == TDA8295_ID) { | ||
| 700 | if (debug) | ||
| 701 | printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", | ||
| 702 | __func__, (id == TDA8295_ID) ? | ||
| 703 | "tda8295c1" : "tda8295c2", | ||
| 704 | i2c_adapter_id(i2c_props->adap), | ||
| 705 | i2c_props->addr); | ||
| 706 | return 0; | ||
| 707 | } | ||
| 708 | |||
| 709 | return -ENODEV; | ||
| 710 | } | ||
| 711 | |||
| 712 | static struct analog_demod_ops tda8290_ops = { | ||
| 713 | .set_params = tda8290_set_params, | ||
| 714 | .has_signal = tda8290_has_signal, | ||
| 715 | .standby = tda8290_standby, | ||
| 716 | .release = tda829x_release, | ||
| 717 | .i2c_gate_ctrl = tda8290_i2c_bridge, | ||
| 718 | }; | ||
| 719 | |||
| 720 | static struct analog_demod_ops tda8295_ops = { | ||
| 721 | .set_params = tda8295_set_params, | ||
| 722 | .has_signal = tda8295_has_signal, | ||
| 723 | .standby = tda8295_standby, | ||
| 724 | .release = tda829x_release, | ||
| 725 | .i2c_gate_ctrl = tda8295_i2c_bridge, | ||
| 726 | }; | ||
| 727 | |||
| 728 | struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, | ||
| 729 | struct i2c_adapter *i2c_adap, u8 i2c_addr, | ||
| 730 | struct tda829x_config *cfg) | ||
| 731 | { | ||
| 732 | struct tda8290_priv *priv = NULL; | ||
| 733 | char *name; | ||
| 734 | |||
| 735 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); | ||
| 736 | if (priv == NULL) | ||
| 737 | return NULL; | ||
| 738 | fe->analog_demod_priv = priv; | ||
| 739 | |||
| 740 | priv->i2c_props.addr = i2c_addr; | ||
| 741 | priv->i2c_props.adap = i2c_adap; | ||
| 742 | priv->i2c_props.name = "tda829x"; | ||
| 743 | if (cfg) | ||
| 744 | priv->cfg.config = cfg->lna_cfg; | ||
| 745 | |||
| 746 | if (tda8290_probe(&priv->i2c_props) == 0) { | ||
| 747 | priv->ver = TDA8290; | ||
| 748 | memcpy(&fe->ops.analog_ops, &tda8290_ops, | ||
| 749 | sizeof(struct analog_demod_ops)); | ||
| 750 | } | ||
| 751 | |||
| 752 | if (tda8295_probe(&priv->i2c_props) == 0) { | ||
| 753 | priv->ver = TDA8295; | ||
| 754 | memcpy(&fe->ops.analog_ops, &tda8295_ops, | ||
| 755 | sizeof(struct analog_demod_ops)); | ||
| 756 | } | ||
| 757 | |||
| 758 | if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { | ||
| 759 | tda8295_power(fe, 1); | ||
| 760 | if (tda829x_find_tuner(fe) < 0) | ||
| 761 | goto fail; | ||
| 762 | } | ||
| 763 | |||
| 764 | switch (priv->ver) { | ||
| 765 | case TDA8290: | ||
| 766 | name = "tda8290"; | ||
| 767 | break; | ||
| 768 | case TDA8295: | ||
| 769 | name = "tda8295"; | ||
| 770 | break; | ||
| 771 | case TDA8290 | TDA8275: | ||
| 772 | name = "tda8290+75"; | ||
| 773 | break; | ||
| 774 | case TDA8295 | TDA8275: | ||
| 775 | name = "tda8295+75"; | ||
| 776 | break; | ||
| 777 | case TDA8290 | TDA8275A: | ||
| 778 | name = "tda8290+75a"; | ||
| 779 | break; | ||
| 780 | case TDA8295 | TDA8275A: | ||
| 781 | name = "tda8295+75a"; | ||
| 782 | break; | ||
| 783 | case TDA8290 | TDA18271: | ||
| 784 | name = "tda8290+18271"; | ||
| 785 | break; | ||
| 786 | case TDA8295 | TDA18271: | ||
| 787 | name = "tda8295+18271"; | ||
| 788 | break; | ||
| 789 | default: | ||
| 790 | goto fail; | ||
| 791 | } | ||
| 792 | tuner_info("type set to %s\n", name); | ||
| 793 | |||
| 794 | fe->ops.analog_ops.info.name = name; | ||
| 795 | |||
| 796 | if (priv->ver & TDA8290) { | ||
| 797 | if (priv->ver & (TDA8275 | TDA8275A)) | ||
| 798 | tda8290_init_tuner(fe); | ||
| 799 | tda8290_init_if(fe); | ||
| 800 | } else if (priv->ver & TDA8295) | ||
| 801 | tda8295_init_if(fe); | ||
| 802 | |||
| 803 | return fe; | ||
| 804 | |||
| 805 | fail: | ||
| 806 | memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); | ||
| 807 | |||
| 808 | tda829x_release(fe); | ||
| 809 | return NULL; | ||
| 810 | } | ||
| 811 | EXPORT_SYMBOL_GPL(tda829x_attach); | ||
| 812 | |||
| 813 | int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) | ||
| 814 | { | ||
| 815 | struct tuner_i2c_props i2c_props = { | ||
| 816 | .adap = i2c_adap, | ||
| 817 | .addr = i2c_addr, | ||
| 818 | }; | ||
| 819 | |||
| 820 | unsigned char soft_reset[] = { 0x00, 0x00 }; | ||
| 821 | unsigned char easy_mode_b[] = { 0x01, 0x02 }; | ||
| 822 | unsigned char easy_mode_g[] = { 0x01, 0x04 }; | ||
| 823 | unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; | ||
| 824 | unsigned char addr_dto_lsb = 0x07; | ||
| 825 | unsigned char data; | ||
| 826 | #define PROBE_BUFFER_SIZE 8 | ||
| 827 | unsigned char buf[PROBE_BUFFER_SIZE]; | ||
| 828 | int i; | ||
| 829 | |||
| 830 | /* rule out tda9887, which would return the same byte repeatedly */ | ||
| 831 | tuner_i2c_xfer_send_recv(&i2c_props, | ||
| 832 | soft_reset, 1, buf, PROBE_BUFFER_SIZE); | ||
| 833 | for (i = 1; i < PROBE_BUFFER_SIZE; i++) { | ||
| 834 | if (buf[i] != buf[0]) | ||
| 835 | break; | ||
| 836 | } | ||
| 837 | |||
| 838 | /* all bytes are equal, not a tda829x - probably a tda9887 */ | ||
| 839 | if (i == PROBE_BUFFER_SIZE) | ||
| 840 | return -ENODEV; | ||
| 841 | |||
| 842 | if ((tda8290_probe(&i2c_props) == 0) || | ||
| 843 | (tda8295_probe(&i2c_props) == 0)) | ||
| 844 | return 0; | ||
| 845 | |||
| 846 | /* fall back to old probing method */ | ||
| 847 | tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); | ||
| 848 | tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); | ||
| 849 | tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); | ||
| 850 | if (data == 0) { | ||
| 851 | tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); | ||
| 852 | tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); | ||
| 853 | tuner_i2c_xfer_send_recv(&i2c_props, | ||
| 854 | &addr_dto_lsb, 1, &data, 1); | ||
| 855 | if (data == 0x7b) { | ||
| 856 | return 0; | ||
| 857 | } | ||
| 858 | } | ||
| 859 | tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); | ||
| 860 | return -ENODEV; | ||
| 861 | } | ||
| 862 | EXPORT_SYMBOL_GPL(tda829x_probe); | ||
| 863 | |||
| 864 | MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); | ||
| 865 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); | ||
| 866 | MODULE_LICENSE("GPL"); | ||
| 867 | |||
| 868 | /* | ||
| 869 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 870 | * --------------------------------------------------------------------------- | ||
| 871 | * Local variables: | ||
| 872 | * c-basic-offset: 8 | ||
| 873 | * End: | ||
| 874 | */ | ||
diff --git a/drivers/media/common/tuners/tda8290.h b/drivers/media/common/tuners/tda8290.h new file mode 100644 index 00000000000..7e288b26fcc --- /dev/null +++ b/drivers/media/common/tuners/tda8290.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or | ||
| 5 | (at your option) any later version. | ||
| 6 | |||
| 7 | This program is distributed in the hope that it will be useful, | ||
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | GNU General Public License for more details. | ||
| 11 | |||
| 12 | You should have received a copy of the GNU General Public License | ||
| 13 | along with this program; if not, write to the Free Software | ||
| 14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __TDA8290_H__ | ||
| 18 | #define __TDA8290_H__ | ||
| 19 | |||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include "dvb_frontend.h" | ||
| 22 | |||
| 23 | struct tda829x_config { | ||
| 24 | unsigned int lna_cfg; | ||
| 25 | |||
| 26 | unsigned int probe_tuner:1; | ||
| 27 | #define TDA829X_PROBE_TUNER 0 | ||
| 28 | #define TDA829X_DONT_PROBE 1 | ||
| 29 | }; | ||
| 30 | |||
| 31 | #if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) | ||
| 32 | extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); | ||
| 33 | |||
| 34 | extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, | ||
| 35 | struct i2c_adapter *i2c_adap, | ||
| 36 | u8 i2c_addr, | ||
| 37 | struct tda829x_config *cfg); | ||
| 38 | #else | ||
| 39 | static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) | ||
| 40 | { | ||
| 41 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 42 | return -EINVAL; | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, | ||
| 46 | struct i2c_adapter *i2c_adap, | ||
| 47 | u8 i2c_addr, | ||
| 48 | struct tda829x_config *cfg) | ||
| 49 | { | ||
| 50 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
| 51 | __func__); | ||
| 52 | return NULL; | ||
| 53 | } | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #endif /* __TDA8290_H__ */ | ||
diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c new file mode 100644 index 00000000000..cdb645d5743 --- /dev/null +++ b/drivers/media/common/tuners/tda9887.c | |||
| @@ -0,0 +1,717 @@ | |||
| 1 | #include <linux/module.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/i2c.h> | ||
| 4 | #include <linux/types.h> | ||
| 5 | #include <linux/init.h> | ||
| 6 | #include <linux/errno.h> | ||
| 7 | #include <linux/delay.h> | ||
| 8 | #include <linux/videodev2.h> | ||
| 9 | #include <media/v4l2-common.h> | ||
| 10 | #include <media/tuner.h> | ||
| 11 | #include "tuner-i2c.h" | ||
| 12 | #include "tda9887.h" | ||
| 13 | |||
| 14 | |||
| 15 | /* Chips: | ||
| 16 | TDA9885 (PAL, NTSC) | ||
| 17 | TDA9886 (PAL, SECAM, NTSC) | ||
| 18 | TDA9887 (PAL, SECAM, NTSC, FM Radio) | ||
| 19 | |||
| 20 | Used as part of several tuners | ||
| 21 | */ | ||
| 22 | |||
| 23 | static int debug; | ||
| 24 | module_param(debug, int, 0644); | ||
| 25 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 26 | |||
| 27 | static DEFINE_MUTEX(tda9887_list_mutex); | ||
| 28 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 29 | |||
| 30 | struct tda9887_priv { | ||
| 31 | struct tuner_i2c_props i2c_props; | ||
| 32 | struct list_head hybrid_tuner_instance_list; | ||
| 33 | |||
| 34 | unsigned char data[4]; | ||
| 35 | unsigned int config; | ||
| 36 | unsigned int mode; | ||
| 37 | unsigned int audmode; | ||
| 38 | v4l2_std_id std; | ||
| 39 | |||
| 40 | bool standby; | ||
| 41 | }; | ||
| 42 | |||
| 43 | /* ---------------------------------------------------------------------- */ | ||
| 44 | |||
| 45 | #define UNSET (-1U) | ||
| 46 | |||
| 47 | struct tvnorm { | ||
| 48 | v4l2_std_id std; | ||
| 49 | char *name; | ||
| 50 | unsigned char b; | ||
| 51 | unsigned char c; | ||
| 52 | unsigned char e; | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* ---------------------------------------------------------------------- */ | ||
| 56 | |||
| 57 | // | ||
| 58 | // TDA defines | ||
| 59 | // | ||
| 60 | |||
| 61 | //// first reg (b) | ||
| 62 | #define cVideoTrapBypassOFF 0x00 // bit b0 | ||
| 63 | #define cVideoTrapBypassON 0x01 // bit b0 | ||
| 64 | |||
| 65 | #define cAutoMuteFmInactive 0x00 // bit b1 | ||
| 66 | #define cAutoMuteFmActive 0x02 // bit b1 | ||
| 67 | |||
| 68 | #define cIntercarrier 0x00 // bit b2 | ||
| 69 | #define cQSS 0x04 // bit b2 | ||
| 70 | |||
| 71 | #define cPositiveAmTV 0x00 // bit b3:4 | ||
| 72 | #define cFmRadio 0x08 // bit b3:4 | ||
| 73 | #define cNegativeFmTV 0x10 // bit b3:4 | ||
| 74 | |||
| 75 | |||
| 76 | #define cForcedMuteAudioON 0x20 // bit b5 | ||
| 77 | #define cForcedMuteAudioOFF 0x00 // bit b5 | ||
| 78 | |||
| 79 | #define cOutputPort1Active 0x00 // bit b6 | ||
| 80 | #define cOutputPort1Inactive 0x40 // bit b6 | ||
| 81 | |||
| 82 | #define cOutputPort2Active 0x00 // bit b7 | ||
| 83 | #define cOutputPort2Inactive 0x80 // bit b7 | ||
| 84 | |||
| 85 | |||
| 86 | //// second reg (c) | ||
| 87 | #define cDeemphasisOFF 0x00 // bit c5 | ||
| 88 | #define cDeemphasisON 0x20 // bit c5 | ||
| 89 | |||
| 90 | #define cDeemphasis75 0x00 // bit c6 | ||
| 91 | #define cDeemphasis50 0x40 // bit c6 | ||
| 92 | |||
| 93 | #define cAudioGain0 0x00 // bit c7 | ||
| 94 | #define cAudioGain6 0x80 // bit c7 | ||
| 95 | |||
| 96 | #define cTopMask 0x1f // bit c0:4 | ||
| 97 | #define cTopDefault 0x10 // bit c0:4 | ||
| 98 | |||
| 99 | //// third reg (e) | ||
| 100 | #define cAudioIF_4_5 0x00 // bit e0:1 | ||
| 101 | #define cAudioIF_5_5 0x01 // bit e0:1 | ||
| 102 | #define cAudioIF_6_0 0x02 // bit e0:1 | ||
| 103 | #define cAudioIF_6_5 0x03 // bit e0:1 | ||
| 104 | |||
| 105 | |||
| 106 | #define cVideoIFMask 0x1c // bit e2:4 | ||
| 107 | /* Video IF selection in TV Mode (bit B3=0) */ | ||
| 108 | #define cVideoIF_58_75 0x00 // bit e2:4 | ||
| 109 | #define cVideoIF_45_75 0x04 // bit e2:4 | ||
| 110 | #define cVideoIF_38_90 0x08 // bit e2:4 | ||
| 111 | #define cVideoIF_38_00 0x0C // bit e2:4 | ||
| 112 | #define cVideoIF_33_90 0x10 // bit e2:4 | ||
| 113 | #define cVideoIF_33_40 0x14 // bit e2:4 | ||
| 114 | #define cRadioIF_45_75 0x18 // bit e2:4 | ||
| 115 | #define cRadioIF_38_90 0x1C // bit e2:4 | ||
| 116 | |||
| 117 | /* IF1 selection in Radio Mode (bit B3=1) */ | ||
| 118 | #define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) | ||
| 119 | #define cRadioIF_41_30 0x04 // bit e2,4 | ||
| 120 | |||
| 121 | /* Output of AFC pin in radio mode when bit E7=1 */ | ||
| 122 | #define cRadioAGC_SIF 0x00 // bit e3 | ||
| 123 | #define cRadioAGC_FM 0x08 // bit e3 | ||
| 124 | |||
| 125 | #define cTunerGainNormal 0x00 // bit e5 | ||
| 126 | #define cTunerGainLow 0x20 // bit e5 | ||
| 127 | |||
| 128 | #define cGating_18 0x00 // bit e6 | ||
| 129 | #define cGating_36 0x40 // bit e6 | ||
| 130 | |||
| 131 | #define cAgcOutON 0x80 // bit e7 | ||
| 132 | #define cAgcOutOFF 0x00 // bit e7 | ||
| 133 | |||
| 134 | /* ---------------------------------------------------------------------- */ | ||
| 135 | |||
| 136 | static struct tvnorm tvnorms[] = { | ||
| 137 | { | ||
| 138 | .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, | ||
| 139 | .name = "PAL-BGHN", | ||
| 140 | .b = ( cNegativeFmTV | | ||
| 141 | cQSS ), | ||
| 142 | .c = ( cDeemphasisON | | ||
| 143 | cDeemphasis50 | | ||
| 144 | cTopDefault), | ||
| 145 | .e = ( cGating_36 | | ||
| 146 | cAudioIF_5_5 | | ||
| 147 | cVideoIF_38_90 ), | ||
| 148 | },{ | ||
| 149 | .std = V4L2_STD_PAL_I, | ||
| 150 | .name = "PAL-I", | ||
| 151 | .b = ( cNegativeFmTV | | ||
| 152 | cQSS ), | ||
| 153 | .c = ( cDeemphasisON | | ||
| 154 | cDeemphasis50 | | ||
| 155 | cTopDefault), | ||
| 156 | .e = ( cGating_36 | | ||
| 157 | cAudioIF_6_0 | | ||
| 158 | cVideoIF_38_90 ), | ||
| 159 | },{ | ||
| 160 | .std = V4L2_STD_PAL_DK, | ||
| 161 | .name = "PAL-DK", | ||
| 162 | .b = ( cNegativeFmTV | | ||
| 163 | cQSS ), | ||
| 164 | .c = ( cDeemphasisON | | ||
| 165 | cDeemphasis50 | | ||
| 166 | cTopDefault), | ||
| 167 | .e = ( cGating_36 | | ||
| 168 | cAudioIF_6_5 | | ||
| 169 | cVideoIF_38_90 ), | ||
| 170 | },{ | ||
| 171 | .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, | ||
| 172 | .name = "PAL-M/Nc", | ||
| 173 | .b = ( cNegativeFmTV | | ||
| 174 | cQSS ), | ||
| 175 | .c = ( cDeemphasisON | | ||
| 176 | cDeemphasis75 | | ||
| 177 | cTopDefault), | ||
| 178 | .e = ( cGating_36 | | ||
| 179 | cAudioIF_4_5 | | ||
| 180 | cVideoIF_45_75 ), | ||
| 181 | },{ | ||
| 182 | .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, | ||
| 183 | .name = "SECAM-BGH", | ||
| 184 | .b = ( cNegativeFmTV | | ||
| 185 | cQSS ), | ||
| 186 | .c = ( cTopDefault), | ||
| 187 | .e = ( cAudioIF_5_5 | | ||
| 188 | cVideoIF_38_90 ), | ||
| 189 | },{ | ||
| 190 | .std = V4L2_STD_SECAM_L, | ||
| 191 | .name = "SECAM-L", | ||
| 192 | .b = ( cPositiveAmTV | | ||
| 193 | cQSS ), | ||
| 194 | .c = ( cTopDefault), | ||
| 195 | .e = ( cGating_36 | | ||
| 196 | cAudioIF_6_5 | | ||
| 197 | cVideoIF_38_90 ), | ||
| 198 | },{ | ||
| 199 | .std = V4L2_STD_SECAM_LC, | ||
| 200 | .name = "SECAM-L'", | ||
| 201 | .b = ( cOutputPort2Inactive | | ||
| 202 | cPositiveAmTV | | ||
| 203 | cQSS ), | ||
| 204 | .c = ( cTopDefault), | ||
| 205 | .e = ( cGating_36 | | ||
| 206 | cAudioIF_6_5 | | ||
| 207 | cVideoIF_33_90 ), | ||
| 208 | },{ | ||
| 209 | .std = V4L2_STD_SECAM_DK, | ||
| 210 | .name = "SECAM-DK", | ||
| 211 | .b = ( cNegativeFmTV | | ||
| 212 | cQSS ), | ||
| 213 | .c = ( cDeemphasisON | | ||
| 214 | cDeemphasis50 | | ||
| 215 | cTopDefault), | ||
| 216 | .e = ( cGating_36 | | ||
| 217 | cAudioIF_6_5 | | ||
| 218 | cVideoIF_38_90 ), | ||
| 219 | },{ | ||
| 220 | .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, | ||
| 221 | .name = "NTSC-M", | ||
| 222 | .b = ( cNegativeFmTV | | ||
| 223 | cQSS ), | ||
| 224 | .c = ( cDeemphasisON | | ||
| 225 | cDeemphasis75 | | ||
| 226 | cTopDefault), | ||
| 227 | .e = ( cGating_36 | | ||
| 228 | cAudioIF_4_5 | | ||
| 229 | cVideoIF_45_75 ), | ||
| 230 | },{ | ||
| 231 | .std = V4L2_STD_NTSC_M_JP, | ||
| 232 | .name = "NTSC-M-JP", | ||
| 233 | .b = ( cNegativeFmTV | | ||
| 234 | cQSS ), | ||
| 235 | .c = ( cDeemphasisON | | ||
| 236 | cDeemphasis50 | | ||
| 237 | cTopDefault), | ||
| 238 | .e = ( cGating_36 | | ||
| 239 | cAudioIF_4_5 | | ||
| 240 | cVideoIF_58_75 ), | ||
| 241 | } | ||
| 242 | }; | ||
| 243 | |||
| 244 | static struct tvnorm radio_stereo = { | ||
| 245 | .name = "Radio Stereo", | ||
| 246 | .b = ( cFmRadio | | ||
| 247 | cQSS ), | ||
| 248 | .c = ( cDeemphasisOFF | | ||
| 249 | cAudioGain6 | | ||
| 250 | cTopDefault), | ||
| 251 | .e = ( cTunerGainLow | | ||
| 252 | cAudioIF_5_5 | | ||
| 253 | cRadioIF_38_90 ), | ||
| 254 | }; | ||
| 255 | |||
| 256 | static struct tvnorm radio_mono = { | ||
| 257 | .name = "Radio Mono", | ||
| 258 | .b = ( cFmRadio | | ||
| 259 | cQSS ), | ||
| 260 | .c = ( cDeemphasisON | | ||
| 261 | cDeemphasis75 | | ||
| 262 | cTopDefault), | ||
| 263 | .e = ( cTunerGainLow | | ||
| 264 | cAudioIF_5_5 | | ||
| 265 | cRadioIF_38_90 ), | ||
| 266 | }; | ||
| 267 | |||
| 268 | /* ---------------------------------------------------------------------- */ | ||
| 269 | |||
| 270 | static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) | ||
| 271 | { | ||
| 272 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 273 | |||
| 274 | static char *afc[16] = { | ||
| 275 | "- 12.5 kHz", | ||
| 276 | "- 37.5 kHz", | ||
| 277 | "- 62.5 kHz", | ||
| 278 | "- 87.5 kHz", | ||
| 279 | "-112.5 kHz", | ||
| 280 | "-137.5 kHz", | ||
| 281 | "-162.5 kHz", | ||
| 282 | "-187.5 kHz [min]", | ||
| 283 | "+187.5 kHz [max]", | ||
| 284 | "+162.5 kHz", | ||
| 285 | "+137.5 kHz", | ||
| 286 | "+112.5 kHz", | ||
| 287 | "+ 87.5 kHz", | ||
| 288 | "+ 62.5 kHz", | ||
| 289 | "+ 37.5 kHz", | ||
| 290 | "+ 12.5 kHz", | ||
| 291 | }; | ||
| 292 | tuner_info("read: 0x%2x\n", buf[0]); | ||
| 293 | tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); | ||
| 294 | tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); | ||
| 295 | tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); | ||
| 296 | tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); | ||
| 297 | tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); | ||
| 298 | } | ||
| 299 | |||
| 300 | static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) | ||
| 301 | { | ||
| 302 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 303 | |||
| 304 | static char *sound[4] = { | ||
| 305 | "AM/TV", | ||
| 306 | "FM/radio", | ||
| 307 | "FM/TV", | ||
| 308 | "FM/radio" | ||
| 309 | }; | ||
| 310 | static char *adjust[32] = { | ||
| 311 | "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", | ||
| 312 | "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", | ||
| 313 | "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", | ||
| 314 | "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" | ||
| 315 | }; | ||
| 316 | static char *deemph[4] = { | ||
| 317 | "no", "no", "75", "50" | ||
| 318 | }; | ||
| 319 | static char *carrier[4] = { | ||
| 320 | "4.5 MHz", | ||
| 321 | "5.5 MHz", | ||
| 322 | "6.0 MHz", | ||
| 323 | "6.5 MHz / AM" | ||
| 324 | }; | ||
| 325 | static char *vif[8] = { | ||
| 326 | "58.75 MHz", | ||
| 327 | "45.75 MHz", | ||
| 328 | "38.9 MHz", | ||
| 329 | "38.0 MHz", | ||
| 330 | "33.9 MHz", | ||
| 331 | "33.4 MHz", | ||
| 332 | "45.75 MHz + pin13", | ||
| 333 | "38.9 MHz + pin13", | ||
| 334 | }; | ||
| 335 | static char *rif[4] = { | ||
| 336 | "44 MHz", | ||
| 337 | "52 MHz", | ||
| 338 | "52 MHz", | ||
| 339 | "44 MHz", | ||
| 340 | }; | ||
| 341 | |||
| 342 | tuner_info("write: byte B 0x%02x\n", buf[1]); | ||
| 343 | tuner_info(" B0 video mode : %s\n", | ||
| 344 | (buf[1] & 0x01) ? "video trap" : "sound trap"); | ||
| 345 | tuner_info(" B1 auto mute fm : %s\n", | ||
| 346 | (buf[1] & 0x02) ? "yes" : "no"); | ||
| 347 | tuner_info(" B2 carrier mode : %s\n", | ||
| 348 | (buf[1] & 0x04) ? "QSS" : "Intercarrier"); | ||
| 349 | tuner_info(" B3-4 tv sound/radio : %s\n", | ||
| 350 | sound[(buf[1] & 0x18) >> 3]); | ||
| 351 | tuner_info(" B5 force mute audio: %s\n", | ||
| 352 | (buf[1] & 0x20) ? "yes" : "no"); | ||
| 353 | tuner_info(" B6 output port 1 : %s\n", | ||
| 354 | (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); | ||
| 355 | tuner_info(" B7 output port 2 : %s\n", | ||
| 356 | (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); | ||
| 357 | |||
| 358 | tuner_info("write: byte C 0x%02x\n", buf[2]); | ||
| 359 | tuner_info(" C0-4 top adjustment : %s dB\n", | ||
| 360 | adjust[buf[2] & 0x1f]); | ||
| 361 | tuner_info(" C5-6 de-emphasis : %s\n", | ||
| 362 | deemph[(buf[2] & 0x60) >> 5]); | ||
| 363 | tuner_info(" C7 audio gain : %s\n", | ||
| 364 | (buf[2] & 0x80) ? "-6" : "0"); | ||
| 365 | |||
| 366 | tuner_info("write: byte E 0x%02x\n", buf[3]); | ||
| 367 | tuner_info(" E0-1 sound carrier : %s\n", | ||
| 368 | carrier[(buf[3] & 0x03)]); | ||
| 369 | tuner_info(" E6 l pll gating : %s\n", | ||
| 370 | (buf[3] & 0x40) ? "36" : "13"); | ||
| 371 | |||
| 372 | if (buf[1] & 0x08) { | ||
| 373 | /* radio */ | ||
| 374 | tuner_info(" E2-4 video if : %s\n", | ||
| 375 | rif[(buf[3] & 0x0c) >> 2]); | ||
| 376 | tuner_info(" E7 vif agc output : %s\n", | ||
| 377 | (buf[3] & 0x80) | ||
| 378 | ? ((buf[3] & 0x10) ? "fm-agc radio" : | ||
| 379 | "sif-agc radio") | ||
| 380 | : "fm radio carrier afc"); | ||
| 381 | } else { | ||
| 382 | /* video */ | ||
| 383 | tuner_info(" E2-4 video if : %s\n", | ||
| 384 | vif[(buf[3] & 0x1c) >> 2]); | ||
| 385 | tuner_info(" E5 tuner gain : %s\n", | ||
| 386 | (buf[3] & 0x80) | ||
| 387 | ? ((buf[3] & 0x20) ? "external" : "normal") | ||
| 388 | : ((buf[3] & 0x20) ? "minimum" : "normal")); | ||
| 389 | tuner_info(" E7 vif agc output : %s\n", | ||
| 390 | (buf[3] & 0x80) ? ((buf[3] & 0x20) | ||
| 391 | ? "pin3 port, pin22 vif agc out" | ||
| 392 | : "pin22 port, pin3 vif acg ext in") | ||
| 393 | : "pin3+pin22 port"); | ||
| 394 | } | ||
| 395 | tuner_info("--\n"); | ||
| 396 | } | ||
| 397 | |||
| 398 | /* ---------------------------------------------------------------------- */ | ||
| 399 | |||
| 400 | static int tda9887_set_tvnorm(struct dvb_frontend *fe) | ||
| 401 | { | ||
| 402 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 403 | struct tvnorm *norm = NULL; | ||
| 404 | char *buf = priv->data; | ||
| 405 | int i; | ||
| 406 | |||
| 407 | if (priv->mode == V4L2_TUNER_RADIO) { | ||
| 408 | if (priv->audmode == V4L2_TUNER_MODE_MONO) | ||
| 409 | norm = &radio_mono; | ||
| 410 | else | ||
| 411 | norm = &radio_stereo; | ||
| 412 | } else { | ||
| 413 | for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { | ||
| 414 | if (tvnorms[i].std & priv->std) { | ||
| 415 | norm = tvnorms+i; | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | if (NULL == norm) { | ||
| 421 | tuner_dbg("Unsupported tvnorm entry - audio muted\n"); | ||
| 422 | return -1; | ||
| 423 | } | ||
| 424 | |||
| 425 | tuner_dbg("configure for: %s\n", norm->name); | ||
| 426 | buf[1] = norm->b; | ||
| 427 | buf[2] = norm->c; | ||
| 428 | buf[3] = norm->e; | ||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | static unsigned int port1 = UNSET; | ||
| 433 | static unsigned int port2 = UNSET; | ||
| 434 | static unsigned int qss = UNSET; | ||
| 435 | static unsigned int adjust = UNSET; | ||
| 436 | |||
| 437 | module_param(port1, int, 0644); | ||
| 438 | module_param(port2, int, 0644); | ||
| 439 | module_param(qss, int, 0644); | ||
| 440 | module_param(adjust, int, 0644); | ||
| 441 | |||
| 442 | static int tda9887_set_insmod(struct dvb_frontend *fe) | ||
| 443 | { | ||
| 444 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 445 | char *buf = priv->data; | ||
| 446 | |||
| 447 | if (UNSET != port1) { | ||
| 448 | if (port1) | ||
| 449 | buf[1] |= cOutputPort1Inactive; | ||
| 450 | else | ||
| 451 | buf[1] &= ~cOutputPort1Inactive; | ||
| 452 | } | ||
| 453 | if (UNSET != port2) { | ||
| 454 | if (port2) | ||
| 455 | buf[1] |= cOutputPort2Inactive; | ||
| 456 | else | ||
| 457 | buf[1] &= ~cOutputPort2Inactive; | ||
| 458 | } | ||
| 459 | |||
| 460 | if (UNSET != qss) { | ||
| 461 | if (qss) | ||
| 462 | buf[1] |= cQSS; | ||
| 463 | else | ||
| 464 | buf[1] &= ~cQSS; | ||
| 465 | } | ||
| 466 | |||
| 467 | if (adjust < 0x20) { | ||
| 468 | buf[2] &= ~cTopMask; | ||
| 469 | buf[2] |= adjust; | ||
| 470 | } | ||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | static int tda9887_do_config(struct dvb_frontend *fe) | ||
| 475 | { | ||
| 476 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 477 | char *buf = priv->data; | ||
| 478 | |||
| 479 | if (priv->config & TDA9887_PORT1_ACTIVE) | ||
| 480 | buf[1] &= ~cOutputPort1Inactive; | ||
| 481 | if (priv->config & TDA9887_PORT1_INACTIVE) | ||
| 482 | buf[1] |= cOutputPort1Inactive; | ||
| 483 | if (priv->config & TDA9887_PORT2_ACTIVE) | ||
| 484 | buf[1] &= ~cOutputPort2Inactive; | ||
| 485 | if (priv->config & TDA9887_PORT2_INACTIVE) | ||
| 486 | buf[1] |= cOutputPort2Inactive; | ||
| 487 | |||
| 488 | if (priv->config & TDA9887_QSS) | ||
| 489 | buf[1] |= cQSS; | ||
| 490 | if (priv->config & TDA9887_INTERCARRIER) | ||
| 491 | buf[1] &= ~cQSS; | ||
| 492 | |||
| 493 | if (priv->config & TDA9887_AUTOMUTE) | ||
| 494 | buf[1] |= cAutoMuteFmActive; | ||
| 495 | if (priv->config & TDA9887_DEEMPHASIS_MASK) { | ||
| 496 | buf[2] &= ~0x60; | ||
| 497 | switch (priv->config & TDA9887_DEEMPHASIS_MASK) { | ||
| 498 | case TDA9887_DEEMPHASIS_NONE: | ||
| 499 | buf[2] |= cDeemphasisOFF; | ||
| 500 | break; | ||
| 501 | case TDA9887_DEEMPHASIS_50: | ||
| 502 | buf[2] |= cDeemphasisON | cDeemphasis50; | ||
| 503 | break; | ||
| 504 | case TDA9887_DEEMPHASIS_75: | ||
| 505 | buf[2] |= cDeemphasisON | cDeemphasis75; | ||
| 506 | break; | ||
| 507 | } | ||
| 508 | } | ||
| 509 | if (priv->config & TDA9887_TOP_SET) { | ||
| 510 | buf[2] &= ~cTopMask; | ||
| 511 | buf[2] |= (priv->config >> 8) & cTopMask; | ||
| 512 | } | ||
| 513 | if ((priv->config & TDA9887_INTERCARRIER_NTSC) && | ||
| 514 | (priv->std & V4L2_STD_NTSC)) | ||
| 515 | buf[1] &= ~cQSS; | ||
| 516 | if (priv->config & TDA9887_GATING_18) | ||
| 517 | buf[3] &= ~cGating_36; | ||
| 518 | |||
| 519 | if (priv->mode == V4L2_TUNER_RADIO) { | ||
| 520 | if (priv->config & TDA9887_RIF_41_3) { | ||
| 521 | buf[3] &= ~cVideoIFMask; | ||
| 522 | buf[3] |= cRadioIF_41_30; | ||
| 523 | } | ||
| 524 | if (priv->config & TDA9887_GAIN_NORMAL) | ||
| 525 | buf[3] &= ~cTunerGainLow; | ||
| 526 | } | ||
| 527 | |||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | |||
| 531 | /* ---------------------------------------------------------------------- */ | ||
| 532 | |||
| 533 | static int tda9887_status(struct dvb_frontend *fe) | ||
| 534 | { | ||
| 535 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 536 | unsigned char buf[1]; | ||
| 537 | int rc; | ||
| 538 | |||
| 539 | memset(buf,0,sizeof(buf)); | ||
| 540 | if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) | ||
| 541 | tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); | ||
| 542 | dump_read_message(fe, buf); | ||
| 543 | return 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | static void tda9887_configure(struct dvb_frontend *fe) | ||
| 547 | { | ||
| 548 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 549 | int rc; | ||
| 550 | |||
| 551 | memset(priv->data,0,sizeof(priv->data)); | ||
| 552 | tda9887_set_tvnorm(fe); | ||
| 553 | |||
| 554 | /* A note on the port settings: | ||
| 555 | These settings tend to depend on the specifics of the board. | ||
| 556 | By default they are set to inactive (bit value 1) by this driver, | ||
| 557 | overwriting any changes made by the tvnorm. This means that it | ||
| 558 | is the responsibility of the module using the tda9887 to set | ||
| 559 | these values in case of changes in the tvnorm. | ||
| 560 | In many cases port 2 should be made active (0) when selecting | ||
| 561 | SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. | ||
| 562 | |||
| 563 | For the other standards the tda9887 application note says that | ||
| 564 | the ports should be set to active (0), but, again, that may | ||
| 565 | differ depending on the precise hardware configuration. | ||
| 566 | */ | ||
| 567 | priv->data[1] |= cOutputPort1Inactive; | ||
| 568 | priv->data[1] |= cOutputPort2Inactive; | ||
| 569 | |||
| 570 | tda9887_do_config(fe); | ||
| 571 | tda9887_set_insmod(fe); | ||
| 572 | |||
| 573 | if (priv->standby) | ||
| 574 | priv->data[1] |= cForcedMuteAudioON; | ||
| 575 | |||
| 576 | tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", | ||
| 577 | priv->data[1], priv->data[2], priv->data[3]); | ||
| 578 | if (debug > 1) | ||
| 579 | dump_write_message(fe, priv->data); | ||
| 580 | |||
| 581 | if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) | ||
| 582 | tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
| 583 | |||
| 584 | if (debug > 2) { | ||
| 585 | msleep_interruptible(1000); | ||
| 586 | tda9887_status(fe); | ||
| 587 | } | ||
| 588 | } | ||
| 589 | |||
| 590 | /* ---------------------------------------------------------------------- */ | ||
| 591 | |||
| 592 | static void tda9887_tuner_status(struct dvb_frontend *fe) | ||
| 593 | { | ||
| 594 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 595 | tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", | ||
| 596 | priv->data[1], priv->data[2], priv->data[3]); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int tda9887_get_afc(struct dvb_frontend *fe) | ||
| 600 | { | ||
| 601 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 602 | static int AFC_BITS_2_kHz[] = { | ||
| 603 | -12500, -37500, -62500, -97500, | ||
| 604 | -112500, -137500, -162500, -187500, | ||
| 605 | 187500, 162500, 137500, 112500, | ||
| 606 | 97500 , 62500, 37500 , 12500 | ||
| 607 | }; | ||
| 608 | int afc=0; | ||
| 609 | __u8 reg = 0; | ||
| 610 | |||
| 611 | if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) | ||
| 612 | afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; | ||
| 613 | |||
| 614 | return afc; | ||
| 615 | } | ||
| 616 | |||
| 617 | static void tda9887_standby(struct dvb_frontend *fe) | ||
| 618 | { | ||
| 619 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 620 | |||
| 621 | priv->standby = true; | ||
| 622 | |||
| 623 | tda9887_configure(fe); | ||
| 624 | } | ||
| 625 | |||
| 626 | static void tda9887_set_params(struct dvb_frontend *fe, | ||
| 627 | struct analog_parameters *params) | ||
| 628 | { | ||
| 629 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 630 | |||
| 631 | priv->standby = false; | ||
| 632 | priv->mode = params->mode; | ||
| 633 | priv->audmode = params->audmode; | ||
| 634 | priv->std = params->std; | ||
| 635 | tda9887_configure(fe); | ||
| 636 | } | ||
| 637 | |||
| 638 | static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
| 639 | { | ||
| 640 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 641 | |||
| 642 | priv->config = *(unsigned int *)priv_cfg; | ||
| 643 | tda9887_configure(fe); | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | } | ||
| 647 | |||
| 648 | static void tda9887_release(struct dvb_frontend *fe) | ||
| 649 | { | ||
| 650 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
| 651 | |||
| 652 | mutex_lock(&tda9887_list_mutex); | ||
| 653 | |||
| 654 | if (priv) | ||
| 655 | hybrid_tuner_release_state(priv); | ||
| 656 | |||
| 657 | mutex_unlock(&tda9887_list_mutex); | ||
| 658 | |||
| 659 | fe->analog_demod_priv = NULL; | ||
| 660 | } | ||
| 661 | |||
| 662 | static struct analog_demod_ops tda9887_ops = { | ||
| 663 | .info = { | ||
| 664 | .name = "tda9887", | ||
| 665 | }, | ||
| 666 | .set_params = tda9887_set_params, | ||
| 667 | .standby = tda9887_standby, | ||
| 668 | .tuner_status = tda9887_tuner_status, | ||
| 669 | .get_afc = tda9887_get_afc, | ||
| 670 | .release = tda9887_release, | ||
| 671 | .set_config = tda9887_set_config, | ||
| 672 | }; | ||
| 673 | |||
| 674 | struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, | ||
| 675 | struct i2c_adapter *i2c_adap, | ||
| 676 | u8 i2c_addr) | ||
| 677 | { | ||
| 678 | struct tda9887_priv *priv = NULL; | ||
| 679 | int instance; | ||
| 680 | |||
| 681 | mutex_lock(&tda9887_list_mutex); | ||
| 682 | |||
| 683 | instance = hybrid_tuner_request_state(struct tda9887_priv, priv, | ||
| 684 | hybrid_tuner_instance_list, | ||
| 685 | i2c_adap, i2c_addr, "tda9887"); | ||
| 686 | switch (instance) { | ||
| 687 | case 0: | ||
| 688 | mutex_unlock(&tda9887_list_mutex); | ||
| 689 | return NULL; | ||
| 690 | case 1: | ||
| 691 | fe->analog_demod_priv = priv; | ||
| 692 | priv->standby = true; | ||
| 693 | tuner_info("tda988[5/6/7] found\n"); | ||
| 694 | break; | ||
| 695 | default: | ||
| 696 | fe->analog_demod_priv = priv; | ||
| 697 | break; | ||
| 698 | } | ||
| 699 | |||
| 700 | mutex_unlock(&tda9887_list_mutex); | ||
| 701 | |||
| 702 | memcpy(&fe->ops.analog_ops, &tda9887_ops, | ||
| 703 | sizeof(struct analog_demod_ops)); | ||
| 704 | |||
| 705 | return fe; | ||
| 706 | } | ||
| 707 | EXPORT_SYMBOL_GPL(tda9887_attach); | ||
| 708 | |||
| 709 | MODULE_LICENSE("GPL"); | ||
| 710 | |||
| 711 | /* | ||
| 712 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 713 | * --------------------------------------------------------------------------- | ||
| 714 | * Local variables: | ||
| 715 | * c-basic-offset: 8 | ||
| 716 | * End: | ||
| 717 | */ | ||
diff --git a/drivers/media/common/tuners/tda9887.h b/drivers/media/common/tuners/tda9887.h new file mode 100644 index 00000000000..acc419e8c4f --- /dev/null +++ b/drivers/media/common/tuners/tda9887.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or | ||
| 5 | (at your option) any later version. | ||
| 6 | |||
| 7 | This program is distributed in the hope that it will be useful, | ||
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | GNU General Public License for more details. | ||
| 11 | |||
| 12 | You should have received a copy of the GNU General Public License | ||
| 13 | along with this program; if not, write to the Free Software | ||
| 14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __TDA9887_H__ | ||
| 18 | #define __TDA9887_H__ | ||
| 19 | |||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include "dvb_frontend.h" | ||
| 22 | |||
| 23 | /* ------------------------------------------------------------------------ */ | ||
| 24 | #if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) | ||
| 25 | extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, | ||
| 26 | struct i2c_adapter *i2c_adap, | ||
| 27 | u8 i2c_addr); | ||
| 28 | #else | ||
| 29 | static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, | ||
| 30 | struct i2c_adapter *i2c_adap, | ||
| 31 | u8 i2c_addr) | ||
| 32 | { | ||
| 33 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 34 | return NULL; | ||
| 35 | } | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #endif /* __TDA9887_H__ */ | ||
diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/common/tuners/tea5761.c new file mode 100644 index 00000000000..bf78cb9fc52 --- /dev/null +++ b/drivers/media/common/tuners/tea5761.c | |||
| @@ -0,0 +1,348 @@ | |||
| 1 | /* | ||
| 2 | * For Philips TEA5761 FM Chip | ||
| 3 | * I2C address is allways 0x20 (0x10 at 7-bit mode). | ||
| 4 | * | ||
| 5 | * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
| 6 | * This code is placed under the terms of the GNUv2 General Public License | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/videodev2.h> | ||
| 14 | #include <media/tuner.h> | ||
| 15 | #include "tuner-i2c.h" | ||
| 16 | #include "tea5761.h" | ||
| 17 | |||
| 18 | static int debug; | ||
| 19 | module_param(debug, int, 0644); | ||
| 20 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 21 | |||
| 22 | struct tea5761_priv { | ||
| 23 | struct tuner_i2c_props i2c_props; | ||
| 24 | |||
| 25 | u32 frequency; | ||
| 26 | bool standby; | ||
| 27 | }; | ||
| 28 | |||
| 29 | /*****************************************************************************/ | ||
| 30 | |||
| 31 | /*************************** | ||
| 32 | * TEA5761HN I2C registers * | ||
| 33 | ***************************/ | ||
| 34 | |||
| 35 | /* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ | ||
| 36 | |||
| 37 | /* first byte for reading */ | ||
| 38 | #define TEA5761_INTREG_IFFLAG 0x10 | ||
| 39 | #define TEA5761_INTREG_LEVFLAG 0x8 | ||
| 40 | #define TEA5761_INTREG_FRRFLAG 0x2 | ||
| 41 | #define TEA5761_INTREG_BLFLAG 0x1 | ||
| 42 | |||
| 43 | /* second byte for reading / byte for writing */ | ||
| 44 | #define TEA5761_INTREG_IFMSK 0x10 | ||
| 45 | #define TEA5761_INTREG_LEVMSK 0x8 | ||
| 46 | #define TEA5761_INTREG_FRMSK 0x2 | ||
| 47 | #define TEA5761_INTREG_BLMSK 0x1 | ||
| 48 | |||
| 49 | /* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ | ||
| 50 | |||
| 51 | /* First byte */ | ||
| 52 | #define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ | ||
| 53 | #define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ | ||
| 54 | |||
| 55 | /* Bits 0-5 for divider MSB */ | ||
| 56 | |||
| 57 | /* Second byte */ | ||
| 58 | /* Bits 0-7 for divider LSB */ | ||
| 59 | |||
| 60 | /* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ | ||
| 61 | |||
| 62 | /* first byte */ | ||
| 63 | |||
| 64 | #define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ | ||
| 65 | #define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ | ||
| 66 | #define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ | ||
| 67 | #define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ | ||
| 68 | #define TEA5761_TNCTRL_AFM 0x04 | ||
| 69 | #define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ | ||
| 70 | #define TEA5761_TNCTRL_SNC 0x01 | ||
| 71 | |||
| 72 | /* second byte */ | ||
| 73 | |||
| 74 | #define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ | ||
| 75 | #define TEA5761_TNCTRL_SSL_1 0x40 | ||
| 76 | #define TEA5761_TNCTRL_SSL_0 0x20 | ||
| 77 | #define TEA5761_TNCTRL_HLSI 0x10 | ||
| 78 | #define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ | ||
| 79 | #define TEA5761_TNCTRL_SWP 0x04 | ||
| 80 | #define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ | ||
| 81 | #define TEA5761_TNCTRL_AHLSI 0x01 | ||
| 82 | |||
| 83 | /* FRQCHECK - Read: bytes 6 and 7 */ | ||
| 84 | /* First byte */ | ||
| 85 | |||
| 86 | /* Bits 0-5 for divider MSB */ | ||
| 87 | |||
| 88 | /* Second byte */ | ||
| 89 | /* Bits 0-7 for divider LSB */ | ||
| 90 | |||
| 91 | /* TUNCHECK - Read: bytes 8 and 9 */ | ||
| 92 | |||
| 93 | /* First byte */ | ||
| 94 | #define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ | ||
| 95 | #define TEA5761_TUNCHECK_TUNTO 0x01 | ||
| 96 | |||
| 97 | /* Second byte */ | ||
| 98 | #define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ | ||
| 99 | #define TEA5761_TUNCHECK_LD 0x08 | ||
| 100 | #define TEA5761_TUNCHECK_STEREO 0x04 | ||
| 101 | |||
| 102 | /* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ | ||
| 103 | |||
| 104 | /* All zero = no test mode */ | ||
| 105 | |||
| 106 | /* MANID - Read: bytes 12 and 13 */ | ||
| 107 | |||
| 108 | /* First byte - should be 0x10 */ | ||
| 109 | #define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ | ||
| 110 | #define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ | ||
| 111 | |||
| 112 | /* Second byte - Should be 0x2b */ | ||
| 113 | |||
| 114 | #define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ | ||
| 115 | #define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ | ||
| 116 | |||
| 117 | /* Chip ID - Read: bytes 14 and 15 */ | ||
| 118 | |||
| 119 | /* First byte - should be 0x57 */ | ||
| 120 | |||
| 121 | /* Second byte - should be 0x61 */ | ||
| 122 | |||
| 123 | /*****************************************************************************/ | ||
| 124 | |||
| 125 | #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ | ||
| 126 | static void tea5761_status_dump(unsigned char *buffer) | ||
| 127 | { | ||
| 128 | unsigned int div, frq; | ||
| 129 | |||
| 130 | div = ((buffer[2] & 0x3f) << 8) | buffer[3]; | ||
| 131 | |||
| 132 | frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ | ||
| 133 | |||
| 134 | printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n", | ||
| 135 | frq / 1000, frq % 1000, div); | ||
| 136 | } | ||
| 137 | |||
| 138 | /* Freq should be specifyed at 62.5 Hz */ | ||
| 139 | static int __set_radio_freq(struct dvb_frontend *fe, | ||
| 140 | unsigned int freq, | ||
| 141 | bool mono) | ||
| 142 | { | ||
| 143 | struct tea5761_priv *priv = fe->tuner_priv; | ||
| 144 | unsigned int frq = freq; | ||
| 145 | unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; | ||
| 146 | unsigned div; | ||
| 147 | int rc; | ||
| 148 | |||
| 149 | tuner_dbg("radio freq counter %d\n", frq); | ||
| 150 | |||
| 151 | if (priv->standby) { | ||
| 152 | tuner_dbg("TEA5761 set to standby mode\n"); | ||
| 153 | buffer[5] |= TEA5761_TNCTRL_MU; | ||
| 154 | } else { | ||
| 155 | buffer[4] |= TEA5761_TNCTRL_PUPD_0; | ||
| 156 | } | ||
| 157 | |||
| 158 | |||
| 159 | if (mono) { | ||
| 160 | tuner_dbg("TEA5761 set to mono\n"); | ||
| 161 | buffer[5] |= TEA5761_TNCTRL_MST; | ||
| 162 | } else { | ||
| 163 | tuner_dbg("TEA5761 set to stereo\n"); | ||
| 164 | } | ||
| 165 | |||
| 166 | div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; | ||
| 167 | buffer[1] = (div >> 8) & 0x3f; | ||
| 168 | buffer[2] = div & 0xff; | ||
| 169 | |||
| 170 | if (debug) | ||
| 171 | tea5761_status_dump(buffer); | ||
| 172 | |||
| 173 | if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) | ||
| 174 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
| 175 | |||
| 176 | priv->frequency = frq * 125 / 2; | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static int set_radio_freq(struct dvb_frontend *fe, | ||
| 182 | struct analog_parameters *params) | ||
| 183 | { | ||
| 184 | struct tea5761_priv *priv = fe->analog_demod_priv; | ||
| 185 | |||
| 186 | priv->standby = false; | ||
| 187 | |||
| 188 | return __set_radio_freq(fe, params->frequency, | ||
| 189 | params->audmode == V4L2_TUNER_MODE_MONO); | ||
| 190 | } | ||
| 191 | |||
| 192 | static int set_radio_sleep(struct dvb_frontend *fe) | ||
| 193 | { | ||
| 194 | struct tea5761_priv *priv = fe->analog_demod_priv; | ||
| 195 | |||
| 196 | priv->standby = true; | ||
| 197 | |||
| 198 | return __set_radio_freq(fe, priv->frequency, false); | ||
| 199 | } | ||
| 200 | |||
| 201 | static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) | ||
| 202 | { | ||
| 203 | struct tea5761_priv *priv = fe->tuner_priv; | ||
| 204 | int rc; | ||
| 205 | |||
| 206 | memset(buffer, 0, 16); | ||
| 207 | if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { | ||
| 208 | tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); | ||
| 209 | return -EREMOTEIO; | ||
| 210 | } | ||
| 211 | |||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) | ||
| 216 | { | ||
| 217 | struct tea5761_priv *priv = fe->tuner_priv; | ||
| 218 | |||
| 219 | int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); | ||
| 220 | |||
| 221 | tuner_dbg("Signal strength: %d\n", signal); | ||
| 222 | |||
| 223 | return signal; | ||
| 224 | } | ||
| 225 | |||
| 226 | static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) | ||
| 227 | { | ||
| 228 | struct tea5761_priv *priv = fe->tuner_priv; | ||
| 229 | |||
| 230 | int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; | ||
| 231 | |||
| 232 | tuner_dbg("Radio ST GET = %02x\n", stereo); | ||
| 233 | |||
| 234 | return (stereo ? V4L2_TUNER_SUB_STEREO : 0); | ||
| 235 | } | ||
| 236 | |||
| 237 | static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 238 | { | ||
| 239 | unsigned char buffer[16]; | ||
| 240 | |||
| 241 | *status = 0; | ||
| 242 | |||
| 243 | if (0 == tea5761_read_status(fe, buffer)) { | ||
| 244 | if (tea5761_signal(fe, buffer)) | ||
| 245 | *status = TUNER_STATUS_LOCKED; | ||
| 246 | if (tea5761_stereo(fe, buffer)) | ||
| 247 | *status |= TUNER_STATUS_STEREO; | ||
| 248 | } | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
| 254 | { | ||
| 255 | unsigned char buffer[16]; | ||
| 256 | |||
| 257 | *strength = 0; | ||
| 258 | |||
| 259 | if (0 == tea5761_read_status(fe, buffer)) | ||
| 260 | *strength = tea5761_signal(fe, buffer); | ||
| 261 | |||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | ||
| 266 | { | ||
| 267 | unsigned char buffer[16]; | ||
| 268 | int rc; | ||
| 269 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; | ||
| 270 | |||
| 271 | if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { | ||
| 272 | printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); | ||
| 273 | return -EINVAL; | ||
| 274 | } | ||
| 275 | |||
| 276 | if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { | ||
| 277 | printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." | ||
| 278 | " It is not a TEA5761\n", | ||
| 279 | buffer[13], buffer[14], buffer[15]); | ||
| 280 | return -EINVAL; | ||
| 281 | } | ||
| 282 | printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " | ||
| 283 | "Manufacturer ID= 0x%02x\n", | ||
| 284 | buffer[14], buffer[15], buffer[13]); | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int tea5761_release(struct dvb_frontend *fe) | ||
| 290 | { | ||
| 291 | kfree(fe->tuner_priv); | ||
| 292 | fe->tuner_priv = NULL; | ||
| 293 | |||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 298 | { | ||
| 299 | struct tea5761_priv *priv = fe->tuner_priv; | ||
| 300 | *frequency = priv->frequency; | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static struct dvb_tuner_ops tea5761_tuner_ops = { | ||
| 305 | .info = { | ||
| 306 | .name = "tea5761", // Philips TEA5761HN FM Radio | ||
| 307 | }, | ||
| 308 | .set_analog_params = set_radio_freq, | ||
| 309 | .sleep = set_radio_sleep, | ||
| 310 | .release = tea5761_release, | ||
| 311 | .get_frequency = tea5761_get_frequency, | ||
| 312 | .get_status = tea5761_get_status, | ||
| 313 | .get_rf_strength = tea5761_get_rf_strength, | ||
| 314 | }; | ||
| 315 | |||
| 316 | struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
| 317 | struct i2c_adapter* i2c_adap, | ||
| 318 | u8 i2c_addr) | ||
| 319 | { | ||
| 320 | struct tea5761_priv *priv = NULL; | ||
| 321 | |||
| 322 | if (tea5761_autodetection(i2c_adap, i2c_addr) != 0) | ||
| 323 | return NULL; | ||
| 324 | |||
| 325 | priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); | ||
| 326 | if (priv == NULL) | ||
| 327 | return NULL; | ||
| 328 | fe->tuner_priv = priv; | ||
| 329 | |||
| 330 | priv->i2c_props.addr = i2c_addr; | ||
| 331 | priv->i2c_props.adap = i2c_adap; | ||
| 332 | priv->i2c_props.name = "tea5761"; | ||
| 333 | |||
| 334 | memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, | ||
| 335 | sizeof(struct dvb_tuner_ops)); | ||
| 336 | |||
| 337 | tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); | ||
| 338 | |||
| 339 | return fe; | ||
| 340 | } | ||
| 341 | |||
| 342 | |||
| 343 | EXPORT_SYMBOL_GPL(tea5761_attach); | ||
| 344 | EXPORT_SYMBOL_GPL(tea5761_autodetection); | ||
| 345 | |||
| 346 | MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); | ||
| 347 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
| 348 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tea5761.h b/drivers/media/common/tuners/tea5761.h new file mode 100644 index 00000000000..2e2ff82c95a --- /dev/null +++ b/drivers/media/common/tuners/tea5761.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or | ||
| 5 | (at your option) any later version. | ||
| 6 | |||
| 7 | This program is distributed in the hope that it will be useful, | ||
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | GNU General Public License for more details. | ||
| 11 | |||
| 12 | You should have received a copy of the GNU General Public License | ||
| 13 | along with this program; if not, write to the Free Software | ||
| 14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __TEA5761_H__ | ||
| 18 | #define __TEA5761_H__ | ||
| 19 | |||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include "dvb_frontend.h" | ||
| 22 | |||
| 23 | #if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) | ||
| 24 | extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); | ||
| 25 | |||
| 26 | extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
| 27 | struct i2c_adapter* i2c_adap, | ||
| 28 | u8 i2c_addr); | ||
| 29 | #else | ||
| 30 | static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, | ||
| 31 | u8 i2c_addr) | ||
| 32 | { | ||
| 33 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
| 34 | __func__); | ||
| 35 | return -EINVAL; | ||
| 36 | } | ||
| 37 | |||
| 38 | static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
| 39 | struct i2c_adapter* i2c_adap, | ||
| 40 | u8 i2c_addr) | ||
| 41 | { | ||
| 42 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 43 | return NULL; | ||
| 44 | } | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #endif /* __TEA5761_H__ */ | ||
diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/common/tuners/tea5767.c new file mode 100644 index 00000000000..36e85d81acb --- /dev/null +++ b/drivers/media/common/tuners/tea5767.c | |||
| @@ -0,0 +1,475 @@ | |||
| 1 | /* | ||
| 2 | * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview | ||
| 3 | * I2C address is allways 0xC0. | ||
| 4 | * | ||
| 5 | * | ||
| 6 | * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
| 7 | * This code is placed under the terms of the GNU General Public License | ||
| 8 | * | ||
| 9 | * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa | ||
| 10 | * from their contributions on DScaler. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/videodev2.h> | ||
| 17 | #include "tuner-i2c.h" | ||
| 18 | #include "tea5767.h" | ||
| 19 | |||
| 20 | static int debug; | ||
| 21 | module_param(debug, int, 0644); | ||
| 22 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 23 | |||
| 24 | /*****************************************************************************/ | ||
| 25 | |||
| 26 | struct tea5767_priv { | ||
| 27 | struct tuner_i2c_props i2c_props; | ||
| 28 | u32 frequency; | ||
| 29 | struct tea5767_ctrl ctrl; | ||
| 30 | }; | ||
| 31 | |||
| 32 | /*****************************************************************************/ | ||
| 33 | |||
| 34 | /****************************** | ||
| 35 | * Write mode register values * | ||
| 36 | ******************************/ | ||
| 37 | |||
| 38 | /* First register */ | ||
| 39 | #define TEA5767_MUTE 0x80 /* Mutes output */ | ||
| 40 | #define TEA5767_SEARCH 0x40 /* Activates station search */ | ||
| 41 | /* Bits 0-5 for divider MSB */ | ||
| 42 | |||
| 43 | /* Second register */ | ||
| 44 | /* Bits 0-7 for divider LSB */ | ||
| 45 | |||
| 46 | /* Third register */ | ||
| 47 | |||
| 48 | /* Station search from botton to up */ | ||
| 49 | #define TEA5767_SEARCH_UP 0x80 | ||
| 50 | |||
| 51 | /* Searches with ADC output = 10 */ | ||
| 52 | #define TEA5767_SRCH_HIGH_LVL 0x60 | ||
| 53 | |||
| 54 | /* Searches with ADC output = 10 */ | ||
| 55 | #define TEA5767_SRCH_MID_LVL 0x40 | ||
| 56 | |||
| 57 | /* Searches with ADC output = 5 */ | ||
| 58 | #define TEA5767_SRCH_LOW_LVL 0x20 | ||
| 59 | |||
| 60 | /* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ | ||
| 61 | #define TEA5767_HIGH_LO_INJECT 0x10 | ||
| 62 | |||
| 63 | /* Disable stereo */ | ||
| 64 | #define TEA5767_MONO 0x08 | ||
| 65 | |||
| 66 | /* Disable right channel and turns to mono */ | ||
| 67 | #define TEA5767_MUTE_RIGHT 0x04 | ||
| 68 | |||
| 69 | /* Disable left channel and turns to mono */ | ||
| 70 | #define TEA5767_MUTE_LEFT 0x02 | ||
| 71 | |||
| 72 | #define TEA5767_PORT1_HIGH 0x01 | ||
| 73 | |||
| 74 | /* Fourth register */ | ||
| 75 | #define TEA5767_PORT2_HIGH 0x80 | ||
| 76 | /* Chips stops working. Only I2C bus remains on */ | ||
| 77 | #define TEA5767_STDBY 0x40 | ||
| 78 | |||
| 79 | /* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ | ||
| 80 | #define TEA5767_JAPAN_BAND 0x20 | ||
| 81 | |||
| 82 | /* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ | ||
| 83 | #define TEA5767_XTAL_32768 0x10 | ||
| 84 | |||
| 85 | /* Cuts weak signals */ | ||
| 86 | #define TEA5767_SOFT_MUTE 0x08 | ||
| 87 | |||
| 88 | /* Activates high cut control */ | ||
| 89 | #define TEA5767_HIGH_CUT_CTRL 0x04 | ||
| 90 | |||
| 91 | /* Activates stereo noise control */ | ||
| 92 | #define TEA5767_ST_NOISE_CTL 0x02 | ||
| 93 | |||
| 94 | /* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ | ||
| 95 | #define TEA5767_SRCH_IND 0x01 | ||
| 96 | |||
| 97 | /* Fifth register */ | ||
| 98 | |||
| 99 | /* By activating, it will use Xtal at 13 MHz as reference for divider */ | ||
| 100 | #define TEA5767_PLLREF_ENABLE 0x80 | ||
| 101 | |||
| 102 | /* By activating, deemphasis=50, or else, deemphasis of 50us */ | ||
| 103 | #define TEA5767_DEEMPH_75 0X40 | ||
| 104 | |||
| 105 | /***************************** | ||
| 106 | * Read mode register values * | ||
| 107 | *****************************/ | ||
| 108 | |||
| 109 | /* First register */ | ||
| 110 | #define TEA5767_READY_FLAG_MASK 0x80 | ||
| 111 | #define TEA5767_BAND_LIMIT_MASK 0X40 | ||
| 112 | /* Bits 0-5 for divider MSB after search or preset */ | ||
| 113 | |||
| 114 | /* Second register */ | ||
| 115 | /* Bits 0-7 for divider LSB after search or preset */ | ||
| 116 | |||
| 117 | /* Third register */ | ||
| 118 | #define TEA5767_STEREO_MASK 0x80 | ||
| 119 | #define TEA5767_IF_CNTR_MASK 0x7f | ||
| 120 | |||
| 121 | /* Fourth register */ | ||
| 122 | #define TEA5767_ADC_LEVEL_MASK 0xf0 | ||
| 123 | |||
| 124 | /* should be 0 */ | ||
| 125 | #define TEA5767_CHIP_ID_MASK 0x0f | ||
| 126 | |||
| 127 | /* Fifth register */ | ||
| 128 | /* Reserved for future extensions */ | ||
| 129 | #define TEA5767_RESERVED_MASK 0xff | ||
| 130 | |||
| 131 | /*****************************************************************************/ | ||
| 132 | |||
| 133 | static void tea5767_status_dump(struct tea5767_priv *priv, | ||
| 134 | unsigned char *buffer) | ||
| 135 | { | ||
| 136 | unsigned int div, frq; | ||
| 137 | |||
| 138 | if (TEA5767_READY_FLAG_MASK & buffer[0]) | ||
| 139 | tuner_info("Ready Flag ON\n"); | ||
| 140 | else | ||
| 141 | tuner_info("Ready Flag OFF\n"); | ||
| 142 | |||
| 143 | if (TEA5767_BAND_LIMIT_MASK & buffer[0]) | ||
| 144 | tuner_info("Tuner at band limit\n"); | ||
| 145 | else | ||
| 146 | tuner_info("Tuner not at band limit\n"); | ||
| 147 | |||
| 148 | div = ((buffer[0] & 0x3f) << 8) | buffer[1]; | ||
| 149 | |||
| 150 | switch (priv->ctrl.xtal_freq) { | ||
| 151 | case TEA5767_HIGH_LO_13MHz: | ||
| 152 | frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ | ||
| 153 | break; | ||
| 154 | case TEA5767_LOW_LO_13MHz: | ||
| 155 | frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ | ||
| 156 | break; | ||
| 157 | case TEA5767_LOW_LO_32768: | ||
| 158 | frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ | ||
| 159 | break; | ||
| 160 | case TEA5767_HIGH_LO_32768: | ||
| 161 | default: | ||
| 162 | frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | buffer[0] = (div >> 8) & 0x3f; | ||
| 166 | buffer[1] = div & 0xff; | ||
| 167 | |||
| 168 | tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", | ||
| 169 | frq / 1000, frq % 1000, div); | ||
| 170 | |||
| 171 | if (TEA5767_STEREO_MASK & buffer[2]) | ||
| 172 | tuner_info("Stereo\n"); | ||
| 173 | else | ||
| 174 | tuner_info("Mono\n"); | ||
| 175 | |||
| 176 | tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); | ||
| 177 | |||
| 178 | tuner_info("ADC Level = %d\n", | ||
| 179 | (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); | ||
| 180 | |||
| 181 | tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); | ||
| 182 | |||
| 183 | tuner_info("Reserved = 0x%02x\n", | ||
| 184 | (buffer[4] & TEA5767_RESERVED_MASK)); | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Freq should be specifyed at 62.5 Hz */ | ||
| 188 | static int set_radio_freq(struct dvb_frontend *fe, | ||
| 189 | struct analog_parameters *params) | ||
| 190 | { | ||
| 191 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 192 | unsigned int frq = params->frequency; | ||
| 193 | unsigned char buffer[5]; | ||
| 194 | unsigned div; | ||
| 195 | int rc; | ||
| 196 | |||
| 197 | tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); | ||
| 198 | |||
| 199 | buffer[2] = 0; | ||
| 200 | |||
| 201 | if (priv->ctrl.port1) | ||
| 202 | buffer[2] |= TEA5767_PORT1_HIGH; | ||
| 203 | |||
| 204 | if (params->audmode == V4L2_TUNER_MODE_MONO) { | ||
| 205 | tuner_dbg("TEA5767 set to mono\n"); | ||
| 206 | buffer[2] |= TEA5767_MONO; | ||
| 207 | } else { | ||
| 208 | tuner_dbg("TEA5767 set to stereo\n"); | ||
| 209 | } | ||
| 210 | |||
| 211 | |||
| 212 | buffer[3] = 0; | ||
| 213 | |||
| 214 | if (priv->ctrl.port2) | ||
| 215 | buffer[3] |= TEA5767_PORT2_HIGH; | ||
| 216 | |||
| 217 | if (priv->ctrl.high_cut) | ||
| 218 | buffer[3] |= TEA5767_HIGH_CUT_CTRL; | ||
| 219 | |||
| 220 | if (priv->ctrl.st_noise) | ||
| 221 | buffer[3] |= TEA5767_ST_NOISE_CTL; | ||
| 222 | |||
| 223 | if (priv->ctrl.soft_mute) | ||
| 224 | buffer[3] |= TEA5767_SOFT_MUTE; | ||
| 225 | |||
| 226 | if (priv->ctrl.japan_band) | ||
| 227 | buffer[3] |= TEA5767_JAPAN_BAND; | ||
| 228 | |||
| 229 | buffer[4] = 0; | ||
| 230 | |||
| 231 | if (priv->ctrl.deemph_75) | ||
| 232 | buffer[4] |= TEA5767_DEEMPH_75; | ||
| 233 | |||
| 234 | if (priv->ctrl.pllref) | ||
| 235 | buffer[4] |= TEA5767_PLLREF_ENABLE; | ||
| 236 | |||
| 237 | |||
| 238 | /* Rounds freq to next decimal value - for 62.5 KHz step */ | ||
| 239 | /* frq = 20*(frq/16)+radio_frq[frq%16]; */ | ||
| 240 | |||
| 241 | switch (priv->ctrl.xtal_freq) { | ||
| 242 | case TEA5767_HIGH_LO_13MHz: | ||
| 243 | tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); | ||
| 244 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | ||
| 245 | div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; | ||
| 246 | break; | ||
| 247 | case TEA5767_LOW_LO_13MHz: | ||
| 248 | tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); | ||
| 249 | |||
| 250 | div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; | ||
| 251 | break; | ||
| 252 | case TEA5767_LOW_LO_32768: | ||
| 253 | tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); | ||
| 254 | buffer[3] |= TEA5767_XTAL_32768; | ||
| 255 | /* const 700=4000*175 Khz - to adjust freq to right value */ | ||
| 256 | div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; | ||
| 257 | break; | ||
| 258 | case TEA5767_HIGH_LO_32768: | ||
| 259 | default: | ||
| 260 | tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); | ||
| 261 | |||
| 262 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | ||
| 263 | buffer[3] |= TEA5767_XTAL_32768; | ||
| 264 | div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | buffer[0] = (div >> 8) & 0x3f; | ||
| 268 | buffer[1] = div & 0xff; | ||
| 269 | |||
| 270 | if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) | ||
| 271 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
| 272 | |||
| 273 | if (debug) { | ||
| 274 | if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) | ||
| 275 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
| 276 | else | ||
| 277 | tea5767_status_dump(priv, buffer); | ||
| 278 | } | ||
| 279 | |||
| 280 | priv->frequency = frq * 125 / 2; | ||
| 281 | |||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) | ||
| 286 | { | ||
| 287 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 288 | int rc; | ||
| 289 | |||
| 290 | memset(buffer, 0, 5); | ||
| 291 | if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { | ||
| 292 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
| 293 | return -EREMOTEIO; | ||
| 294 | } | ||
| 295 | |||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) | ||
| 300 | { | ||
| 301 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 302 | |||
| 303 | int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); | ||
| 304 | |||
| 305 | tuner_dbg("Signal strength: %d\n", signal); | ||
| 306 | |||
| 307 | return signal; | ||
| 308 | } | ||
| 309 | |||
| 310 | static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) | ||
| 311 | { | ||
| 312 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 313 | |||
| 314 | int stereo = buffer[2] & TEA5767_STEREO_MASK; | ||
| 315 | |||
| 316 | tuner_dbg("Radio ST GET = %02x\n", stereo); | ||
| 317 | |||
| 318 | return (stereo ? V4L2_TUNER_SUB_STEREO : 0); | ||
| 319 | } | ||
| 320 | |||
| 321 | static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 322 | { | ||
| 323 | unsigned char buffer[5]; | ||
| 324 | |||
| 325 | *status = 0; | ||
| 326 | |||
| 327 | if (0 == tea5767_read_status(fe, buffer)) { | ||
| 328 | if (tea5767_signal(fe, buffer)) | ||
| 329 | *status = TUNER_STATUS_LOCKED; | ||
| 330 | if (tea5767_stereo(fe, buffer)) | ||
| 331 | *status |= TUNER_STATUS_STEREO; | ||
| 332 | } | ||
| 333 | |||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 337 | static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
| 338 | { | ||
| 339 | unsigned char buffer[5]; | ||
| 340 | |||
| 341 | *strength = 0; | ||
| 342 | |||
| 343 | if (0 == tea5767_read_status(fe, buffer)) | ||
| 344 | *strength = tea5767_signal(fe, buffer); | ||
| 345 | |||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 349 | static int tea5767_standby(struct dvb_frontend *fe) | ||
| 350 | { | ||
| 351 | unsigned char buffer[5]; | ||
| 352 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 353 | unsigned div, rc; | ||
| 354 | |||
| 355 | div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ | ||
| 356 | buffer[0] = (div >> 8) & 0x3f; | ||
| 357 | buffer[1] = div & 0xff; | ||
| 358 | buffer[2] = TEA5767_PORT1_HIGH; | ||
| 359 | buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | | ||
| 360 | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; | ||
| 361 | buffer[4] = 0; | ||
| 362 | |||
| 363 | if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) | ||
| 364 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | ||
| 370 | { | ||
| 371 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; | ||
| 372 | unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
| 373 | int rc; | ||
| 374 | |||
| 375 | if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { | ||
| 376 | printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); | ||
| 377 | return -EINVAL; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* If all bytes are the same then it's a TV tuner and not a tea5767 */ | ||
| 381 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && | ||
| 382 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { | ||
| 383 | printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); | ||
| 384 | return -EINVAL; | ||
| 385 | } | ||
| 386 | |||
| 387 | /* Status bytes: | ||
| 388 | * Byte 4: bit 3:1 : CI (Chip Identification) == 0 | ||
| 389 | * bit 0 : internally set to 0 | ||
| 390 | * Byte 5: bit 7:0 : == 0 | ||
| 391 | */ | ||
| 392 | if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { | ||
| 393 | printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); | ||
| 394 | return -EINVAL; | ||
| 395 | } | ||
| 396 | |||
| 397 | |||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | static int tea5767_release(struct dvb_frontend *fe) | ||
| 402 | { | ||
| 403 | kfree(fe->tuner_priv); | ||
| 404 | fe->tuner_priv = NULL; | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 410 | { | ||
| 411 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 412 | *frequency = priv->frequency; | ||
| 413 | |||
| 414 | return 0; | ||
| 415 | } | ||
| 416 | |||
| 417 | static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) | ||
| 418 | { | ||
| 419 | struct tea5767_priv *priv = fe->tuner_priv; | ||
| 420 | |||
| 421 | memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); | ||
| 422 | |||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | static struct dvb_tuner_ops tea5767_tuner_ops = { | ||
| 427 | .info = { | ||
| 428 | .name = "tea5767", // Philips TEA5767HN FM Radio | ||
| 429 | }, | ||
| 430 | |||
| 431 | .set_analog_params = set_radio_freq, | ||
| 432 | .set_config = tea5767_set_config, | ||
| 433 | .sleep = tea5767_standby, | ||
| 434 | .release = tea5767_release, | ||
| 435 | .get_frequency = tea5767_get_frequency, | ||
| 436 | .get_status = tea5767_get_status, | ||
| 437 | .get_rf_strength = tea5767_get_rf_strength, | ||
| 438 | }; | ||
| 439 | |||
| 440 | struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
| 441 | struct i2c_adapter* i2c_adap, | ||
| 442 | u8 i2c_addr) | ||
| 443 | { | ||
| 444 | struct tea5767_priv *priv = NULL; | ||
| 445 | |||
| 446 | priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); | ||
| 447 | if (priv == NULL) | ||
| 448 | return NULL; | ||
| 449 | fe->tuner_priv = priv; | ||
| 450 | |||
| 451 | priv->i2c_props.addr = i2c_addr; | ||
| 452 | priv->i2c_props.adap = i2c_adap; | ||
| 453 | priv->i2c_props.name = "tea5767"; | ||
| 454 | |||
| 455 | priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; | ||
| 456 | priv->ctrl.port1 = 1; | ||
| 457 | priv->ctrl.port2 = 1; | ||
| 458 | priv->ctrl.high_cut = 1; | ||
| 459 | priv->ctrl.st_noise = 1; | ||
| 460 | priv->ctrl.japan_band = 1; | ||
| 461 | |||
| 462 | memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, | ||
| 463 | sizeof(struct dvb_tuner_ops)); | ||
| 464 | |||
| 465 | tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); | ||
| 466 | |||
| 467 | return fe; | ||
| 468 | } | ||
| 469 | |||
| 470 | EXPORT_SYMBOL_GPL(tea5767_attach); | ||
| 471 | EXPORT_SYMBOL_GPL(tea5767_autodetection); | ||
| 472 | |||
| 473 | MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); | ||
| 474 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
| 475 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tea5767.h b/drivers/media/common/tuners/tea5767.h new file mode 100644 index 00000000000..d30ab1b483d --- /dev/null +++ b/drivers/media/common/tuners/tea5767.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or | ||
| 5 | (at your option) any later version. | ||
| 6 | |||
| 7 | This program is distributed in the hope that it will be useful, | ||
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | GNU General Public License for more details. | ||
| 11 | |||
| 12 | You should have received a copy of the GNU General Public License | ||
| 13 | along with this program; if not, write to the Free Software | ||
| 14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __TEA5767_H__ | ||
| 18 | #define __TEA5767_H__ | ||
| 19 | |||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include "dvb_frontend.h" | ||
| 22 | |||
| 23 | enum tea5767_xtal { | ||
| 24 | TEA5767_LOW_LO_32768 = 0, | ||
| 25 | TEA5767_HIGH_LO_32768 = 1, | ||
| 26 | TEA5767_LOW_LO_13MHz = 2, | ||
| 27 | TEA5767_HIGH_LO_13MHz = 3, | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct tea5767_ctrl { | ||
| 31 | unsigned int port1:1; | ||
| 32 | unsigned int port2:1; | ||
| 33 | unsigned int high_cut:1; | ||
| 34 | unsigned int st_noise:1; | ||
| 35 | unsigned int soft_mute:1; | ||
| 36 | unsigned int japan_band:1; | ||
| 37 | unsigned int deemph_75:1; | ||
| 38 | unsigned int pllref:1; | ||
| 39 | enum tea5767_xtal xtal_freq; | ||
| 40 | }; | ||
| 41 | |||
| 42 | #if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) | ||
| 43 | extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); | ||
| 44 | |||
| 45 | extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
| 46 | struct i2c_adapter* i2c_adap, | ||
| 47 | u8 i2c_addr); | ||
| 48 | #else | ||
| 49 | static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, | ||
| 50 | u8 i2c_addr) | ||
| 51 | { | ||
| 52 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
| 53 | __func__); | ||
| 54 | return -EINVAL; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
| 58 | struct i2c_adapter* i2c_adap, | ||
| 59 | u8 i2c_addr) | ||
| 60 | { | ||
| 61 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 62 | return NULL; | ||
| 63 | } | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #endif /* __TEA5767_H__ */ | ||
diff --git a/drivers/media/common/tuners/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h new file mode 100644 index 00000000000..18f005634c6 --- /dev/null +++ b/drivers/media/common/tuners/tuner-i2c.h | |||
| @@ -0,0 +1,182 @@ | |||
| 1 | /* | ||
| 2 | tuner-i2c.h - i2c interface for different tuners | ||
| 3 | |||
| 4 | Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) | ||
| 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 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __TUNER_I2C_H__ | ||
| 22 | #define __TUNER_I2C_H__ | ||
| 23 | |||
| 24 | #include <linux/i2c.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | |||
| 27 | struct tuner_i2c_props { | ||
| 28 | u8 addr; | ||
| 29 | struct i2c_adapter *adap; | ||
| 30 | |||
| 31 | /* used for tuner instance management */ | ||
| 32 | int count; | ||
| 33 | char *name; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) | ||
| 37 | { | ||
| 38 | struct i2c_msg msg = { .addr = props->addr, .flags = 0, | ||
| 39 | .buf = buf, .len = len }; | ||
| 40 | int ret = i2c_transfer(props->adap, &msg, 1); | ||
| 41 | |||
| 42 | return (ret == 1) ? len : ret; | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) | ||
| 46 | { | ||
| 47 | struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, | ||
| 48 | .buf = buf, .len = len }; | ||
| 49 | int ret = i2c_transfer(props->adap, &msg, 1); | ||
| 50 | |||
| 51 | return (ret == 1) ? len : ret; | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, | ||
| 55 | char *obuf, int olen, | ||
| 56 | char *ibuf, int ilen) | ||
| 57 | { | ||
| 58 | struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, | ||
| 59 | .buf = obuf, .len = olen }, | ||
| 60 | { .addr = props->addr, .flags = I2C_M_RD, | ||
| 61 | .buf = ibuf, .len = ilen } }; | ||
| 62 | int ret = i2c_transfer(props->adap, msg, 2); | ||
| 63 | |||
| 64 | return (ret == 2) ? ilen : ret; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Callers must declare as a global for the module: | ||
| 68 | * | ||
| 69 | * static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 70 | * | ||
| 71 | * hybrid_tuner_instance_list should be the third argument | ||
| 72 | * passed into hybrid_tuner_request_state(). | ||
| 73 | * | ||
| 74 | * state structure must contain the following: | ||
| 75 | * | ||
| 76 | * struct list_head hybrid_tuner_instance_list; | ||
| 77 | * struct tuner_i2c_props i2c_props; | ||
| 78 | * | ||
| 79 | * hybrid_tuner_instance_list (both within state structure and globally) | ||
| 80 | * is only required if the driver is using hybrid_tuner_request_state | ||
| 81 | * and hybrid_tuner_release_state to manage state sharing between | ||
| 82 | * multiple instances of hybrid tuners. | ||
| 83 | */ | ||
| 84 | |||
| 85 | #define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ | ||
| 86 | printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ | ||
| 87 | i2cprops.adap ? \ | ||
| 88 | i2c_adapter_id(i2cprops.adap) : -1, \ | ||
| 89 | i2cprops.addr, ##arg); \ | ||
| 90 | } while (0) | ||
| 91 | |||
| 92 | /* TO DO: convert all callers of these macros to pass in | ||
| 93 | * struct tuner_i2c_props, then remove the macro wrappers */ | ||
| 94 | |||
| 95 | #define __tuner_warn(i2cprops, fmt, arg...) do { \ | ||
| 96 | tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ | ||
| 97 | } while (0) | ||
| 98 | |||
| 99 | #define __tuner_info(i2cprops, fmt, arg...) do { \ | ||
| 100 | tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ | ||
| 101 | } while (0) | ||
| 102 | |||
| 103 | #define __tuner_err(i2cprops, fmt, arg...) do { \ | ||
| 104 | tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ | ||
| 105 | } while (0) | ||
| 106 | |||
| 107 | #define __tuner_dbg(i2cprops, fmt, arg...) do { \ | ||
| 108 | if ((debug)) \ | ||
| 109 | tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ | ||
| 110 | } while (0) | ||
| 111 | |||
| 112 | #define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) | ||
| 113 | #define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) | ||
| 114 | #define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) | ||
| 115 | #define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) | ||
| 116 | |||
| 117 | /****************************************************************************/ | ||
| 118 | |||
| 119 | /* The return value of hybrid_tuner_request_state indicates the number of | ||
| 120 | * instances using this tuner object. | ||
| 121 | * | ||
| 122 | * 0 - no instances, indicates an error - kzalloc must have failed | ||
| 123 | * | ||
| 124 | * 1 - one instance, indicates that the tuner object was created successfully | ||
| 125 | * | ||
| 126 | * 2 (or more) instances, indicates that an existing tuner object was found | ||
| 127 | */ | ||
| 128 | |||
| 129 | #define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ | ||
| 130 | ({ \ | ||
| 131 | int __ret = 0; \ | ||
| 132 | list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ | ||
| 133 | if (((i2cadap) && (state->i2c_props.adap)) && \ | ||
| 134 | ((i2c_adapter_id(state->i2c_props.adap) == \ | ||
| 135 | i2c_adapter_id(i2cadap)) && \ | ||
| 136 | (i2caddr == state->i2c_props.addr))) { \ | ||
| 137 | __tuner_info(state->i2c_props, \ | ||
| 138 | "attaching existing instance\n"); \ | ||
| 139 | state->i2c_props.count++; \ | ||
| 140 | __ret = state->i2c_props.count; \ | ||
| 141 | break; \ | ||
| 142 | } \ | ||
| 143 | } \ | ||
| 144 | if (0 == __ret) { \ | ||
| 145 | state = kzalloc(sizeof(type), GFP_KERNEL); \ | ||
| 146 | if (NULL == state) \ | ||
| 147 | goto __fail; \ | ||
| 148 | state->i2c_props.addr = i2caddr; \ | ||
| 149 | state->i2c_props.adap = i2cadap; \ | ||
| 150 | state->i2c_props.name = devname; \ | ||
| 151 | __tuner_info(state->i2c_props, \ | ||
| 152 | "creating new instance\n"); \ | ||
| 153 | list_add_tail(&state->hybrid_tuner_instance_list, &list);\ | ||
| 154 | state->i2c_props.count++; \ | ||
| 155 | __ret = state->i2c_props.count; \ | ||
| 156 | } \ | ||
| 157 | __fail: \ | ||
| 158 | __ret; \ | ||
| 159 | }) | ||
| 160 | |||
| 161 | #define hybrid_tuner_release_state(state) \ | ||
| 162 | ({ \ | ||
| 163 | int __ret; \ | ||
| 164 | state->i2c_props.count--; \ | ||
| 165 | __ret = state->i2c_props.count; \ | ||
| 166 | if (!state->i2c_props.count) { \ | ||
| 167 | __tuner_info(state->i2c_props, "destroying instance\n");\ | ||
| 168 | list_del(&state->hybrid_tuner_instance_list); \ | ||
| 169 | kfree(state); \ | ||
| 170 | } \ | ||
| 171 | __ret; \ | ||
| 172 | }) | ||
| 173 | |||
| 174 | #define hybrid_tuner_report_instance_count(state) \ | ||
| 175 | ({ \ | ||
| 176 | int __ret = 0; \ | ||
| 177 | if (state) \ | ||
| 178 | __ret = state->i2c_props.count; \ | ||
| 179 | __ret; \ | ||
| 180 | }) | ||
| 181 | |||
| 182 | #endif /* __TUNER_I2C_H__ */ | ||
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c new file mode 100644 index 00000000000..f8ee29e6059 --- /dev/null +++ b/drivers/media/common/tuners/tuner-simple.c | |||
| @@ -0,0 +1,1131 @@ | |||
| 1 | /* | ||
| 2 | * i2c tv tuner chip device driver | ||
| 3 | * controls all those simple 4-control-bytes style tuners. | ||
| 4 | * | ||
| 5 | * This "tuner-simple" module was split apart from the original "tuner" module. | ||
| 6 | */ | ||
| 7 | #include <linux/delay.h> | ||
| 8 | #include <linux/i2c.h> | ||
| 9 | #include <linux/videodev2.h> | ||
| 10 | #include <media/tuner.h> | ||
| 11 | #include <media/v4l2-common.h> | ||
| 12 | #include <media/tuner-types.h> | ||
| 13 | #include "tuner-i2c.h" | ||
| 14 | #include "tuner-simple.h" | ||
| 15 | |||
| 16 | static int debug; | ||
| 17 | module_param(debug, int, 0644); | ||
| 18 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 19 | |||
| 20 | #define TUNER_SIMPLE_MAX 64 | ||
| 21 | static unsigned int simple_devcount; | ||
| 22 | |||
| 23 | static int offset; | ||
| 24 | module_param(offset, int, 0664); | ||
| 25 | MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); | ||
| 26 | |||
| 27 | static unsigned int atv_input[TUNER_SIMPLE_MAX] = \ | ||
| 28 | { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; | ||
| 29 | static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \ | ||
| 30 | { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; | ||
| 31 | module_param_array(atv_input, int, NULL, 0644); | ||
| 32 | module_param_array(dtv_input, int, NULL, 0644); | ||
| 33 | MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect"); | ||
| 34 | MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect"); | ||
| 35 | |||
| 36 | /* ---------------------------------------------------------------------- */ | ||
| 37 | |||
| 38 | /* tv standard selection for Temic 4046 FM5 | ||
| 39 | this value takes the low bits of control byte 2 | ||
| 40 | from datasheet Rev.01, Feb.00 | ||
| 41 | standard BG I L L2 D | ||
| 42 | picture IF 38.9 38.9 38.9 33.95 38.9 | ||
| 43 | sound 1 33.4 32.9 32.4 40.45 32.4 | ||
| 44 | sound 2 33.16 | ||
| 45 | NICAM 33.05 32.348 33.05 33.05 | ||
| 46 | */ | ||
| 47 | #define TEMIC_SET_PAL_I 0x05 | ||
| 48 | #define TEMIC_SET_PAL_DK 0x09 | ||
| 49 | #define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ | ||
| 50 | #define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ | ||
| 51 | #define TEMIC_SET_PAL_BG 0x0c | ||
| 52 | |||
| 53 | /* tv tuner system standard selection for Philips FQ1216ME | ||
| 54 | this value takes the low bits of control byte 2 | ||
| 55 | from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") | ||
| 56 | standard BG DK I L L` | ||
| 57 | picture carrier 38.90 38.90 38.90 38.90 33.95 | ||
| 58 | colour 34.47 34.47 34.47 34.47 38.38 | ||
| 59 | sound 1 33.40 32.40 32.90 32.40 40.45 | ||
| 60 | sound 2 33.16 - - - - | ||
| 61 | NICAM 33.05 33.05 32.35 33.05 39.80 | ||
| 62 | */ | ||
| 63 | #define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ | ||
| 64 | #define PHILIPS_SET_PAL_BGDK 0x09 | ||
| 65 | #define PHILIPS_SET_PAL_L2 0x0a | ||
| 66 | #define PHILIPS_SET_PAL_L 0x0b | ||
| 67 | |||
| 68 | /* system switching for Philips FI1216MF MK2 | ||
| 69 | from datasheet "1996 Jul 09", | ||
| 70 | standard BG L L' | ||
| 71 | picture carrier 38.90 38.90 33.95 | ||
| 72 | colour 34.47 34.37 38.38 | ||
| 73 | sound 1 33.40 32.40 40.45 | ||
| 74 | sound 2 33.16 - - | ||
| 75 | NICAM 33.05 33.05 39.80 | ||
| 76 | */ | ||
| 77 | #define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ | ||
| 78 | #define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ | ||
| 79 | #define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ | ||
| 80 | |||
| 81 | /* Control byte */ | ||
| 82 | |||
| 83 | #define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ | ||
| 84 | #define TUNER_RATIO_SELECT_50 0x00 | ||
| 85 | #define TUNER_RATIO_SELECT_32 0x02 | ||
| 86 | #define TUNER_RATIO_SELECT_166 0x04 | ||
| 87 | #define TUNER_RATIO_SELECT_62 0x06 | ||
| 88 | |||
| 89 | #define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ | ||
| 90 | |||
| 91 | /* Status byte */ | ||
| 92 | |||
| 93 | #define TUNER_POR 0x80 | ||
| 94 | #define TUNER_FL 0x40 | ||
| 95 | #define TUNER_MODE 0x38 | ||
| 96 | #define TUNER_AFC 0x07 | ||
| 97 | #define TUNER_SIGNAL 0x07 | ||
| 98 | #define TUNER_STEREO 0x10 | ||
| 99 | |||
| 100 | #define TUNER_PLL_LOCKED 0x40 | ||
| 101 | #define TUNER_STEREO_MK3 0x04 | ||
| 102 | |||
| 103 | static DEFINE_MUTEX(tuner_simple_list_mutex); | ||
| 104 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 105 | |||
| 106 | struct tuner_simple_priv { | ||
| 107 | unsigned int nr; | ||
| 108 | u16 last_div; | ||
| 109 | |||
| 110 | struct tuner_i2c_props i2c_props; | ||
| 111 | struct list_head hybrid_tuner_instance_list; | ||
| 112 | |||
| 113 | unsigned int type; | ||
| 114 | struct tunertype *tun; | ||
| 115 | |||
| 116 | u32 frequency; | ||
| 117 | u32 bandwidth; | ||
| 118 | }; | ||
| 119 | |||
| 120 | /* ---------------------------------------------------------------------- */ | ||
| 121 | |||
| 122 | static int tuner_read_status(struct dvb_frontend *fe) | ||
| 123 | { | ||
| 124 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 125 | unsigned char byte; | ||
| 126 | |||
| 127 | if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) | ||
| 128 | return 0; | ||
| 129 | |||
| 130 | return byte; | ||
| 131 | } | ||
| 132 | |||
| 133 | static inline int tuner_signal(const int status) | ||
| 134 | { | ||
| 135 | return (status & TUNER_SIGNAL) << 13; | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline int tuner_stereo(const int type, const int status) | ||
| 139 | { | ||
| 140 | switch (type) { | ||
| 141 | case TUNER_PHILIPS_FM1216ME_MK3: | ||
| 142 | case TUNER_PHILIPS_FM1236_MK3: | ||
| 143 | case TUNER_PHILIPS_FM1256_IH3: | ||
| 144 | case TUNER_LG_NTSC_TAPE: | ||
| 145 | case TUNER_TCL_MF02GIP_5N: | ||
| 146 | return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); | ||
| 147 | case TUNER_PHILIPS_FM1216MK5: | ||
| 148 | return status | TUNER_STEREO; | ||
| 149 | default: | ||
| 150 | return status & TUNER_STEREO; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | static inline int tuner_islocked(const int status) | ||
| 155 | { | ||
| 156 | return (status & TUNER_FL); | ||
| 157 | } | ||
| 158 | |||
| 159 | static inline int tuner_afcstatus(const int status) | ||
| 160 | { | ||
| 161 | return (status & TUNER_AFC) - 2; | ||
| 162 | } | ||
| 163 | |||
| 164 | |||
| 165 | static int simple_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 166 | { | ||
| 167 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 168 | int tuner_status; | ||
| 169 | |||
| 170 | if (priv->i2c_props.adap == NULL) | ||
| 171 | return -EINVAL; | ||
| 172 | |||
| 173 | tuner_status = tuner_read_status(fe); | ||
| 174 | |||
| 175 | *status = 0; | ||
| 176 | |||
| 177 | if (tuner_islocked(tuner_status)) | ||
| 178 | *status = TUNER_STATUS_LOCKED; | ||
| 179 | if (tuner_stereo(priv->type, tuner_status)) | ||
| 180 | *status |= TUNER_STATUS_STEREO; | ||
| 181 | |||
| 182 | tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
| 188 | { | ||
| 189 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 190 | int signal; | ||
| 191 | |||
| 192 | if (priv->i2c_props.adap == NULL) | ||
| 193 | return -EINVAL; | ||
| 194 | |||
| 195 | signal = tuner_signal(tuner_read_status(fe)); | ||
| 196 | |||
| 197 | *strength = signal; | ||
| 198 | |||
| 199 | tuner_dbg("Signal strength: %d\n", signal); | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* ---------------------------------------------------------------------- */ | ||
| 205 | |||
| 206 | static inline char *tuner_param_name(enum param_type type) | ||
| 207 | { | ||
| 208 | char *name; | ||
| 209 | |||
| 210 | switch (type) { | ||
| 211 | case TUNER_PARAM_TYPE_RADIO: | ||
| 212 | name = "radio"; | ||
| 213 | break; | ||
| 214 | case TUNER_PARAM_TYPE_PAL: | ||
| 215 | name = "pal"; | ||
| 216 | break; | ||
| 217 | case TUNER_PARAM_TYPE_SECAM: | ||
| 218 | name = "secam"; | ||
| 219 | break; | ||
| 220 | case TUNER_PARAM_TYPE_NTSC: | ||
| 221 | name = "ntsc"; | ||
| 222 | break; | ||
| 223 | case TUNER_PARAM_TYPE_DIGITAL: | ||
| 224 | name = "digital"; | ||
| 225 | break; | ||
| 226 | default: | ||
| 227 | name = "unknown"; | ||
| 228 | break; | ||
| 229 | } | ||
| 230 | return name; | ||
| 231 | } | ||
| 232 | |||
| 233 | static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, | ||
| 234 | enum param_type desired_type) | ||
| 235 | { | ||
| 236 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 237 | struct tunertype *tun = priv->tun; | ||
| 238 | int i; | ||
| 239 | |||
| 240 | for (i = 0; i < tun->count; i++) | ||
| 241 | if (desired_type == tun->params[i].type) | ||
| 242 | break; | ||
| 243 | |||
| 244 | /* use default tuner params if desired_type not available */ | ||
| 245 | if (i == tun->count) { | ||
| 246 | tuner_dbg("desired params (%s) undefined for tuner %d\n", | ||
| 247 | tuner_param_name(desired_type), priv->type); | ||
| 248 | i = 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | tuner_dbg("using tuner params #%d (%s)\n", i, | ||
| 252 | tuner_param_name(tun->params[i].type)); | ||
| 253 | |||
| 254 | return &tun->params[i]; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int simple_config_lookup(struct dvb_frontend *fe, | ||
| 258 | struct tuner_params *t_params, | ||
| 259 | unsigned *frequency, u8 *config, u8 *cb) | ||
| 260 | { | ||
| 261 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 262 | int i; | ||
| 263 | |||
| 264 | for (i = 0; i < t_params->count; i++) { | ||
| 265 | if (*frequency > t_params->ranges[i].limit) | ||
| 266 | continue; | ||
| 267 | break; | ||
| 268 | } | ||
| 269 | if (i == t_params->count) { | ||
| 270 | tuner_dbg("frequency out of range (%d > %d)\n", | ||
| 271 | *frequency, t_params->ranges[i - 1].limit); | ||
| 272 | *frequency = t_params->ranges[--i].limit; | ||
| 273 | } | ||
| 274 | *config = t_params->ranges[i].config; | ||
| 275 | *cb = t_params->ranges[i].cb; | ||
| 276 | |||
| 277 | tuner_dbg("freq = %d.%02d (%d), range = %d, " | ||
| 278 | "config = 0x%02x, cb = 0x%02x\n", | ||
| 279 | *frequency / 16, *frequency % 16 * 100 / 16, *frequency, | ||
| 280 | i, *config, *cb); | ||
| 281 | |||
| 282 | return i; | ||
| 283 | } | ||
| 284 | |||
| 285 | /* ---------------------------------------------------------------------- */ | ||
| 286 | |||
| 287 | static void simple_set_rf_input(struct dvb_frontend *fe, | ||
| 288 | u8 *config, u8 *cb, unsigned int rf) | ||
| 289 | { | ||
| 290 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 291 | |||
| 292 | switch (priv->type) { | ||
| 293 | case TUNER_PHILIPS_TUV1236D: | ||
| 294 | switch (rf) { | ||
| 295 | case 1: | ||
| 296 | *cb |= 0x08; | ||
| 297 | break; | ||
| 298 | default: | ||
| 299 | *cb &= ~0x08; | ||
| 300 | break; | ||
| 301 | } | ||
| 302 | break; | ||
| 303 | case TUNER_PHILIPS_FCV1236D: | ||
| 304 | switch (rf) { | ||
| 305 | case 1: | ||
| 306 | *cb |= 0x01; | ||
| 307 | break; | ||
| 308 | default: | ||
| 309 | *cb &= ~0x01; | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | break; | ||
| 313 | default: | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | static int simple_std_setup(struct dvb_frontend *fe, | ||
| 319 | struct analog_parameters *params, | ||
| 320 | u8 *config, u8 *cb) | ||
| 321 | { | ||
| 322 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 323 | int rc; | ||
| 324 | |||
| 325 | /* tv norm specific stuff for multi-norm tuners */ | ||
| 326 | switch (priv->type) { | ||
| 327 | case TUNER_PHILIPS_SECAM: /* FI1216MF */ | ||
| 328 | /* 0x01 -> ??? no change ??? */ | ||
| 329 | /* 0x02 -> PAL BDGHI / SECAM L */ | ||
| 330 | /* 0x04 -> ??? PAL others / SECAM others ??? */ | ||
| 331 | *cb &= ~0x03; | ||
| 332 | if (params->std & V4L2_STD_SECAM_L) | ||
| 333 | /* also valid for V4L2_STD_SECAM */ | ||
| 334 | *cb |= PHILIPS_MF_SET_STD_L; | ||
| 335 | else if (params->std & V4L2_STD_SECAM_LC) | ||
| 336 | *cb |= PHILIPS_MF_SET_STD_LC; | ||
| 337 | else /* V4L2_STD_B|V4L2_STD_GH */ | ||
| 338 | *cb |= PHILIPS_MF_SET_STD_BG; | ||
| 339 | break; | ||
| 340 | |||
| 341 | case TUNER_TEMIC_4046FM5: | ||
| 342 | *cb &= ~0x0f; | ||
| 343 | |||
| 344 | if (params->std & V4L2_STD_PAL_BG) { | ||
| 345 | *cb |= TEMIC_SET_PAL_BG; | ||
| 346 | |||
| 347 | } else if (params->std & V4L2_STD_PAL_I) { | ||
| 348 | *cb |= TEMIC_SET_PAL_I; | ||
| 349 | |||
| 350 | } else if (params->std & V4L2_STD_PAL_DK) { | ||
| 351 | *cb |= TEMIC_SET_PAL_DK; | ||
| 352 | |||
| 353 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
| 354 | *cb |= TEMIC_SET_PAL_L; | ||
| 355 | |||
| 356 | } | ||
| 357 | break; | ||
| 358 | |||
| 359 | case TUNER_PHILIPS_FQ1216ME: | ||
| 360 | *cb &= ~0x0f; | ||
| 361 | |||
| 362 | if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { | ||
| 363 | *cb |= PHILIPS_SET_PAL_BGDK; | ||
| 364 | |||
| 365 | } else if (params->std & V4L2_STD_PAL_I) { | ||
| 366 | *cb |= PHILIPS_SET_PAL_I; | ||
| 367 | |||
| 368 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
| 369 | *cb |= PHILIPS_SET_PAL_L; | ||
| 370 | |||
| 371 | } | ||
| 372 | break; | ||
| 373 | |||
| 374 | case TUNER_PHILIPS_FCV1236D: | ||
| 375 | /* 0x00 -> ATSC antenna input 1 */ | ||
| 376 | /* 0x01 -> ATSC antenna input 2 */ | ||
| 377 | /* 0x02 -> NTSC antenna input 1 */ | ||
| 378 | /* 0x03 -> NTSC antenna input 2 */ | ||
| 379 | *cb &= ~0x03; | ||
| 380 | if (!(params->std & V4L2_STD_ATSC)) | ||
| 381 | *cb |= 2; | ||
| 382 | break; | ||
| 383 | |||
| 384 | case TUNER_MICROTUNE_4042FI5: | ||
| 385 | /* Set the charge pump for fast tuning */ | ||
| 386 | *config |= TUNER_CHARGE_PUMP; | ||
| 387 | break; | ||
| 388 | |||
| 389 | case TUNER_PHILIPS_TUV1236D: | ||
| 390 | { | ||
| 391 | struct tuner_i2c_props i2c = priv->i2c_props; | ||
| 392 | /* 0x40 -> ATSC antenna input 1 */ | ||
| 393 | /* 0x48 -> ATSC antenna input 2 */ | ||
| 394 | /* 0x00 -> NTSC antenna input 1 */ | ||
| 395 | /* 0x08 -> NTSC antenna input 2 */ | ||
| 396 | u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; | ||
| 397 | *cb &= ~0x40; | ||
| 398 | if (params->std & V4L2_STD_ATSC) { | ||
| 399 | *cb |= 0x40; | ||
| 400 | buffer[1] = 0x04; | ||
| 401 | } | ||
| 402 | /* set to the correct mode (analog or digital) */ | ||
| 403 | i2c.addr = 0x0a; | ||
| 404 | rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); | ||
| 405 | if (2 != rc) | ||
| 406 | tuner_warn("i2c i/o error: rc == %d " | ||
| 407 | "(should be 2)\n", rc); | ||
| 408 | rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); | ||
| 409 | if (2 != rc) | ||
| 410 | tuner_warn("i2c i/o error: rc == %d " | ||
| 411 | "(should be 2)\n", rc); | ||
| 412 | break; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | if (atv_input[priv->nr]) | ||
| 416 | simple_set_rf_input(fe, config, cb, atv_input[priv->nr]); | ||
| 417 | |||
| 418 | return 0; | ||
| 419 | } | ||
| 420 | |||
| 421 | static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) | ||
| 422 | { | ||
| 423 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 424 | int rc; | ||
| 425 | u8 buffer[2]; | ||
| 426 | |||
| 427 | buffer[0] = (config & ~0x38) | 0x18; | ||
| 428 | buffer[1] = aux; | ||
| 429 | |||
| 430 | tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); | ||
| 431 | |||
| 432 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); | ||
| 433 | if (2 != rc) | ||
| 434 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); | ||
| 435 | |||
| 436 | return rc == 2 ? 0 : rc; | ||
| 437 | } | ||
| 438 | |||
| 439 | static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, | ||
| 440 | u16 div, u8 config, u8 cb) | ||
| 441 | { | ||
| 442 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 443 | int rc; | ||
| 444 | |||
| 445 | switch (priv->type) { | ||
| 446 | case TUNER_LG_TDVS_H06XF: | ||
| 447 | simple_set_aux_byte(fe, config, 0x20); | ||
| 448 | break; | ||
| 449 | case TUNER_PHILIPS_FQ1216LME_MK3: | ||
| 450 | simple_set_aux_byte(fe, config, 0x60); /* External AGC */ | ||
| 451 | break; | ||
| 452 | case TUNER_MICROTUNE_4042FI5: | ||
| 453 | { | ||
| 454 | /* FIXME - this may also work for other tuners */ | ||
| 455 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
| 456 | u8 status_byte = 0; | ||
| 457 | |||
| 458 | /* Wait until the PLL locks */ | ||
| 459 | for (;;) { | ||
| 460 | if (time_after(jiffies, timeout)) | ||
| 461 | return 0; | ||
| 462 | rc = tuner_i2c_xfer_recv(&priv->i2c_props, | ||
| 463 | &status_byte, 1); | ||
| 464 | if (1 != rc) { | ||
| 465 | tuner_warn("i2c i/o read error: rc == %d " | ||
| 466 | "(should be 1)\n", rc); | ||
| 467 | break; | ||
| 468 | } | ||
| 469 | if (status_byte & TUNER_PLL_LOCKED) | ||
| 470 | break; | ||
| 471 | udelay(10); | ||
| 472 | } | ||
| 473 | |||
| 474 | /* Set the charge pump for optimized phase noise figure */ | ||
| 475 | config &= ~TUNER_CHARGE_PUMP; | ||
| 476 | buffer[0] = (div>>8) & 0x7f; | ||
| 477 | buffer[1] = div & 0xff; | ||
| 478 | buffer[2] = config; | ||
| 479 | buffer[3] = cb; | ||
| 480 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
| 481 | buffer[0], buffer[1], buffer[2], buffer[3]); | ||
| 482 | |||
| 483 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
| 484 | if (4 != rc) | ||
| 485 | tuner_warn("i2c i/o error: rc == %d " | ||
| 486 | "(should be 4)\n", rc); | ||
| 487 | break; | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) | ||
| 495 | { | ||
| 496 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 497 | |||
| 498 | switch (priv->type) { | ||
| 499 | case TUNER_TENA_9533_DI: | ||
| 500 | case TUNER_YMEC_TVF_5533MF: | ||
| 501 | tuner_dbg("This tuner doesn't have FM. " | ||
| 502 | "Most cards have a TEA5767 for FM\n"); | ||
| 503 | return 0; | ||
| 504 | case TUNER_PHILIPS_FM1216ME_MK3: | ||
| 505 | case TUNER_PHILIPS_FM1236_MK3: | ||
| 506 | case TUNER_PHILIPS_FMD1216ME_MK3: | ||
| 507 | case TUNER_PHILIPS_FMD1216MEX_MK3: | ||
| 508 | case TUNER_LG_NTSC_TAPE: | ||
| 509 | case TUNER_PHILIPS_FM1256_IH3: | ||
| 510 | case TUNER_TCL_MF02GIP_5N: | ||
| 511 | buffer[3] = 0x19; | ||
| 512 | break; | ||
| 513 | case TUNER_PHILIPS_FM1216MK5: | ||
| 514 | buffer[2] = 0x88; | ||
| 515 | buffer[3] = 0x09; | ||
| 516 | break; | ||
| 517 | case TUNER_TNF_5335MF: | ||
| 518 | buffer[3] = 0x11; | ||
| 519 | break; | ||
| 520 | case TUNER_LG_PAL_FM: | ||
| 521 | buffer[3] = 0xa5; | ||
| 522 | break; | ||
| 523 | case TUNER_THOMSON_DTT761X: | ||
| 524 | buffer[3] = 0x39; | ||
| 525 | break; | ||
| 526 | case TUNER_PHILIPS_FQ1216LME_MK3: | ||
| 527 | case TUNER_PHILIPS_FQ1236_MK5: | ||
| 528 | tuner_err("This tuner doesn't have FM\n"); | ||
| 529 | /* Set the low band for sanity, since it covers 88-108 MHz */ | ||
| 530 | buffer[3] = 0x01; | ||
| 531 | break; | ||
| 532 | case TUNER_MICROTUNE_4049FM5: | ||
| 533 | default: | ||
| 534 | buffer[3] = 0xa4; | ||
| 535 | break; | ||
| 536 | } | ||
| 537 | |||
| 538 | return 0; | ||
| 539 | } | ||
| 540 | |||
| 541 | /* ---------------------------------------------------------------------- */ | ||
| 542 | |||
| 543 | static int simple_set_tv_freq(struct dvb_frontend *fe, | ||
| 544 | struct analog_parameters *params) | ||
| 545 | { | ||
| 546 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 547 | u8 config, cb; | ||
| 548 | u16 div; | ||
| 549 | u8 buffer[4]; | ||
| 550 | int rc, IFPCoff, i; | ||
| 551 | enum param_type desired_type; | ||
| 552 | struct tuner_params *t_params; | ||
| 553 | |||
| 554 | /* IFPCoff = Video Intermediate Frequency - Vif: | ||
| 555 | 940 =16*58.75 NTSC/J (Japan) | ||
| 556 | 732 =16*45.75 M/N STD | ||
| 557 | 704 =16*44 ATSC (at DVB code) | ||
| 558 | 632 =16*39.50 I U.K. | ||
| 559 | 622.4=16*38.90 B/G D/K I, L STD | ||
| 560 | 592 =16*37.00 D China | ||
| 561 | 590 =16.36.875 B Australia | ||
| 562 | 543.2=16*33.95 L' STD | ||
| 563 | 171.2=16*10.70 FM Radio (at set_radio_freq) | ||
| 564 | */ | ||
| 565 | |||
| 566 | if (params->std == V4L2_STD_NTSC_M_JP) { | ||
| 567 | IFPCoff = 940; | ||
| 568 | desired_type = TUNER_PARAM_TYPE_NTSC; | ||
| 569 | } else if ((params->std & V4L2_STD_MN) && | ||
| 570 | !(params->std & ~V4L2_STD_MN)) { | ||
| 571 | IFPCoff = 732; | ||
| 572 | desired_type = TUNER_PARAM_TYPE_NTSC; | ||
| 573 | } else if (params->std == V4L2_STD_SECAM_LC) { | ||
| 574 | IFPCoff = 543; | ||
| 575 | desired_type = TUNER_PARAM_TYPE_SECAM; | ||
| 576 | } else { | ||
| 577 | IFPCoff = 623; | ||
| 578 | desired_type = TUNER_PARAM_TYPE_PAL; | ||
| 579 | } | ||
| 580 | |||
| 581 | t_params = simple_tuner_params(fe, desired_type); | ||
| 582 | |||
| 583 | i = simple_config_lookup(fe, t_params, ¶ms->frequency, | ||
| 584 | &config, &cb); | ||
| 585 | |||
| 586 | div = params->frequency + IFPCoff + offset; | ||
| 587 | |||
| 588 | tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " | ||
| 589 | "Offset=%d.%02d MHz, div=%0d\n", | ||
| 590 | params->frequency / 16, params->frequency % 16 * 100 / 16, | ||
| 591 | IFPCoff / 16, IFPCoff % 16 * 100 / 16, | ||
| 592 | offset / 16, offset % 16 * 100 / 16, div); | ||
| 593 | |||
| 594 | /* tv norm specific stuff for multi-norm tuners */ | ||
| 595 | simple_std_setup(fe, params, &config, &cb); | ||
| 596 | |||
| 597 | if (t_params->cb_first_if_lower_freq && div < priv->last_div) { | ||
| 598 | buffer[0] = config; | ||
| 599 | buffer[1] = cb; | ||
| 600 | buffer[2] = (div>>8) & 0x7f; | ||
| 601 | buffer[3] = div & 0xff; | ||
| 602 | } else { | ||
| 603 | buffer[0] = (div>>8) & 0x7f; | ||
| 604 | buffer[1] = div & 0xff; | ||
| 605 | buffer[2] = config; | ||
| 606 | buffer[3] = cb; | ||
| 607 | } | ||
| 608 | priv->last_div = div; | ||
| 609 | if (t_params->has_tda9887) { | ||
| 610 | struct v4l2_priv_tun_config tda9887_cfg; | ||
| 611 | int tda_config = 0; | ||
| 612 | int is_secam_l = (params->std & (V4L2_STD_SECAM_L | | ||
| 613 | V4L2_STD_SECAM_LC)) && | ||
| 614 | !(params->std & ~(V4L2_STD_SECAM_L | | ||
| 615 | V4L2_STD_SECAM_LC)); | ||
| 616 | |||
| 617 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
| 618 | tda9887_cfg.priv = &tda_config; | ||
| 619 | |||
| 620 | if (params->std == V4L2_STD_SECAM_LC) { | ||
| 621 | if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) | ||
| 622 | tda_config |= TDA9887_PORT1_ACTIVE; | ||
| 623 | if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) | ||
| 624 | tda_config |= TDA9887_PORT2_ACTIVE; | ||
| 625 | } else { | ||
| 626 | if (t_params->port1_active) | ||
| 627 | tda_config |= TDA9887_PORT1_ACTIVE; | ||
| 628 | if (t_params->port2_active) | ||
| 629 | tda_config |= TDA9887_PORT2_ACTIVE; | ||
| 630 | } | ||
| 631 | if (t_params->intercarrier_mode) | ||
| 632 | tda_config |= TDA9887_INTERCARRIER; | ||
| 633 | if (is_secam_l) { | ||
| 634 | if (i == 0 && t_params->default_top_secam_low) | ||
| 635 | tda_config |= TDA9887_TOP(t_params->default_top_secam_low); | ||
| 636 | else if (i == 1 && t_params->default_top_secam_mid) | ||
| 637 | tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); | ||
| 638 | else if (t_params->default_top_secam_high) | ||
| 639 | tda_config |= TDA9887_TOP(t_params->default_top_secam_high); | ||
| 640 | } else { | ||
| 641 | if (i == 0 && t_params->default_top_low) | ||
| 642 | tda_config |= TDA9887_TOP(t_params->default_top_low); | ||
| 643 | else if (i == 1 && t_params->default_top_mid) | ||
| 644 | tda_config |= TDA9887_TOP(t_params->default_top_mid); | ||
| 645 | else if (t_params->default_top_high) | ||
| 646 | tda_config |= TDA9887_TOP(t_params->default_top_high); | ||
| 647 | } | ||
| 648 | if (t_params->default_pll_gating_18) | ||
| 649 | tda_config |= TDA9887_GATING_18; | ||
| 650 | i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, | ||
| 651 | &tda9887_cfg); | ||
| 652 | } | ||
| 653 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
| 654 | buffer[0], buffer[1], buffer[2], buffer[3]); | ||
| 655 | |||
| 656 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
| 657 | if (4 != rc) | ||
| 658 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
| 659 | |||
| 660 | simple_post_tune(fe, &buffer[0], div, config, cb); | ||
| 661 | |||
| 662 | return 0; | ||
| 663 | } | ||
| 664 | |||
| 665 | static int simple_set_radio_freq(struct dvb_frontend *fe, | ||
| 666 | struct analog_parameters *params) | ||
| 667 | { | ||
| 668 | struct tunertype *tun; | ||
| 669 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 670 | u8 buffer[4]; | ||
| 671 | u16 div; | ||
| 672 | int rc, j; | ||
| 673 | struct tuner_params *t_params; | ||
| 674 | unsigned int freq = params->frequency; | ||
| 675 | |||
| 676 | tun = priv->tun; | ||
| 677 | |||
| 678 | for (j = tun->count-1; j > 0; j--) | ||
| 679 | if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) | ||
| 680 | break; | ||
| 681 | /* default t_params (j=0) will be used if desired type wasn't found */ | ||
| 682 | t_params = &tun->params[j]; | ||
| 683 | |||
| 684 | /* Select Radio 1st IF used */ | ||
| 685 | switch (t_params->radio_if) { | ||
| 686 | case 0: /* 10.7 MHz */ | ||
| 687 | freq += (unsigned int)(10.7*16000); | ||
| 688 | break; | ||
| 689 | case 1: /* 33.3 MHz */ | ||
| 690 | freq += (unsigned int)(33.3*16000); | ||
| 691 | break; | ||
| 692 | case 2: /* 41.3 MHz */ | ||
| 693 | freq += (unsigned int)(41.3*16000); | ||
| 694 | break; | ||
| 695 | default: | ||
| 696 | tuner_warn("Unsupported radio_if value %d\n", | ||
| 697 | t_params->radio_if); | ||
| 698 | return 0; | ||
| 699 | } | ||
| 700 | |||
| 701 | buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | | ||
| 702 | TUNER_RATIO_SELECT_50; /* 50 kHz step */ | ||
| 703 | |||
| 704 | /* Bandswitch byte */ | ||
| 705 | simple_radio_bandswitch(fe, &buffer[0]); | ||
| 706 | |||
| 707 | /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps | ||
| 708 | freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = | ||
| 709 | freq * (1/800) */ | ||
| 710 | div = (freq + 400) / 800; | ||
| 711 | |||
| 712 | if (t_params->cb_first_if_lower_freq && div < priv->last_div) { | ||
| 713 | buffer[0] = buffer[2]; | ||
| 714 | buffer[1] = buffer[3]; | ||
| 715 | buffer[2] = (div>>8) & 0x7f; | ||
| 716 | buffer[3] = div & 0xff; | ||
| 717 | } else { | ||
| 718 | buffer[0] = (div>>8) & 0x7f; | ||
| 719 | buffer[1] = div & 0xff; | ||
| 720 | } | ||
| 721 | |||
| 722 | tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
| 723 | buffer[0], buffer[1], buffer[2], buffer[3]); | ||
| 724 | priv->last_div = div; | ||
| 725 | |||
| 726 | if (t_params->has_tda9887) { | ||
| 727 | int config = 0; | ||
| 728 | struct v4l2_priv_tun_config tda9887_cfg; | ||
| 729 | |||
| 730 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
| 731 | tda9887_cfg.priv = &config; | ||
| 732 | |||
| 733 | if (t_params->port1_active && | ||
| 734 | !t_params->port1_fm_high_sensitivity) | ||
| 735 | config |= TDA9887_PORT1_ACTIVE; | ||
| 736 | if (t_params->port2_active && | ||
| 737 | !t_params->port2_fm_high_sensitivity) | ||
| 738 | config |= TDA9887_PORT2_ACTIVE; | ||
| 739 | if (t_params->intercarrier_mode) | ||
| 740 | config |= TDA9887_INTERCARRIER; | ||
| 741 | /* if (t_params->port1_set_for_fm_mono) | ||
| 742 | config &= ~TDA9887_PORT1_ACTIVE;*/ | ||
| 743 | if (t_params->fm_gain_normal) | ||
| 744 | config |= TDA9887_GAIN_NORMAL; | ||
| 745 | if (t_params->radio_if == 2) | ||
| 746 | config |= TDA9887_RIF_41_3; | ||
| 747 | i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, | ||
| 748 | &tda9887_cfg); | ||
| 749 | } | ||
| 750 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
| 751 | if (4 != rc) | ||
| 752 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
| 753 | |||
| 754 | return 0; | ||
| 755 | } | ||
| 756 | |||
| 757 | static int simple_set_params(struct dvb_frontend *fe, | ||
| 758 | struct analog_parameters *params) | ||
| 759 | { | ||
| 760 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 761 | int ret = -EINVAL; | ||
| 762 | |||
| 763 | if (priv->i2c_props.adap == NULL) | ||
| 764 | return -EINVAL; | ||
| 765 | |||
| 766 | switch (params->mode) { | ||
| 767 | case V4L2_TUNER_RADIO: | ||
| 768 | ret = simple_set_radio_freq(fe, params); | ||
| 769 | priv->frequency = params->frequency * 125 / 2; | ||
| 770 | break; | ||
| 771 | case V4L2_TUNER_ANALOG_TV: | ||
| 772 | case V4L2_TUNER_DIGITAL_TV: | ||
| 773 | ret = simple_set_tv_freq(fe, params); | ||
| 774 | priv->frequency = params->frequency * 62500; | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | priv->bandwidth = 0; | ||
| 778 | |||
| 779 | return ret; | ||
| 780 | } | ||
| 781 | |||
| 782 | static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, | ||
| 783 | const struct dvb_frontend_parameters *params) | ||
| 784 | { | ||
| 785 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 786 | |||
| 787 | switch (priv->type) { | ||
| 788 | case TUNER_PHILIPS_FMD1216ME_MK3: | ||
| 789 | case TUNER_PHILIPS_FMD1216MEX_MK3: | ||
| 790 | if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && | ||
| 791 | params->frequency >= 158870000) | ||
| 792 | buf[3] |= 0x08; | ||
| 793 | break; | ||
| 794 | case TUNER_PHILIPS_TD1316: | ||
| 795 | /* determine band */ | ||
| 796 | buf[3] |= (params->frequency < 161000000) ? 1 : | ||
| 797 | (params->frequency < 444000000) ? 2 : 4; | ||
| 798 | |||
| 799 | /* setup PLL filter */ | ||
| 800 | if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) | ||
| 801 | buf[3] |= 1 << 3; | ||
| 802 | break; | ||
| 803 | case TUNER_PHILIPS_TUV1236D: | ||
| 804 | case TUNER_PHILIPS_FCV1236D: | ||
| 805 | { | ||
| 806 | unsigned int new_rf; | ||
| 807 | |||
| 808 | if (dtv_input[priv->nr]) | ||
| 809 | new_rf = dtv_input[priv->nr]; | ||
| 810 | else | ||
| 811 | switch (params->u.vsb.modulation) { | ||
| 812 | case QAM_64: | ||
| 813 | case QAM_256: | ||
| 814 | new_rf = 1; | ||
| 815 | break; | ||
| 816 | case VSB_8: | ||
| 817 | default: | ||
| 818 | new_rf = 0; | ||
| 819 | break; | ||
| 820 | } | ||
| 821 | simple_set_rf_input(fe, &buf[2], &buf[3], new_rf); | ||
| 822 | break; | ||
| 823 | } | ||
| 824 | default: | ||
| 825 | break; | ||
| 826 | } | ||
| 827 | } | ||
| 828 | |||
| 829 | static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, | ||
| 830 | const struct dvb_frontend_parameters *params) | ||
| 831 | { | ||
| 832 | /* This function returns the tuned frequency on success, 0 on error */ | ||
| 833 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 834 | struct tunertype *tun = priv->tun; | ||
| 835 | static struct tuner_params *t_params; | ||
| 836 | u8 config, cb; | ||
| 837 | u32 div; | ||
| 838 | int ret; | ||
| 839 | unsigned frequency = params->frequency / 62500; | ||
| 840 | |||
| 841 | if (!tun->stepsize) { | ||
| 842 | /* tuner-core was loaded before the digital tuner was | ||
| 843 | * configured and somehow picked the wrong tuner type */ | ||
| 844 | tuner_err("attempt to treat tuner %d (%s) as digital tuner " | ||
| 845 | "without stepsize defined.\n", | ||
| 846 | priv->type, priv->tun->name); | ||
| 847 | return 0; /* failure */ | ||
| 848 | } | ||
| 849 | |||
| 850 | t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); | ||
| 851 | ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); | ||
| 852 | if (ret < 0) | ||
| 853 | return 0; /* failure */ | ||
| 854 | |||
| 855 | div = ((frequency + t_params->iffreq) * 62500 + offset + | ||
| 856 | tun->stepsize/2) / tun->stepsize; | ||
| 857 | |||
| 858 | buf[0] = div >> 8; | ||
| 859 | buf[1] = div & 0xff; | ||
| 860 | buf[2] = config; | ||
| 861 | buf[3] = cb; | ||
| 862 | |||
| 863 | simple_set_dvb(fe, buf, params); | ||
| 864 | |||
| 865 | tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", | ||
| 866 | tun->name, div, buf[0], buf[1], buf[2], buf[3]); | ||
| 867 | |||
| 868 | /* calculate the frequency we set it to */ | ||
| 869 | return (div * tun->stepsize) - t_params->iffreq; | ||
| 870 | } | ||
| 871 | |||
| 872 | static int simple_dvb_calc_regs(struct dvb_frontend *fe, | ||
| 873 | struct dvb_frontend_parameters *params, | ||
| 874 | u8 *buf, int buf_len) | ||
| 875 | { | ||
| 876 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 877 | u32 frequency; | ||
| 878 | |||
| 879 | if (buf_len < 5) | ||
| 880 | return -EINVAL; | ||
| 881 | |||
| 882 | frequency = simple_dvb_configure(fe, buf+1, params); | ||
| 883 | if (frequency == 0) | ||
| 884 | return -EINVAL; | ||
| 885 | |||
| 886 | buf[0] = priv->i2c_props.addr; | ||
| 887 | |||
| 888 | priv->frequency = frequency; | ||
| 889 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? | ||
| 890 | params->u.ofdm.bandwidth : 0; | ||
| 891 | |||
| 892 | return 5; | ||
| 893 | } | ||
| 894 | |||
| 895 | static int simple_dvb_set_params(struct dvb_frontend *fe, | ||
| 896 | struct dvb_frontend_parameters *params) | ||
| 897 | { | ||
| 898 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 899 | u32 prev_freq, prev_bw; | ||
| 900 | int ret; | ||
| 901 | u8 buf[5]; | ||
| 902 | |||
| 903 | if (priv->i2c_props.adap == NULL) | ||
| 904 | return -EINVAL; | ||
| 905 | |||
| 906 | prev_freq = priv->frequency; | ||
| 907 | prev_bw = priv->bandwidth; | ||
| 908 | |||
| 909 | ret = simple_dvb_calc_regs(fe, params, buf, 5); | ||
| 910 | if (ret != 5) | ||
| 911 | goto fail; | ||
| 912 | |||
| 913 | /* put analog demod in standby when tuning digital */ | ||
| 914 | if (fe->ops.analog_ops.standby) | ||
| 915 | fe->ops.analog_ops.standby(fe); | ||
| 916 | |||
| 917 | if (fe->ops.i2c_gate_ctrl) | ||
| 918 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 919 | |||
| 920 | /* buf[0] contains the i2c address, but * | ||
| 921 | * we already have it in i2c_props.addr */ | ||
| 922 | ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); | ||
| 923 | if (ret != 4) | ||
| 924 | goto fail; | ||
| 925 | |||
| 926 | return 0; | ||
| 927 | fail: | ||
| 928 | /* calc_regs sets frequency and bandwidth. if we failed, unset them */ | ||
| 929 | priv->frequency = prev_freq; | ||
| 930 | priv->bandwidth = prev_bw; | ||
| 931 | |||
| 932 | return ret; | ||
| 933 | } | ||
| 934 | |||
| 935 | static int simple_init(struct dvb_frontend *fe) | ||
| 936 | { | ||
| 937 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 938 | |||
| 939 | if (priv->i2c_props.adap == NULL) | ||
| 940 | return -EINVAL; | ||
| 941 | |||
| 942 | if (priv->tun->initdata) { | ||
| 943 | int ret; | ||
| 944 | |||
| 945 | if (fe->ops.i2c_gate_ctrl) | ||
| 946 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 947 | |||
| 948 | ret = tuner_i2c_xfer_send(&priv->i2c_props, | ||
| 949 | priv->tun->initdata + 1, | ||
| 950 | priv->tun->initdata[0]); | ||
| 951 | if (ret != priv->tun->initdata[0]) | ||
| 952 | return ret; | ||
| 953 | } | ||
| 954 | |||
| 955 | return 0; | ||
| 956 | } | ||
| 957 | |||
| 958 | static int simple_sleep(struct dvb_frontend *fe) | ||
| 959 | { | ||
| 960 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 961 | |||
| 962 | if (priv->i2c_props.adap == NULL) | ||
| 963 | return -EINVAL; | ||
| 964 | |||
| 965 | if (priv->tun->sleepdata) { | ||
| 966 | int ret; | ||
| 967 | |||
| 968 | if (fe->ops.i2c_gate_ctrl) | ||
| 969 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 970 | |||
| 971 | ret = tuner_i2c_xfer_send(&priv->i2c_props, | ||
| 972 | priv->tun->sleepdata + 1, | ||
| 973 | priv->tun->sleepdata[0]); | ||
| 974 | if (ret != priv->tun->sleepdata[0]) | ||
| 975 | return ret; | ||
| 976 | } | ||
| 977 | |||
| 978 | return 0; | ||
| 979 | } | ||
| 980 | |||
| 981 | static int simple_release(struct dvb_frontend *fe) | ||
| 982 | { | ||
| 983 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 984 | |||
| 985 | mutex_lock(&tuner_simple_list_mutex); | ||
| 986 | |||
| 987 | if (priv) | ||
| 988 | hybrid_tuner_release_state(priv); | ||
| 989 | |||
| 990 | mutex_unlock(&tuner_simple_list_mutex); | ||
| 991 | |||
| 992 | fe->tuner_priv = NULL; | ||
| 993 | |||
| 994 | return 0; | ||
| 995 | } | ||
| 996 | |||
| 997 | static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 998 | { | ||
| 999 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 1000 | *frequency = priv->frequency; | ||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| 1005 | { | ||
| 1006 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
| 1007 | *bandwidth = priv->bandwidth; | ||
| 1008 | return 0; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | static struct dvb_tuner_ops simple_tuner_ops = { | ||
| 1012 | .init = simple_init, | ||
| 1013 | .sleep = simple_sleep, | ||
| 1014 | .set_analog_params = simple_set_params, | ||
| 1015 | .set_params = simple_dvb_set_params, | ||
| 1016 | .calc_regs = simple_dvb_calc_regs, | ||
| 1017 | .release = simple_release, | ||
| 1018 | .get_frequency = simple_get_frequency, | ||
| 1019 | .get_bandwidth = simple_get_bandwidth, | ||
| 1020 | .get_status = simple_get_status, | ||
| 1021 | .get_rf_strength = simple_get_rf_strength, | ||
| 1022 | }; | ||
| 1023 | |||
| 1024 | struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, | ||
| 1025 | struct i2c_adapter *i2c_adap, | ||
| 1026 | u8 i2c_addr, | ||
| 1027 | unsigned int type) | ||
| 1028 | { | ||
| 1029 | struct tuner_simple_priv *priv = NULL; | ||
| 1030 | int instance; | ||
| 1031 | |||
| 1032 | if (type >= tuner_count) { | ||
| 1033 | printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", | ||
| 1034 | __func__, type, tuner_count-1); | ||
| 1035 | return NULL; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /* If i2c_adap is set, check that the tuner is at the correct address. | ||
| 1039 | * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly | ||
| 1040 | * by the digital demod via calc_regs. | ||
| 1041 | */ | ||
| 1042 | if (i2c_adap != NULL) { | ||
| 1043 | u8 b[1]; | ||
| 1044 | struct i2c_msg msg = { | ||
| 1045 | .addr = i2c_addr, .flags = I2C_M_RD, | ||
| 1046 | .buf = b, .len = 1, | ||
| 1047 | }; | ||
| 1048 | |||
| 1049 | if (fe->ops.i2c_gate_ctrl) | ||
| 1050 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 1051 | |||
| 1052 | if (1 != i2c_transfer(i2c_adap, &msg, 1)) | ||
| 1053 | printk(KERN_WARNING "tuner-simple %d-%04x: " | ||
| 1054 | "unable to probe %s, proceeding anyway.", | ||
| 1055 | i2c_adapter_id(i2c_adap), i2c_addr, | ||
| 1056 | tuners[type].name); | ||
| 1057 | |||
| 1058 | if (fe->ops.i2c_gate_ctrl) | ||
| 1059 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | mutex_lock(&tuner_simple_list_mutex); | ||
| 1063 | |||
| 1064 | instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, | ||
| 1065 | hybrid_tuner_instance_list, | ||
| 1066 | i2c_adap, i2c_addr, | ||
| 1067 | "tuner-simple"); | ||
| 1068 | switch (instance) { | ||
| 1069 | case 0: | ||
| 1070 | mutex_unlock(&tuner_simple_list_mutex); | ||
| 1071 | return NULL; | ||
| 1072 | case 1: | ||
| 1073 | fe->tuner_priv = priv; | ||
| 1074 | |||
| 1075 | priv->type = type; | ||
| 1076 | priv->tun = &tuners[type]; | ||
| 1077 | priv->nr = simple_devcount++; | ||
| 1078 | break; | ||
| 1079 | default: | ||
| 1080 | fe->tuner_priv = priv; | ||
| 1081 | break; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | mutex_unlock(&tuner_simple_list_mutex); | ||
| 1085 | |||
| 1086 | memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, | ||
| 1087 | sizeof(struct dvb_tuner_ops)); | ||
| 1088 | |||
| 1089 | if (type != priv->type) | ||
| 1090 | tuner_warn("couldn't set type to %d. Using %d (%s) instead\n", | ||
| 1091 | type, priv->type, priv->tun->name); | ||
| 1092 | else | ||
| 1093 | tuner_info("type set to %d (%s)\n", | ||
| 1094 | priv->type, priv->tun->name); | ||
| 1095 | |||
| 1096 | if ((debug) || ((atv_input[priv->nr] > 0) || | ||
| 1097 | (dtv_input[priv->nr] > 0))) { | ||
| 1098 | if (0 == atv_input[priv->nr]) | ||
| 1099 | tuner_info("tuner %d atv rf input will be " | ||
| 1100 | "autoselected\n", priv->nr); | ||
| 1101 | else | ||
| 1102 | tuner_info("tuner %d atv rf input will be " | ||
| 1103 | "set to input %d (insmod option)\n", | ||
| 1104 | priv->nr, atv_input[priv->nr]); | ||
| 1105 | if (0 == dtv_input[priv->nr]) | ||
| 1106 | tuner_info("tuner %d dtv rf input will be " | ||
| 1107 | "autoselected\n", priv->nr); | ||
| 1108 | else | ||
| 1109 | tuner_info("tuner %d dtv rf input will be " | ||
| 1110 | "set to input %d (insmod option)\n", | ||
| 1111 | priv->nr, dtv_input[priv->nr]); | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, | ||
| 1115 | sizeof(fe->ops.tuner_ops.info.name)); | ||
| 1116 | |||
| 1117 | return fe; | ||
| 1118 | } | ||
| 1119 | EXPORT_SYMBOL_GPL(simple_tuner_attach); | ||
| 1120 | |||
| 1121 | MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); | ||
| 1122 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | ||
| 1123 | MODULE_LICENSE("GPL"); | ||
| 1124 | |||
| 1125 | /* | ||
| 1126 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
| 1127 | * --------------------------------------------------------------------------- | ||
| 1128 | * Local variables: | ||
| 1129 | * c-basic-offset: 8 | ||
| 1130 | * End: | ||
| 1131 | */ | ||
diff --git a/drivers/media/common/tuners/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h new file mode 100644 index 00000000000..381fa5d35a9 --- /dev/null +++ b/drivers/media/common/tuners/tuner-simple.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or | ||
| 5 | (at your option) any later version. | ||
| 6 | |||
| 7 | This program is distributed in the hope that it will be useful, | ||
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | GNU General Public License for more details. | ||
| 11 | |||
| 12 | You should have received a copy of the GNU General Public License | ||
| 13 | along with this program; if not, write to the Free Software | ||
| 14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __TUNER_SIMPLE_H__ | ||
| 18 | #define __TUNER_SIMPLE_H__ | ||
| 19 | |||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include "dvb_frontend.h" | ||
| 22 | |||
| 23 | #if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) | ||
| 24 | extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, | ||
| 25 | struct i2c_adapter *i2c_adap, | ||
| 26 | u8 i2c_addr, | ||
| 27 | unsigned int type); | ||
| 28 | #else | ||
| 29 | static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, | ||
| 30 | struct i2c_adapter *i2c_adap, | ||
| 31 | u8 i2c_addr, | ||
| 32 | unsigned int type) | ||
| 33 | { | ||
| 34 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 35 | return NULL; | ||
| 36 | } | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #endif /* __TUNER_SIMPLE_H__ */ | ||
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c new file mode 100644 index 00000000000..94a603a6084 --- /dev/null +++ b/drivers/media/common/tuners/tuner-types.c | |||
| @@ -0,0 +1,1878 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * i2c tv tuner chip device type database. | ||
| 4 | * | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/i2c.h> | ||
| 8 | #include <media/tuner.h> | ||
| 9 | #include <media/tuner-types.h> | ||
| 10 | |||
| 11 | /* ---------------------------------------------------------------------- */ | ||
| 12 | |||
| 13 | /* | ||
| 14 | * The floats in the tuner struct are computed at compile time | ||
| 15 | * by gcc and cast back to integers. Thus we don't violate the | ||
| 16 | * "no float in kernel" rule. | ||
| 17 | * | ||
| 18 | * A tuner_range may be referenced by multiple tuner_params structs. | ||
| 19 | * There are many duplicates in here. Reusing tuner_range structs, | ||
| 20 | * rather than defining new ones for each tuner, will cut down on | ||
| 21 | * memory usage, and is preferred when possible. | ||
| 22 | * | ||
| 23 | * Each tuner_params array may contain one or more elements, one | ||
| 24 | * for each video standard. | ||
| 25 | * | ||
| 26 | * FIXME: tuner_params struct contains an element, tda988x. We must | ||
| 27 | * set this for all tuners that contain a tda988x chip, and then we | ||
| 28 | * can remove this setting from the various card structs. | ||
| 29 | * | ||
| 30 | * FIXME: Right now, all tuners are using the first tuner_params[] | ||
| 31 | * array element for analog mode. In the future, we will be merging | ||
| 32 | * similar tuner definitions together, such that each tuner definition | ||
| 33 | * will have a tuner_params struct for each available video standard. | ||
| 34 | * At that point, the tuner_params[] array element will be chosen | ||
| 35 | * based on the video standard in use. | ||
| 36 | */ | ||
| 37 | |||
| 38 | /* The following was taken from dvb-pll.c: */ | ||
| 39 | |||
| 40 | /* Set AGC TOP value to 103 dBuV: | ||
| 41 | * 0x80 = Control Byte | ||
| 42 | * 0x40 = 250 uA charge pump (irrelevant) | ||
| 43 | * 0x18 = Aux Byte to follow | ||
| 44 | * 0x06 = 64.5 kHz divider (irrelevant) | ||
| 45 | * 0x01 = Disable Vt (aka sleep) | ||
| 46 | * | ||
| 47 | * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) | ||
| 48 | * 0x50 = AGC Take over point = 103 dBuV | ||
| 49 | */ | ||
| 50 | static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; | ||
| 51 | |||
| 52 | /* 0x04 = 166.67 kHz divider | ||
| 53 | * | ||
| 54 | * 0x80 = AGC Time constant 50ms Iagc = 9 uA | ||
| 55 | * 0x20 = AGC Take over point = 112 dBuV | ||
| 56 | */ | ||
| 57 | static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; | ||
| 58 | |||
| 59 | /* 0-9 */ | ||
| 60 | /* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ | ||
| 61 | |||
| 62 | static struct tuner_range tuner_temic_pal_ranges[] = { | ||
| 63 | { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 64 | { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, | ||
| 65 | { 16 * 999.99 , 0x8e, 0x01, }, | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct tuner_params tuner_temic_pal_params[] = { | ||
| 69 | { | ||
| 70 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 71 | .ranges = tuner_temic_pal_ranges, | ||
| 72 | .count = ARRAY_SIZE(tuner_temic_pal_ranges), | ||
| 73 | }, | ||
| 74 | }; | ||
| 75 | |||
| 76 | /* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ | ||
| 77 | |||
| 78 | static struct tuner_range tuner_philips_pal_i_ranges[] = { | ||
| 79 | { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, | ||
| 80 | { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, | ||
| 81 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static struct tuner_params tuner_philips_pal_i_params[] = { | ||
| 85 | { | ||
| 86 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 87 | .ranges = tuner_philips_pal_i_ranges, | ||
| 88 | .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), | ||
| 89 | }, | ||
| 90 | }; | ||
| 91 | |||
| 92 | /* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ | ||
| 93 | |||
| 94 | static struct tuner_range tuner_philips_ntsc_ranges[] = { | ||
| 95 | { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, | ||
| 96 | { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, | ||
| 97 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static struct tuner_params tuner_philips_ntsc_params[] = { | ||
| 101 | { | ||
| 102 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 103 | .ranges = tuner_philips_ntsc_ranges, | ||
| 104 | .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), | ||
| 105 | .cb_first_if_lower_freq = 1, | ||
| 106 | }, | ||
| 107 | }; | ||
| 108 | |||
| 109 | /* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ | ||
| 110 | |||
| 111 | static struct tuner_range tuner_philips_secam_ranges[] = { | ||
| 112 | { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, | ||
| 113 | { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, | ||
| 114 | { 16 * 999.99 , 0x8e, 0x37, }, | ||
| 115 | }; | ||
| 116 | |||
| 117 | static struct tuner_params tuner_philips_secam_params[] = { | ||
| 118 | { | ||
| 119 | .type = TUNER_PARAM_TYPE_SECAM, | ||
| 120 | .ranges = tuner_philips_secam_ranges, | ||
| 121 | .count = ARRAY_SIZE(tuner_philips_secam_ranges), | ||
| 122 | .cb_first_if_lower_freq = 1, | ||
| 123 | }, | ||
| 124 | }; | ||
| 125 | |||
| 126 | /* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ | ||
| 127 | |||
| 128 | static struct tuner_range tuner_philips_pal_ranges[] = { | ||
| 129 | { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, | ||
| 130 | { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, | ||
| 131 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 132 | }; | ||
| 133 | |||
| 134 | static struct tuner_params tuner_philips_pal_params[] = { | ||
| 135 | { | ||
| 136 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 137 | .ranges = tuner_philips_pal_ranges, | ||
| 138 | .count = ARRAY_SIZE(tuner_philips_pal_ranges), | ||
| 139 | .cb_first_if_lower_freq = 1, | ||
| 140 | }, | ||
| 141 | }; | ||
| 142 | |||
| 143 | /* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ | ||
| 144 | |||
| 145 | static struct tuner_range tuner_temic_ntsc_ranges[] = { | ||
| 146 | { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 147 | { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, | ||
| 148 | { 16 * 999.99 , 0x8e, 0x01, }, | ||
| 149 | }; | ||
| 150 | |||
| 151 | static struct tuner_params tuner_temic_ntsc_params[] = { | ||
| 152 | { | ||
| 153 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 154 | .ranges = tuner_temic_ntsc_ranges, | ||
| 155 | .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), | ||
| 156 | }, | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ | ||
| 160 | |||
| 161 | static struct tuner_range tuner_temic_pal_i_ranges[] = { | ||
| 162 | { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 163 | { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, | ||
| 164 | { 16 * 999.99 , 0x8e, 0x01, }, | ||
| 165 | }; | ||
| 166 | |||
| 167 | static struct tuner_params tuner_temic_pal_i_params[] = { | ||
| 168 | { | ||
| 169 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 170 | .ranges = tuner_temic_pal_i_ranges, | ||
| 171 | .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), | ||
| 172 | }, | ||
| 173 | }; | ||
| 174 | |||
| 175 | /* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ | ||
| 176 | |||
| 177 | static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { | ||
| 178 | { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, | ||
| 179 | { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, | ||
| 180 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 181 | }; | ||
| 182 | |||
| 183 | static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { | ||
| 184 | { | ||
| 185 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 186 | .ranges = tuner_temic_4036fy5_ntsc_ranges, | ||
| 187 | .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), | ||
| 188 | }, | ||
| 189 | }; | ||
| 190 | |||
| 191 | /* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ | ||
| 192 | |||
| 193 | static struct tuner_range tuner_alps_tsb_1_ranges[] = { | ||
| 194 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 195 | { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 196 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 197 | }; | ||
| 198 | |||
| 199 | static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { | ||
| 200 | { | ||
| 201 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 202 | .ranges = tuner_alps_tsb_1_ranges, | ||
| 203 | .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), | ||
| 204 | }, | ||
| 205 | }; | ||
| 206 | |||
| 207 | /* 10-19 */ | ||
| 208 | /* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */ | ||
| 209 | |||
| 210 | static struct tuner_params tuner_alps_tsb_1_params[] = { | ||
| 211 | { | ||
| 212 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 213 | .ranges = tuner_alps_tsb_1_ranges, | ||
| 214 | .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), | ||
| 215 | }, | ||
| 216 | }; | ||
| 217 | |||
| 218 | /* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ | ||
| 219 | |||
| 220 | static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { | ||
| 221 | { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 222 | { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 223 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static struct tuner_params tuner_alps_tsbb5_params[] = { | ||
| 227 | { | ||
| 228 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 229 | .ranges = tuner_alps_tsb_5_pal_ranges, | ||
| 230 | .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), | ||
| 231 | }, | ||
| 232 | }; | ||
| 233 | |||
| 234 | /* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */ | ||
| 235 | |||
| 236 | static struct tuner_params tuner_alps_tsbe5_params[] = { | ||
| 237 | { | ||
| 238 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 239 | .ranges = tuner_alps_tsb_5_pal_ranges, | ||
| 240 | .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), | ||
| 241 | }, | ||
| 242 | }; | ||
| 243 | |||
| 244 | /* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */ | ||
| 245 | |||
| 246 | static struct tuner_params tuner_alps_tsbc5_params[] = { | ||
| 247 | { | ||
| 248 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 249 | .ranges = tuner_alps_tsb_5_pal_ranges, | ||
| 250 | .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), | ||
| 251 | }, | ||
| 252 | }; | ||
| 253 | |||
| 254 | /* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ | ||
| 255 | |||
| 256 | static struct tuner_range tuner_lg_pal_ranges[] = { | ||
| 257 | { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 258 | { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 259 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static struct tuner_params tuner_temic_4006fh5_params[] = { | ||
| 263 | { | ||
| 264 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 265 | .ranges = tuner_lg_pal_ranges, | ||
| 266 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 267 | }, | ||
| 268 | }; | ||
| 269 | |||
| 270 | /* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ | ||
| 271 | |||
| 272 | static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { | ||
| 273 | { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, | ||
| 274 | { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, | ||
| 275 | { 16 * 999.99 , 0x8e, 0x11, }, | ||
| 276 | }; | ||
| 277 | |||
| 278 | static struct tuner_params tuner_alps_tshc6_params[] = { | ||
| 279 | { | ||
| 280 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 281 | .ranges = tuner_alps_tshc6_ntsc_ranges, | ||
| 282 | .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), | ||
| 283 | }, | ||
| 284 | }; | ||
| 285 | |||
| 286 | /* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ | ||
| 287 | |||
| 288 | static struct tuner_range tuner_temic_pal_dk_ranges[] = { | ||
| 289 | { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, | ||
| 290 | { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, | ||
| 291 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 292 | }; | ||
| 293 | |||
| 294 | static struct tuner_params tuner_temic_pal_dk_params[] = { | ||
| 295 | { | ||
| 296 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 297 | .ranges = tuner_temic_pal_dk_ranges, | ||
| 298 | .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), | ||
| 299 | }, | ||
| 300 | }; | ||
| 301 | |||
| 302 | /* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ | ||
| 303 | |||
| 304 | static struct tuner_range tuner_philips_ntsc_m_ranges[] = { | ||
| 305 | { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 306 | { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 307 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 308 | }; | ||
| 309 | |||
| 310 | static struct tuner_params tuner_philips_ntsc_m_params[] = { | ||
| 311 | { | ||
| 312 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 313 | .ranges = tuner_philips_ntsc_m_ranges, | ||
| 314 | .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), | ||
| 315 | }, | ||
| 316 | }; | ||
| 317 | |||
| 318 | /* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ | ||
| 319 | |||
| 320 | static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { | ||
| 321 | { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 322 | { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 323 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 324 | }; | ||
| 325 | |||
| 326 | static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { | ||
| 327 | { | ||
| 328 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 329 | .ranges = tuner_temic_40x6f_5_pal_ranges, | ||
| 330 | .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), | ||
| 331 | }, | ||
| 332 | }; | ||
| 333 | |||
| 334 | /* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */ | ||
| 335 | |||
| 336 | static struct tuner_params tuner_temic_4006fn5_multi_params[] = { | ||
| 337 | { | ||
| 338 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 339 | .ranges = tuner_temic_40x6f_5_pal_ranges, | ||
| 340 | .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), | ||
| 341 | }, | ||
| 342 | }; | ||
| 343 | |||
| 344 | /* 20-29 */ | ||
| 345 | /* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ | ||
| 346 | |||
| 347 | static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { | ||
| 348 | { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 349 | { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 350 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 351 | }; | ||
| 352 | |||
| 353 | static struct tuner_params tuner_temic_4009f_5_params[] = { | ||
| 354 | { | ||
| 355 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 356 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
| 357 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
| 358 | }, | ||
| 359 | }; | ||
| 360 | |||
| 361 | /* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ | ||
| 362 | |||
| 363 | static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { | ||
| 364 | { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 365 | { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 366 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 367 | }; | ||
| 368 | |||
| 369 | static struct tuner_params tuner_temic_4039fr5_params[] = { | ||
| 370 | { | ||
| 371 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 372 | .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, | ||
| 373 | .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), | ||
| 374 | }, | ||
| 375 | }; | ||
| 376 | |||
| 377 | /* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ | ||
| 378 | |||
| 379 | static struct tuner_params tuner_temic_4046fm5_params[] = { | ||
| 380 | { | ||
| 381 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 382 | .ranges = tuner_temic_40x6f_5_pal_ranges, | ||
| 383 | .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), | ||
| 384 | }, | ||
| 385 | }; | ||
| 386 | |||
| 387 | /* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ | ||
| 388 | |||
| 389 | static struct tuner_params tuner_philips_pal_dk_params[] = { | ||
| 390 | { | ||
| 391 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 392 | .ranges = tuner_lg_pal_ranges, | ||
| 393 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 394 | }, | ||
| 395 | }; | ||
| 396 | |||
| 397 | /* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */ | ||
| 398 | |||
| 399 | static struct tuner_params tuner_philips_fq1216me_params[] = { | ||
| 400 | { | ||
| 401 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 402 | .ranges = tuner_lg_pal_ranges, | ||
| 403 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 404 | .has_tda9887 = 1, | ||
| 405 | .port1_active = 1, | ||
| 406 | .port2_active = 1, | ||
| 407 | .port2_invert_for_secam_lc = 1, | ||
| 408 | }, | ||
| 409 | }; | ||
| 410 | |||
| 411 | /* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */ | ||
| 412 | |||
| 413 | static struct tuner_params tuner_lg_pal_i_fm_params[] = { | ||
| 414 | { | ||
| 415 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 416 | .ranges = tuner_lg_pal_ranges, | ||
| 417 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 418 | }, | ||
| 419 | }; | ||
| 420 | |||
| 421 | /* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */ | ||
| 422 | |||
| 423 | static struct tuner_params tuner_lg_pal_i_params[] = { | ||
| 424 | { | ||
| 425 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 426 | .ranges = tuner_lg_pal_ranges, | ||
| 427 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 428 | }, | ||
| 429 | }; | ||
| 430 | |||
| 431 | /* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ | ||
| 432 | |||
| 433 | static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { | ||
| 434 | { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 435 | { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 436 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 437 | }; | ||
| 438 | |||
| 439 | static struct tuner_params tuner_lg_ntsc_fm_params[] = { | ||
| 440 | { | ||
| 441 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 442 | .ranges = tuner_lg_ntsc_fm_ranges, | ||
| 443 | .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), | ||
| 444 | }, | ||
| 445 | }; | ||
| 446 | |||
| 447 | /* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */ | ||
| 448 | |||
| 449 | static struct tuner_params tuner_lg_pal_fm_params[] = { | ||
| 450 | { | ||
| 451 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 452 | .ranges = tuner_lg_pal_ranges, | ||
| 453 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 454 | }, | ||
| 455 | }; | ||
| 456 | |||
| 457 | /* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */ | ||
| 458 | |||
| 459 | static struct tuner_params tuner_lg_pal_params[] = { | ||
| 460 | { | ||
| 461 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 462 | .ranges = tuner_lg_pal_ranges, | ||
| 463 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
| 464 | }, | ||
| 465 | }; | ||
| 466 | |||
| 467 | /* 30-39 */ | ||
| 468 | /* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */ | ||
| 469 | |||
| 470 | static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { | ||
| 471 | { | ||
| 472 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 473 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
| 474 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
| 475 | }, | ||
| 476 | }; | ||
| 477 | |||
| 478 | /* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ | ||
| 479 | |||
| 480 | static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { | ||
| 481 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 482 | { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 483 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 484 | }; | ||
| 485 | |||
| 486 | static struct tuner_params tuner_sharp_2u5jf5540_params[] = { | ||
| 487 | { | ||
| 488 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 489 | .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, | ||
| 490 | .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), | ||
| 491 | }, | ||
| 492 | }; | ||
| 493 | |||
| 494 | /* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ | ||
| 495 | |||
| 496 | static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { | ||
| 497 | { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, | ||
| 498 | { 16 * 464 /*MHz*/, 0x8e, 0x90, }, | ||
| 499 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 500 | }; | ||
| 501 | |||
| 502 | static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { | ||
| 503 | { | ||
| 504 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 505 | .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, | ||
| 506 | .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), | ||
| 507 | }, | ||
| 508 | }; | ||
| 509 | |||
| 510 | /* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */ | ||
| 511 | |||
| 512 | static struct tuner_params tuner_temic_4106fh5_params[] = { | ||
| 513 | { | ||
| 514 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 515 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
| 516 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
| 517 | }, | ||
| 518 | }; | ||
| 519 | |||
| 520 | /* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ | ||
| 521 | |||
| 522 | static struct tuner_params tuner_temic_4012fy5_params[] = { | ||
| 523 | { | ||
| 524 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 525 | .ranges = tuner_temic_pal_ranges, | ||
| 526 | .count = ARRAY_SIZE(tuner_temic_pal_ranges), | ||
| 527 | }, | ||
| 528 | }; | ||
| 529 | |||
| 530 | /* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ | ||
| 531 | |||
| 532 | static struct tuner_params tuner_temic_4136_fy5_params[] = { | ||
| 533 | { | ||
| 534 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 535 | .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, | ||
| 536 | .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), | ||
| 537 | }, | ||
| 538 | }; | ||
| 539 | |||
| 540 | /* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ | ||
| 541 | |||
| 542 | static struct tuner_range tuner_lg_new_tapc_ranges[] = { | ||
| 543 | { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 544 | { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 545 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 546 | }; | ||
| 547 | |||
| 548 | static struct tuner_params tuner_lg_pal_new_tapc_params[] = { | ||
| 549 | { | ||
| 550 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 551 | .ranges = tuner_lg_new_tapc_ranges, | ||
| 552 | .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), | ||
| 553 | }, | ||
| 554 | }; | ||
| 555 | |||
| 556 | /* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ | ||
| 557 | |||
| 558 | static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { | ||
| 559 | { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 560 | { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 561 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 562 | }; | ||
| 563 | |||
| 564 | static struct tuner_params tuner_fm1216me_mk3_params[] = { | ||
| 565 | { | ||
| 566 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 567 | .ranges = tuner_fm1216me_mk3_pal_ranges, | ||
| 568 | .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), | ||
| 569 | .cb_first_if_lower_freq = 1, | ||
| 570 | .has_tda9887 = 1, | ||
| 571 | .port1_active = 1, | ||
| 572 | .port2_active = 1, | ||
| 573 | .port2_invert_for_secam_lc = 1, | ||
| 574 | .port1_fm_high_sensitivity = 1, | ||
| 575 | .default_top_mid = -2, | ||
| 576 | .default_top_secam_mid = -2, | ||
| 577 | .default_top_secam_high = -2, | ||
| 578 | }, | ||
| 579 | }; | ||
| 580 | |||
| 581 | /* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ | ||
| 582 | |||
| 583 | static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { | ||
| 584 | { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, | ||
| 585 | { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, | ||
| 586 | { 16 * 864.00 , 0xce, 0x04, }, | ||
| 587 | }; | ||
| 588 | |||
| 589 | static struct tuner_params tuner_fm1216mk5_params[] = { | ||
| 590 | { | ||
| 591 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 592 | .ranges = tuner_fm1216mk5_pal_ranges, | ||
| 593 | .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), | ||
| 594 | .cb_first_if_lower_freq = 1, | ||
| 595 | .has_tda9887 = 1, | ||
| 596 | .port1_active = 1, | ||
| 597 | .port2_active = 1, | ||
| 598 | .port2_invert_for_secam_lc = 1, | ||
| 599 | .port1_fm_high_sensitivity = 1, | ||
| 600 | .default_top_mid = -2, | ||
| 601 | .default_top_secam_mid = -2, | ||
| 602 | .default_top_secam_high = -2, | ||
| 603 | }, | ||
| 604 | }; | ||
| 605 | |||
| 606 | /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ | ||
| 607 | |||
| 608 | static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { | ||
| 609 | { | ||
| 610 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 611 | .ranges = tuner_lg_new_tapc_ranges, | ||
| 612 | .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), | ||
| 613 | }, | ||
| 614 | }; | ||
| 615 | |||
| 616 | /* 40-49 */ | ||
| 617 | /* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */ | ||
| 618 | |||
| 619 | static struct tuner_params tuner_hitachi_ntsc_params[] = { | ||
| 620 | { | ||
| 621 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 622 | .ranges = tuner_lg_new_tapc_ranges, | ||
| 623 | .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), | ||
| 624 | }, | ||
| 625 | }; | ||
| 626 | |||
| 627 | /* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ | ||
| 628 | |||
| 629 | static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { | ||
| 630 | { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 631 | { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, | ||
| 632 | { 16 * 999.99 , 0x8e, 0xcf, }, | ||
| 633 | }; | ||
| 634 | |||
| 635 | static struct tuner_params tuner_philips_pal_mk_params[] = { | ||
| 636 | { | ||
| 637 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 638 | .ranges = tuner_philips_pal_mk_pal_ranges, | ||
| 639 | .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), | ||
| 640 | }, | ||
| 641 | }; | ||
| 642 | |||
| 643 | /* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */ | ||
| 644 | |||
| 645 | static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = { | ||
| 646 | { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, }, | ||
| 647 | { 16 * 451.25 /*MHz*/, 0x8e, 0x92, }, | ||
| 648 | { 16 * 999.99 , 0x8e, 0x32, }, | ||
| 649 | }; | ||
| 650 | |||
| 651 | static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = { | ||
| 652 | { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, }, | ||
| 653 | { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, | ||
| 654 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 655 | }; | ||
| 656 | |||
| 657 | static struct tuner_params tuner_philips_fcv1236d_params[] = { | ||
| 658 | { | ||
| 659 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 660 | .ranges = tuner_philips_fcv1236d_ntsc_ranges, | ||
| 661 | .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges), | ||
| 662 | }, | ||
| 663 | { | ||
| 664 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 665 | .ranges = tuner_philips_fcv1236d_atsc_ranges, | ||
| 666 | .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges), | ||
| 667 | .iffreq = 16 * 44.00, | ||
| 668 | }, | ||
| 669 | }; | ||
| 670 | |||
| 671 | /* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ | ||
| 672 | |||
| 673 | static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { | ||
| 674 | { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 675 | { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 676 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 677 | }; | ||
| 678 | |||
| 679 | static struct tuner_params tuner_fm1236_mk3_params[] = { | ||
| 680 | { | ||
| 681 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 682 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
| 683 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
| 684 | .cb_first_if_lower_freq = 1, | ||
| 685 | .has_tda9887 = 1, | ||
| 686 | .port1_active = 1, | ||
| 687 | .port2_active = 1, | ||
| 688 | .port1_fm_high_sensitivity = 1, | ||
| 689 | }, | ||
| 690 | }; | ||
| 691 | |||
| 692 | /* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ | ||
| 693 | |||
| 694 | static struct tuner_params tuner_philips_4in1_params[] = { | ||
| 695 | { | ||
| 696 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 697 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
| 698 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
| 699 | }, | ||
| 700 | }; | ||
| 701 | |||
| 702 | /* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */ | ||
| 703 | |||
| 704 | static struct tuner_params tuner_microtune_4049_fm5_params[] = { | ||
| 705 | { | ||
| 706 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 707 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
| 708 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
| 709 | .has_tda9887 = 1, | ||
| 710 | .port1_invert_for_secam_lc = 1, | ||
| 711 | .default_pll_gating_18 = 1, | ||
| 712 | .fm_gain_normal=1, | ||
| 713 | .radio_if = 1, /* 33.3 MHz */ | ||
| 714 | }, | ||
| 715 | }; | ||
| 716 | |||
| 717 | /* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ | ||
| 718 | |||
| 719 | static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { | ||
| 720 | { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, | ||
| 721 | { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, | ||
| 722 | { 16 * 999.99 , 0xce, 0x08, }, | ||
| 723 | }; | ||
| 724 | |||
| 725 | static struct tuner_params tuner_panasonic_vp27_params[] = { | ||
| 726 | { | ||
| 727 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 728 | .ranges = tuner_panasonic_vp27_ntsc_ranges, | ||
| 729 | .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), | ||
| 730 | .has_tda9887 = 1, | ||
| 731 | .intercarrier_mode = 1, | ||
| 732 | .default_top_low = -3, | ||
| 733 | .default_top_mid = -3, | ||
| 734 | .default_top_high = -3, | ||
| 735 | }, | ||
| 736 | }; | ||
| 737 | |||
| 738 | /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ | ||
| 739 | |||
| 740 | static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { | ||
| 741 | { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, | ||
| 742 | { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, | ||
| 743 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
| 744 | }; | ||
| 745 | |||
| 746 | static struct tuner_params tuner_tnf_8831bgff_params[] = { | ||
| 747 | { | ||
| 748 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 749 | .ranges = tuner_tnf_8831bgff_pal_ranges, | ||
| 750 | .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), | ||
| 751 | }, | ||
| 752 | }; | ||
| 753 | |||
| 754 | /* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ | ||
| 755 | |||
| 756 | static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { | ||
| 757 | { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, | ||
| 758 | { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, | ||
| 759 | { 16 * 999.99 , 0x8e, 0x31, }, | ||
| 760 | }; | ||
| 761 | |||
| 762 | static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = { | ||
| 763 | { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, }, | ||
| 764 | { 16 * 457.00 /*MHz*/, 0x8e, 0x91, }, | ||
| 765 | { 16 * 999.99 , 0x8e, 0x31, }, | ||
| 766 | }; | ||
| 767 | |||
| 768 | static struct tuner_params tuner_microtune_4042fi5_params[] = { | ||
| 769 | { | ||
| 770 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 771 | .ranges = tuner_microtune_4042fi5_ntsc_ranges, | ||
| 772 | .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), | ||
| 773 | }, | ||
| 774 | { | ||
| 775 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 776 | .ranges = tuner_microtune_4042fi5_atsc_ranges, | ||
| 777 | .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges), | ||
| 778 | .iffreq = 16 * 44.00 /*MHz*/, | ||
| 779 | }, | ||
| 780 | }; | ||
| 781 | |||
| 782 | /* 50-59 */ | ||
| 783 | /* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ | ||
| 784 | |||
| 785 | static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { | ||
| 786 | { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 787 | { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 788 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 789 | }; | ||
| 790 | |||
| 791 | static struct tuner_params tuner_tcl_2002n_params[] = { | ||
| 792 | { | ||
| 793 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 794 | .ranges = tuner_tcl_2002n_ntsc_ranges, | ||
| 795 | .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), | ||
| 796 | .cb_first_if_lower_freq = 1, | ||
| 797 | }, | ||
| 798 | }; | ||
| 799 | |||
| 800 | /* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ | ||
| 801 | |||
| 802 | static struct tuner_params tuner_philips_fm1256_ih3_params[] = { | ||
| 803 | { | ||
| 804 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 805 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
| 806 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
| 807 | .radio_if = 1, /* 33.3 MHz */ | ||
| 808 | }, | ||
| 809 | }; | ||
| 810 | |||
| 811 | /* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ | ||
| 812 | |||
| 813 | /* single range used for both ntsc and atsc */ | ||
| 814 | static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { | ||
| 815 | { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, | ||
| 816 | { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, | ||
| 817 | { 16 * 999.99 , 0x8e, 0x3c, }, | ||
| 818 | }; | ||
| 819 | |||
| 820 | static struct tuner_params tuner_thomson_dtt7610_params[] = { | ||
| 821 | { | ||
| 822 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 823 | .ranges = tuner_thomson_dtt7610_ntsc_ranges, | ||
| 824 | .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), | ||
| 825 | }, | ||
| 826 | { | ||
| 827 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 828 | .ranges = tuner_thomson_dtt7610_ntsc_ranges, | ||
| 829 | .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), | ||
| 830 | .iffreq = 16 * 44.00 /*MHz*/, | ||
| 831 | }, | ||
| 832 | }; | ||
| 833 | |||
| 834 | /* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ | ||
| 835 | |||
| 836 | static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { | ||
| 837 | { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, | ||
| 838 | { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, | ||
| 839 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 840 | }; | ||
| 841 | |||
| 842 | static struct tuner_params tuner_philips_fq1286_params[] = { | ||
| 843 | { | ||
| 844 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 845 | .ranges = tuner_philips_fq1286_ntsc_ranges, | ||
| 846 | .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), | ||
| 847 | }, | ||
| 848 | }; | ||
| 849 | |||
| 850 | /* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ | ||
| 851 | |||
| 852 | static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { | ||
| 853 | { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, | ||
| 854 | { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, | ||
| 855 | { 16 * 999.99 , 0xce, 0x08, }, | ||
| 856 | }; | ||
| 857 | |||
| 858 | static struct tuner_params tuner_tcl_2002mb_params[] = { | ||
| 859 | { | ||
| 860 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 861 | .ranges = tuner_tcl_2002mb_pal_ranges, | ||
| 862 | .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), | ||
| 863 | }, | ||
| 864 | }; | ||
| 865 | |||
| 866 | /* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ | ||
| 867 | |||
| 868 | static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { | ||
| 869 | { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, | ||
| 870 | { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, | ||
| 871 | { 16 * 999.99 , 0xce, 0x04, }, | ||
| 872 | }; | ||
| 873 | |||
| 874 | static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { | ||
| 875 | { | ||
| 876 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 877 | .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, | ||
| 878 | .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), | ||
| 879 | .has_tda9887 = 1, | ||
| 880 | .port1_active = 1, | ||
| 881 | .port2_invert_for_secam_lc = 1, | ||
| 882 | .default_top_mid = -2, | ||
| 883 | .default_top_secam_low = -2, | ||
| 884 | .default_top_secam_mid = -2, | ||
| 885 | .default_top_secam_high = -2, | ||
| 886 | }, | ||
| 887 | }; | ||
| 888 | |||
| 889 | /* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */ | ||
| 890 | |||
| 891 | static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { | ||
| 892 | { | ||
| 893 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 894 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
| 895 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
| 896 | }, | ||
| 897 | }; | ||
| 898 | |||
| 899 | /* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ | ||
| 900 | |||
| 901 | static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { | ||
| 902 | { | ||
| 903 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 904 | .ranges = tuner_philips_ntsc_m_ranges, | ||
| 905 | .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), | ||
| 906 | }, | ||
| 907 | }; | ||
| 908 | |||
| 909 | /* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ | ||
| 910 | |||
| 911 | static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { | ||
| 912 | { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 913 | { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 914 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 915 | }; | ||
| 916 | |||
| 917 | static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { | ||
| 918 | { | ||
| 919 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 920 | .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, | ||
| 921 | .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), | ||
| 922 | }, | ||
| 923 | }; | ||
| 924 | |||
| 925 | /* 60-69 */ | ||
| 926 | /* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */ | ||
| 927 | /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ | ||
| 928 | |||
| 929 | static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { | ||
| 930 | { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, | ||
| 931 | { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, | ||
| 932 | { 16 * 999.99 , 0x8e, 0x3c, }, | ||
| 933 | }; | ||
| 934 | |||
| 935 | static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = { | ||
| 936 | { 16 * 147.00 /*MHz*/, 0x8e, 0x39, }, | ||
| 937 | { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, }, | ||
| 938 | { 16 * 999.99 , 0x8e, 0x3c, }, | ||
| 939 | }; | ||
| 940 | |||
| 941 | static struct tuner_params tuner_thomson_dtt761x_params[] = { | ||
| 942 | { | ||
| 943 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 944 | .ranges = tuner_thomson_dtt761x_ntsc_ranges, | ||
| 945 | .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), | ||
| 946 | .has_tda9887 = 1, | ||
| 947 | .fm_gain_normal = 1, | ||
| 948 | .radio_if = 2, /* 41.3 MHz */ | ||
| 949 | }, | ||
| 950 | { | ||
| 951 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 952 | .ranges = tuner_thomson_dtt761x_atsc_ranges, | ||
| 953 | .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges), | ||
| 954 | .iffreq = 16 * 44.00, /*MHz*/ | ||
| 955 | }, | ||
| 956 | }; | ||
| 957 | |||
| 958 | /* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ | ||
| 959 | |||
| 960 | static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { | ||
| 961 | { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 962 | { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 963 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 964 | }; | ||
| 965 | |||
| 966 | static struct tuner_params tuner_tena_9533_di_params[] = { | ||
| 967 | { | ||
| 968 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 969 | .ranges = tuner_tena_9533_di_pal_ranges, | ||
| 970 | .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), | ||
| 971 | }, | ||
| 972 | }; | ||
| 973 | |||
| 974 | /* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ | ||
| 975 | |||
| 976 | static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { | ||
| 977 | { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, | ||
| 978 | { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, | ||
| 979 | { 16 * 999.99 , 0x86, 0x08, }, | ||
| 980 | }; | ||
| 981 | |||
| 982 | static struct tuner_params tuner_tena_tnf_5337_params[] = { | ||
| 983 | { | ||
| 984 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 985 | .ranges = tuner_tena_tnf_5337_ntsc_ranges, | ||
| 986 | .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), | ||
| 987 | }, | ||
| 988 | }; | ||
| 989 | |||
| 990 | /* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ | ||
| 991 | |||
| 992 | static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { | ||
| 993 | { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, | ||
| 994 | { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, | ||
| 995 | { 16 * 999.99 , 0x86, 0x54, }, | ||
| 996 | }; | ||
| 997 | |||
| 998 | static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = { | ||
| 999 | { 16 * 143.87 /*MHz*/, 0xbc, 0x41 }, | ||
| 1000 | { 16 * 158.87 /*MHz*/, 0xf4, 0x41 }, | ||
| 1001 | { 16 * 329.87 /*MHz*/, 0xbc, 0x42 }, | ||
| 1002 | { 16 * 441.87 /*MHz*/, 0xf4, 0x42 }, | ||
| 1003 | { 16 * 625.87 /*MHz*/, 0xbc, 0x44 }, | ||
| 1004 | { 16 * 803.87 /*MHz*/, 0xf4, 0x44 }, | ||
| 1005 | { 16 * 999.99 , 0xfc, 0x44 }, | ||
| 1006 | }; | ||
| 1007 | |||
| 1008 | static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { | ||
| 1009 | { | ||
| 1010 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1011 | .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, | ||
| 1012 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), | ||
| 1013 | .has_tda9887 = 1, | ||
| 1014 | .port1_active = 1, | ||
| 1015 | .port2_active = 1, | ||
| 1016 | .port2_fm_high_sensitivity = 1, | ||
| 1017 | .port2_invert_for_secam_lc = 1, | ||
| 1018 | .port1_set_for_fm_mono = 1, | ||
| 1019 | }, | ||
| 1020 | { | ||
| 1021 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1022 | .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, | ||
| 1023 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), | ||
| 1024 | .iffreq = 16 * 36.125, /*MHz*/ | ||
| 1025 | }, | ||
| 1026 | }; | ||
| 1027 | |||
| 1028 | static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { | ||
| 1029 | { | ||
| 1030 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1031 | .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, | ||
| 1032 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), | ||
| 1033 | .has_tda9887 = 1, | ||
| 1034 | .port1_active = 1, | ||
| 1035 | .port2_active = 1, | ||
| 1036 | .port2_fm_high_sensitivity = 1, | ||
| 1037 | .port2_invert_for_secam_lc = 1, | ||
| 1038 | .port1_set_for_fm_mono = 1, | ||
| 1039 | .radio_if = 1, | ||
| 1040 | .fm_gain_normal = 1, | ||
| 1041 | }, | ||
| 1042 | { | ||
| 1043 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1044 | .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, | ||
| 1045 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), | ||
| 1046 | .iffreq = 16 * 36.125, /*MHz*/ | ||
| 1047 | }, | ||
| 1048 | }; | ||
| 1049 | |||
| 1050 | /* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ | ||
| 1051 | |||
| 1052 | static struct tuner_range tuner_tua6034_ntsc_ranges[] = { | ||
| 1053 | { 16 * 165.00 /*MHz*/, 0x8e, 0x01 }, | ||
| 1054 | { 16 * 450.00 /*MHz*/, 0x8e, 0x02 }, | ||
| 1055 | { 16 * 999.99 , 0x8e, 0x04 }, | ||
| 1056 | }; | ||
| 1057 | |||
| 1058 | static struct tuner_range tuner_tua6034_atsc_ranges[] = { | ||
| 1059 | { 16 * 165.00 /*MHz*/, 0xce, 0x01 }, | ||
| 1060 | { 16 * 450.00 /*MHz*/, 0xce, 0x02 }, | ||
| 1061 | { 16 * 999.99 , 0xce, 0x04 }, | ||
| 1062 | }; | ||
| 1063 | |||
| 1064 | static struct tuner_params tuner_lg_tdvs_h06xf_params[] = { | ||
| 1065 | { | ||
| 1066 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1067 | .ranges = tuner_tua6034_ntsc_ranges, | ||
| 1068 | .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), | ||
| 1069 | }, | ||
| 1070 | { | ||
| 1071 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1072 | .ranges = tuner_tua6034_atsc_ranges, | ||
| 1073 | .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges), | ||
| 1074 | .iffreq = 16 * 44.00, | ||
| 1075 | }, | ||
| 1076 | }; | ||
| 1077 | |||
| 1078 | /* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ | ||
| 1079 | |||
| 1080 | static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { | ||
| 1081 | { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 1082 | { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 1083 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 1084 | }; | ||
| 1085 | |||
| 1086 | static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { | ||
| 1087 | { | ||
| 1088 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1089 | .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, | ||
| 1090 | .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), | ||
| 1091 | }, | ||
| 1092 | }; | ||
| 1093 | |||
| 1094 | /* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ | ||
| 1095 | |||
| 1096 | static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { | ||
| 1097 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 1098 | { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 1099 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 1100 | }; | ||
| 1101 | |||
| 1102 | static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { | ||
| 1103 | { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 1104 | { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 1105 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 1106 | }; | ||
| 1107 | |||
| 1108 | static struct tuner_params tuner_lg_taln_params[] = { | ||
| 1109 | { | ||
| 1110 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1111 | .ranges = tuner_lg_taln_ntsc_ranges, | ||
| 1112 | .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), | ||
| 1113 | },{ | ||
| 1114 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1115 | .ranges = tuner_lg_taln_pal_secam_ranges, | ||
| 1116 | .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), | ||
| 1117 | }, | ||
| 1118 | }; | ||
| 1119 | |||
| 1120 | /* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ | ||
| 1121 | |||
| 1122 | static struct tuner_range tuner_philips_td1316_pal_ranges[] = { | ||
| 1123 | { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, | ||
| 1124 | { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, | ||
| 1125 | { 16 * 999.99 , 0xc8, 0xa4, }, | ||
| 1126 | }; | ||
| 1127 | |||
| 1128 | static struct tuner_range tuner_philips_td1316_dvb_ranges[] = { | ||
| 1129 | { 16 * 93.834 /*MHz*/, 0xca, 0x60, }, | ||
| 1130 | { 16 * 123.834 /*MHz*/, 0xca, 0xa0, }, | ||
| 1131 | { 16 * 163.834 /*MHz*/, 0xca, 0xc0, }, | ||
| 1132 | { 16 * 253.834 /*MHz*/, 0xca, 0x60, }, | ||
| 1133 | { 16 * 383.834 /*MHz*/, 0xca, 0xa0, }, | ||
| 1134 | { 16 * 443.834 /*MHz*/, 0xca, 0xc0, }, | ||
| 1135 | { 16 * 583.834 /*MHz*/, 0xca, 0x60, }, | ||
| 1136 | { 16 * 793.834 /*MHz*/, 0xca, 0xa0, }, | ||
| 1137 | { 16 * 999.999 , 0xca, 0xe0, }, | ||
| 1138 | }; | ||
| 1139 | |||
| 1140 | static struct tuner_params tuner_philips_td1316_params[] = { | ||
| 1141 | { | ||
| 1142 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1143 | .ranges = tuner_philips_td1316_pal_ranges, | ||
| 1144 | .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), | ||
| 1145 | }, | ||
| 1146 | { | ||
| 1147 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1148 | .ranges = tuner_philips_td1316_dvb_ranges, | ||
| 1149 | .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges), | ||
| 1150 | .iffreq = 16 * 36.166667 /*MHz*/, | ||
| 1151 | }, | ||
| 1152 | }; | ||
| 1153 | |||
| 1154 | /* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ | ||
| 1155 | |||
| 1156 | static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { | ||
| 1157 | { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, | ||
| 1158 | { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, | ||
| 1159 | { 16 * 999.99 , 0xce, 0x04, }, | ||
| 1160 | }; | ||
| 1161 | |||
| 1162 | static struct tuner_range tuner_tuv1236d_atsc_ranges[] = { | ||
| 1163 | { 16 * 157.25 /*MHz*/, 0xc6, 0x41, }, | ||
| 1164 | { 16 * 454.00 /*MHz*/, 0xc6, 0x42, }, | ||
| 1165 | { 16 * 999.99 , 0xc6, 0x44, }, | ||
| 1166 | }; | ||
| 1167 | |||
| 1168 | static struct tuner_params tuner_tuv1236d_params[] = { | ||
| 1169 | { | ||
| 1170 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1171 | .ranges = tuner_tuv1236d_ntsc_ranges, | ||
| 1172 | .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), | ||
| 1173 | }, | ||
| 1174 | { | ||
| 1175 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1176 | .ranges = tuner_tuv1236d_atsc_ranges, | ||
| 1177 | .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges), | ||
| 1178 | .iffreq = 16 * 44.00, | ||
| 1179 | }, | ||
| 1180 | }; | ||
| 1181 | |||
| 1182 | /* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ | ||
| 1183 | /* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF | ||
| 1184 | * but it is expected to work also with other Tenna/Ymec | ||
| 1185 | * models based on TI SN 761677 chip on both PAL and NTSC | ||
| 1186 | */ | ||
| 1187 | |||
| 1188 | static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { | ||
| 1189 | { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 1190 | { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 1191 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 1192 | }; | ||
| 1193 | |||
| 1194 | static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { | ||
| 1195 | { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 1196 | { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 1197 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
| 1198 | }; | ||
| 1199 | |||
| 1200 | static struct tuner_params tuner_tnf_5335mf_params[] = { | ||
| 1201 | { | ||
| 1202 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1203 | .ranges = tuner_tnf_5335mf_ntsc_ranges, | ||
| 1204 | .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), | ||
| 1205 | }, | ||
| 1206 | { | ||
| 1207 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1208 | .ranges = tuner_tnf_5335_d_if_pal_ranges, | ||
| 1209 | .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), | ||
| 1210 | }, | ||
| 1211 | }; | ||
| 1212 | |||
| 1213 | /* 70-79 */ | ||
| 1214 | /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ | ||
| 1215 | |||
| 1216 | /* '+ 4' turns on the Low Noise Amplifier */ | ||
| 1217 | static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { | ||
| 1218 | { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, | ||
| 1219 | { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, | ||
| 1220 | { 16 * 999.99 , 0xce, 0x08 + 4, }, | ||
| 1221 | }; | ||
| 1222 | |||
| 1223 | static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { | ||
| 1224 | { | ||
| 1225 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1226 | .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, | ||
| 1227 | .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), | ||
| 1228 | }, | ||
| 1229 | }; | ||
| 1230 | |||
| 1231 | /* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ | ||
| 1232 | |||
| 1233 | static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = { | ||
| 1234 | { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, | ||
| 1235 | { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, | ||
| 1236 | { 16 * 999.99 , 0xf6, 0x18, }, | ||
| 1237 | }; | ||
| 1238 | |||
| 1239 | static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = { | ||
| 1240 | { 16 * 250.00 /*MHz*/, 0xb4, 0x12, }, | ||
| 1241 | { 16 * 455.00 /*MHz*/, 0xfe, 0x11, }, | ||
| 1242 | { 16 * 775.50 /*MHz*/, 0xbc, 0x18, }, | ||
| 1243 | { 16 * 999.99 , 0xf4, 0x18, }, | ||
| 1244 | }; | ||
| 1245 | |||
| 1246 | static struct tuner_params tuner_thomson_fe6600_params[] = { | ||
| 1247 | { | ||
| 1248 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1249 | .ranges = tuner_thomson_fe6600_pal_ranges, | ||
| 1250 | .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges), | ||
| 1251 | }, | ||
| 1252 | { | ||
| 1253 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1254 | .ranges = tuner_thomson_fe6600_dvb_ranges, | ||
| 1255 | .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges), | ||
| 1256 | .iffreq = 16 * 36.125 /*MHz*/, | ||
| 1257 | }, | ||
| 1258 | }; | ||
| 1259 | |||
| 1260 | /* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ | ||
| 1261 | |||
| 1262 | /* '+ 4' turns on the Low Noise Amplifier */ | ||
| 1263 | static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { | ||
| 1264 | { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, | ||
| 1265 | { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, | ||
| 1266 | { 16 * 999.99 , 0xce, 0x08 + 4, }, | ||
| 1267 | }; | ||
| 1268 | |||
| 1269 | static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { | ||
| 1270 | { | ||
| 1271 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1272 | .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges, | ||
| 1273 | .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges), | ||
| 1274 | .has_tda9887 = 1, | ||
| 1275 | .port1_active = 1, | ||
| 1276 | .port2_active = 1, | ||
| 1277 | .port2_invert_for_secam_lc = 1, | ||
| 1278 | }, | ||
| 1279 | }; | ||
| 1280 | |||
| 1281 | /* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ | ||
| 1282 | |||
| 1283 | static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { | ||
| 1284 | { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, | ||
| 1285 | { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, | ||
| 1286 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 1287 | }; | ||
| 1288 | |||
| 1289 | static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { | ||
| 1290 | { | ||
| 1291 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1292 | .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, | ||
| 1293 | .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), | ||
| 1294 | .cb_first_if_lower_freq = 1, | ||
| 1295 | }, | ||
| 1296 | }; | ||
| 1297 | |||
| 1298 | /* 80-89 */ | ||
| 1299 | /* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ | ||
| 1300 | |||
| 1301 | static struct tuner_params tuner_fq1216lme_mk3_params[] = { | ||
| 1302 | { | ||
| 1303 | .type = TUNER_PARAM_TYPE_PAL, | ||
| 1304 | .ranges = tuner_fm1216me_mk3_pal_ranges, | ||
| 1305 | .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), | ||
| 1306 | .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ | ||
| 1307 | .has_tda9887 = 1, /* TDA9886 */ | ||
| 1308 | .port1_active = 1, | ||
| 1309 | .port2_active = 1, | ||
| 1310 | .port2_invert_for_secam_lc = 1, | ||
| 1311 | .default_top_low = 4, | ||
| 1312 | .default_top_mid = 4, | ||
| 1313 | .default_top_high = 4, | ||
| 1314 | .default_top_secam_low = 4, | ||
| 1315 | .default_top_secam_mid = 4, | ||
| 1316 | .default_top_secam_high = 4, | ||
| 1317 | }, | ||
| 1318 | }; | ||
| 1319 | |||
| 1320 | /* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ | ||
| 1321 | |||
| 1322 | static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { | ||
| 1323 | /* The datasheet specified channel ranges and the bandswitch byte */ | ||
| 1324 | /* The control byte value of 0x8e is just a guess */ | ||
| 1325 | { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ | ||
| 1326 | { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ | ||
| 1327 | { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ | ||
| 1328 | }; | ||
| 1329 | |||
| 1330 | static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { | ||
| 1331 | { | ||
| 1332 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1333 | .ranges = tuner_partsnic_pti_5nf05_ranges, | ||
| 1334 | .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), | ||
| 1335 | .cb_first_if_lower_freq = 1, /* not specified but safe to do */ | ||
| 1336 | }, | ||
| 1337 | }; | ||
| 1338 | |||
| 1339 | /* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ | ||
| 1340 | |||
| 1341 | static struct tuner_range tuner_cu1216l_ranges[] = { | ||
| 1342 | { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, | ||
| 1343 | { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, | ||
| 1344 | { 16 * 999.99 , 0xce, 0x04 }, | ||
| 1345 | }; | ||
| 1346 | |||
| 1347 | static struct tuner_params tuner_philips_cu1216l_params[] = { | ||
| 1348 | { | ||
| 1349 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
| 1350 | .ranges = tuner_cu1216l_ranges, | ||
| 1351 | .count = ARRAY_SIZE(tuner_cu1216l_ranges), | ||
| 1352 | .iffreq = 16 * 36.125, /*MHz*/ | ||
| 1353 | }, | ||
| 1354 | }; | ||
| 1355 | |||
| 1356 | /* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */ | ||
| 1357 | |||
| 1358 | static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = { | ||
| 1359 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
| 1360 | { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, | ||
| 1361 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
| 1362 | }; | ||
| 1363 | |||
| 1364 | static struct tuner_params tuner_sony_btf_pxn01z_params[] = { | ||
| 1365 | { | ||
| 1366 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1367 | .ranges = tuner_sony_btf_pxn01z_ranges, | ||
| 1368 | .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges), | ||
| 1369 | }, | ||
| 1370 | }; | ||
| 1371 | |||
| 1372 | /* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ | ||
| 1373 | |||
| 1374 | static struct tuner_params tuner_philips_fq1236_mk5_params[] = { | ||
| 1375 | { | ||
| 1376 | .type = TUNER_PARAM_TYPE_NTSC, | ||
| 1377 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
| 1378 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
| 1379 | .has_tda9887 = 1, /* TDA9885, no FM radio */ | ||
| 1380 | }, | ||
| 1381 | }; | ||
| 1382 | |||
| 1383 | /* --------------------------------------------------------------------- */ | ||
| 1384 | |||
| 1385 | struct tunertype tuners[] = { | ||
| 1386 | /* 0-9 */ | ||
| 1387 | [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ | ||
| 1388 | .name = "Temic PAL (4002 FH5)", | ||
| 1389 | .params = tuner_temic_pal_params, | ||
| 1390 | .count = ARRAY_SIZE(tuner_temic_pal_params), | ||
| 1391 | }, | ||
| 1392 | [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ | ||
| 1393 | .name = "Philips PAL_I (FI1246 and compatibles)", | ||
| 1394 | .params = tuner_philips_pal_i_params, | ||
| 1395 | .count = ARRAY_SIZE(tuner_philips_pal_i_params), | ||
| 1396 | }, | ||
| 1397 | [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ | ||
| 1398 | .name = "Philips NTSC (FI1236,FM1236 and compatibles)", | ||
| 1399 | .params = tuner_philips_ntsc_params, | ||
| 1400 | .count = ARRAY_SIZE(tuner_philips_ntsc_params), | ||
| 1401 | }, | ||
| 1402 | [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ | ||
| 1403 | .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", | ||
| 1404 | .params = tuner_philips_secam_params, | ||
| 1405 | .count = ARRAY_SIZE(tuner_philips_secam_params), | ||
| 1406 | }, | ||
| 1407 | [TUNER_ABSENT] = { /* Tuner Absent */ | ||
| 1408 | .name = "NoTuner", | ||
| 1409 | }, | ||
| 1410 | [TUNER_PHILIPS_PAL] = { /* Philips PAL */ | ||
| 1411 | .name = "Philips PAL_BG (FI1216 and compatibles)", | ||
| 1412 | .params = tuner_philips_pal_params, | ||
| 1413 | .count = ARRAY_SIZE(tuner_philips_pal_params), | ||
| 1414 | }, | ||
| 1415 | [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ | ||
| 1416 | .name = "Temic NTSC (4032 FY5)", | ||
| 1417 | .params = tuner_temic_ntsc_params, | ||
| 1418 | .count = ARRAY_SIZE(tuner_temic_ntsc_params), | ||
| 1419 | }, | ||
| 1420 | [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ | ||
| 1421 | .name = "Temic PAL_I (4062 FY5)", | ||
| 1422 | .params = tuner_temic_pal_i_params, | ||
| 1423 | .count = ARRAY_SIZE(tuner_temic_pal_i_params), | ||
| 1424 | }, | ||
| 1425 | [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ | ||
| 1426 | .name = "Temic NTSC (4036 FY5)", | ||
| 1427 | .params = tuner_temic_4036fy5_ntsc_params, | ||
| 1428 | .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), | ||
| 1429 | }, | ||
| 1430 | [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ | ||
| 1431 | .name = "Alps HSBH1", | ||
| 1432 | .params = tuner_alps_tsbh1_ntsc_params, | ||
| 1433 | .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), | ||
| 1434 | }, | ||
| 1435 | |||
| 1436 | /* 10-19 */ | ||
| 1437 | [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ | ||
| 1438 | .name = "Alps TSBE1", | ||
| 1439 | .params = tuner_alps_tsb_1_params, | ||
| 1440 | .count = ARRAY_SIZE(tuner_alps_tsb_1_params), | ||
| 1441 | }, | ||
| 1442 | [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ | ||
| 1443 | .name = "Alps TSBB5", | ||
| 1444 | .params = tuner_alps_tsbb5_params, | ||
| 1445 | .count = ARRAY_SIZE(tuner_alps_tsbb5_params), | ||
| 1446 | }, | ||
| 1447 | [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ | ||
| 1448 | .name = "Alps TSBE5", | ||
| 1449 | .params = tuner_alps_tsbe5_params, | ||
| 1450 | .count = ARRAY_SIZE(tuner_alps_tsbe5_params), | ||
| 1451 | }, | ||
| 1452 | [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ | ||
| 1453 | .name = "Alps TSBC5", | ||
| 1454 | .params = tuner_alps_tsbc5_params, | ||
| 1455 | .count = ARRAY_SIZE(tuner_alps_tsbc5_params), | ||
| 1456 | }, | ||
| 1457 | [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ | ||
| 1458 | .name = "Temic PAL_BG (4006FH5)", | ||
| 1459 | .params = tuner_temic_4006fh5_params, | ||
| 1460 | .count = ARRAY_SIZE(tuner_temic_4006fh5_params), | ||
| 1461 | }, | ||
| 1462 | [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ | ||
| 1463 | .name = "Alps TSCH6", | ||
| 1464 | .params = tuner_alps_tshc6_params, | ||
| 1465 | .count = ARRAY_SIZE(tuner_alps_tshc6_params), | ||
| 1466 | }, | ||
| 1467 | [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ | ||
| 1468 | .name = "Temic PAL_DK (4016 FY5)", | ||
| 1469 | .params = tuner_temic_pal_dk_params, | ||
| 1470 | .count = ARRAY_SIZE(tuner_temic_pal_dk_params), | ||
| 1471 | }, | ||
| 1472 | [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ | ||
| 1473 | .name = "Philips NTSC_M (MK2)", | ||
| 1474 | .params = tuner_philips_ntsc_m_params, | ||
| 1475 | .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), | ||
| 1476 | }, | ||
| 1477 | [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ | ||
| 1478 | .name = "Temic PAL_I (4066 FY5)", | ||
| 1479 | .params = tuner_temic_4066fy5_pal_i_params, | ||
| 1480 | .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), | ||
| 1481 | }, | ||
| 1482 | [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ | ||
| 1483 | .name = "Temic PAL* auto (4006 FN5)", | ||
| 1484 | .params = tuner_temic_4006fn5_multi_params, | ||
| 1485 | .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), | ||
| 1486 | }, | ||
| 1487 | |||
| 1488 | /* 20-29 */ | ||
| 1489 | [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ | ||
| 1490 | .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", | ||
| 1491 | .params = tuner_temic_4009f_5_params, | ||
| 1492 | .count = ARRAY_SIZE(tuner_temic_4009f_5_params), | ||
| 1493 | }, | ||
| 1494 | [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ | ||
| 1495 | .name = "Temic NTSC (4039 FR5)", | ||
| 1496 | .params = tuner_temic_4039fr5_params, | ||
| 1497 | .count = ARRAY_SIZE(tuner_temic_4039fr5_params), | ||
| 1498 | }, | ||
| 1499 | [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ | ||
| 1500 | .name = "Temic PAL/SECAM multi (4046 FM5)", | ||
| 1501 | .params = tuner_temic_4046fm5_params, | ||
| 1502 | .count = ARRAY_SIZE(tuner_temic_4046fm5_params), | ||
| 1503 | }, | ||
| 1504 | [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ | ||
| 1505 | .name = "Philips PAL_DK (FI1256 and compatibles)", | ||
| 1506 | .params = tuner_philips_pal_dk_params, | ||
| 1507 | .count = ARRAY_SIZE(tuner_philips_pal_dk_params), | ||
| 1508 | }, | ||
| 1509 | [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ | ||
| 1510 | .name = "Philips PAL/SECAM multi (FQ1216ME)", | ||
| 1511 | .params = tuner_philips_fq1216me_params, | ||
| 1512 | .count = ARRAY_SIZE(tuner_philips_fq1216me_params), | ||
| 1513 | }, | ||
| 1514 | [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ | ||
| 1515 | .name = "LG PAL_I+FM (TAPC-I001D)", | ||
| 1516 | .params = tuner_lg_pal_i_fm_params, | ||
| 1517 | .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), | ||
| 1518 | }, | ||
| 1519 | [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ | ||
| 1520 | .name = "LG PAL_I (TAPC-I701D)", | ||
| 1521 | .params = tuner_lg_pal_i_params, | ||
| 1522 | .count = ARRAY_SIZE(tuner_lg_pal_i_params), | ||
| 1523 | }, | ||
| 1524 | [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ | ||
| 1525 | .name = "LG NTSC+FM (TPI8NSR01F)", | ||
| 1526 | .params = tuner_lg_ntsc_fm_params, | ||
| 1527 | .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), | ||
| 1528 | }, | ||
| 1529 | [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ | ||
| 1530 | .name = "LG PAL_BG+FM (TPI8PSB01D)", | ||
| 1531 | .params = tuner_lg_pal_fm_params, | ||
| 1532 | .count = ARRAY_SIZE(tuner_lg_pal_fm_params), | ||
| 1533 | }, | ||
| 1534 | [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ | ||
| 1535 | .name = "LG PAL_BG (TPI8PSB11D)", | ||
| 1536 | .params = tuner_lg_pal_params, | ||
| 1537 | .count = ARRAY_SIZE(tuner_lg_pal_params), | ||
| 1538 | }, | ||
| 1539 | |||
| 1540 | /* 30-39 */ | ||
| 1541 | [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ | ||
| 1542 | .name = "Temic PAL* auto + FM (4009 FN5)", | ||
| 1543 | .params = tuner_temic_4009_fn5_multi_pal_fm_params, | ||
| 1544 | .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), | ||
| 1545 | }, | ||
| 1546 | [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ | ||
| 1547 | .name = "SHARP NTSC_JP (2U5JF5540)", | ||
| 1548 | .params = tuner_sharp_2u5jf5540_params, | ||
| 1549 | .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), | ||
| 1550 | }, | ||
| 1551 | [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ | ||
| 1552 | .name = "Samsung PAL TCPM9091PD27", | ||
| 1553 | .params = tuner_samsung_pal_tcpm9091pd27_params, | ||
| 1554 | .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), | ||
| 1555 | }, | ||
| 1556 | [TUNER_MT2032] = { /* Microtune PAL|NTSC */ | ||
| 1557 | .name = "MT20xx universal", | ||
| 1558 | /* see mt20xx.c for details */ }, | ||
| 1559 | [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ | ||
| 1560 | .name = "Temic PAL_BG (4106 FH5)", | ||
| 1561 | .params = tuner_temic_4106fh5_params, | ||
| 1562 | .count = ARRAY_SIZE(tuner_temic_4106fh5_params), | ||
| 1563 | }, | ||
| 1564 | [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ | ||
| 1565 | .name = "Temic PAL_DK/SECAM_L (4012 FY5)", | ||
| 1566 | .params = tuner_temic_4012fy5_params, | ||
| 1567 | .count = ARRAY_SIZE(tuner_temic_4012fy5_params), | ||
| 1568 | }, | ||
| 1569 | [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ | ||
| 1570 | .name = "Temic NTSC (4136 FY5)", | ||
| 1571 | .params = tuner_temic_4136_fy5_params, | ||
| 1572 | .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), | ||
| 1573 | }, | ||
| 1574 | [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ | ||
| 1575 | .name = "LG PAL (newer TAPC series)", | ||
| 1576 | .params = tuner_lg_pal_new_tapc_params, | ||
| 1577 | .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), | ||
| 1578 | }, | ||
| 1579 | [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ | ||
| 1580 | .name = "Philips PAL/SECAM multi (FM1216ME MK3)", | ||
| 1581 | .params = tuner_fm1216me_mk3_params, | ||
| 1582 | .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), | ||
| 1583 | }, | ||
| 1584 | [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ | ||
| 1585 | .name = "LG NTSC (newer TAPC series)", | ||
| 1586 | .params = tuner_lg_ntsc_new_tapc_params, | ||
| 1587 | .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), | ||
| 1588 | }, | ||
| 1589 | |||
| 1590 | /* 40-49 */ | ||
| 1591 | [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ | ||
| 1592 | .name = "HITACHI V7-J180AT", | ||
| 1593 | .params = tuner_hitachi_ntsc_params, | ||
| 1594 | .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), | ||
| 1595 | }, | ||
| 1596 | [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ | ||
| 1597 | .name = "Philips PAL_MK (FI1216 MK)", | ||
| 1598 | .params = tuner_philips_pal_mk_params, | ||
| 1599 | .count = ARRAY_SIZE(tuner_philips_pal_mk_params), | ||
| 1600 | }, | ||
| 1601 | [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */ | ||
| 1602 | .name = "Philips FCV1236D ATSC/NTSC dual in", | ||
| 1603 | .params = tuner_philips_fcv1236d_params, | ||
| 1604 | .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), | ||
| 1605 | .min = 16 * 53.00, | ||
| 1606 | .max = 16 * 803.00, | ||
| 1607 | .stepsize = 62500, | ||
| 1608 | }, | ||
| 1609 | [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ | ||
| 1610 | .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", | ||
| 1611 | .params = tuner_fm1236_mk3_params, | ||
| 1612 | .count = ARRAY_SIZE(tuner_fm1236_mk3_params), | ||
| 1613 | }, | ||
| 1614 | [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ | ||
| 1615 | .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", | ||
| 1616 | .params = tuner_philips_4in1_params, | ||
| 1617 | .count = ARRAY_SIZE(tuner_philips_4in1_params), | ||
| 1618 | }, | ||
| 1619 | [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ | ||
| 1620 | .name = "Microtune 4049 FM5", | ||
| 1621 | .params = tuner_microtune_4049_fm5_params, | ||
| 1622 | .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), | ||
| 1623 | }, | ||
| 1624 | [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ | ||
| 1625 | .name = "Panasonic VP27s/ENGE4324D", | ||
| 1626 | .params = tuner_panasonic_vp27_params, | ||
| 1627 | .count = ARRAY_SIZE(tuner_panasonic_vp27_params), | ||
| 1628 | }, | ||
| 1629 | [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ | ||
| 1630 | .name = "LG NTSC (TAPE series)", | ||
| 1631 | .params = tuner_fm1236_mk3_params, | ||
| 1632 | .count = ARRAY_SIZE(tuner_fm1236_mk3_params), | ||
| 1633 | }, | ||
| 1634 | [TUNER_TNF_8831BGFF] = { /* Philips PAL */ | ||
| 1635 | .name = "Tenna TNF 8831 BGFF)", | ||
| 1636 | .params = tuner_tnf_8831bgff_params, | ||
| 1637 | .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), | ||
| 1638 | }, | ||
| 1639 | [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ | ||
| 1640 | .name = "Microtune 4042 FI5 ATSC/NTSC dual in", | ||
| 1641 | .params = tuner_microtune_4042fi5_params, | ||
| 1642 | .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), | ||
| 1643 | .min = 16 * 57.00, | ||
| 1644 | .max = 16 * 858.00, | ||
| 1645 | .stepsize = 62500, | ||
| 1646 | }, | ||
| 1647 | |||
| 1648 | /* 50-59 */ | ||
| 1649 | [TUNER_TCL_2002N] = { /* TCL NTSC */ | ||
| 1650 | .name = "TCL 2002N", | ||
| 1651 | .params = tuner_tcl_2002n_params, | ||
| 1652 | .count = ARRAY_SIZE(tuner_tcl_2002n_params), | ||
| 1653 | }, | ||
| 1654 | [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ | ||
| 1655 | .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", | ||
| 1656 | .params = tuner_philips_fm1256_ih3_params, | ||
| 1657 | .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), | ||
| 1658 | }, | ||
| 1659 | [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ | ||
| 1660 | .name = "Thomson DTT 7610 (ATSC/NTSC)", | ||
| 1661 | .params = tuner_thomson_dtt7610_params, | ||
| 1662 | .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), | ||
| 1663 | .min = 16 * 44.00, | ||
| 1664 | .max = 16 * 958.00, | ||
| 1665 | .stepsize = 62500, | ||
| 1666 | }, | ||
| 1667 | [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ | ||
| 1668 | .name = "Philips FQ1286", | ||
| 1669 | .params = tuner_philips_fq1286_params, | ||
| 1670 | .count = ARRAY_SIZE(tuner_philips_fq1286_params), | ||
| 1671 | }, | ||
| 1672 | [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ | ||
| 1673 | .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", | ||
| 1674 | /* see tda8290.c for details */ }, | ||
| 1675 | [TUNER_TCL_2002MB] = { /* TCL PAL */ | ||
| 1676 | .name = "TCL 2002MB", | ||
| 1677 | .params = tuner_tcl_2002mb_params, | ||
| 1678 | .count = ARRAY_SIZE(tuner_tcl_2002mb_params), | ||
| 1679 | }, | ||
| 1680 | [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ | ||
| 1681 | .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", | ||
| 1682 | .params = tuner_philips_fq1216ame_mk4_params, | ||
| 1683 | .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), | ||
| 1684 | }, | ||
| 1685 | [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ | ||
| 1686 | .name = "Philips FQ1236A MK4", | ||
| 1687 | .params = tuner_philips_fq1236a_mk4_params, | ||
| 1688 | .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), | ||
| 1689 | }, | ||
| 1690 | [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ | ||
| 1691 | .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", | ||
| 1692 | .params = tuner_ymec_tvf_8531mf_params, | ||
| 1693 | .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), | ||
| 1694 | }, | ||
| 1695 | [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ | ||
| 1696 | .name = "Ymec TVision TVF-5533MF", | ||
| 1697 | .params = tuner_ymec_tvf_5533mf_params, | ||
| 1698 | .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), | ||
| 1699 | }, | ||
| 1700 | |||
| 1701 | /* 60-69 */ | ||
| 1702 | [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ | ||
| 1703 | /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ | ||
| 1704 | .name = "Thomson DTT 761X (ATSC/NTSC)", | ||
| 1705 | .params = tuner_thomson_dtt761x_params, | ||
| 1706 | .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), | ||
| 1707 | .min = 16 * 57.00, | ||
| 1708 | .max = 16 * 863.00, | ||
| 1709 | .stepsize = 62500, | ||
| 1710 | .initdata = tua603x_agc103, | ||
| 1711 | }, | ||
| 1712 | [TUNER_TENA_9533_DI] = { /* Philips PAL */ | ||
| 1713 | .name = "Tena TNF9533-D/IF/TNF9533-B/DF", | ||
| 1714 | .params = tuner_tena_9533_di_params, | ||
| 1715 | .count = ARRAY_SIZE(tuner_tena_9533_di_params), | ||
| 1716 | }, | ||
| 1717 | [TUNER_TEA5767] = { /* Philips RADIO */ | ||
| 1718 | .name = "Philips TEA5767HN FM Radio", | ||
| 1719 | /* see tea5767.c for details */ | ||
| 1720 | }, | ||
| 1721 | [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ | ||
| 1722 | .name = "Philips FMD1216ME MK3 Hybrid Tuner", | ||
| 1723 | .params = tuner_philips_fmd1216me_mk3_params, | ||
| 1724 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), | ||
| 1725 | .min = 16 * 50.87, | ||
| 1726 | .max = 16 * 858.00, | ||
| 1727 | .stepsize = 166667, | ||
| 1728 | .initdata = tua603x_agc112, | ||
| 1729 | .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, | ||
| 1730 | }, | ||
| 1731 | [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */ | ||
| 1732 | .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */ | ||
| 1733 | .params = tuner_lg_tdvs_h06xf_params, | ||
| 1734 | .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params), | ||
| 1735 | .min = 16 * 54.00, | ||
| 1736 | .max = 16 * 863.00, | ||
| 1737 | .stepsize = 62500, | ||
| 1738 | .initdata = tua603x_agc103, | ||
| 1739 | }, | ||
| 1740 | [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ | ||
| 1741 | .name = "Ymec TVF66T5-B/DFF", | ||
| 1742 | .params = tuner_ymec_tvf66t5_b_dff_params, | ||
| 1743 | .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), | ||
| 1744 | }, | ||
| 1745 | [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ | ||
| 1746 | .name = "LG TALN series", | ||
| 1747 | .params = tuner_lg_taln_params, | ||
| 1748 | .count = ARRAY_SIZE(tuner_lg_taln_params), | ||
| 1749 | }, | ||
| 1750 | [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ | ||
| 1751 | .name = "Philips TD1316 Hybrid Tuner", | ||
| 1752 | .params = tuner_philips_td1316_params, | ||
| 1753 | .count = ARRAY_SIZE(tuner_philips_td1316_params), | ||
| 1754 | .min = 16 * 87.00, | ||
| 1755 | .max = 16 * 895.00, | ||
| 1756 | .stepsize = 166667, | ||
| 1757 | }, | ||
| 1758 | [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ | ||
| 1759 | .name = "Philips TUV1236D ATSC/NTSC dual in", | ||
| 1760 | .params = tuner_tuv1236d_params, | ||
| 1761 | .count = ARRAY_SIZE(tuner_tuv1236d_params), | ||
| 1762 | .min = 16 * 54.00, | ||
| 1763 | .max = 16 * 864.00, | ||
| 1764 | .stepsize = 62500, | ||
| 1765 | }, | ||
| 1766 | [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ | ||
| 1767 | .name = "Tena TNF 5335 and similar models", | ||
| 1768 | .params = tuner_tnf_5335mf_params, | ||
| 1769 | .count = ARRAY_SIZE(tuner_tnf_5335mf_params), | ||
| 1770 | }, | ||
| 1771 | |||
| 1772 | /* 70-79 */ | ||
| 1773 | [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ | ||
| 1774 | .name = "Samsung TCPN 2121P30A", | ||
| 1775 | .params = tuner_samsung_tcpn_2121p30a_params, | ||
| 1776 | .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), | ||
| 1777 | }, | ||
| 1778 | [TUNER_XC2028] = { /* Xceive 2028 */ | ||
| 1779 | .name = "Xceive xc2028/xc3028 tuner", | ||
| 1780 | /* see tuner-xc2028.c for details */ | ||
| 1781 | }, | ||
| 1782 | [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ | ||
| 1783 | .name = "Thomson FE6600", | ||
| 1784 | .params = tuner_thomson_fe6600_params, | ||
| 1785 | .count = ARRAY_SIZE(tuner_thomson_fe6600_params), | ||
| 1786 | .min = 16 * 44.25, | ||
| 1787 | .max = 16 * 858.00, | ||
| 1788 | .stepsize = 166667, | ||
| 1789 | }, | ||
| 1790 | [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */ | ||
| 1791 | .name = "Samsung TCPG 6121P30A", | ||
| 1792 | .params = tuner_samsung_tcpg_6121p30a_params, | ||
| 1793 | .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), | ||
| 1794 | }, | ||
| 1795 | [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator. | ||
| 1796 | This chip is part of some modern tuners */ | ||
| 1797 | .name = "Philips TDA988[5,6,7] IF PLL Demodulator", | ||
| 1798 | /* see tda9887.c for details */ | ||
| 1799 | }, | ||
| 1800 | [TUNER_TEA5761] = { /* Philips RADIO */ | ||
| 1801 | .name = "Philips TEA5761 FM Radio", | ||
| 1802 | /* see tea5767.c for details */ | ||
| 1803 | }, | ||
| 1804 | [TUNER_XC5000] = { /* Xceive 5000 */ | ||
| 1805 | .name = "Xceive 5000 tuner", | ||
| 1806 | /* see xc5000.c for details */ | ||
| 1807 | }, | ||
| 1808 | [TUNER_XC4000] = { /* Xceive 4000 */ | ||
| 1809 | .name = "Xceive 4000 tuner", | ||
| 1810 | /* see xc4000.c for details */ | ||
| 1811 | }, | ||
| 1812 | [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ | ||
| 1813 | .name = "TCL tuner MF02GIP-5N-E", | ||
| 1814 | .params = tuner_tcl_mf02gip_5n_params, | ||
| 1815 | .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), | ||
| 1816 | }, | ||
| 1817 | [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ | ||
| 1818 | .name = "Philips FMD1216MEX MK3 Hybrid Tuner", | ||
| 1819 | .params = tuner_philips_fmd1216mex_mk3_params, | ||
| 1820 | .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), | ||
| 1821 | .min = 16 * 50.87, | ||
| 1822 | .max = 16 * 858.00, | ||
| 1823 | .stepsize = 166667, | ||
| 1824 | .initdata = tua603x_agc112, | ||
| 1825 | .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, | ||
| 1826 | }, | ||
| 1827 | [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ | ||
| 1828 | .name = "Philips PAL/SECAM multi (FM1216 MK5)", | ||
| 1829 | .params = tuner_fm1216mk5_params, | ||
| 1830 | .count = ARRAY_SIZE(tuner_fm1216mk5_params), | ||
| 1831 | }, | ||
| 1832 | |||
| 1833 | /* 80-89 */ | ||
| 1834 | [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ | ||
| 1835 | .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", | ||
| 1836 | .params = tuner_fq1216lme_mk3_params, | ||
| 1837 | .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), | ||
| 1838 | }, | ||
| 1839 | |||
| 1840 | [TUNER_PARTSNIC_PTI_5NF05] = { | ||
| 1841 | .name = "Partsnic (Daewoo) PTI-5NF05", | ||
| 1842 | .params = tuner_partsnic_pti_5nf05_params, | ||
| 1843 | .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), | ||
| 1844 | }, | ||
| 1845 | [TUNER_PHILIPS_CU1216L] = { | ||
| 1846 | .name = "Philips CU1216L", | ||
| 1847 | .params = tuner_philips_cu1216l_params, | ||
| 1848 | .count = ARRAY_SIZE(tuner_philips_cu1216l_params), | ||
| 1849 | .stepsize = 62500, | ||
| 1850 | }, | ||
| 1851 | [TUNER_NXP_TDA18271] = { | ||
| 1852 | .name = "NXP TDA18271", | ||
| 1853 | /* see tda18271-fe.c for details */ | ||
| 1854 | }, | ||
| 1855 | [TUNER_SONY_BTF_PXN01Z] = { | ||
| 1856 | .name = "Sony BTF-Pxn01Z", | ||
| 1857 | .params = tuner_sony_btf_pxn01z_params, | ||
| 1858 | .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), | ||
| 1859 | }, | ||
| 1860 | [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ | ||
| 1861 | .name = "Philips FQ1236 MK5", | ||
| 1862 | .params = tuner_philips_fq1236_mk5_params, | ||
| 1863 | .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), | ||
| 1864 | }, | ||
| 1865 | [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ | ||
| 1866 | .name = "Tena TNF5337 MFD", | ||
| 1867 | .params = tuner_tena_tnf_5337_params, | ||
| 1868 | .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), | ||
| 1869 | }, | ||
| 1870 | }; | ||
| 1871 | EXPORT_SYMBOL(tuners); | ||
| 1872 | |||
| 1873 | unsigned const int tuner_count = ARRAY_SIZE(tuners); | ||
| 1874 | EXPORT_SYMBOL(tuner_count); | ||
| 1875 | |||
| 1876 | MODULE_DESCRIPTION("Simple tuner device type database"); | ||
| 1877 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | ||
| 1878 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h new file mode 100644 index 00000000000..74dc46a71f6 --- /dev/null +++ b/drivers/media/common/tuners/tuner-xc2028-types.h | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* tuner-xc2028_types | ||
| 2 | * | ||
| 3 | * This file includes internal tipes to be used inside tuner-xc2028. | ||
| 4 | * Shouldn't be included outside tuner-xc2028 | ||
| 5 | * | ||
| 6 | * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
| 7 | * This code is placed under the terms of the GNU General Public License v2 | ||
| 8 | */ | ||
| 9 | |||
| 10 | /* xc3028 firmware types */ | ||
| 11 | |||
| 12 | /* BASE firmware should be loaded before any other firmware */ | ||
| 13 | #define BASE (1<<0) | ||
| 14 | #define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) | ||
| 15 | |||
| 16 | /* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ | ||
| 17 | #define F8MHZ (1<<1) | ||
| 18 | |||
| 19 | /* Multichannel Television Sound (MTS) | ||
| 20 | Those firmwares are capable of using xc2038 DSP to decode audio and | ||
| 21 | produce a baseband audio output on some pins of the chip. | ||
| 22 | There are MTS firmwares for the most used video standards. It should be | ||
| 23 | required to use MTS firmwares, depending on the way audio is routed into | ||
| 24 | the bridge chip | ||
| 25 | */ | ||
| 26 | #define MTS (1<<2) | ||
| 27 | |||
| 28 | /* FIXME: I have no idea what's the difference between | ||
| 29 | D2620 and D2633 firmwares | ||
| 30 | */ | ||
| 31 | #define D2620 (1<<3) | ||
| 32 | #define D2633 (1<<4) | ||
| 33 | |||
| 34 | /* DTV firmwares for 6, 7 and 8 MHz | ||
| 35 | DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS | ||
| 36 | DTV8 - 8MHz - DVB-C/DVB-T | ||
| 37 | */ | ||
| 38 | #define DTV6 (1 << 5) | ||
| 39 | #define QAM (1 << 6) | ||
| 40 | #define DTV7 (1<<7) | ||
| 41 | #define DTV78 (1<<8) | ||
| 42 | #define DTV8 (1<<9) | ||
| 43 | |||
| 44 | #define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) | ||
| 45 | |||
| 46 | /* There's a FM | BASE firmware + FM specific firmware (std=0) */ | ||
| 47 | #define FM (1<<10) | ||
| 48 | |||
| 49 | #define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) | ||
| 50 | |||
| 51 | /* Applies only for FM firmware | ||
| 52 | Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) | ||
| 53 | */ | ||
| 54 | #define INPUT1 (1<<11) | ||
| 55 | |||
| 56 | |||
| 57 | /* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) | ||
| 58 | and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) | ||
| 59 | There are variants both with and without NOGD | ||
| 60 | Those firmwares produce better result with LCD displays | ||
| 61 | */ | ||
| 62 | #define LCD (1<<12) | ||
| 63 | |||
| 64 | /* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) | ||
| 65 | and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) | ||
| 66 | The NOGD firmwares don't have group delay compensation filter | ||
| 67 | */ | ||
| 68 | #define NOGD (1<<13) | ||
| 69 | |||
| 70 | /* Old firmwares were broken into init0 and init1 */ | ||
| 71 | #define INIT1 (1<<14) | ||
| 72 | |||
| 73 | /* SCODE firmware selects particular behaviours */ | ||
| 74 | #define MONO (1 << 15) | ||
| 75 | #define ATSC (1 << 16) | ||
| 76 | #define IF (1 << 17) | ||
| 77 | #define LG60 (1 << 18) | ||
| 78 | #define ATI638 (1 << 19) | ||
| 79 | #define OREN538 (1 << 20) | ||
| 80 | #define OREN36 (1 << 21) | ||
| 81 | #define TOYOTA388 (1 << 22) | ||
| 82 | #define TOYOTA794 (1 << 23) | ||
| 83 | #define DIBCOM52 (1 << 24) | ||
| 84 | #define ZARLINK456 (1 << 25) | ||
| 85 | #define CHINA (1 << 26) | ||
| 86 | #define F6MHZ (1 << 27) | ||
| 87 | #define INPUT2 (1 << 28) | ||
| 88 | #define SCODE (1 << 29) | ||
| 89 | |||
| 90 | /* This flag identifies that the scode table has a new format */ | ||
| 91 | #define HAS_IF (1 << 30) | ||
| 92 | |||
| 93 | /* There are different scode tables for MTS and non-MTS. | ||
| 94 | The MTS firmwares support mono only | ||
| 95 | */ | ||
| 96 | #define SCODE_TYPES (SCODE | MTS) | ||
| 97 | |||
| 98 | |||
| 99 | /* Newer types not defined on videodev2.h. | ||
| 100 | The original idea were to move all those types to videodev2.h, but | ||
| 101 | it seemed overkill, since, with the exception of SECAM/K3, the other | ||
| 102 | types seem to be autodetected. | ||
| 103 | It is not clear where secam/k3 is used, nor we have a feedback of this | ||
| 104 | working or being autodetected by the standard secam firmware. | ||
| 105 | */ | ||
| 106 | |||
| 107 | #define V4L2_STD_SECAM_K3 (0x04000000) | ||
| 108 | |||
| 109 | /* Audio types */ | ||
| 110 | |||
| 111 | #define V4L2_STD_A2_A (1LL<<32) | ||
| 112 | #define V4L2_STD_A2_B (1LL<<33) | ||
| 113 | #define V4L2_STD_NICAM_A (1LL<<34) | ||
| 114 | #define V4L2_STD_NICAM_B (1LL<<35) | ||
| 115 | #define V4L2_STD_AM (1LL<<36) | ||
| 116 | #define V4L2_STD_BTSC (1LL<<37) | ||
| 117 | #define V4L2_STD_EIAJ (1LL<<38) | ||
| 118 | |||
| 119 | #define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) | ||
| 120 | #define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) | ||
| 121 | |||
| 122 | /* To preserve backward compatibilty, | ||
| 123 | (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported | ||
| 124 | */ | ||
| 125 | |||
| 126 | #define V4L2_STD_AUDIO (V4L2_STD_A2 | \ | ||
| 127 | V4L2_STD_NICAM | \ | ||
| 128 | V4L2_STD_AM | \ | ||
| 129 | V4L2_STD_BTSC | \ | ||
| 130 | V4L2_STD_EIAJ) | ||
| 131 | |||
| 132 | /* Used standards with audio restrictions */ | ||
| 133 | |||
| 134 | #define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) | ||
| 135 | #define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) | ||
| 136 | #define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) | ||
| 137 | #define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) | ||
| 138 | #define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) | ||
| 139 | #define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) | ||
| 140 | #define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) | ||
| 141 | #define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) | ||
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c new file mode 100644 index 00000000000..16fba6b5961 --- /dev/null +++ b/drivers/media/common/tuners/tuner-xc2028.c | |||
| @@ -0,0 +1,1356 @@ | |||
| 1 | /* tuner-xc2028 | ||
| 2 | * | ||
| 3 | * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
| 4 | * | ||
| 5 | * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) | ||
| 6 | * - frontend interface | ||
| 7 | * | ||
| 8 | * This code is placed under the terms of the GNU General Public License v2 | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/i2c.h> | ||
| 12 | #include <asm/div64.h> | ||
| 13 | #include <linux/firmware.h> | ||
| 14 | #include <linux/videodev2.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <media/tuner.h> | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <asm/unaligned.h> | ||
| 20 | #include "tuner-i2c.h" | ||
| 21 | #include "tuner-xc2028.h" | ||
| 22 | #include "tuner-xc2028-types.h" | ||
| 23 | |||
| 24 | #include <linux/dvb/frontend.h> | ||
| 25 | #include "dvb_frontend.h" | ||
| 26 | |||
| 27 | |||
| 28 | static int debug; | ||
| 29 | module_param(debug, int, 0644); | ||
| 30 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
| 31 | |||
| 32 | static int no_poweroff; | ||
| 33 | module_param(no_poweroff, int, 0644); | ||
| 34 | MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" | ||
| 35 | "1 keep device energized and with tuner ready all the times.\n" | ||
| 36 | " Faster, but consumes more power and keeps the device hotter\n"); | ||
| 37 | |||
| 38 | static char audio_std[8]; | ||
| 39 | module_param_string(audio_std, audio_std, sizeof(audio_std), 0); | ||
| 40 | MODULE_PARM_DESC(audio_std, | ||
| 41 | "Audio standard. XC3028 audio decoder explicitly " | ||
| 42 | "needs to know what audio\n" | ||
| 43 | "standard is needed for some video standards with audio A2 or NICAM.\n" | ||
| 44 | "The valid values are:\n" | ||
| 45 | "A2\n" | ||
| 46 | "A2/A\n" | ||
| 47 | "A2/B\n" | ||
| 48 | "NICAM\n" | ||
| 49 | "NICAM/A\n" | ||
| 50 | "NICAM/B\n"); | ||
| 51 | |||
| 52 | static char firmware_name[30]; | ||
| 53 | module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); | ||
| 54 | MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " | ||
| 55 | "default firmware name\n"); | ||
| 56 | |||
| 57 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 58 | static DEFINE_MUTEX(xc2028_list_mutex); | ||
| 59 | |||
| 60 | /* struct for storing firmware table */ | ||
| 61 | struct firmware_description { | ||
| 62 | unsigned int type; | ||
| 63 | v4l2_std_id id; | ||
| 64 | __u16 int_freq; | ||
| 65 | unsigned char *ptr; | ||
| 66 | unsigned int size; | ||
| 67 | }; | ||
| 68 | |||
| 69 | struct firmware_properties { | ||
| 70 | unsigned int type; | ||
| 71 | v4l2_std_id id; | ||
| 72 | v4l2_std_id std_req; | ||
| 73 | __u16 int_freq; | ||
| 74 | unsigned int scode_table; | ||
| 75 | int scode_nr; | ||
| 76 | }; | ||
| 77 | |||
| 78 | struct xc2028_data { | ||
| 79 | struct list_head hybrid_tuner_instance_list; | ||
| 80 | struct tuner_i2c_props i2c_props; | ||
| 81 | __u32 frequency; | ||
| 82 | |||
| 83 | struct firmware_description *firm; | ||
| 84 | int firm_size; | ||
| 85 | __u16 firm_version; | ||
| 86 | |||
| 87 | __u16 hwmodel; | ||
| 88 | __u16 hwvers; | ||
| 89 | |||
| 90 | struct xc2028_ctrl ctrl; | ||
| 91 | |||
| 92 | struct firmware_properties cur_fw; | ||
| 93 | |||
| 94 | struct mutex lock; | ||
| 95 | }; | ||
| 96 | |||
| 97 | #define i2c_send(priv, buf, size) ({ \ | ||
| 98 | int _rc; \ | ||
| 99 | _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ | ||
| 100 | if (size != _rc) \ | ||
| 101 | tuner_info("i2c output error: rc = %d (should be %d)\n",\ | ||
| 102 | _rc, (int)size); \ | ||
| 103 | if (priv->ctrl.msleep) \ | ||
| 104 | msleep(priv->ctrl.msleep); \ | ||
| 105 | _rc; \ | ||
| 106 | }) | ||
| 107 | |||
| 108 | #define i2c_rcv(priv, buf, size) ({ \ | ||
| 109 | int _rc; \ | ||
| 110 | _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ | ||
| 111 | if (size != _rc) \ | ||
| 112 | tuner_err("i2c input error: rc = %d (should be %d)\n", \ | ||
| 113 | _rc, (int)size); \ | ||
| 114 | _rc; \ | ||
| 115 | }) | ||
| 116 | |||
| 117 | #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ | ||
| 118 | int _rc; \ | ||
| 119 | _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ | ||
| 120 | ibuf, isize); \ | ||
| 121 | if (isize != _rc) \ | ||
| 122 | tuner_err("i2c input error: rc = %d (should be %d)\n", \ | ||
| 123 | _rc, (int)isize); \ | ||
| 124 | if (priv->ctrl.msleep) \ | ||
| 125 | msleep(priv->ctrl.msleep); \ | ||
| 126 | _rc; \ | ||
| 127 | }) | ||
| 128 | |||
| 129 | #define send_seq(priv, data...) ({ \ | ||
| 130 | static u8 _val[] = data; \ | ||
| 131 | int _rc; \ | ||
| 132 | if (sizeof(_val) != \ | ||
| 133 | (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ | ||
| 134 | _val, sizeof(_val)))) { \ | ||
| 135 | tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ | ||
| 136 | } else if (priv->ctrl.msleep) \ | ||
| 137 | msleep(priv->ctrl.msleep); \ | ||
| 138 | _rc; \ | ||
| 139 | }) | ||
| 140 | |||
| 141 | static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) | ||
| 142 | { | ||
| 143 | unsigned char buf[2]; | ||
| 144 | unsigned char ibuf[2]; | ||
| 145 | |||
| 146 | tuner_dbg("%s %04x called\n", __func__, reg); | ||
| 147 | |||
| 148 | buf[0] = reg >> 8; | ||
| 149 | buf[1] = (unsigned char) reg; | ||
| 150 | |||
| 151 | if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) | ||
| 152 | return -EIO; | ||
| 153 | |||
| 154 | *val = (ibuf[1]) | (ibuf[0] << 8); | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) | ||
| 159 | static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) | ||
| 160 | { | ||
| 161 | if (type & BASE) | ||
| 162 | printk("BASE "); | ||
| 163 | if (type & INIT1) | ||
| 164 | printk("INIT1 "); | ||
| 165 | if (type & F8MHZ) | ||
| 166 | printk("F8MHZ "); | ||
| 167 | if (type & MTS) | ||
| 168 | printk("MTS "); | ||
| 169 | if (type & D2620) | ||
| 170 | printk("D2620 "); | ||
| 171 | if (type & D2633) | ||
| 172 | printk("D2633 "); | ||
| 173 | if (type & DTV6) | ||
| 174 | printk("DTV6 "); | ||
| 175 | if (type & QAM) | ||
| 176 | printk("QAM "); | ||
| 177 | if (type & DTV7) | ||
| 178 | printk("DTV7 "); | ||
| 179 | if (type & DTV78) | ||
| 180 | printk("DTV78 "); | ||
| 181 | if (type & DTV8) | ||
| 182 | printk("DTV8 "); | ||
| 183 | if (type & FM) | ||
| 184 | printk("FM "); | ||
| 185 | if (type & INPUT1) | ||
| 186 | printk("INPUT1 "); | ||
| 187 | if (type & LCD) | ||
| 188 | printk("LCD "); | ||
| 189 | if (type & NOGD) | ||
| 190 | printk("NOGD "); | ||
| 191 | if (type & MONO) | ||
| 192 | printk("MONO "); | ||
| 193 | if (type & ATSC) | ||
| 194 | printk("ATSC "); | ||
| 195 | if (type & IF) | ||
| 196 | printk("IF "); | ||
| 197 | if (type & LG60) | ||
| 198 | printk("LG60 "); | ||
| 199 | if (type & ATI638) | ||
| 200 | printk("ATI638 "); | ||
| 201 | if (type & OREN538) | ||
| 202 | printk("OREN538 "); | ||
| 203 | if (type & OREN36) | ||
| 204 | printk("OREN36 "); | ||
| 205 | if (type & TOYOTA388) | ||
| 206 | printk("TOYOTA388 "); | ||
| 207 | if (type & TOYOTA794) | ||
| 208 | printk("TOYOTA794 "); | ||
| 209 | if (type & DIBCOM52) | ||
| 210 | printk("DIBCOM52 "); | ||
| 211 | if (type & ZARLINK456) | ||
| 212 | printk("ZARLINK456 "); | ||
| 213 | if (type & CHINA) | ||
| 214 | printk("CHINA "); | ||
| 215 | if (type & F6MHZ) | ||
| 216 | printk("F6MHZ "); | ||
| 217 | if (type & INPUT2) | ||
| 218 | printk("INPUT2 "); | ||
| 219 | if (type & SCODE) | ||
| 220 | printk("SCODE "); | ||
| 221 | if (type & HAS_IF) | ||
| 222 | printk("HAS_IF_%d ", int_freq); | ||
| 223 | } | ||
| 224 | |||
| 225 | static v4l2_std_id parse_audio_std_option(void) | ||
| 226 | { | ||
| 227 | if (strcasecmp(audio_std, "A2") == 0) | ||
| 228 | return V4L2_STD_A2; | ||
| 229 | if (strcasecmp(audio_std, "A2/A") == 0) | ||
| 230 | return V4L2_STD_A2_A; | ||
| 231 | if (strcasecmp(audio_std, "A2/B") == 0) | ||
| 232 | return V4L2_STD_A2_B; | ||
| 233 | if (strcasecmp(audio_std, "NICAM") == 0) | ||
| 234 | return V4L2_STD_NICAM; | ||
| 235 | if (strcasecmp(audio_std, "NICAM/A") == 0) | ||
| 236 | return V4L2_STD_NICAM_A; | ||
| 237 | if (strcasecmp(audio_std, "NICAM/B") == 0) | ||
| 238 | return V4L2_STD_NICAM_B; | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static void free_firmware(struct xc2028_data *priv) | ||
| 244 | { | ||
| 245 | int i; | ||
| 246 | tuner_dbg("%s called\n", __func__); | ||
| 247 | |||
| 248 | if (!priv->firm) | ||
| 249 | return; | ||
| 250 | |||
| 251 | for (i = 0; i < priv->firm_size; i++) | ||
| 252 | kfree(priv->firm[i].ptr); | ||
| 253 | |||
| 254 | kfree(priv->firm); | ||
| 255 | |||
| 256 | priv->firm = NULL; | ||
| 257 | priv->firm_size = 0; | ||
| 258 | |||
| 259 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
| 260 | } | ||
| 261 | |||
| 262 | static int load_all_firmwares(struct dvb_frontend *fe) | ||
| 263 | { | ||
| 264 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 265 | const struct firmware *fw = NULL; | ||
| 266 | const unsigned char *p, *endp; | ||
| 267 | int rc = 0; | ||
| 268 | int n, n_array; | ||
| 269 | char name[33]; | ||
| 270 | char *fname; | ||
| 271 | |||
| 272 | tuner_dbg("%s called\n", __func__); | ||
| 273 | |||
| 274 | if (!firmware_name[0]) | ||
| 275 | fname = priv->ctrl.fname; | ||
| 276 | else | ||
| 277 | fname = firmware_name; | ||
| 278 | |||
| 279 | tuner_dbg("Reading firmware %s\n", fname); | ||
| 280 | rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); | ||
| 281 | if (rc < 0) { | ||
| 282 | if (rc == -ENOENT) | ||
| 283 | tuner_err("Error: firmware %s not found.\n", | ||
| 284 | fname); | ||
| 285 | else | ||
| 286 | tuner_err("Error %d while requesting firmware %s \n", | ||
| 287 | rc, fname); | ||
| 288 | |||
| 289 | return rc; | ||
| 290 | } | ||
| 291 | p = fw->data; | ||
| 292 | endp = p + fw->size; | ||
| 293 | |||
| 294 | if (fw->size < sizeof(name) - 1 + 2 + 2) { | ||
| 295 | tuner_err("Error: firmware file %s has invalid size!\n", | ||
| 296 | fname); | ||
| 297 | goto corrupt; | ||
| 298 | } | ||
| 299 | |||
| 300 | memcpy(name, p, sizeof(name) - 1); | ||
| 301 | name[sizeof(name) - 1] = 0; | ||
| 302 | p += sizeof(name) - 1; | ||
| 303 | |||
| 304 | priv->firm_version = get_unaligned_le16(p); | ||
| 305 | p += 2; | ||
| 306 | |||
| 307 | n_array = get_unaligned_le16(p); | ||
| 308 | p += 2; | ||
| 309 | |||
| 310 | tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", | ||
| 311 | n_array, fname, name, | ||
| 312 | priv->firm_version >> 8, priv->firm_version & 0xff); | ||
| 313 | |||
| 314 | priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); | ||
| 315 | if (priv->firm == NULL) { | ||
| 316 | tuner_err("Not enough memory to load firmware file.\n"); | ||
| 317 | rc = -ENOMEM; | ||
| 318 | goto err; | ||
| 319 | } | ||
| 320 | priv->firm_size = n_array; | ||
| 321 | |||
| 322 | n = -1; | ||
| 323 | while (p < endp) { | ||
| 324 | __u32 type, size; | ||
| 325 | v4l2_std_id id; | ||
| 326 | __u16 int_freq = 0; | ||
| 327 | |||
| 328 | n++; | ||
| 329 | if (n >= n_array) { | ||
| 330 | tuner_err("More firmware images in file than " | ||
| 331 | "were expected!\n"); | ||
| 332 | goto corrupt; | ||
| 333 | } | ||
| 334 | |||
| 335 | /* Checks if there's enough bytes to read */ | ||
| 336 | if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) | ||
| 337 | goto header; | ||
| 338 | |||
| 339 | type = get_unaligned_le32(p); | ||
| 340 | p += sizeof(type); | ||
| 341 | |||
| 342 | id = get_unaligned_le64(p); | ||
| 343 | p += sizeof(id); | ||
| 344 | |||
| 345 | if (type & HAS_IF) { | ||
| 346 | int_freq = get_unaligned_le16(p); | ||
| 347 | p += sizeof(int_freq); | ||
| 348 | if (endp - p < sizeof(size)) | ||
| 349 | goto header; | ||
| 350 | } | ||
| 351 | |||
| 352 | size = get_unaligned_le32(p); | ||
| 353 | p += sizeof(size); | ||
| 354 | |||
| 355 | if (!size || size > endp - p) { | ||
| 356 | tuner_err("Firmware type "); | ||
| 357 | dump_firm_type(type); | ||
| 358 | printk("(%x), id %llx is corrupted " | ||
| 359 | "(size=%d, expected %d)\n", | ||
| 360 | type, (unsigned long long)id, | ||
| 361 | (unsigned)(endp - p), size); | ||
| 362 | goto corrupt; | ||
| 363 | } | ||
| 364 | |||
| 365 | priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); | ||
| 366 | if (priv->firm[n].ptr == NULL) { | ||
| 367 | tuner_err("Not enough memory to load firmware file.\n"); | ||
| 368 | rc = -ENOMEM; | ||
| 369 | goto err; | ||
| 370 | } | ||
| 371 | tuner_dbg("Reading firmware type "); | ||
| 372 | if (debug) { | ||
| 373 | dump_firm_type_and_int_freq(type, int_freq); | ||
| 374 | printk("(%x), id %llx, size=%d.\n", | ||
| 375 | type, (unsigned long long)id, size); | ||
| 376 | } | ||
| 377 | |||
| 378 | memcpy(priv->firm[n].ptr, p, size); | ||
| 379 | priv->firm[n].type = type; | ||
| 380 | priv->firm[n].id = id; | ||
| 381 | priv->firm[n].size = size; | ||
| 382 | priv->firm[n].int_freq = int_freq; | ||
| 383 | |||
| 384 | p += size; | ||
| 385 | } | ||
| 386 | |||
| 387 | if (n + 1 != priv->firm_size) { | ||
| 388 | tuner_err("Firmware file is incomplete!\n"); | ||
| 389 | goto corrupt; | ||
| 390 | } | ||
| 391 | |||
| 392 | goto done; | ||
| 393 | |||
| 394 | header: | ||
| 395 | tuner_err("Firmware header is incomplete!\n"); | ||
| 396 | corrupt: | ||
| 397 | rc = -EINVAL; | ||
| 398 | tuner_err("Error: firmware file is corrupted!\n"); | ||
| 399 | |||
| 400 | err: | ||
| 401 | tuner_info("Releasing partially loaded firmware file.\n"); | ||
| 402 | free_firmware(priv); | ||
| 403 | |||
| 404 | done: | ||
| 405 | release_firmware(fw); | ||
| 406 | if (rc == 0) | ||
| 407 | tuner_dbg("Firmware files loaded.\n"); | ||
| 408 | |||
| 409 | return rc; | ||
| 410 | } | ||
| 411 | |||
| 412 | static int seek_firmware(struct dvb_frontend *fe, unsigned int type, | ||
| 413 | v4l2_std_id *id) | ||
| 414 | { | ||
| 415 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 416 | int i, best_i = -1, best_nr_matches = 0; | ||
| 417 | unsigned int type_mask = 0; | ||
| 418 | |||
| 419 | tuner_dbg("%s called, want type=", __func__); | ||
| 420 | if (debug) { | ||
| 421 | dump_firm_type(type); | ||
| 422 | printk("(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
| 423 | } | ||
| 424 | |||
| 425 | if (!priv->firm) { | ||
| 426 | tuner_err("Error! firmware not loaded\n"); | ||
| 427 | return -EINVAL; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (((type & ~SCODE) == 0) && (*id == 0)) | ||
| 431 | *id = V4L2_STD_PAL; | ||
| 432 | |||
| 433 | if (type & BASE) | ||
| 434 | type_mask = BASE_TYPES; | ||
| 435 | else if (type & SCODE) { | ||
| 436 | type &= SCODE_TYPES; | ||
| 437 | type_mask = SCODE_TYPES & ~HAS_IF; | ||
| 438 | } else if (type & DTV_TYPES) | ||
| 439 | type_mask = DTV_TYPES; | ||
| 440 | else if (type & STD_SPECIFIC_TYPES) | ||
| 441 | type_mask = STD_SPECIFIC_TYPES; | ||
| 442 | |||
| 443 | type &= type_mask; | ||
| 444 | |||
| 445 | if (!(type & SCODE)) | ||
| 446 | type_mask = ~0; | ||
| 447 | |||
| 448 | /* Seek for exact match */ | ||
| 449 | for (i = 0; i < priv->firm_size; i++) { | ||
| 450 | if ((type == (priv->firm[i].type & type_mask)) && | ||
| 451 | (*id == priv->firm[i].id)) | ||
| 452 | goto found; | ||
| 453 | } | ||
| 454 | |||
| 455 | /* Seek for generic video standard match */ | ||
| 456 | for (i = 0; i < priv->firm_size; i++) { | ||
| 457 | v4l2_std_id match_mask; | ||
| 458 | int nr_matches; | ||
| 459 | |||
| 460 | if (type != (priv->firm[i].type & type_mask)) | ||
| 461 | continue; | ||
| 462 | |||
| 463 | match_mask = *id & priv->firm[i].id; | ||
| 464 | if (!match_mask) | ||
| 465 | continue; | ||
| 466 | |||
| 467 | if ((*id & match_mask) == *id) | ||
| 468 | goto found; /* Supports all the requested standards */ | ||
| 469 | |||
| 470 | nr_matches = hweight64(match_mask); | ||
| 471 | if (nr_matches > best_nr_matches) { | ||
| 472 | best_nr_matches = nr_matches; | ||
| 473 | best_i = i; | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | if (best_nr_matches > 0) { | ||
| 478 | tuner_dbg("Selecting best matching firmware (%d bits) for " | ||
| 479 | "type=", best_nr_matches); | ||
| 480 | dump_firm_type(type); | ||
| 481 | printk("(%x), id %016llx:\n", type, (unsigned long long)*id); | ||
| 482 | i = best_i; | ||
| 483 | goto found; | ||
| 484 | } | ||
| 485 | |||
| 486 | /*FIXME: Would make sense to seek for type "hint" match ? */ | ||
| 487 | |||
| 488 | i = -ENOENT; | ||
| 489 | goto ret; | ||
| 490 | |||
| 491 | found: | ||
| 492 | *id = priv->firm[i].id; | ||
| 493 | |||
| 494 | ret: | ||
| 495 | tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); | ||
| 496 | if (debug) { | ||
| 497 | dump_firm_type(type); | ||
| 498 | printk("(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
| 499 | } | ||
| 500 | return i; | ||
| 501 | } | ||
| 502 | |||
| 503 | static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) | ||
| 504 | { | ||
| 505 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 506 | |||
| 507 | /* analog side (tuner-core) uses i2c_adap->algo_data. | ||
| 508 | * digital side is not guaranteed to have algo_data defined. | ||
| 509 | * | ||
| 510 | * digital side will always have fe->dvb defined. | ||
| 511 | * analog side (tuner-core) doesn't (yet) define fe->dvb. | ||
| 512 | */ | ||
| 513 | |||
| 514 | return (!fe->callback) ? -EINVAL : | ||
| 515 | fe->callback(((fe->dvb) && (fe->dvb->priv)) ? | ||
| 516 | fe->dvb->priv : priv->i2c_props.adap->algo_data, | ||
| 517 | DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); | ||
| 518 | } | ||
| 519 | |||
| 520 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | ||
| 521 | v4l2_std_id *id) | ||
| 522 | { | ||
| 523 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 524 | int pos, rc; | ||
| 525 | unsigned char *p, *endp, buf[priv->ctrl.max_len]; | ||
| 526 | |||
| 527 | tuner_dbg("%s called\n", __func__); | ||
| 528 | |||
| 529 | pos = seek_firmware(fe, type, id); | ||
| 530 | if (pos < 0) | ||
| 531 | return pos; | ||
| 532 | |||
| 533 | tuner_info("Loading firmware for type="); | ||
| 534 | dump_firm_type(priv->firm[pos].type); | ||
| 535 | printk("(%x), id %016llx.\n", priv->firm[pos].type, | ||
| 536 | (unsigned long long)*id); | ||
| 537 | |||
| 538 | p = priv->firm[pos].ptr; | ||
| 539 | endp = p + priv->firm[pos].size; | ||
| 540 | |||
| 541 | while (p < endp) { | ||
| 542 | __u16 size; | ||
| 543 | |||
| 544 | /* Checks if there's enough bytes to read */ | ||
| 545 | if (p + sizeof(size) > endp) { | ||
| 546 | tuner_err("Firmware chunk size is wrong\n"); | ||
| 547 | return -EINVAL; | ||
| 548 | } | ||
| 549 | |||
| 550 | size = le16_to_cpu(*(__u16 *) p); | ||
| 551 | p += sizeof(size); | ||
| 552 | |||
| 553 | if (size == 0xffff) | ||
| 554 | return 0; | ||
| 555 | |||
| 556 | if (!size) { | ||
| 557 | /* Special callback command received */ | ||
| 558 | rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); | ||
| 559 | if (rc < 0) { | ||
| 560 | tuner_err("Error at RESET code %d\n", | ||
| 561 | (*p) & 0x7f); | ||
| 562 | return -EINVAL; | ||
| 563 | } | ||
| 564 | continue; | ||
| 565 | } | ||
| 566 | if (size >= 0xff00) { | ||
| 567 | switch (size) { | ||
| 568 | case 0xff00: | ||
| 569 | rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); | ||
| 570 | if (rc < 0) { | ||
| 571 | tuner_err("Error at RESET code %d\n", | ||
| 572 | (*p) & 0x7f); | ||
| 573 | return -EINVAL; | ||
| 574 | } | ||
| 575 | break; | ||
| 576 | default: | ||
| 577 | tuner_info("Invalid RESET code %d\n", | ||
| 578 | size & 0x7f); | ||
| 579 | return -EINVAL; | ||
| 580 | |||
| 581 | } | ||
| 582 | continue; | ||
| 583 | } | ||
| 584 | |||
| 585 | /* Checks for a sleep command */ | ||
| 586 | if (size & 0x8000) { | ||
| 587 | msleep(size & 0x7fff); | ||
| 588 | continue; | ||
| 589 | } | ||
| 590 | |||
| 591 | if ((size + p > endp)) { | ||
| 592 | tuner_err("missing bytes: need %d, have %d\n", | ||
| 593 | size, (int)(endp - p)); | ||
| 594 | return -EINVAL; | ||
| 595 | } | ||
| 596 | |||
| 597 | buf[0] = *p; | ||
| 598 | p++; | ||
| 599 | size--; | ||
| 600 | |||
| 601 | /* Sends message chunks */ | ||
| 602 | while (size > 0) { | ||
| 603 | int len = (size < priv->ctrl.max_len - 1) ? | ||
| 604 | size : priv->ctrl.max_len - 1; | ||
| 605 | |||
| 606 | memcpy(buf + 1, p, len); | ||
| 607 | |||
| 608 | rc = i2c_send(priv, buf, len + 1); | ||
| 609 | if (rc < 0) { | ||
| 610 | tuner_err("%d returned from send\n", rc); | ||
| 611 | return -EINVAL; | ||
| 612 | } | ||
| 613 | |||
| 614 | p += len; | ||
| 615 | size -= len; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | return 0; | ||
| 619 | } | ||
| 620 | |||
| 621 | static int load_scode(struct dvb_frontend *fe, unsigned int type, | ||
| 622 | v4l2_std_id *id, __u16 int_freq, int scode) | ||
| 623 | { | ||
| 624 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 625 | int pos, rc; | ||
| 626 | unsigned char *p; | ||
| 627 | |||
| 628 | tuner_dbg("%s called\n", __func__); | ||
| 629 | |||
| 630 | if (!int_freq) { | ||
| 631 | pos = seek_firmware(fe, type, id); | ||
| 632 | if (pos < 0) | ||
| 633 | return pos; | ||
| 634 | } else { | ||
| 635 | for (pos = 0; pos < priv->firm_size; pos++) { | ||
| 636 | if ((priv->firm[pos].int_freq == int_freq) && | ||
| 637 | (priv->firm[pos].type & HAS_IF)) | ||
| 638 | break; | ||
| 639 | } | ||
| 640 | if (pos == priv->firm_size) | ||
| 641 | return -ENOENT; | ||
| 642 | } | ||
| 643 | |||
| 644 | p = priv->firm[pos].ptr; | ||
| 645 | |||
| 646 | if (priv->firm[pos].type & HAS_IF) { | ||
| 647 | if (priv->firm[pos].size != 12 * 16 || scode >= 16) | ||
| 648 | return -EINVAL; | ||
| 649 | p += 12 * scode; | ||
| 650 | } else { | ||
| 651 | /* 16 SCODE entries per file; each SCODE entry is 12 bytes and | ||
| 652 | * has a 2-byte size header in the firmware format. */ | ||
| 653 | if (priv->firm[pos].size != 14 * 16 || scode >= 16 || | ||
| 654 | le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) | ||
| 655 | return -EINVAL; | ||
| 656 | p += 14 * scode + 2; | ||
| 657 | } | ||
| 658 | |||
| 659 | tuner_info("Loading SCODE for type="); | ||
| 660 | dump_firm_type_and_int_freq(priv->firm[pos].type, | ||
| 661 | priv->firm[pos].int_freq); | ||
| 662 | printk("(%x), id %016llx.\n", priv->firm[pos].type, | ||
| 663 | (unsigned long long)*id); | ||
| 664 | |||
| 665 | if (priv->firm_version < 0x0202) | ||
| 666 | rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); | ||
| 667 | else | ||
| 668 | rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); | ||
| 669 | if (rc < 0) | ||
| 670 | return -EIO; | ||
| 671 | |||
| 672 | rc = i2c_send(priv, p, 12); | ||
| 673 | if (rc < 0) | ||
| 674 | return -EIO; | ||
| 675 | |||
| 676 | rc = send_seq(priv, {0x00, 0x8c}); | ||
| 677 | if (rc < 0) | ||
| 678 | return -EIO; | ||
| 679 | |||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | |||
| 683 | static int check_firmware(struct dvb_frontend *fe, unsigned int type, | ||
| 684 | v4l2_std_id std, __u16 int_freq) | ||
| 685 | { | ||
| 686 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 687 | struct firmware_properties new_fw; | ||
| 688 | int rc = 0, retry_count = 0; | ||
| 689 | u16 version, hwmodel; | ||
| 690 | v4l2_std_id std0; | ||
| 691 | |||
| 692 | tuner_dbg("%s called\n", __func__); | ||
| 693 | |||
| 694 | if (!priv->firm) { | ||
| 695 | if (!priv->ctrl.fname) { | ||
| 696 | tuner_info("xc2028/3028 firmware name not set!\n"); | ||
| 697 | return -EINVAL; | ||
| 698 | } | ||
| 699 | |||
| 700 | rc = load_all_firmwares(fe); | ||
| 701 | if (rc < 0) | ||
| 702 | return rc; | ||
| 703 | } | ||
| 704 | |||
| 705 | if (priv->ctrl.mts && !(type & FM)) | ||
| 706 | type |= MTS; | ||
| 707 | |||
| 708 | retry: | ||
| 709 | new_fw.type = type; | ||
| 710 | new_fw.id = std; | ||
| 711 | new_fw.std_req = std; | ||
| 712 | new_fw.scode_table = SCODE | priv->ctrl.scode_table; | ||
| 713 | new_fw.scode_nr = 0; | ||
| 714 | new_fw.int_freq = int_freq; | ||
| 715 | |||
| 716 | tuner_dbg("checking firmware, user requested type="); | ||
| 717 | if (debug) { | ||
| 718 | dump_firm_type(new_fw.type); | ||
| 719 | printk("(%x), id %016llx, ", new_fw.type, | ||
| 720 | (unsigned long long)new_fw.std_req); | ||
| 721 | if (!int_freq) { | ||
| 722 | printk("scode_tbl "); | ||
| 723 | dump_firm_type(priv->ctrl.scode_table); | ||
| 724 | printk("(%x), ", priv->ctrl.scode_table); | ||
| 725 | } else | ||
| 726 | printk("int_freq %d, ", new_fw.int_freq); | ||
| 727 | printk("scode_nr %d\n", new_fw.scode_nr); | ||
| 728 | } | ||
| 729 | |||
| 730 | /* No need to reload base firmware if it matches */ | ||
| 731 | if (((BASE | new_fw.type) & BASE_TYPES) == | ||
| 732 | (priv->cur_fw.type & BASE_TYPES)) { | ||
| 733 | tuner_dbg("BASE firmware not changed.\n"); | ||
| 734 | goto skip_base; | ||
| 735 | } | ||
| 736 | |||
| 737 | /* Updating BASE - forget about all currently loaded firmware */ | ||
| 738 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
| 739 | |||
| 740 | /* Reset is needed before loading firmware */ | ||
| 741 | rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); | ||
| 742 | if (rc < 0) | ||
| 743 | goto fail; | ||
| 744 | |||
| 745 | /* BASE firmwares are all std0 */ | ||
| 746 | std0 = 0; | ||
| 747 | rc = load_firmware(fe, BASE | new_fw.type, &std0); | ||
| 748 | if (rc < 0) { | ||
| 749 | tuner_err("Error %d while loading base firmware\n", | ||
| 750 | rc); | ||
| 751 | goto fail; | ||
| 752 | } | ||
| 753 | |||
| 754 | /* Load INIT1, if needed */ | ||
| 755 | tuner_dbg("Load init1 firmware, if exists\n"); | ||
| 756 | |||
| 757 | rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); | ||
| 758 | if (rc == -ENOENT) | ||
| 759 | rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, | ||
| 760 | &std0); | ||
| 761 | if (rc < 0 && rc != -ENOENT) { | ||
| 762 | tuner_err("Error %d while loading init1 firmware\n", | ||
| 763 | rc); | ||
| 764 | goto fail; | ||
| 765 | } | ||
| 766 | |||
| 767 | skip_base: | ||
| 768 | /* | ||
| 769 | * No need to reload standard specific firmware if base firmware | ||
| 770 | * was not reloaded and requested video standards have not changed. | ||
| 771 | */ | ||
| 772 | if (priv->cur_fw.type == (BASE | new_fw.type) && | ||
| 773 | priv->cur_fw.std_req == std) { | ||
| 774 | tuner_dbg("Std-specific firmware already loaded.\n"); | ||
| 775 | goto skip_std_specific; | ||
| 776 | } | ||
| 777 | |||
| 778 | /* Reloading std-specific firmware forces a SCODE update */ | ||
| 779 | priv->cur_fw.scode_table = 0; | ||
| 780 | |||
| 781 | rc = load_firmware(fe, new_fw.type, &new_fw.id); | ||
| 782 | if (rc == -ENOENT) | ||
| 783 | rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); | ||
| 784 | |||
| 785 | if (rc < 0) | ||
| 786 | goto fail; | ||
| 787 | |||
| 788 | skip_std_specific: | ||
| 789 | if (priv->cur_fw.scode_table == new_fw.scode_table && | ||
| 790 | priv->cur_fw.scode_nr == new_fw.scode_nr) { | ||
| 791 | tuner_dbg("SCODE firmware already loaded.\n"); | ||
| 792 | goto check_device; | ||
| 793 | } | ||
| 794 | |||
| 795 | if (new_fw.type & FM) | ||
| 796 | goto check_device; | ||
| 797 | |||
| 798 | /* Load SCODE firmware, if exists */ | ||
| 799 | tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); | ||
| 800 | |||
| 801 | rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, | ||
| 802 | new_fw.int_freq, new_fw.scode_nr); | ||
| 803 | |||
| 804 | check_device: | ||
| 805 | if (xc2028_get_reg(priv, 0x0004, &version) < 0 || | ||
| 806 | xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { | ||
| 807 | tuner_err("Unable to read tuner registers.\n"); | ||
| 808 | goto fail; | ||
| 809 | } | ||
| 810 | |||
| 811 | tuner_dbg("Device is Xceive %d version %d.%d, " | ||
| 812 | "firmware version %d.%d\n", | ||
| 813 | hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, | ||
| 814 | (version & 0xf0) >> 4, version & 0xf); | ||
| 815 | |||
| 816 | |||
| 817 | if (priv->ctrl.read_not_reliable) | ||
| 818 | goto read_not_reliable; | ||
| 819 | |||
| 820 | /* Check firmware version against what we downloaded. */ | ||
| 821 | if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { | ||
| 822 | if (!priv->ctrl.read_not_reliable) { | ||
| 823 | tuner_err("Incorrect readback of firmware version.\n"); | ||
| 824 | goto fail; | ||
| 825 | } else { | ||
| 826 | tuner_err("Returned an incorrect version. However, " | ||
| 827 | "read is not reliable enough. Ignoring it.\n"); | ||
| 828 | hwmodel = 3028; | ||
| 829 | } | ||
| 830 | } | ||
| 831 | |||
| 832 | /* Check that the tuner hardware model remains consistent over time. */ | ||
| 833 | if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { | ||
| 834 | priv->hwmodel = hwmodel; | ||
| 835 | priv->hwvers = version & 0xff00; | ||
| 836 | } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || | ||
| 837 | priv->hwvers != (version & 0xff00)) { | ||
| 838 | tuner_err("Read invalid device hardware information - tuner " | ||
| 839 | "hung?\n"); | ||
| 840 | goto fail; | ||
| 841 | } | ||
| 842 | |||
| 843 | read_not_reliable: | ||
| 844 | memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); | ||
| 845 | |||
| 846 | /* | ||
| 847 | * By setting BASE in cur_fw.type only after successfully loading all | ||
| 848 | * firmwares, we can: | ||
| 849 | * 1. Identify that BASE firmware with type=0 has been loaded; | ||
| 850 | * 2. Tell whether BASE firmware was just changed the next time through. | ||
| 851 | */ | ||
| 852 | priv->cur_fw.type |= BASE; | ||
| 853 | |||
| 854 | return 0; | ||
| 855 | |||
| 856 | fail: | ||
| 857 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
| 858 | if (retry_count < 8) { | ||
| 859 | msleep(50); | ||
| 860 | retry_count++; | ||
| 861 | tuner_dbg("Retrying firmware load\n"); | ||
| 862 | goto retry; | ||
| 863 | } | ||
| 864 | |||
| 865 | if (rc == -ENOENT) | ||
| 866 | rc = -EINVAL; | ||
| 867 | return rc; | ||
| 868 | } | ||
| 869 | |||
| 870 | static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) | ||
| 871 | { | ||
| 872 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 873 | u16 frq_lock, signal = 0; | ||
| 874 | int rc; | ||
| 875 | |||
| 876 | tuner_dbg("%s called\n", __func__); | ||
| 877 | |||
| 878 | mutex_lock(&priv->lock); | ||
| 879 | |||
| 880 | /* Sync Lock Indicator */ | ||
| 881 | rc = xc2028_get_reg(priv, 0x0002, &frq_lock); | ||
| 882 | if (rc < 0) | ||
| 883 | goto ret; | ||
| 884 | |||
| 885 | /* Frequency is locked */ | ||
| 886 | if (frq_lock == 1) | ||
| 887 | signal = 32768; | ||
| 888 | |||
| 889 | /* Get SNR of the video signal */ | ||
| 890 | rc = xc2028_get_reg(priv, 0x0040, &signal); | ||
| 891 | if (rc < 0) | ||
| 892 | goto ret; | ||
| 893 | |||
| 894 | /* Use both frq_lock and signal to generate the result */ | ||
| 895 | signal = signal || ((signal & 0x07) << 12); | ||
| 896 | |||
| 897 | ret: | ||
| 898 | mutex_unlock(&priv->lock); | ||
| 899 | |||
| 900 | *strength = signal; | ||
| 901 | |||
| 902 | tuner_dbg("signal strength is %d\n", signal); | ||
| 903 | |||
| 904 | return rc; | ||
| 905 | } | ||
| 906 | |||
| 907 | #define DIV 15625 | ||
| 908 | |||
| 909 | static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, | ||
| 910 | enum v4l2_tuner_type new_type, | ||
| 911 | unsigned int type, | ||
| 912 | v4l2_std_id std, | ||
| 913 | u16 int_freq) | ||
| 914 | { | ||
| 915 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 916 | int rc = -EINVAL; | ||
| 917 | unsigned char buf[4]; | ||
| 918 | u32 div, offset = 0; | ||
| 919 | |||
| 920 | tuner_dbg("%s called\n", __func__); | ||
| 921 | |||
| 922 | mutex_lock(&priv->lock); | ||
| 923 | |||
| 924 | tuner_dbg("should set frequency %d kHz\n", freq / 1000); | ||
| 925 | |||
| 926 | if (check_firmware(fe, type, std, int_freq) < 0) | ||
| 927 | goto ret; | ||
| 928 | |||
| 929 | /* On some cases xc2028 can disable video output, if | ||
| 930 | * very weak signals are received. By sending a soft | ||
| 931 | * reset, this is re-enabled. So, it is better to always | ||
| 932 | * send a soft reset before changing channels, to be sure | ||
| 933 | * that xc2028 will be in a safe state. | ||
| 934 | * Maybe this might also be needed for DTV. | ||
| 935 | */ | ||
| 936 | if (new_type == V4L2_TUNER_ANALOG_TV) { | ||
| 937 | rc = send_seq(priv, {0x00, 0x00}); | ||
| 938 | |||
| 939 | /* Analog modes require offset = 0 */ | ||
| 940 | } else { | ||
| 941 | /* | ||
| 942 | * Digital modes require an offset to adjust to the | ||
| 943 | * proper frequency. The offset depends on what | ||
| 944 | * firmware version is used. | ||
| 945 | */ | ||
| 946 | |||
| 947 | /* | ||
| 948 | * Adjust to the center frequency. This is calculated by the | ||
| 949 | * formula: offset = 1.25MHz - BW/2 | ||
| 950 | * For DTV 7/8, the firmware uses BW = 8000, so it needs a | ||
| 951 | * further adjustment to get the frequency center on VHF | ||
| 952 | */ | ||
| 953 | if (priv->cur_fw.type & DTV6) | ||
| 954 | offset = 1750000; | ||
| 955 | else if (priv->cur_fw.type & DTV7) | ||
| 956 | offset = 2250000; | ||
| 957 | else /* DTV8 or DTV78 */ | ||
| 958 | offset = 2750000; | ||
| 959 | if ((priv->cur_fw.type & DTV78) && freq < 470000000) | ||
| 960 | offset -= 500000; | ||
| 961 | |||
| 962 | /* | ||
| 963 | * xc3028 additional "magic" | ||
| 964 | * Depending on the firmware version, it needs some adjustments | ||
| 965 | * to properly centralize the frequency. This seems to be | ||
| 966 | * needed to compensate the SCODE table adjustments made by | ||
| 967 | * newer firmwares | ||
| 968 | */ | ||
| 969 | |||
| 970 | #if 1 | ||
| 971 | /* | ||
| 972 | * The proper adjustment would be to do it at s-code table. | ||
| 973 | * However, this didn't work, as reported by | ||
| 974 | * Robert Lowery <rglowery@exemail.com.au> | ||
| 975 | */ | ||
| 976 | |||
| 977 | if (priv->cur_fw.type & DTV7) | ||
| 978 | offset += 500000; | ||
| 979 | |||
| 980 | #else | ||
| 981 | /* | ||
| 982 | * Still need tests for XC3028L (firmware 3.2 or upper) | ||
| 983 | * So, for now, let's just comment the per-firmware | ||
| 984 | * version of this change. Reports with xc3028l working | ||
| 985 | * with and without the lines bellow are welcome | ||
| 986 | */ | ||
| 987 | |||
| 988 | if (priv->firm_version < 0x0302) { | ||
| 989 | if (priv->cur_fw.type & DTV7) | ||
| 990 | offset += 500000; | ||
| 991 | } else { | ||
| 992 | if (priv->cur_fw.type & DTV7) | ||
| 993 | offset -= 300000; | ||
| 994 | else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ | ||
| 995 | offset += 200000; | ||
| 996 | } | ||
| 997 | #endif | ||
| 998 | } | ||
| 999 | |||
| 1000 | div = (freq - offset + DIV / 2) / DIV; | ||
| 1001 | |||
| 1002 | /* CMD= Set frequency */ | ||
| 1003 | if (priv->firm_version < 0x0202) | ||
| 1004 | rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); | ||
| 1005 | else | ||
| 1006 | rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); | ||
| 1007 | if (rc < 0) | ||
| 1008 | goto ret; | ||
| 1009 | |||
| 1010 | /* Return code shouldn't be checked. | ||
| 1011 | The reset CLK is needed only with tm6000. | ||
| 1012 | Driver should work fine even if this fails. | ||
| 1013 | */ | ||
| 1014 | if (priv->ctrl.msleep) | ||
| 1015 | msleep(priv->ctrl.msleep); | ||
| 1016 | do_tuner_callback(fe, XC2028_RESET_CLK, 1); | ||
| 1017 | |||
| 1018 | msleep(10); | ||
| 1019 | |||
| 1020 | buf[0] = 0xff & (div >> 24); | ||
| 1021 | buf[1] = 0xff & (div >> 16); | ||
| 1022 | buf[2] = 0xff & (div >> 8); | ||
| 1023 | buf[3] = 0xff & (div); | ||
| 1024 | |||
| 1025 | rc = i2c_send(priv, buf, sizeof(buf)); | ||
| 1026 | if (rc < 0) | ||
| 1027 | goto ret; | ||
| 1028 | msleep(100); | ||
| 1029 | |||
| 1030 | priv->frequency = freq; | ||
| 1031 | |||
| 1032 | tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n", | ||
| 1033 | buf[0], buf[1], buf[2], buf[3], | ||
| 1034 | freq / 1000000, (freq % 1000000) / 1000); | ||
| 1035 | |||
| 1036 | rc = 0; | ||
| 1037 | |||
| 1038 | ret: | ||
| 1039 | mutex_unlock(&priv->lock); | ||
| 1040 | |||
| 1041 | return rc; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | static int xc2028_set_analog_freq(struct dvb_frontend *fe, | ||
| 1045 | struct analog_parameters *p) | ||
| 1046 | { | ||
| 1047 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 1048 | unsigned int type=0; | ||
| 1049 | |||
| 1050 | tuner_dbg("%s called\n", __func__); | ||
| 1051 | |||
| 1052 | if (p->mode == V4L2_TUNER_RADIO) { | ||
| 1053 | type |= FM; | ||
| 1054 | if (priv->ctrl.input1) | ||
| 1055 | type |= INPUT1; | ||
| 1056 | return generic_set_freq(fe, (625l * p->frequency) / 10, | ||
| 1057 | V4L2_TUNER_RADIO, type, 0, 0); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | /* if std is not defined, choose one */ | ||
| 1061 | if (!p->std) | ||
| 1062 | p->std = V4L2_STD_MN; | ||
| 1063 | |||
| 1064 | /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ | ||
| 1065 | if (!(p->std & V4L2_STD_MN)) | ||
| 1066 | type |= F8MHZ; | ||
| 1067 | |||
| 1068 | /* Add audio hack to std mask */ | ||
| 1069 | p->std |= parse_audio_std_option(); | ||
| 1070 | |||
| 1071 | return generic_set_freq(fe, 62500l * p->frequency, | ||
| 1072 | V4L2_TUNER_ANALOG_TV, type, p->std, 0); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static int xc2028_set_params(struct dvb_frontend *fe, | ||
| 1076 | struct dvb_frontend_parameters *p) | ||
| 1077 | { | ||
| 1078 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 1079 | unsigned int type=0; | ||
| 1080 | fe_bandwidth_t bw = BANDWIDTH_8_MHZ; | ||
| 1081 | u16 demod = 0; | ||
| 1082 | |||
| 1083 | tuner_dbg("%s called\n", __func__); | ||
| 1084 | |||
| 1085 | switch(fe->ops.info.type) { | ||
| 1086 | case FE_OFDM: | ||
| 1087 | bw = p->u.ofdm.bandwidth; | ||
| 1088 | /* | ||
| 1089 | * The only countries with 6MHz seem to be Taiwan/Uruguay. | ||
| 1090 | * Both seem to require QAM firmware for OFDM decoding | ||
| 1091 | * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com> | ||
| 1092 | */ | ||
| 1093 | if (bw == BANDWIDTH_6_MHZ) | ||
| 1094 | type |= QAM; | ||
| 1095 | break; | ||
| 1096 | case FE_ATSC: | ||
| 1097 | bw = BANDWIDTH_6_MHZ; | ||
| 1098 | /* The only ATSC firmware (at least on v2.7) is D2633 */ | ||
| 1099 | type |= ATSC | D2633; | ||
| 1100 | break; | ||
| 1101 | /* DVB-S and pure QAM (FE_QAM) are not supported */ | ||
| 1102 | default: | ||
| 1103 | return -EINVAL; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | switch (bw) { | ||
| 1107 | case BANDWIDTH_8_MHZ: | ||
| 1108 | if (p->frequency < 470000000) | ||
| 1109 | priv->ctrl.vhfbw7 = 0; | ||
| 1110 | else | ||
| 1111 | priv->ctrl.uhfbw8 = 1; | ||
| 1112 | type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; | ||
| 1113 | type |= F8MHZ; | ||
| 1114 | break; | ||
| 1115 | case BANDWIDTH_7_MHZ: | ||
| 1116 | if (p->frequency < 470000000) | ||
| 1117 | priv->ctrl.vhfbw7 = 1; | ||
| 1118 | else | ||
| 1119 | priv->ctrl.uhfbw8 = 0; | ||
| 1120 | type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; | ||
| 1121 | type |= F8MHZ; | ||
| 1122 | break; | ||
| 1123 | case BANDWIDTH_6_MHZ: | ||
| 1124 | type |= DTV6; | ||
| 1125 | priv->ctrl.vhfbw7 = 0; | ||
| 1126 | priv->ctrl.uhfbw8 = 0; | ||
| 1127 | break; | ||
| 1128 | default: | ||
| 1129 | tuner_err("error: bandwidth not supported.\n"); | ||
| 1130 | }; | ||
| 1131 | |||
| 1132 | /* | ||
| 1133 | Selects between D2633 or D2620 firmware. | ||
| 1134 | It doesn't make sense for ATSC, since it should be D2633 on all cases | ||
| 1135 | */ | ||
| 1136 | if (fe->ops.info.type != FE_ATSC) { | ||
| 1137 | switch (priv->ctrl.type) { | ||
| 1138 | case XC2028_D2633: | ||
| 1139 | type |= D2633; | ||
| 1140 | break; | ||
| 1141 | case XC2028_D2620: | ||
| 1142 | type |= D2620; | ||
| 1143 | break; | ||
| 1144 | case XC2028_AUTO: | ||
| 1145 | default: | ||
| 1146 | /* Zarlink seems to need D2633 */ | ||
| 1147 | if (priv->ctrl.demod == XC3028_FE_ZARLINK456) | ||
| 1148 | type |= D2633; | ||
| 1149 | else | ||
| 1150 | type |= D2620; | ||
| 1151 | } | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | /* All S-code tables need a 200kHz shift */ | ||
| 1155 | if (priv->ctrl.demod) { | ||
| 1156 | demod = priv->ctrl.demod; | ||
| 1157 | |||
| 1158 | /* | ||
| 1159 | * Newer firmwares require a 200 kHz offset only for ATSC | ||
| 1160 | */ | ||
| 1161 | if (type == ATSC || priv->firm_version < 0x0302) | ||
| 1162 | demod += 200; | ||
| 1163 | /* | ||
| 1164 | * The DTV7 S-code table needs a 700 kHz shift. | ||
| 1165 | * | ||
| 1166 | * DTV7 is only used in Australia. Germany or Italy may also | ||
| 1167 | * use this firmware after initialization, but a tune to a UHF | ||
| 1168 | * channel should then cause DTV78 to be used. | ||
| 1169 | * | ||
| 1170 | * Unfortunately, on real-field tests, the s-code offset | ||
| 1171 | * didn't work as expected, as reported by | ||
| 1172 | * Robert Lowery <rglowery@exemail.com.au> | ||
| 1173 | */ | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | return generic_set_freq(fe, p->frequency, | ||
| 1177 | V4L2_TUNER_DIGITAL_TV, type, 0, demod); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static int xc2028_sleep(struct dvb_frontend *fe) | ||
| 1181 | { | ||
| 1182 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 1183 | int rc = 0; | ||
| 1184 | |||
| 1185 | /* Avoid firmware reload on slow devices or if PM disabled */ | ||
| 1186 | if (no_poweroff || priv->ctrl.disable_power_mgmt) | ||
| 1187 | return 0; | ||
| 1188 | |||
| 1189 | tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); | ||
| 1190 | if (debug > 1) { | ||
| 1191 | tuner_dbg("Printing sleep stack trace:\n"); | ||
| 1192 | dump_stack(); | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | mutex_lock(&priv->lock); | ||
| 1196 | |||
| 1197 | if (priv->firm_version < 0x0202) | ||
| 1198 | rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); | ||
| 1199 | else | ||
| 1200 | rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); | ||
| 1201 | |||
| 1202 | priv->cur_fw.type = 0; /* need firmware reload */ | ||
| 1203 | |||
| 1204 | mutex_unlock(&priv->lock); | ||
| 1205 | |||
| 1206 | return rc; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | static int xc2028_dvb_release(struct dvb_frontend *fe) | ||
| 1210 | { | ||
| 1211 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 1212 | |||
| 1213 | tuner_dbg("%s called\n", __func__); | ||
| 1214 | |||
| 1215 | mutex_lock(&xc2028_list_mutex); | ||
| 1216 | |||
| 1217 | /* only perform final cleanup if this is the last instance */ | ||
| 1218 | if (hybrid_tuner_report_instance_count(priv) == 1) { | ||
| 1219 | kfree(priv->ctrl.fname); | ||
| 1220 | free_firmware(priv); | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | if (priv) | ||
| 1224 | hybrid_tuner_release_state(priv); | ||
| 1225 | |||
| 1226 | mutex_unlock(&xc2028_list_mutex); | ||
| 1227 | |||
| 1228 | fe->tuner_priv = NULL; | ||
| 1229 | |||
| 1230 | return 0; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| 1234 | { | ||
| 1235 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 1236 | |||
| 1237 | tuner_dbg("%s called\n", __func__); | ||
| 1238 | |||
| 1239 | *frequency = priv->frequency; | ||
| 1240 | |||
| 1241 | return 0; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
| 1245 | { | ||
| 1246 | struct xc2028_data *priv = fe->tuner_priv; | ||
| 1247 | struct xc2028_ctrl *p = priv_cfg; | ||
| 1248 | int rc = 0; | ||
| 1249 | |||
| 1250 | tuner_dbg("%s called\n", __func__); | ||
| 1251 | |||
| 1252 | mutex_lock(&priv->lock); | ||
| 1253 | |||
| 1254 | memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); | ||
| 1255 | if (priv->ctrl.max_len < 9) | ||
| 1256 | priv->ctrl.max_len = 13; | ||
| 1257 | |||
| 1258 | if (p->fname) { | ||
| 1259 | if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { | ||
| 1260 | kfree(priv->ctrl.fname); | ||
| 1261 | free_firmware(priv); | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); | ||
| 1265 | if (priv->ctrl.fname == NULL) | ||
| 1266 | rc = -ENOMEM; | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | mutex_unlock(&priv->lock); | ||
| 1270 | |||
| 1271 | return rc; | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { | ||
| 1275 | .info = { | ||
| 1276 | .name = "Xceive XC3028", | ||
| 1277 | .frequency_min = 42000000, | ||
| 1278 | .frequency_max = 864000000, | ||
| 1279 | .frequency_step = 50000, | ||
| 1280 | }, | ||
| 1281 | |||
| 1282 | .set_config = xc2028_set_config, | ||
| 1283 | .set_analog_params = xc2028_set_analog_freq, | ||
| 1284 | .release = xc2028_dvb_release, | ||
| 1285 | .get_frequency = xc2028_get_frequency, | ||
| 1286 | .get_rf_strength = xc2028_signal, | ||
| 1287 | .set_params = xc2028_set_params, | ||
| 1288 | .sleep = xc2028_sleep, | ||
| 1289 | }; | ||
| 1290 | |||
| 1291 | struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, | ||
| 1292 | struct xc2028_config *cfg) | ||
| 1293 | { | ||
| 1294 | struct xc2028_data *priv; | ||
| 1295 | int instance; | ||
| 1296 | |||
| 1297 | if (debug) | ||
| 1298 | printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); | ||
| 1299 | |||
| 1300 | if (NULL == cfg) | ||
| 1301 | return NULL; | ||
| 1302 | |||
| 1303 | if (!fe) { | ||
| 1304 | printk(KERN_ERR "xc2028: No frontend!\n"); | ||
| 1305 | return NULL; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | mutex_lock(&xc2028_list_mutex); | ||
| 1309 | |||
| 1310 | instance = hybrid_tuner_request_state(struct xc2028_data, priv, | ||
| 1311 | hybrid_tuner_instance_list, | ||
| 1312 | cfg->i2c_adap, cfg->i2c_addr, | ||
| 1313 | "xc2028"); | ||
| 1314 | switch (instance) { | ||
| 1315 | case 0: | ||
| 1316 | /* memory allocation failure */ | ||
| 1317 | goto fail; | ||
| 1318 | break; | ||
| 1319 | case 1: | ||
| 1320 | /* new tuner instance */ | ||
| 1321 | priv->ctrl.max_len = 13; | ||
| 1322 | |||
| 1323 | mutex_init(&priv->lock); | ||
| 1324 | |||
| 1325 | fe->tuner_priv = priv; | ||
| 1326 | break; | ||
| 1327 | case 2: | ||
| 1328 | /* existing tuner instance */ | ||
| 1329 | fe->tuner_priv = priv; | ||
| 1330 | break; | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, | ||
| 1334 | sizeof(xc2028_dvb_tuner_ops)); | ||
| 1335 | |||
| 1336 | tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); | ||
| 1337 | |||
| 1338 | if (cfg->ctrl) | ||
| 1339 | xc2028_set_config(fe, cfg->ctrl); | ||
| 1340 | |||
| 1341 | mutex_unlock(&xc2028_list_mutex); | ||
| 1342 | |||
| 1343 | return fe; | ||
| 1344 | fail: | ||
| 1345 | mutex_unlock(&xc2028_list_mutex); | ||
| 1346 | |||
| 1347 | xc2028_dvb_release(fe); | ||
| 1348 | return NULL; | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | EXPORT_SYMBOL(xc2028_attach); | ||
| 1352 | |||
| 1353 | MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); | ||
| 1354 | MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>"); | ||
| 1355 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
| 1356 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h new file mode 100644 index 00000000000..9778c96a500 --- /dev/null +++ b/drivers/media/common/tuners/tuner-xc2028.h | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* tuner-xc2028 | ||
| 2 | * | ||
| 3 | * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
| 4 | * This code is placed under the terms of the GNU General Public License v2 | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef __TUNER_XC2028_H__ | ||
| 8 | #define __TUNER_XC2028_H__ | ||
| 9 | |||
| 10 | #include "dvb_frontend.h" | ||
| 11 | |||
| 12 | #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" | ||
| 13 | #define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw" | ||
| 14 | |||
| 15 | /* Dmoduler IF (kHz) */ | ||
| 16 | #define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ | ||
| 17 | #define XC3028_FE_LG60 6000 | ||
| 18 | #define XC3028_FE_ATI638 6380 | ||
| 19 | #define XC3028_FE_OREN538 5380 | ||
| 20 | #define XC3028_FE_OREN36 3600 | ||
| 21 | #define XC3028_FE_TOYOTA388 3880 | ||
| 22 | #define XC3028_FE_TOYOTA794 7940 | ||
| 23 | #define XC3028_FE_DIBCOM52 5200 | ||
| 24 | #define XC3028_FE_ZARLINK456 4560 | ||
| 25 | #define XC3028_FE_CHINA 5200 | ||
| 26 | |||
| 27 | enum firmware_type { | ||
| 28 | XC2028_AUTO = 0, /* By default, auto-detects */ | ||
| 29 | XC2028_D2633, | ||
| 30 | XC2028_D2620, | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct xc2028_ctrl { | ||
| 34 | char *fname; | ||
| 35 | int max_len; | ||
| 36 | int msleep; | ||
| 37 | unsigned int scode_table; | ||
| 38 | unsigned int mts :1; | ||
| 39 | unsigned int input1:1; | ||
| 40 | unsigned int vhfbw7:1; | ||
| 41 | unsigned int uhfbw8:1; | ||
| 42 | unsigned int disable_power_mgmt:1; | ||
| 43 | unsigned int read_not_reliable:1; | ||
| 44 | unsigned int demod; | ||
| 45 | enum firmware_type type:2; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct xc2028_config { | ||
| 49 | struct i2c_adapter *i2c_adap; | ||
| 50 | u8 i2c_addr; | ||
| 51 | struct xc2028_ctrl *ctrl; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* xc2028 commands for callback */ | ||
| 55 | #define XC2028_TUNER_RESET 0 | ||
| 56 | #define XC2028_RESET_CLK 1 | ||
| 57 | |||
| 58 | #if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) | ||
| 59 | extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, | ||
| 60 | struct xc2028_config *cfg); | ||
| 61 | #else | ||
| 62 | static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, | ||
| 63 | struct xc2028_config *cfg) | ||
| 64 | { | ||
| 65 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
| 66 | __func__); | ||
| 67 | return NULL; | ||
| 68 | } | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #endif /* __TUNER_XC2028_H__ */ | ||
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c new file mode 100644 index 00000000000..634f4d9b6c6 --- /dev/null +++ b/drivers/media/common/tuners/xc4000.c | |||
| @@ -0,0 +1,1691 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Xceive Corporation | ||
| 5 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
| 6 | * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 7 | * Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it> | ||
| 8 | * Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/moduleparam.h> | ||
| 27 | #include <linux/videodev2.h> | ||
| 28 | #include <linux/delay.h> | ||
| 29 | #include <linux/dvb/frontend.h> | ||
| 30 | #include <linux/i2c.h> | ||
| 31 | #include <linux/mutex.h> | ||
| 32 | #include <asm/unaligned.h> | ||
| 33 | |||
| 34 | #include "dvb_frontend.h" | ||
| 35 | |||
| 36 | #include "xc4000.h" | ||
| 37 | #include "tuner-i2c.h" | ||
| 38 | #include "tuner-xc2028-types.h" | ||
| 39 | |||
| 40 | static int debug; | ||
| 41 | module_param(debug, int, 0644); | ||
| 42 | MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); | ||
| 43 | |||
| 44 | static int no_poweroff; | ||
| 45 | module_param(no_poweroff, int, 0644); | ||
| 46 | MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " | ||
| 47 | "0 (default): use device-specific default mode)."); | ||
| 48 | |||
| 49 | static int audio_std; | ||
| 50 | module_param(audio_std, int, 0644); | ||
| 51 | MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " | ||
| 52 | "needs to know what audio standard is needed for some video standards " | ||
| 53 | "with audio A2 or NICAM. The valid settings are a sum of:\n" | ||
| 54 | " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" | ||
| 55 | " 2: use A2 instead of NICAM or BTSC\n" | ||
| 56 | " 4: use SECAM/K3 instead of K1\n" | ||
| 57 | " 8: use PAL-D/K audio for SECAM-D/K\n" | ||
| 58 | "16: use FM radio input 1 instead of input 2\n" | ||
| 59 | "32: use mono audio (the lower three bits are ignored)"); | ||
| 60 | |||
| 61 | static char firmware_name[30]; | ||
| 62 | module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); | ||
| 63 | MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " | ||
| 64 | "default firmware name."); | ||
| 65 | |||
| 66 | static DEFINE_MUTEX(xc4000_list_mutex); | ||
| 67 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 68 | |||
| 69 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | ||
| 70 | printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) | ||
| 71 | |||
| 72 | /* struct for storing firmware table */ | ||
| 73 | struct firmware_description { | ||
| 74 | unsigned int type; | ||
| 75 | v4l2_std_id id; | ||
| 76 | __u16 int_freq; | ||
| 77 | unsigned char *ptr; | ||
| 78 | unsigned int size; | ||
| 79 | }; | ||
| 80 | |||
| 81 | struct firmware_properties { | ||
| 82 | unsigned int type; | ||
| 83 | v4l2_std_id id; | ||
| 84 | v4l2_std_id std_req; | ||
| 85 | __u16 int_freq; | ||
| 86 | unsigned int scode_table; | ||
| 87 | int scode_nr; | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct xc4000_priv { | ||
| 91 | struct tuner_i2c_props i2c_props; | ||
| 92 | struct list_head hybrid_tuner_instance_list; | ||
| 93 | struct firmware_description *firm; | ||
| 94 | int firm_size; | ||
| 95 | u32 if_khz; | ||
| 96 | u32 freq_hz; | ||
| 97 | u32 bandwidth; | ||
| 98 | u8 video_standard; | ||
| 99 | u8 rf_mode; | ||
| 100 | u8 default_pm; | ||
| 101 | u8 dvb_amplitude; | ||
| 102 | u8 set_smoothedcvbs; | ||
| 103 | u8 ignore_i2c_write_errors; | ||
| 104 | __u16 firm_version; | ||
| 105 | struct firmware_properties cur_fw; | ||
| 106 | __u16 hwmodel; | ||
| 107 | __u16 hwvers; | ||
| 108 | struct mutex lock; | ||
| 109 | }; | ||
| 110 | |||
| 111 | #define XC4000_AUDIO_STD_B 1 | ||
| 112 | #define XC4000_AUDIO_STD_A2 2 | ||
| 113 | #define XC4000_AUDIO_STD_K3 4 | ||
| 114 | #define XC4000_AUDIO_STD_L 8 | ||
| 115 | #define XC4000_AUDIO_STD_INPUT1 16 | ||
| 116 | #define XC4000_AUDIO_STD_MONO 32 | ||
| 117 | |||
| 118 | #define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" | ||
| 119 | |||
| 120 | /* Misc Defines */ | ||
| 121 | #define MAX_TV_STANDARD 24 | ||
| 122 | #define XC_MAX_I2C_WRITE_LENGTH 64 | ||
| 123 | #define XC_POWERED_DOWN 0x80000000U | ||
| 124 | |||
| 125 | /* Signal Types */ | ||
| 126 | #define XC_RF_MODE_AIR 0 | ||
| 127 | #define XC_RF_MODE_CABLE 1 | ||
| 128 | |||
| 129 | /* Product id */ | ||
| 130 | #define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 | ||
| 131 | #define XC_PRODUCT_ID_XC4000 0x0FA0 | ||
| 132 | #define XC_PRODUCT_ID_XC4100 0x1004 | ||
| 133 | |||
| 134 | /* Registers (Write-only) */ | ||
| 135 | #define XREG_INIT 0x00 | ||
| 136 | #define XREG_VIDEO_MODE 0x01 | ||
| 137 | #define XREG_AUDIO_MODE 0x02 | ||
| 138 | #define XREG_RF_FREQ 0x03 | ||
| 139 | #define XREG_D_CODE 0x04 | ||
| 140 | #define XREG_DIRECTSITTING_MODE 0x05 | ||
| 141 | #define XREG_SEEK_MODE 0x06 | ||
| 142 | #define XREG_POWER_DOWN 0x08 | ||
| 143 | #define XREG_SIGNALSOURCE 0x0A | ||
| 144 | #define XREG_SMOOTHEDCVBS 0x0E | ||
| 145 | #define XREG_AMPLITUDE 0x10 | ||
| 146 | |||
| 147 | /* Registers (Read-only) */ | ||
| 148 | #define XREG_ADC_ENV 0x00 | ||
| 149 | #define XREG_QUALITY 0x01 | ||
| 150 | #define XREG_FRAME_LINES 0x02 | ||
| 151 | #define XREG_HSYNC_FREQ 0x03 | ||
| 152 | #define XREG_LOCK 0x04 | ||
| 153 | #define XREG_FREQ_ERROR 0x05 | ||
| 154 | #define XREG_SNR 0x06 | ||
| 155 | #define XREG_VERSION 0x07 | ||
| 156 | #define XREG_PRODUCT_ID 0x08 | ||
| 157 | |||
| 158 | /* | ||
| 159 | Basic firmware description. This will remain with | ||
| 160 | the driver for documentation purposes. | ||
| 161 | |||
| 162 | This represents an I2C firmware file encoded as a | ||
| 163 | string of unsigned char. Format is as follows: | ||
| 164 | |||
| 165 | char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB | ||
| 166 | char[1 ]=len0_LSB -> length of first write transaction | ||
| 167 | char[2 ]=data0 -> first byte to be sent | ||
| 168 | char[3 ]=data1 | ||
| 169 | char[4 ]=data2 | ||
| 170 | char[ ]=... | ||
| 171 | char[M ]=dataN -> last byte to be sent | ||
| 172 | char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB | ||
| 173 | char[M+2]=len1_LSB -> length of second write transaction | ||
| 174 | char[M+3]=data0 | ||
| 175 | char[M+4]=data1 | ||
| 176 | ... | ||
| 177 | etc. | ||
| 178 | |||
| 179 | The [len] value should be interpreted as follows: | ||
| 180 | |||
| 181 | len= len_MSB _ len_LSB | ||
| 182 | len=1111_1111_1111_1111 : End of I2C_SEQUENCE | ||
| 183 | len=0000_0000_0000_0000 : Reset command: Do hardware reset | ||
| 184 | len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) | ||
| 185 | len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms | ||
| 186 | |||
| 187 | For the RESET and WAIT commands, the two following bytes will contain | ||
| 188 | immediately the length of the following transaction. | ||
| 189 | */ | ||
| 190 | |||
| 191 | struct XC_TV_STANDARD { | ||
| 192 | const char *Name; | ||
| 193 | u16 audio_mode; | ||
| 194 | u16 video_mode; | ||
| 195 | u16 int_freq; | ||
| 196 | }; | ||
| 197 | |||
| 198 | /* Tuner standards */ | ||
| 199 | #define XC4000_MN_NTSC_PAL_BTSC 0 | ||
| 200 | #define XC4000_MN_NTSC_PAL_A2 1 | ||
| 201 | #define XC4000_MN_NTSC_PAL_EIAJ 2 | ||
| 202 | #define XC4000_MN_NTSC_PAL_Mono 3 | ||
| 203 | #define XC4000_BG_PAL_A2 4 | ||
| 204 | #define XC4000_BG_PAL_NICAM 5 | ||
| 205 | #define XC4000_BG_PAL_MONO 6 | ||
| 206 | #define XC4000_I_PAL_NICAM 7 | ||
| 207 | #define XC4000_I_PAL_NICAM_MONO 8 | ||
| 208 | #define XC4000_DK_PAL_A2 9 | ||
| 209 | #define XC4000_DK_PAL_NICAM 10 | ||
| 210 | #define XC4000_DK_PAL_MONO 11 | ||
| 211 | #define XC4000_DK_SECAM_A2DK1 12 | ||
| 212 | #define XC4000_DK_SECAM_A2LDK3 13 | ||
| 213 | #define XC4000_DK_SECAM_A2MONO 14 | ||
| 214 | #define XC4000_DK_SECAM_NICAM 15 | ||
| 215 | #define XC4000_L_SECAM_NICAM 16 | ||
| 216 | #define XC4000_LC_SECAM_NICAM 17 | ||
| 217 | #define XC4000_DTV6 18 | ||
| 218 | #define XC4000_DTV8 19 | ||
| 219 | #define XC4000_DTV7_8 20 | ||
| 220 | #define XC4000_DTV7 21 | ||
| 221 | #define XC4000_FM_Radio_INPUT2 22 | ||
| 222 | #define XC4000_FM_Radio_INPUT1 23 | ||
| 223 | |||
| 224 | static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { | ||
| 225 | {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, | ||
| 226 | {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, | ||
| 227 | {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, | ||
| 228 | {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, | ||
| 229 | {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, | ||
| 230 | {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, | ||
| 231 | {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, | ||
| 232 | {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, | ||
| 233 | {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, | ||
| 234 | {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, | ||
| 235 | {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, | ||
| 236 | {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, | ||
| 237 | {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, | ||
| 238 | {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, | ||
| 239 | {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, | ||
| 240 | {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, | ||
| 241 | {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, | ||
| 242 | {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, | ||
| 243 | {"DTV6", 0x00C0, 0x8002, 0}, | ||
| 244 | {"DTV8", 0x00C0, 0x800B, 0}, | ||
| 245 | {"DTV7/8", 0x00C0, 0x801B, 0}, | ||
| 246 | {"DTV7", 0x00C0, 0x8007, 0}, | ||
| 247 | {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, | ||
| 248 | {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} | ||
| 249 | }; | ||
| 250 | |||
| 251 | static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); | ||
| 252 | static int xc4000_tuner_reset(struct dvb_frontend *fe); | ||
| 253 | static void xc_debug_dump(struct xc4000_priv *priv); | ||
| 254 | |||
| 255 | static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) | ||
| 256 | { | ||
| 257 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, | ||
| 258 | .flags = 0, .buf = buf, .len = len }; | ||
| 259 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { | ||
| 260 | if (priv->ignore_i2c_write_errors == 0) { | ||
| 261 | printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", | ||
| 262 | len); | ||
| 263 | if (len == 4) { | ||
| 264 | printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0], | ||
| 265 | buf[1], buf[2], buf[3]); | ||
| 266 | } | ||
| 267 | return -EREMOTEIO; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int xc4000_tuner_reset(struct dvb_frontend *fe) | ||
| 274 | { | ||
| 275 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 276 | int ret; | ||
| 277 | |||
| 278 | dprintk(1, "%s()\n", __func__); | ||
| 279 | |||
| 280 | if (fe->callback) { | ||
| 281 | ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? | ||
| 282 | fe->dvb->priv : | ||
| 283 | priv->i2c_props.adap->algo_data, | ||
| 284 | DVB_FRONTEND_COMPONENT_TUNER, | ||
| 285 | XC4000_TUNER_RESET, 0); | ||
| 286 | if (ret) { | ||
| 287 | printk(KERN_ERR "xc4000: reset failed\n"); | ||
| 288 | return -EREMOTEIO; | ||
| 289 | } | ||
| 290 | } else { | ||
| 291 | printk(KERN_ERR "xc4000: no tuner reset callback function, " | ||
| 292 | "fatal\n"); | ||
| 293 | return -EINVAL; | ||
| 294 | } | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) | ||
| 299 | { | ||
| 300 | u8 buf[4]; | ||
| 301 | int result; | ||
| 302 | |||
| 303 | buf[0] = (regAddr >> 8) & 0xFF; | ||
| 304 | buf[1] = regAddr & 0xFF; | ||
| 305 | buf[2] = (i2cData >> 8) & 0xFF; | ||
| 306 | buf[3] = i2cData & 0xFF; | ||
| 307 | result = xc_send_i2c_data(priv, buf, 4); | ||
| 308 | |||
| 309 | return result; | ||
| 310 | } | ||
| 311 | |||
| 312 | static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) | ||
| 313 | { | ||
| 314 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 315 | |||
| 316 | int i, nbytes_to_send, result; | ||
| 317 | unsigned int len, pos, index; | ||
| 318 | u8 buf[XC_MAX_I2C_WRITE_LENGTH]; | ||
| 319 | |||
| 320 | index = 0; | ||
| 321 | while ((i2c_sequence[index] != 0xFF) || | ||
| 322 | (i2c_sequence[index + 1] != 0xFF)) { | ||
| 323 | len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; | ||
| 324 | if (len == 0x0000) { | ||
| 325 | /* RESET command */ | ||
| 326 | /* NOTE: this is ignored, as the reset callback was */ | ||
| 327 | /* already called by check_firmware() */ | ||
| 328 | index += 2; | ||
| 329 | } else if (len & 0x8000) { | ||
| 330 | /* WAIT command */ | ||
| 331 | msleep(len & 0x7FFF); | ||
| 332 | index += 2; | ||
| 333 | } else { | ||
| 334 | /* Send i2c data whilst ensuring individual transactions | ||
| 335 | * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. | ||
| 336 | */ | ||
| 337 | index += 2; | ||
| 338 | buf[0] = i2c_sequence[index]; | ||
| 339 | buf[1] = i2c_sequence[index + 1]; | ||
| 340 | pos = 2; | ||
| 341 | while (pos < len) { | ||
| 342 | if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) | ||
| 343 | nbytes_to_send = | ||
| 344 | XC_MAX_I2C_WRITE_LENGTH; | ||
| 345 | else | ||
| 346 | nbytes_to_send = (len - pos + 2); | ||
| 347 | for (i = 2; i < nbytes_to_send; i++) { | ||
| 348 | buf[i] = i2c_sequence[index + pos + | ||
| 349 | i - 2]; | ||
| 350 | } | ||
| 351 | result = xc_send_i2c_data(priv, buf, | ||
| 352 | nbytes_to_send); | ||
| 353 | |||
| 354 | if (result != 0) | ||
| 355 | return result; | ||
| 356 | |||
| 357 | pos += nbytes_to_send - 2; | ||
| 358 | } | ||
| 359 | index += len; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 365 | static int xc_set_tv_standard(struct xc4000_priv *priv, | ||
| 366 | u16 video_mode, u16 audio_mode) | ||
| 367 | { | ||
| 368 | int ret; | ||
| 369 | dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); | ||
| 370 | dprintk(1, "%s() Standard = %s\n", | ||
| 371 | __func__, | ||
| 372 | xc4000_standard[priv->video_standard].Name); | ||
| 373 | |||
| 374 | /* Don't complain when the request fails because of i2c stretching */ | ||
| 375 | priv->ignore_i2c_write_errors = 1; | ||
| 376 | |||
| 377 | ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); | ||
| 378 | if (ret == 0) | ||
| 379 | ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); | ||
| 380 | |||
| 381 | priv->ignore_i2c_write_errors = 0; | ||
| 382 | |||
| 383 | return ret; | ||
| 384 | } | ||
| 385 | |||
| 386 | static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) | ||
| 387 | { | ||
| 388 | dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, | ||
| 389 | rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); | ||
| 390 | |||
| 391 | if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { | ||
| 392 | rf_mode = XC_RF_MODE_CABLE; | ||
| 393 | printk(KERN_ERR | ||
| 394 | "%s(), Invalid mode, defaulting to CABLE", | ||
| 395 | __func__); | ||
| 396 | } | ||
| 397 | return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); | ||
| 398 | } | ||
| 399 | |||
| 400 | static const struct dvb_tuner_ops xc4000_tuner_ops; | ||
| 401 | |||
| 402 | static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) | ||
| 403 | { | ||
| 404 | u16 freq_code; | ||
| 405 | |||
| 406 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
| 407 | |||
| 408 | if ((freq_hz > xc4000_tuner_ops.info.frequency_max) || | ||
| 409 | (freq_hz < xc4000_tuner_ops.info.frequency_min)) | ||
| 410 | return -EINVAL; | ||
| 411 | |||
| 412 | freq_code = (u16)(freq_hz / 15625); | ||
| 413 | |||
| 414 | /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the | ||
| 415 | FINERFREQ for all normal tuning (the doc indicates reg 0x03 should | ||
| 416 | only be used for fast scanning for channel lock) */ | ||
| 417 | /* WAS: XREG_FINERFREQ */ | ||
| 418 | return xc_write_reg(priv, XREG_RF_FREQ, freq_code); | ||
| 419 | } | ||
| 420 | |||
| 421 | static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) | ||
| 422 | { | ||
| 423 | return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); | ||
| 424 | } | ||
| 425 | |||
| 426 | static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) | ||
| 427 | { | ||
| 428 | int result; | ||
| 429 | u16 regData; | ||
| 430 | u32 tmp; | ||
| 431 | |||
| 432 | result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); | ||
| 433 | if (result != 0) | ||
| 434 | return result; | ||
| 435 | |||
| 436 | tmp = (u32)regData & 0xFFFFU; | ||
| 437 | tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); | ||
| 438 | (*freq_error_hz) = tmp * 15625; | ||
| 439 | return result; | ||
| 440 | } | ||
| 441 | |||
| 442 | static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) | ||
| 443 | { | ||
| 444 | return xc4000_readreg(priv, XREG_LOCK, lock_status); | ||
| 445 | } | ||
| 446 | |||
| 447 | static int xc_get_version(struct xc4000_priv *priv, | ||
| 448 | u8 *hw_majorversion, u8 *hw_minorversion, | ||
| 449 | u8 *fw_majorversion, u8 *fw_minorversion) | ||
| 450 | { | ||
| 451 | u16 data; | ||
| 452 | int result; | ||
| 453 | |||
| 454 | result = xc4000_readreg(priv, XREG_VERSION, &data); | ||
| 455 | if (result != 0) | ||
| 456 | return result; | ||
| 457 | |||
| 458 | (*hw_majorversion) = (data >> 12) & 0x0F; | ||
| 459 | (*hw_minorversion) = (data >> 8) & 0x0F; | ||
| 460 | (*fw_majorversion) = (data >> 4) & 0x0F; | ||
| 461 | (*fw_minorversion) = data & 0x0F; | ||
| 462 | |||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 466 | static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) | ||
| 467 | { | ||
| 468 | u16 regData; | ||
| 469 | int result; | ||
| 470 | |||
| 471 | result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); | ||
| 472 | if (result != 0) | ||
| 473 | return result; | ||
| 474 | |||
| 475 | (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; | ||
| 476 | return result; | ||
| 477 | } | ||
| 478 | |||
| 479 | static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) | ||
| 480 | { | ||
| 481 | return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); | ||
| 482 | } | ||
| 483 | |||
| 484 | static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) | ||
| 485 | { | ||
| 486 | return xc4000_readreg(priv, XREG_QUALITY, quality); | ||
| 487 | } | ||
| 488 | |||
| 489 | static u16 xc_wait_for_lock(struct xc4000_priv *priv) | ||
| 490 | { | ||
| 491 | u16 lock_state = 0; | ||
| 492 | int watchdog_count = 40; | ||
| 493 | |||
| 494 | while ((lock_state == 0) && (watchdog_count > 0)) { | ||
| 495 | xc_get_lock_status(priv, &lock_state); | ||
| 496 | if (lock_state != 1) { | ||
| 497 | msleep(5); | ||
| 498 | watchdog_count--; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | return lock_state; | ||
| 502 | } | ||
| 503 | |||
| 504 | static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) | ||
| 505 | { | ||
| 506 | int found = 1; | ||
| 507 | int result; | ||
| 508 | |||
| 509 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
| 510 | |||
| 511 | /* Don't complain when the request fails because of i2c stretching */ | ||
| 512 | priv->ignore_i2c_write_errors = 1; | ||
| 513 | result = xc_set_rf_frequency(priv, freq_hz); | ||
| 514 | priv->ignore_i2c_write_errors = 0; | ||
| 515 | |||
| 516 | if (result != 0) | ||
| 517 | return 0; | ||
| 518 | |||
| 519 | /* wait for lock only in analog TV mode */ | ||
| 520 | if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { | ||
| 521 | if (xc_wait_for_lock(priv) != 1) | ||
| 522 | found = 0; | ||
| 523 | } | ||
| 524 | |||
| 525 | /* Wait for stats to stabilize. | ||
| 526 | * Frame Lines needs two frame times after initial lock | ||
| 527 | * before it is valid. | ||
| 528 | */ | ||
| 529 | msleep(debug ? 100 : 10); | ||
| 530 | |||
| 531 | if (debug) | ||
| 532 | xc_debug_dump(priv); | ||
| 533 | |||
| 534 | return found; | ||
| 535 | } | ||
| 536 | |||
| 537 | static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) | ||
| 538 | { | ||
| 539 | u8 buf[2] = { reg >> 8, reg & 0xff }; | ||
| 540 | u8 bval[2] = { 0, 0 }; | ||
| 541 | struct i2c_msg msg[2] = { | ||
| 542 | { .addr = priv->i2c_props.addr, | ||
| 543 | .flags = 0, .buf = &buf[0], .len = 2 }, | ||
| 544 | { .addr = priv->i2c_props.addr, | ||
| 545 | .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, | ||
| 546 | }; | ||
| 547 | |||
| 548 | if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { | ||
| 549 | printk(KERN_ERR "xc4000: I2C read failed\n"); | ||
| 550 | return -EREMOTEIO; | ||
| 551 | } | ||
| 552 | |||
| 553 | *val = (bval[0] << 8) | bval[1]; | ||
| 554 | return 0; | ||
| 555 | } | ||
| 556 | |||
| 557 | #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) | ||
| 558 | static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) | ||
| 559 | { | ||
| 560 | if (type & BASE) | ||
| 561 | printk(KERN_CONT "BASE "); | ||
| 562 | if (type & INIT1) | ||
| 563 | printk(KERN_CONT "INIT1 "); | ||
| 564 | if (type & F8MHZ) | ||
| 565 | printk(KERN_CONT "F8MHZ "); | ||
| 566 | if (type & MTS) | ||
| 567 | printk(KERN_CONT "MTS "); | ||
| 568 | if (type & D2620) | ||
| 569 | printk(KERN_CONT "D2620 "); | ||
| 570 | if (type & D2633) | ||
| 571 | printk(KERN_CONT "D2633 "); | ||
| 572 | if (type & DTV6) | ||
| 573 | printk(KERN_CONT "DTV6 "); | ||
| 574 | if (type & QAM) | ||
| 575 | printk(KERN_CONT "QAM "); | ||
| 576 | if (type & DTV7) | ||
| 577 | printk(KERN_CONT "DTV7 "); | ||
| 578 | if (type & DTV78) | ||
| 579 | printk(KERN_CONT "DTV78 "); | ||
| 580 | if (type & DTV8) | ||
| 581 | printk(KERN_CONT "DTV8 "); | ||
| 582 | if (type & FM) | ||
| 583 | printk(KERN_CONT "FM "); | ||
| 584 | if (type & INPUT1) | ||
| 585 | printk(KERN_CONT "INPUT1 "); | ||
| 586 | if (type & LCD) | ||
| 587 | printk(KERN_CONT "LCD "); | ||
| 588 | if (type & NOGD) | ||
| 589 | printk(KERN_CONT "NOGD "); | ||
| 590 | if (type & MONO) | ||
| 591 | printk(KERN_CONT "MONO "); | ||
| 592 | if (type & ATSC) | ||
| 593 | printk(KERN_CONT "ATSC "); | ||
| 594 | if (type & IF) | ||
| 595 | printk(KERN_CONT "IF "); | ||
| 596 | if (type & LG60) | ||
| 597 | printk(KERN_CONT "LG60 "); | ||
| 598 | if (type & ATI638) | ||
| 599 | printk(KERN_CONT "ATI638 "); | ||
| 600 | if (type & OREN538) | ||
| 601 | printk(KERN_CONT "OREN538 "); | ||
| 602 | if (type & OREN36) | ||
| 603 | printk(KERN_CONT "OREN36 "); | ||
| 604 | if (type & TOYOTA388) | ||
| 605 | printk(KERN_CONT "TOYOTA388 "); | ||
| 606 | if (type & TOYOTA794) | ||
| 607 | printk(KERN_CONT "TOYOTA794 "); | ||
| 608 | if (type & DIBCOM52) | ||
| 609 | printk(KERN_CONT "DIBCOM52 "); | ||
| 610 | if (type & ZARLINK456) | ||
| 611 | printk(KERN_CONT "ZARLINK456 "); | ||
| 612 | if (type & CHINA) | ||
| 613 | printk(KERN_CONT "CHINA "); | ||
| 614 | if (type & F6MHZ) | ||
| 615 | printk(KERN_CONT "F6MHZ "); | ||
| 616 | if (type & INPUT2) | ||
| 617 | printk(KERN_CONT "INPUT2 "); | ||
| 618 | if (type & SCODE) | ||
| 619 | printk(KERN_CONT "SCODE "); | ||
| 620 | if (type & HAS_IF) | ||
| 621 | printk(KERN_CONT "HAS_IF_%d ", int_freq); | ||
| 622 | } | ||
| 623 | |||
| 624 | static int seek_firmware(struct dvb_frontend *fe, unsigned int type, | ||
| 625 | v4l2_std_id *id) | ||
| 626 | { | ||
| 627 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 628 | int i, best_i = -1; | ||
| 629 | unsigned int best_nr_diffs = 255U; | ||
| 630 | |||
| 631 | if (!priv->firm) { | ||
| 632 | printk(KERN_ERR "Error! firmware not loaded\n"); | ||
| 633 | return -EINVAL; | ||
| 634 | } | ||
| 635 | |||
| 636 | if (((type & ~SCODE) == 0) && (*id == 0)) | ||
| 637 | *id = V4L2_STD_PAL; | ||
| 638 | |||
| 639 | /* Seek for generic video standard match */ | ||
| 640 | for (i = 0; i < priv->firm_size; i++) { | ||
| 641 | v4l2_std_id id_diff_mask = | ||
| 642 | (priv->firm[i].id ^ (*id)) & (*id); | ||
| 643 | unsigned int type_diff_mask = | ||
| 644 | (priv->firm[i].type ^ type) | ||
| 645 | & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); | ||
| 646 | unsigned int nr_diffs; | ||
| 647 | |||
| 648 | if (type_diff_mask | ||
| 649 | & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) | ||
| 650 | continue; | ||
| 651 | |||
| 652 | nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); | ||
| 653 | if (!nr_diffs) /* Supports all the requested standards */ | ||
| 654 | goto found; | ||
| 655 | |||
| 656 | if (nr_diffs < best_nr_diffs) { | ||
| 657 | best_nr_diffs = nr_diffs; | ||
| 658 | best_i = i; | ||
| 659 | } | ||
| 660 | } | ||
| 661 | |||
| 662 | /* FIXME: Would make sense to seek for type "hint" match ? */ | ||
| 663 | if (best_i < 0) { | ||
| 664 | i = -ENOENT; | ||
| 665 | goto ret; | ||
| 666 | } | ||
| 667 | |||
| 668 | if (best_nr_diffs > 0U) { | ||
| 669 | printk(KERN_WARNING | ||
| 670 | "Selecting best matching firmware (%u bits differ) for " | ||
| 671 | "type=(%x), id %016llx:\n", | ||
| 672 | best_nr_diffs, type, (unsigned long long)*id); | ||
| 673 | i = best_i; | ||
| 674 | } | ||
| 675 | |||
| 676 | found: | ||
| 677 | *id = priv->firm[i].id; | ||
| 678 | |||
| 679 | ret: | ||
| 680 | if (debug) { | ||
| 681 | printk(KERN_DEBUG "%s firmware for type=", | ||
| 682 | (i < 0) ? "Can't find" : "Found"); | ||
| 683 | dump_firm_type(type); | ||
| 684 | printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
| 685 | } | ||
| 686 | return i; | ||
| 687 | } | ||
| 688 | |||
| 689 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | ||
| 690 | v4l2_std_id *id) | ||
| 691 | { | ||
| 692 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 693 | int pos, rc; | ||
| 694 | unsigned char *p; | ||
| 695 | |||
| 696 | pos = seek_firmware(fe, type, id); | ||
| 697 | if (pos < 0) | ||
| 698 | return pos; | ||
| 699 | |||
| 700 | p = priv->firm[pos].ptr; | ||
| 701 | |||
| 702 | /* Don't complain when the request fails because of i2c stretching */ | ||
| 703 | priv->ignore_i2c_write_errors = 1; | ||
| 704 | |||
| 705 | rc = xc_load_i2c_sequence(fe, p); | ||
| 706 | |||
| 707 | priv->ignore_i2c_write_errors = 0; | ||
| 708 | |||
| 709 | return rc; | ||
| 710 | } | ||
| 711 | |||
| 712 | static int xc4000_fwupload(struct dvb_frontend *fe) | ||
| 713 | { | ||
| 714 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 715 | const struct firmware *fw = NULL; | ||
| 716 | const unsigned char *p, *endp; | ||
| 717 | int rc = 0; | ||
| 718 | int n, n_array; | ||
| 719 | char name[33]; | ||
| 720 | const char *fname; | ||
| 721 | |||
| 722 | if (firmware_name[0] != '\0') | ||
| 723 | fname = firmware_name; | ||
| 724 | else | ||
| 725 | fname = XC4000_DEFAULT_FIRMWARE; | ||
| 726 | |||
| 727 | dprintk(1, "Reading firmware %s\n", fname); | ||
| 728 | rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); | ||
| 729 | if (rc < 0) { | ||
| 730 | if (rc == -ENOENT) | ||
| 731 | printk(KERN_ERR "Error: firmware %s not found.\n", fname); | ||
| 732 | else | ||
| 733 | printk(KERN_ERR "Error %d while requesting firmware %s\n", | ||
| 734 | rc, fname); | ||
| 735 | |||
| 736 | return rc; | ||
| 737 | } | ||
| 738 | p = fw->data; | ||
| 739 | endp = p + fw->size; | ||
| 740 | |||
| 741 | if (fw->size < sizeof(name) - 1 + 2 + 2) { | ||
| 742 | printk(KERN_ERR "Error: firmware file %s has invalid size!\n", | ||
| 743 | fname); | ||
| 744 | goto corrupt; | ||
| 745 | } | ||
| 746 | |||
| 747 | memcpy(name, p, sizeof(name) - 1); | ||
| 748 | name[sizeof(name) - 1] = '\0'; | ||
| 749 | p += sizeof(name) - 1; | ||
| 750 | |||
| 751 | priv->firm_version = get_unaligned_le16(p); | ||
| 752 | p += 2; | ||
| 753 | |||
| 754 | n_array = get_unaligned_le16(p); | ||
| 755 | p += 2; | ||
| 756 | |||
| 757 | dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", | ||
| 758 | n_array, fname, name, | ||
| 759 | priv->firm_version >> 8, priv->firm_version & 0xff); | ||
| 760 | |||
| 761 | priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); | ||
| 762 | if (priv->firm == NULL) { | ||
| 763 | printk(KERN_ERR "Not enough memory to load firmware file.\n"); | ||
| 764 | rc = -ENOMEM; | ||
| 765 | goto done; | ||
| 766 | } | ||
| 767 | priv->firm_size = n_array; | ||
| 768 | |||
| 769 | n = -1; | ||
| 770 | while (p < endp) { | ||
| 771 | __u32 type, size; | ||
| 772 | v4l2_std_id id; | ||
| 773 | __u16 int_freq = 0; | ||
| 774 | |||
| 775 | n++; | ||
| 776 | if (n >= n_array) { | ||
| 777 | printk(KERN_ERR "More firmware images in file than " | ||
| 778 | "were expected!\n"); | ||
| 779 | goto corrupt; | ||
| 780 | } | ||
| 781 | |||
| 782 | /* Checks if there's enough bytes to read */ | ||
| 783 | if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) | ||
| 784 | goto header; | ||
| 785 | |||
| 786 | type = get_unaligned_le32(p); | ||
| 787 | p += sizeof(type); | ||
| 788 | |||
| 789 | id = get_unaligned_le64(p); | ||
| 790 | p += sizeof(id); | ||
| 791 | |||
| 792 | if (type & HAS_IF) { | ||
| 793 | int_freq = get_unaligned_le16(p); | ||
| 794 | p += sizeof(int_freq); | ||
| 795 | if (endp - p < sizeof(size)) | ||
| 796 | goto header; | ||
| 797 | } | ||
| 798 | |||
| 799 | size = get_unaligned_le32(p); | ||
| 800 | p += sizeof(size); | ||
| 801 | |||
| 802 | if (!size || size > endp - p) { | ||
| 803 | printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n", | ||
| 804 | type, (unsigned long long)id, | ||
| 805 | (unsigned)(endp - p), size); | ||
| 806 | goto corrupt; | ||
| 807 | } | ||
| 808 | |||
| 809 | priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); | ||
| 810 | if (priv->firm[n].ptr == NULL) { | ||
| 811 | printk(KERN_ERR "Not enough memory to load firmware file.\n"); | ||
| 812 | rc = -ENOMEM; | ||
| 813 | goto done; | ||
| 814 | } | ||
| 815 | |||
| 816 | if (debug) { | ||
| 817 | printk(KERN_DEBUG "Reading firmware type "); | ||
| 818 | dump_firm_type_and_int_freq(type, int_freq); | ||
| 819 | printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", | ||
| 820 | type, (unsigned long long)id, size); | ||
| 821 | } | ||
| 822 | |||
| 823 | memcpy(priv->firm[n].ptr, p, size); | ||
| 824 | priv->firm[n].type = type; | ||
| 825 | priv->firm[n].id = id; | ||
| 826 | priv->firm[n].size = size; | ||
| 827 | priv->firm[n].int_freq = int_freq; | ||
| 828 | |||
| 829 | p += size; | ||
| 830 | } | ||
| 831 | |||
| 832 | if (n + 1 != priv->firm_size) { | ||
| 833 | printk(KERN_ERR "Firmware file is incomplete!\n"); | ||
| 834 | goto corrupt; | ||
| 835 | } | ||
| 836 | |||
| 837 | goto done; | ||
| 838 | |||
| 839 | header: | ||
| 840 | printk(KERN_ERR "Firmware header is incomplete!\n"); | ||
| 841 | corrupt: | ||
| 842 | rc = -EINVAL; | ||
| 843 | printk(KERN_ERR "Error: firmware file is corrupted!\n"); | ||
| 844 | |||
| 845 | done: | ||
| 846 | release_firmware(fw); | ||
| 847 | if (rc == 0) | ||
| 848 | dprintk(1, "Firmware files loaded.\n"); | ||
| 849 | |||
| 850 | return rc; | ||
| 851 | } | ||
| 852 | |||
| 853 | static int load_scode(struct dvb_frontend *fe, unsigned int type, | ||
| 854 | v4l2_std_id *id, __u16 int_freq, int scode) | ||
| 855 | { | ||
| 856 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 857 | int pos, rc; | ||
| 858 | unsigned char *p; | ||
| 859 | u8 scode_buf[13]; | ||
| 860 | u8 indirect_mode[5]; | ||
| 861 | |||
| 862 | dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); | ||
| 863 | |||
| 864 | if (!int_freq) { | ||
| 865 | pos = seek_firmware(fe, type, id); | ||
| 866 | if (pos < 0) | ||
| 867 | return pos; | ||
| 868 | } else { | ||
| 869 | for (pos = 0; pos < priv->firm_size; pos++) { | ||
| 870 | if ((priv->firm[pos].int_freq == int_freq) && | ||
| 871 | (priv->firm[pos].type & HAS_IF)) | ||
| 872 | break; | ||
| 873 | } | ||
| 874 | if (pos == priv->firm_size) | ||
| 875 | return -ENOENT; | ||
| 876 | } | ||
| 877 | |||
| 878 | p = priv->firm[pos].ptr; | ||
| 879 | |||
| 880 | if (priv->firm[pos].size != 12 * 16 || scode >= 16) | ||
| 881 | return -EINVAL; | ||
| 882 | p += 12 * scode; | ||
| 883 | |||
| 884 | if (debug) { | ||
| 885 | tuner_info("Loading SCODE for type="); | ||
| 886 | dump_firm_type_and_int_freq(priv->firm[pos].type, | ||
| 887 | priv->firm[pos].int_freq); | ||
| 888 | printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, | ||
| 889 | (unsigned long long)*id); | ||
| 890 | } | ||
| 891 | |||
| 892 | scode_buf[0] = 0x00; | ||
| 893 | memcpy(&scode_buf[1], p, 12); | ||
| 894 | |||
| 895 | /* Enter direct-mode */ | ||
| 896 | rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); | ||
| 897 | if (rc < 0) { | ||
| 898 | printk(KERN_ERR "failed to put device into direct mode!\n"); | ||
| 899 | return -EIO; | ||
| 900 | } | ||
| 901 | |||
| 902 | rc = xc_send_i2c_data(priv, scode_buf, 13); | ||
| 903 | if (rc != 0) { | ||
| 904 | /* Even if the send failed, make sure we set back to indirect | ||
| 905 | mode */ | ||
| 906 | printk(KERN_ERR "Failed to set scode %d\n", rc); | ||
| 907 | } | ||
| 908 | |||
| 909 | /* Switch back to indirect-mode */ | ||
| 910 | memset(indirect_mode, 0, sizeof(indirect_mode)); | ||
| 911 | indirect_mode[4] = 0x88; | ||
| 912 | xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); | ||
| 913 | msleep(10); | ||
| 914 | |||
| 915 | return 0; | ||
| 916 | } | ||
| 917 | |||
| 918 | static int check_firmware(struct dvb_frontend *fe, unsigned int type, | ||
| 919 | v4l2_std_id std, __u16 int_freq) | ||
| 920 | { | ||
| 921 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 922 | struct firmware_properties new_fw; | ||
| 923 | int rc = 0, is_retry = 0; | ||
| 924 | u16 hwmodel; | ||
| 925 | v4l2_std_id std0; | ||
| 926 | u8 hw_major, hw_minor, fw_major, fw_minor; | ||
| 927 | |||
| 928 | dprintk(1, "%s called\n", __func__); | ||
| 929 | |||
| 930 | if (!priv->firm) { | ||
| 931 | rc = xc4000_fwupload(fe); | ||
| 932 | if (rc < 0) | ||
| 933 | return rc; | ||
| 934 | } | ||
| 935 | |||
| 936 | retry: | ||
| 937 | new_fw.type = type; | ||
| 938 | new_fw.id = std; | ||
| 939 | new_fw.std_req = std; | ||
| 940 | new_fw.scode_table = SCODE; | ||
| 941 | new_fw.scode_nr = 0; | ||
| 942 | new_fw.int_freq = int_freq; | ||
| 943 | |||
| 944 | dprintk(1, "checking firmware, user requested type="); | ||
| 945 | if (debug) { | ||
| 946 | dump_firm_type(new_fw.type); | ||
| 947 | printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, | ||
| 948 | (unsigned long long)new_fw.std_req); | ||
| 949 | if (!int_freq) | ||
| 950 | printk(KERN_CONT "scode_tbl "); | ||
| 951 | else | ||
| 952 | printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); | ||
| 953 | printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); | ||
| 954 | } | ||
| 955 | |||
| 956 | /* No need to reload base firmware if it matches */ | ||
| 957 | if (priv->cur_fw.type & BASE) { | ||
| 958 | dprintk(1, "BASE firmware not changed.\n"); | ||
| 959 | goto skip_base; | ||
| 960 | } | ||
| 961 | |||
| 962 | /* Updating BASE - forget about all currently loaded firmware */ | ||
| 963 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
| 964 | |||
| 965 | /* Reset is needed before loading firmware */ | ||
| 966 | rc = xc4000_tuner_reset(fe); | ||
| 967 | if (rc < 0) | ||
| 968 | goto fail; | ||
| 969 | |||
| 970 | /* BASE firmwares are all std0 */ | ||
| 971 | std0 = 0; | ||
| 972 | rc = load_firmware(fe, BASE, &std0); | ||
| 973 | if (rc < 0) { | ||
| 974 | printk(KERN_ERR "Error %d while loading base firmware\n", rc); | ||
| 975 | goto fail; | ||
| 976 | } | ||
| 977 | |||
| 978 | /* Load INIT1, if needed */ | ||
| 979 | dprintk(1, "Load init1 firmware, if exists\n"); | ||
| 980 | |||
| 981 | rc = load_firmware(fe, BASE | INIT1, &std0); | ||
| 982 | if (rc == -ENOENT) | ||
| 983 | rc = load_firmware(fe, BASE | INIT1, &std0); | ||
| 984 | if (rc < 0 && rc != -ENOENT) { | ||
| 985 | tuner_err("Error %d while loading init1 firmware\n", | ||
| 986 | rc); | ||
| 987 | goto fail; | ||
| 988 | } | ||
| 989 | |||
| 990 | skip_base: | ||
| 991 | /* | ||
| 992 | * No need to reload standard specific firmware if base firmware | ||
| 993 | * was not reloaded and requested video standards have not changed. | ||
| 994 | */ | ||
| 995 | if (priv->cur_fw.type == (BASE | new_fw.type) && | ||
| 996 | priv->cur_fw.std_req == std) { | ||
| 997 | dprintk(1, "Std-specific firmware already loaded.\n"); | ||
| 998 | goto skip_std_specific; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | /* Reloading std-specific firmware forces a SCODE update */ | ||
| 1002 | priv->cur_fw.scode_table = 0; | ||
| 1003 | |||
| 1004 | /* Load the standard firmware */ | ||
| 1005 | rc = load_firmware(fe, new_fw.type, &new_fw.id); | ||
| 1006 | |||
| 1007 | if (rc < 0) | ||
| 1008 | goto fail; | ||
| 1009 | |||
| 1010 | skip_std_specific: | ||
| 1011 | if (priv->cur_fw.scode_table == new_fw.scode_table && | ||
| 1012 | priv->cur_fw.scode_nr == new_fw.scode_nr) { | ||
| 1013 | dprintk(1, "SCODE firmware already loaded.\n"); | ||
| 1014 | goto check_device; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | /* Load SCODE firmware, if exists */ | ||
| 1018 | rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, | ||
| 1019 | new_fw.int_freq, new_fw.scode_nr); | ||
| 1020 | if (rc != 0) | ||
| 1021 | dprintk(1, "load scode failed %d\n", rc); | ||
| 1022 | |||
| 1023 | check_device: | ||
| 1024 | rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel); | ||
| 1025 | |||
| 1026 | if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, | ||
| 1027 | &fw_minor) != 0) { | ||
| 1028 | printk(KERN_ERR "Unable to read tuner registers.\n"); | ||
| 1029 | goto fail; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | dprintk(1, "Device is Xceive %d version %d.%d, " | ||
| 1033 | "firmware version %d.%d\n", | ||
| 1034 | hwmodel, hw_major, hw_minor, fw_major, fw_minor); | ||
| 1035 | |||
| 1036 | /* Check firmware version against what we downloaded. */ | ||
| 1037 | if (priv->firm_version != ((fw_major << 8) | fw_minor)) { | ||
| 1038 | printk(KERN_WARNING | ||
| 1039 | "Incorrect readback of firmware version %d.%d.\n", | ||
| 1040 | fw_major, fw_minor); | ||
| 1041 | goto fail; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /* Check that the tuner hardware model remains consistent over time. */ | ||
| 1045 | if (priv->hwmodel == 0 && | ||
| 1046 | (hwmodel == XC_PRODUCT_ID_XC4000 || | ||
| 1047 | hwmodel == XC_PRODUCT_ID_XC4100)) { | ||
| 1048 | priv->hwmodel = hwmodel; | ||
| 1049 | priv->hwvers = (hw_major << 8) | hw_minor; | ||
| 1050 | } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || | ||
| 1051 | priv->hwvers != ((hw_major << 8) | hw_minor)) { | ||
| 1052 | printk(KERN_WARNING | ||
| 1053 | "Read invalid device hardware information - tuner " | ||
| 1054 | "hung?\n"); | ||
| 1055 | goto fail; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); | ||
| 1059 | |||
| 1060 | /* | ||
| 1061 | * By setting BASE in cur_fw.type only after successfully loading all | ||
| 1062 | * firmwares, we can: | ||
| 1063 | * 1. Identify that BASE firmware with type=0 has been loaded; | ||
| 1064 | * 2. Tell whether BASE firmware was just changed the next time through. | ||
| 1065 | */ | ||
| 1066 | priv->cur_fw.type |= BASE; | ||
| 1067 | |||
| 1068 | return 0; | ||
| 1069 | |||
| 1070 | fail: | ||
| 1071 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
| 1072 | if (!is_retry) { | ||
| 1073 | msleep(50); | ||
| 1074 | is_retry = 1; | ||
| 1075 | dprintk(1, "Retrying firmware load\n"); | ||
| 1076 | goto retry; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | if (rc == -ENOENT) | ||
| 1080 | rc = -EINVAL; | ||
| 1081 | return rc; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | static void xc_debug_dump(struct xc4000_priv *priv) | ||
| 1085 | { | ||
| 1086 | u16 adc_envelope; | ||
| 1087 | u32 freq_error_hz = 0; | ||
| 1088 | u16 lock_status; | ||
| 1089 | u32 hsync_freq_hz = 0; | ||
| 1090 | u16 frame_lines; | ||
| 1091 | u16 quality; | ||
| 1092 | u8 hw_majorversion = 0, hw_minorversion = 0; | ||
| 1093 | u8 fw_majorversion = 0, fw_minorversion = 0; | ||
| 1094 | |||
| 1095 | xc_get_adc_envelope(priv, &adc_envelope); | ||
| 1096 | dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); | ||
| 1097 | |||
| 1098 | xc_get_frequency_error(priv, &freq_error_hz); | ||
| 1099 | dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); | ||
| 1100 | |||
| 1101 | xc_get_lock_status(priv, &lock_status); | ||
| 1102 | dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", | ||
| 1103 | lock_status); | ||
| 1104 | |||
| 1105 | xc_get_version(priv, &hw_majorversion, &hw_minorversion, | ||
| 1106 | &fw_majorversion, &fw_minorversion); | ||
| 1107 | dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", | ||
| 1108 | hw_majorversion, hw_minorversion, | ||
| 1109 | fw_majorversion, fw_minorversion); | ||
| 1110 | |||
| 1111 | if (priv->video_standard < XC4000_DTV6) { | ||
| 1112 | xc_get_hsync_freq(priv, &hsync_freq_hz); | ||
| 1113 | dprintk(1, "*** Horizontal sync frequency = %d Hz\n", | ||
| 1114 | hsync_freq_hz); | ||
| 1115 | |||
| 1116 | xc_get_frame_lines(priv, &frame_lines); | ||
| 1117 | dprintk(1, "*** Frame lines = %d\n", frame_lines); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | xc_get_quality(priv, &quality); | ||
| 1121 | dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | static int xc4000_set_params(struct dvb_frontend *fe, | ||
| 1125 | struct dvb_frontend_parameters *params) | ||
| 1126 | { | ||
| 1127 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1128 | unsigned int type; | ||
| 1129 | int ret = -EREMOTEIO; | ||
| 1130 | |||
| 1131 | dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); | ||
| 1132 | |||
| 1133 | mutex_lock(&priv->lock); | ||
| 1134 | |||
| 1135 | if (fe->ops.info.type == FE_ATSC) { | ||
| 1136 | dprintk(1, "%s() ATSC\n", __func__); | ||
| 1137 | switch (params->u.vsb.modulation) { | ||
| 1138 | case VSB_8: | ||
| 1139 | case VSB_16: | ||
| 1140 | dprintk(1, "%s() VSB modulation\n", __func__); | ||
| 1141 | priv->rf_mode = XC_RF_MODE_AIR; | ||
| 1142 | priv->freq_hz = params->frequency - 1750000; | ||
| 1143 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 1144 | priv->video_standard = XC4000_DTV6; | ||
| 1145 | type = DTV6; | ||
| 1146 | break; | ||
| 1147 | case QAM_64: | ||
| 1148 | case QAM_256: | ||
| 1149 | case QAM_AUTO: | ||
| 1150 | dprintk(1, "%s() QAM modulation\n", __func__); | ||
| 1151 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
| 1152 | priv->freq_hz = params->frequency - 1750000; | ||
| 1153 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 1154 | priv->video_standard = XC4000_DTV6; | ||
| 1155 | type = DTV6; | ||
| 1156 | break; | ||
| 1157 | default: | ||
| 1158 | ret = -EINVAL; | ||
| 1159 | goto fail; | ||
| 1160 | } | ||
| 1161 | } else if (fe->ops.info.type == FE_OFDM) { | ||
| 1162 | dprintk(1, "%s() OFDM\n", __func__); | ||
| 1163 | switch (params->u.ofdm.bandwidth) { | ||
| 1164 | case BANDWIDTH_6_MHZ: | ||
| 1165 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 1166 | priv->video_standard = XC4000_DTV6; | ||
| 1167 | priv->freq_hz = params->frequency - 1750000; | ||
| 1168 | type = DTV6; | ||
| 1169 | break; | ||
| 1170 | case BANDWIDTH_7_MHZ: | ||
| 1171 | priv->bandwidth = BANDWIDTH_7_MHZ; | ||
| 1172 | priv->video_standard = XC4000_DTV7; | ||
| 1173 | priv->freq_hz = params->frequency - 2250000; | ||
| 1174 | type = DTV7; | ||
| 1175 | break; | ||
| 1176 | case BANDWIDTH_8_MHZ: | ||
| 1177 | priv->bandwidth = BANDWIDTH_8_MHZ; | ||
| 1178 | priv->video_standard = XC4000_DTV8; | ||
| 1179 | priv->freq_hz = params->frequency - 2750000; | ||
| 1180 | type = DTV8; | ||
| 1181 | break; | ||
| 1182 | case BANDWIDTH_AUTO: | ||
| 1183 | if (params->frequency < 400000000) { | ||
| 1184 | priv->bandwidth = BANDWIDTH_7_MHZ; | ||
| 1185 | priv->freq_hz = params->frequency - 2250000; | ||
| 1186 | } else { | ||
| 1187 | priv->bandwidth = BANDWIDTH_8_MHZ; | ||
| 1188 | priv->freq_hz = params->frequency - 2750000; | ||
| 1189 | } | ||
| 1190 | priv->video_standard = XC4000_DTV7_8; | ||
| 1191 | type = DTV78; | ||
| 1192 | break; | ||
| 1193 | default: | ||
| 1194 | printk(KERN_ERR "xc4000 bandwidth not set!\n"); | ||
| 1195 | ret = -EINVAL; | ||
| 1196 | goto fail; | ||
| 1197 | } | ||
| 1198 | priv->rf_mode = XC_RF_MODE_AIR; | ||
| 1199 | } else { | ||
| 1200 | printk(KERN_ERR "xc4000 modulation type not supported!\n"); | ||
| 1201 | ret = -EINVAL; | ||
| 1202 | goto fail; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | dprintk(1, "%s() frequency=%d (compensated)\n", | ||
| 1206 | __func__, priv->freq_hz); | ||
| 1207 | |||
| 1208 | /* Make sure the correct firmware type is loaded */ | ||
| 1209 | if (check_firmware(fe, type, 0, priv->if_khz) != 0) | ||
| 1210 | goto fail; | ||
| 1211 | |||
| 1212 | ret = xc_set_signal_source(priv, priv->rf_mode); | ||
| 1213 | if (ret != 0) { | ||
| 1214 | printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", | ||
| 1215 | priv->rf_mode); | ||
| 1216 | goto fail; | ||
| 1217 | } else { | ||
| 1218 | u16 video_mode, audio_mode; | ||
| 1219 | video_mode = xc4000_standard[priv->video_standard].video_mode; | ||
| 1220 | audio_mode = xc4000_standard[priv->video_standard].audio_mode; | ||
| 1221 | if (type == DTV6 && priv->firm_version != 0x0102) | ||
| 1222 | video_mode |= 0x0001; | ||
| 1223 | ret = xc_set_tv_standard(priv, video_mode, audio_mode); | ||
| 1224 | if (ret != 0) { | ||
| 1225 | printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); | ||
| 1226 | /* DJH - do not return when it fails... */ | ||
| 1227 | /* goto fail; */ | ||
| 1228 | } | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) | ||
| 1232 | ret = 0; | ||
| 1233 | if (priv->dvb_amplitude != 0) { | ||
| 1234 | if (xc_write_reg(priv, XREG_AMPLITUDE, | ||
| 1235 | (priv->firm_version != 0x0102 || | ||
| 1236 | priv->dvb_amplitude != 134 ? | ||
| 1237 | priv->dvb_amplitude : 132)) != 0) | ||
| 1238 | ret = -EREMOTEIO; | ||
| 1239 | } | ||
| 1240 | if (priv->set_smoothedcvbs != 0) { | ||
| 1241 | if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) | ||
| 1242 | ret = -EREMOTEIO; | ||
| 1243 | } | ||
| 1244 | if (ret != 0) { | ||
| 1245 | printk(KERN_ERR "xc4000: setting registers failed\n"); | ||
| 1246 | /* goto fail; */ | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | xc_tune_channel(priv, priv->freq_hz); | ||
| 1250 | |||
| 1251 | ret = 0; | ||
| 1252 | |||
| 1253 | fail: | ||
| 1254 | mutex_unlock(&priv->lock); | ||
| 1255 | |||
| 1256 | return ret; | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | static int xc4000_set_analog_params(struct dvb_frontend *fe, | ||
| 1260 | struct analog_parameters *params) | ||
| 1261 | { | ||
| 1262 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1263 | unsigned int type = 0; | ||
| 1264 | int ret = -EREMOTEIO; | ||
| 1265 | |||
| 1266 | if (params->mode == V4L2_TUNER_RADIO) { | ||
| 1267 | dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", | ||
| 1268 | __func__, params->frequency); | ||
| 1269 | |||
| 1270 | mutex_lock(&priv->lock); | ||
| 1271 | |||
| 1272 | params->std = 0; | ||
| 1273 | priv->freq_hz = params->frequency * 125L / 2; | ||
| 1274 | |||
| 1275 | if (audio_std & XC4000_AUDIO_STD_INPUT1) { | ||
| 1276 | priv->video_standard = XC4000_FM_Radio_INPUT1; | ||
| 1277 | type = FM | INPUT1; | ||
| 1278 | } else { | ||
| 1279 | priv->video_standard = XC4000_FM_Radio_INPUT2; | ||
| 1280 | type = FM | INPUT2; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | goto tune_channel; | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", | ||
| 1287 | __func__, params->frequency); | ||
| 1288 | |||
| 1289 | mutex_lock(&priv->lock); | ||
| 1290 | |||
| 1291 | /* params->frequency is in units of 62.5khz */ | ||
| 1292 | priv->freq_hz = params->frequency * 62500; | ||
| 1293 | |||
| 1294 | params->std &= V4L2_STD_ALL; | ||
| 1295 | /* if std is not defined, choose one */ | ||
| 1296 | if (!params->std) | ||
| 1297 | params->std = V4L2_STD_PAL_BG; | ||
| 1298 | |||
| 1299 | if (audio_std & XC4000_AUDIO_STD_MONO) | ||
| 1300 | type = MONO; | ||
| 1301 | |||
| 1302 | if (params->std & V4L2_STD_MN) { | ||
| 1303 | params->std = V4L2_STD_MN; | ||
| 1304 | if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
| 1305 | priv->video_standard = XC4000_MN_NTSC_PAL_Mono; | ||
| 1306 | } else if (audio_std & XC4000_AUDIO_STD_A2) { | ||
| 1307 | params->std |= V4L2_STD_A2; | ||
| 1308 | priv->video_standard = XC4000_MN_NTSC_PAL_A2; | ||
| 1309 | } else { | ||
| 1310 | params->std |= V4L2_STD_BTSC; | ||
| 1311 | priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; | ||
| 1312 | } | ||
| 1313 | goto tune_channel; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | if (params->std & V4L2_STD_PAL_BG) { | ||
| 1317 | params->std = V4L2_STD_PAL_BG; | ||
| 1318 | if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
| 1319 | priv->video_standard = XC4000_BG_PAL_MONO; | ||
| 1320 | } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { | ||
| 1321 | if (!(audio_std & XC4000_AUDIO_STD_B)) { | ||
| 1322 | params->std |= V4L2_STD_NICAM_A; | ||
| 1323 | priv->video_standard = XC4000_BG_PAL_NICAM; | ||
| 1324 | } else { | ||
| 1325 | params->std |= V4L2_STD_NICAM_B; | ||
| 1326 | priv->video_standard = XC4000_BG_PAL_NICAM; | ||
| 1327 | } | ||
| 1328 | } else { | ||
| 1329 | if (!(audio_std & XC4000_AUDIO_STD_B)) { | ||
| 1330 | params->std |= V4L2_STD_A2_A; | ||
| 1331 | priv->video_standard = XC4000_BG_PAL_A2; | ||
| 1332 | } else { | ||
| 1333 | params->std |= V4L2_STD_A2_B; | ||
| 1334 | priv->video_standard = XC4000_BG_PAL_A2; | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | goto tune_channel; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | if (params->std & V4L2_STD_PAL_I) { | ||
| 1341 | /* default to NICAM audio standard */ | ||
| 1342 | params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; | ||
| 1343 | if (audio_std & XC4000_AUDIO_STD_MONO) | ||
| 1344 | priv->video_standard = XC4000_I_PAL_NICAM_MONO; | ||
| 1345 | else | ||
| 1346 | priv->video_standard = XC4000_I_PAL_NICAM; | ||
| 1347 | goto tune_channel; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | if (params->std & V4L2_STD_PAL_DK) { | ||
| 1351 | params->std = V4L2_STD_PAL_DK; | ||
| 1352 | if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
| 1353 | priv->video_standard = XC4000_DK_PAL_MONO; | ||
| 1354 | } else if (audio_std & XC4000_AUDIO_STD_A2) { | ||
| 1355 | params->std |= V4L2_STD_A2; | ||
| 1356 | priv->video_standard = XC4000_DK_PAL_A2; | ||
| 1357 | } else { | ||
| 1358 | params->std |= V4L2_STD_NICAM; | ||
| 1359 | priv->video_standard = XC4000_DK_PAL_NICAM; | ||
| 1360 | } | ||
| 1361 | goto tune_channel; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | if (params->std & V4L2_STD_SECAM_DK) { | ||
| 1365 | /* default to A2 audio standard */ | ||
| 1366 | params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; | ||
| 1367 | if (audio_std & XC4000_AUDIO_STD_L) { | ||
| 1368 | type = 0; | ||
| 1369 | priv->video_standard = XC4000_DK_SECAM_NICAM; | ||
| 1370 | } else if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
| 1371 | priv->video_standard = XC4000_DK_SECAM_A2MONO; | ||
| 1372 | } else if (audio_std & XC4000_AUDIO_STD_K3) { | ||
| 1373 | params->std |= V4L2_STD_SECAM_K3; | ||
| 1374 | priv->video_standard = XC4000_DK_SECAM_A2LDK3; | ||
| 1375 | } else { | ||
| 1376 | priv->video_standard = XC4000_DK_SECAM_A2DK1; | ||
| 1377 | } | ||
| 1378 | goto tune_channel; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | if (params->std & V4L2_STD_SECAM_L) { | ||
| 1382 | /* default to NICAM audio standard */ | ||
| 1383 | type = 0; | ||
| 1384 | params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; | ||
| 1385 | priv->video_standard = XC4000_L_SECAM_NICAM; | ||
| 1386 | goto tune_channel; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | if (params->std & V4L2_STD_SECAM_LC) { | ||
| 1390 | /* default to NICAM audio standard */ | ||
| 1391 | type = 0; | ||
| 1392 | params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; | ||
| 1393 | priv->video_standard = XC4000_LC_SECAM_NICAM; | ||
| 1394 | goto tune_channel; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | tune_channel: | ||
| 1398 | /* FIXME: it could be air. */ | ||
| 1399 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
| 1400 | |||
| 1401 | if (check_firmware(fe, type, params->std, | ||
| 1402 | xc4000_standard[priv->video_standard].int_freq) != 0) | ||
| 1403 | goto fail; | ||
| 1404 | |||
| 1405 | ret = xc_set_signal_source(priv, priv->rf_mode); | ||
| 1406 | if (ret != 0) { | ||
| 1407 | printk(KERN_ERR | ||
| 1408 | "xc4000: xc_set_signal_source(%d) failed\n", | ||
| 1409 | priv->rf_mode); | ||
| 1410 | goto fail; | ||
| 1411 | } else { | ||
| 1412 | u16 video_mode, audio_mode; | ||
| 1413 | video_mode = xc4000_standard[priv->video_standard].video_mode; | ||
| 1414 | audio_mode = xc4000_standard[priv->video_standard].audio_mode; | ||
| 1415 | if (priv->video_standard < XC4000_BG_PAL_A2) { | ||
| 1416 | if (type & NOGD) | ||
| 1417 | video_mode &= 0xFF7F; | ||
| 1418 | } else if (priv->video_standard < XC4000_I_PAL_NICAM) { | ||
| 1419 | if (priv->firm_version == 0x0102) | ||
| 1420 | video_mode &= 0xFEFF; | ||
| 1421 | if (audio_std & XC4000_AUDIO_STD_B) | ||
| 1422 | video_mode |= 0x0080; | ||
| 1423 | } | ||
| 1424 | ret = xc_set_tv_standard(priv, video_mode, audio_mode); | ||
| 1425 | if (ret != 0) { | ||
| 1426 | printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); | ||
| 1427 | goto fail; | ||
| 1428 | } | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) | ||
| 1432 | ret = 0; | ||
| 1433 | if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) | ||
| 1434 | ret = -EREMOTEIO; | ||
| 1435 | if (priv->set_smoothedcvbs != 0) { | ||
| 1436 | if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) | ||
| 1437 | ret = -EREMOTEIO; | ||
| 1438 | } | ||
| 1439 | if (ret != 0) { | ||
| 1440 | printk(KERN_ERR "xc4000: setting registers failed\n"); | ||
| 1441 | goto fail; | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | xc_tune_channel(priv, priv->freq_hz); | ||
| 1445 | |||
| 1446 | ret = 0; | ||
| 1447 | |||
| 1448 | fail: | ||
| 1449 | mutex_unlock(&priv->lock); | ||
| 1450 | |||
| 1451 | return ret; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) | ||
| 1455 | { | ||
| 1456 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1457 | |||
| 1458 | *freq = priv->freq_hz; | ||
| 1459 | |||
| 1460 | if (debug) { | ||
| 1461 | mutex_lock(&priv->lock); | ||
| 1462 | if ((priv->cur_fw.type | ||
| 1463 | & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { | ||
| 1464 | u16 snr = 0; | ||
| 1465 | if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { | ||
| 1466 | mutex_unlock(&priv->lock); | ||
| 1467 | dprintk(1, "%s() freq = %u, SNR = %d\n", | ||
| 1468 | __func__, *freq, snr); | ||
| 1469 | return 0; | ||
| 1470 | } | ||
| 1471 | } | ||
| 1472 | mutex_unlock(&priv->lock); | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | dprintk(1, "%s()\n", __func__); | ||
| 1476 | |||
| 1477 | return 0; | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
| 1481 | { | ||
| 1482 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1483 | dprintk(1, "%s()\n", __func__); | ||
| 1484 | |||
| 1485 | *bw = priv->bandwidth; | ||
| 1486 | return 0; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | static int xc4000_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 1490 | { | ||
| 1491 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1492 | u16 lock_status = 0; | ||
| 1493 | |||
| 1494 | mutex_lock(&priv->lock); | ||
| 1495 | |||
| 1496 | if (priv->cur_fw.type & BASE) | ||
| 1497 | xc_get_lock_status(priv, &lock_status); | ||
| 1498 | |||
| 1499 | *status = (lock_status == 1 ? | ||
| 1500 | TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); | ||
| 1501 | if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) | ||
| 1502 | *status &= (~TUNER_STATUS_STEREO); | ||
| 1503 | |||
| 1504 | mutex_unlock(&priv->lock); | ||
| 1505 | |||
| 1506 | dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); | ||
| 1507 | |||
| 1508 | return 0; | ||
| 1509 | } | ||
| 1510 | |||
| 1511 | static int xc4000_sleep(struct dvb_frontend *fe) | ||
| 1512 | { | ||
| 1513 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1514 | int ret = 0; | ||
| 1515 | |||
| 1516 | dprintk(1, "%s()\n", __func__); | ||
| 1517 | |||
| 1518 | mutex_lock(&priv->lock); | ||
| 1519 | |||
| 1520 | /* Avoid firmware reload on slow devices */ | ||
| 1521 | if ((no_poweroff == 2 || | ||
| 1522 | (no_poweroff == 0 && priv->default_pm != 0)) && | ||
| 1523 | (priv->cur_fw.type & BASE) != 0) { | ||
| 1524 | /* force reset and firmware reload */ | ||
| 1525 | priv->cur_fw.type = XC_POWERED_DOWN; | ||
| 1526 | |||
| 1527 | if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { | ||
| 1528 | printk(KERN_ERR | ||
| 1529 | "xc4000: %s() unable to shutdown tuner\n", | ||
| 1530 | __func__); | ||
| 1531 | ret = -EREMOTEIO; | ||
| 1532 | } | ||
| 1533 | msleep(20); | ||
| 1534 | } | ||
| 1535 | |||
| 1536 | mutex_unlock(&priv->lock); | ||
| 1537 | |||
| 1538 | return ret; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | static int xc4000_init(struct dvb_frontend *fe) | ||
| 1542 | { | ||
| 1543 | dprintk(1, "%s()\n", __func__); | ||
| 1544 | |||
| 1545 | return 0; | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | static int xc4000_release(struct dvb_frontend *fe) | ||
| 1549 | { | ||
| 1550 | struct xc4000_priv *priv = fe->tuner_priv; | ||
| 1551 | |||
| 1552 | dprintk(1, "%s()\n", __func__); | ||
| 1553 | |||
| 1554 | mutex_lock(&xc4000_list_mutex); | ||
| 1555 | |||
| 1556 | if (priv) | ||
| 1557 | hybrid_tuner_release_state(priv); | ||
| 1558 | |||
| 1559 | mutex_unlock(&xc4000_list_mutex); | ||
| 1560 | |||
| 1561 | fe->tuner_priv = NULL; | ||
| 1562 | |||
| 1563 | return 0; | ||
| 1564 | } | ||
| 1565 | |||
| 1566 | static const struct dvb_tuner_ops xc4000_tuner_ops = { | ||
| 1567 | .info = { | ||
| 1568 | .name = "Xceive XC4000", | ||
| 1569 | .frequency_min = 1000000, | ||
| 1570 | .frequency_max = 1023000000, | ||
| 1571 | .frequency_step = 50000, | ||
| 1572 | }, | ||
| 1573 | |||
| 1574 | .release = xc4000_release, | ||
| 1575 | .init = xc4000_init, | ||
| 1576 | .sleep = xc4000_sleep, | ||
| 1577 | |||
| 1578 | .set_params = xc4000_set_params, | ||
| 1579 | .set_analog_params = xc4000_set_analog_params, | ||
| 1580 | .get_frequency = xc4000_get_frequency, | ||
| 1581 | .get_bandwidth = xc4000_get_bandwidth, | ||
| 1582 | .get_status = xc4000_get_status | ||
| 1583 | }; | ||
| 1584 | |||
| 1585 | struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | ||
| 1586 | struct i2c_adapter *i2c, | ||
| 1587 | struct xc4000_config *cfg) | ||
| 1588 | { | ||
| 1589 | struct xc4000_priv *priv = NULL; | ||
| 1590 | int instance; | ||
| 1591 | u16 id = 0; | ||
| 1592 | |||
| 1593 | dprintk(1, "%s(%d-%04x)\n", __func__, | ||
| 1594 | i2c ? i2c_adapter_id(i2c) : -1, | ||
| 1595 | cfg ? cfg->i2c_address : -1); | ||
| 1596 | |||
| 1597 | mutex_lock(&xc4000_list_mutex); | ||
| 1598 | |||
| 1599 | instance = hybrid_tuner_request_state(struct xc4000_priv, priv, | ||
| 1600 | hybrid_tuner_instance_list, | ||
| 1601 | i2c, cfg->i2c_address, "xc4000"); | ||
| 1602 | switch (instance) { | ||
| 1603 | case 0: | ||
| 1604 | goto fail; | ||
| 1605 | break; | ||
| 1606 | case 1: | ||
| 1607 | /* new tuner instance */ | ||
| 1608 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 1609 | /* set default configuration */ | ||
| 1610 | priv->if_khz = 4560; | ||
| 1611 | priv->default_pm = 0; | ||
| 1612 | priv->dvb_amplitude = 134; | ||
| 1613 | priv->set_smoothedcvbs = 1; | ||
| 1614 | mutex_init(&priv->lock); | ||
| 1615 | fe->tuner_priv = priv; | ||
| 1616 | break; | ||
| 1617 | default: | ||
| 1618 | /* existing tuner instance */ | ||
| 1619 | fe->tuner_priv = priv; | ||
| 1620 | break; | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | if (cfg->if_khz != 0) { | ||
| 1624 | /* copy configuration if provided by the caller */ | ||
| 1625 | priv->if_khz = cfg->if_khz; | ||
| 1626 | priv->default_pm = cfg->default_pm; | ||
| 1627 | priv->dvb_amplitude = cfg->dvb_amplitude; | ||
| 1628 | priv->set_smoothedcvbs = cfg->set_smoothedcvbs; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | /* Check if firmware has been loaded. It is possible that another | ||
| 1632 | instance of the driver has loaded the firmware. | ||
| 1633 | */ | ||
| 1634 | |||
| 1635 | if (instance == 1) { | ||
| 1636 | if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) | ||
| 1637 | goto fail; | ||
| 1638 | } else { | ||
| 1639 | id = ((priv->cur_fw.type & BASE) != 0 ? | ||
| 1640 | priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | switch (id) { | ||
| 1644 | case XC_PRODUCT_ID_XC4000: | ||
| 1645 | case XC_PRODUCT_ID_XC4100: | ||
| 1646 | printk(KERN_INFO | ||
| 1647 | "xc4000: Successfully identified at address 0x%02x\n", | ||
| 1648 | cfg->i2c_address); | ||
| 1649 | printk(KERN_INFO | ||
| 1650 | "xc4000: Firmware has been loaded previously\n"); | ||
| 1651 | break; | ||
| 1652 | case XC_PRODUCT_ID_FW_NOT_LOADED: | ||
| 1653 | printk(KERN_INFO | ||
| 1654 | "xc4000: Successfully identified at address 0x%02x\n", | ||
| 1655 | cfg->i2c_address); | ||
| 1656 | printk(KERN_INFO | ||
| 1657 | "xc4000: Firmware has not been loaded previously\n"); | ||
| 1658 | break; | ||
| 1659 | default: | ||
| 1660 | printk(KERN_ERR | ||
| 1661 | "xc4000: Device not found at addr 0x%02x (0x%x)\n", | ||
| 1662 | cfg->i2c_address, id); | ||
| 1663 | goto fail; | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | mutex_unlock(&xc4000_list_mutex); | ||
| 1667 | |||
| 1668 | memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, | ||
| 1669 | sizeof(struct dvb_tuner_ops)); | ||
| 1670 | |||
| 1671 | if (instance == 1) { | ||
| 1672 | int ret; | ||
| 1673 | mutex_lock(&priv->lock); | ||
| 1674 | ret = xc4000_fwupload(fe); | ||
| 1675 | mutex_unlock(&priv->lock); | ||
| 1676 | if (ret != 0) | ||
| 1677 | goto fail2; | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | return fe; | ||
| 1681 | fail: | ||
| 1682 | mutex_unlock(&xc4000_list_mutex); | ||
| 1683 | fail2: | ||
| 1684 | xc4000_release(fe); | ||
| 1685 | return NULL; | ||
| 1686 | } | ||
| 1687 | EXPORT_SYMBOL(xc4000_attach); | ||
| 1688 | |||
| 1689 | MODULE_AUTHOR("Steven Toth, Davide Ferri"); | ||
| 1690 | MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); | ||
| 1691 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/common/tuners/xc4000.h new file mode 100644 index 00000000000..e6a44d151cb --- /dev/null +++ b/drivers/media/common/tuners/xc4000.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
| 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 | #ifndef __XC4000_H__ | ||
| 23 | #define __XC4000_H__ | ||
| 24 | |||
| 25 | #include <linux/firmware.h> | ||
| 26 | |||
| 27 | struct dvb_frontend; | ||
| 28 | struct i2c_adapter; | ||
| 29 | |||
| 30 | struct xc4000_config { | ||
| 31 | u8 i2c_address; | ||
| 32 | /* if non-zero, power management is enabled by default */ | ||
| 33 | u8 default_pm; | ||
| 34 | /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */ | ||
| 35 | u8 dvb_amplitude; | ||
| 36 | /* if non-zero, register 0x0E is set to filter analog TV video output */ | ||
| 37 | u8 set_smoothedcvbs; | ||
| 38 | /* IF for DVB-T */ | ||
| 39 | u32 if_khz; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* xc4000 callback command */ | ||
| 43 | #define XC4000_TUNER_RESET 0 | ||
| 44 | |||
| 45 | /* For each bridge framework, when it attaches either analog or digital, | ||
| 46 | * it has to store a reference back to its _core equivalent structure, | ||
| 47 | * so that it can service the hardware by steering gpio's etc. | ||
| 48 | * Each bridge implementation is different so cast devptr accordingly. | ||
| 49 | * The xc4000 driver cares not for this value, other than ensuring | ||
| 50 | * it's passed back to a bridge during tuner_callback(). | ||
| 51 | */ | ||
| 52 | |||
| 53 | #if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE)) | ||
| 54 | extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | ||
| 55 | struct i2c_adapter *i2c, | ||
| 56 | struct xc4000_config *cfg); | ||
| 57 | #else | ||
| 58 | static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | ||
| 59 | struct i2c_adapter *i2c, | ||
| 60 | struct xc4000_config *cfg) | ||
| 61 | { | ||
| 62 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 63 | return NULL; | ||
| 64 | } | ||
| 65 | #endif | ||
| 66 | |||
| 67 | #endif | ||
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c new file mode 100644 index 00000000000..aa1b2e844d3 --- /dev/null +++ b/drivers/media/common/tuners/xc5000.c | |||
| @@ -0,0 +1,1201 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Xceive Corporation | ||
| 5 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
| 6 | * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 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 | * | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/moduleparam.h> | ||
| 26 | #include <linux/videodev2.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | #include <linux/dvb/frontend.h> | ||
| 29 | #include <linux/i2c.h> | ||
| 30 | |||
| 31 | #include "dvb_frontend.h" | ||
| 32 | |||
| 33 | #include "xc5000.h" | ||
| 34 | #include "tuner-i2c.h" | ||
| 35 | |||
| 36 | static int debug; | ||
| 37 | module_param(debug, int, 0644); | ||
| 38 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 39 | |||
| 40 | static int no_poweroff; | ||
| 41 | module_param(no_poweroff, int, 0644); | ||
| 42 | MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" | ||
| 43 | "\t\t1 keep device energized and with tuner ready all the times.\n" | ||
| 44 | "\t\tFaster, but consumes more power and keeps the device hotter"); | ||
| 45 | |||
| 46 | static DEFINE_MUTEX(xc5000_list_mutex); | ||
| 47 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
| 48 | |||
| 49 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | ||
| 50 | printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) | ||
| 51 | |||
| 52 | #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" | ||
| 53 | #define XC5000_DEFAULT_FIRMWARE_SIZE 12401 | ||
| 54 | |||
| 55 | struct xc5000_priv { | ||
| 56 | struct tuner_i2c_props i2c_props; | ||
| 57 | struct list_head hybrid_tuner_instance_list; | ||
| 58 | |||
| 59 | u32 if_khz; | ||
| 60 | u32 freq_hz; | ||
| 61 | u32 bandwidth; | ||
| 62 | u8 video_standard; | ||
| 63 | u8 rf_mode; | ||
| 64 | u8 radio_input; | ||
| 65 | }; | ||
| 66 | |||
| 67 | /* Misc Defines */ | ||
| 68 | #define MAX_TV_STANDARD 24 | ||
| 69 | #define XC_MAX_I2C_WRITE_LENGTH 64 | ||
| 70 | |||
| 71 | /* Signal Types */ | ||
| 72 | #define XC_RF_MODE_AIR 0 | ||
| 73 | #define XC_RF_MODE_CABLE 1 | ||
| 74 | |||
| 75 | /* Result codes */ | ||
| 76 | #define XC_RESULT_SUCCESS 0 | ||
| 77 | #define XC_RESULT_RESET_FAILURE 1 | ||
| 78 | #define XC_RESULT_I2C_WRITE_FAILURE 2 | ||
| 79 | #define XC_RESULT_I2C_READ_FAILURE 3 | ||
| 80 | #define XC_RESULT_OUT_OF_RANGE 5 | ||
| 81 | |||
| 82 | /* Product id */ | ||
| 83 | #define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 | ||
| 84 | #define XC_PRODUCT_ID_FW_LOADED 0x1388 | ||
| 85 | |||
| 86 | /* Registers */ | ||
| 87 | #define XREG_INIT 0x00 | ||
| 88 | #define XREG_VIDEO_MODE 0x01 | ||
| 89 | #define XREG_AUDIO_MODE 0x02 | ||
| 90 | #define XREG_RF_FREQ 0x03 | ||
| 91 | #define XREG_D_CODE 0x04 | ||
| 92 | #define XREG_IF_OUT 0x05 | ||
| 93 | #define XREG_SEEK_MODE 0x07 | ||
| 94 | #define XREG_POWER_DOWN 0x0A /* Obsolete */ | ||
| 95 | /* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ | ||
| 96 | #define XREG_OUTPUT_AMP 0x0B | ||
| 97 | #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ | ||
| 98 | #define XREG_SMOOTHEDCVBS 0x0E | ||
| 99 | #define XREG_XTALFREQ 0x0F | ||
| 100 | #define XREG_FINERFREQ 0x10 | ||
| 101 | #define XREG_DDIMODE 0x11 | ||
| 102 | |||
| 103 | #define XREG_ADC_ENV 0x00 | ||
| 104 | #define XREG_QUALITY 0x01 | ||
| 105 | #define XREG_FRAME_LINES 0x02 | ||
| 106 | #define XREG_HSYNC_FREQ 0x03 | ||
| 107 | #define XREG_LOCK 0x04 | ||
| 108 | #define XREG_FREQ_ERROR 0x05 | ||
| 109 | #define XREG_SNR 0x06 | ||
| 110 | #define XREG_VERSION 0x07 | ||
| 111 | #define XREG_PRODUCT_ID 0x08 | ||
| 112 | #define XREG_BUSY 0x09 | ||
| 113 | #define XREG_BUILD 0x0D | ||
| 114 | |||
| 115 | /* | ||
| 116 | Basic firmware description. This will remain with | ||
| 117 | the driver for documentation purposes. | ||
| 118 | |||
| 119 | This represents an I2C firmware file encoded as a | ||
| 120 | string of unsigned char. Format is as follows: | ||
| 121 | |||
| 122 | char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB | ||
| 123 | char[1 ]=len0_LSB -> length of first write transaction | ||
| 124 | char[2 ]=data0 -> first byte to be sent | ||
| 125 | char[3 ]=data1 | ||
| 126 | char[4 ]=data2 | ||
| 127 | char[ ]=... | ||
| 128 | char[M ]=dataN -> last byte to be sent | ||
| 129 | char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB | ||
| 130 | char[M+2]=len1_LSB -> length of second write transaction | ||
| 131 | char[M+3]=data0 | ||
| 132 | char[M+4]=data1 | ||
| 133 | ... | ||
| 134 | etc. | ||
| 135 | |||
| 136 | The [len] value should be interpreted as follows: | ||
| 137 | |||
| 138 | len= len_MSB _ len_LSB | ||
| 139 | len=1111_1111_1111_1111 : End of I2C_SEQUENCE | ||
| 140 | len=0000_0000_0000_0000 : Reset command: Do hardware reset | ||
| 141 | len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) | ||
| 142 | len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms | ||
| 143 | |||
| 144 | For the RESET and WAIT commands, the two following bytes will contain | ||
| 145 | immediately the length of the following transaction. | ||
| 146 | |||
| 147 | */ | ||
| 148 | struct XC_TV_STANDARD { | ||
| 149 | char *Name; | ||
| 150 | u16 AudioMode; | ||
| 151 | u16 VideoMode; | ||
| 152 | }; | ||
| 153 | |||
| 154 | /* Tuner standards */ | ||
| 155 | #define MN_NTSC_PAL_BTSC 0 | ||
| 156 | #define MN_NTSC_PAL_A2 1 | ||
| 157 | #define MN_NTSC_PAL_EIAJ 2 | ||
| 158 | #define MN_NTSC_PAL_Mono 3 | ||
| 159 | #define BG_PAL_A2 4 | ||
| 160 | #define BG_PAL_NICAM 5 | ||
| 161 | #define BG_PAL_MONO 6 | ||
| 162 | #define I_PAL_NICAM 7 | ||
| 163 | #define I_PAL_NICAM_MONO 8 | ||
| 164 | #define DK_PAL_A2 9 | ||
| 165 | #define DK_PAL_NICAM 10 | ||
| 166 | #define DK_PAL_MONO 11 | ||
| 167 | #define DK_SECAM_A2DK1 12 | ||
| 168 | #define DK_SECAM_A2LDK3 13 | ||
| 169 | #define DK_SECAM_A2MONO 14 | ||
| 170 | #define L_SECAM_NICAM 15 | ||
| 171 | #define LC_SECAM_NICAM 16 | ||
| 172 | #define DTV6 17 | ||
| 173 | #define DTV8 18 | ||
| 174 | #define DTV7_8 19 | ||
| 175 | #define DTV7 20 | ||
| 176 | #define FM_Radio_INPUT2 21 | ||
| 177 | #define FM_Radio_INPUT1 22 | ||
| 178 | #define FM_Radio_INPUT1_MONO 23 | ||
| 179 | |||
| 180 | static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { | ||
| 181 | {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, | ||
| 182 | {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, | ||
| 183 | {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, | ||
| 184 | {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, | ||
| 185 | {"B/G-PAL-A2", 0x0A00, 0x8049}, | ||
| 186 | {"B/G-PAL-NICAM", 0x0C04, 0x8049}, | ||
| 187 | {"B/G-PAL-MONO", 0x0878, 0x8059}, | ||
| 188 | {"I-PAL-NICAM", 0x1080, 0x8009}, | ||
| 189 | {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, | ||
| 190 | {"D/K-PAL-A2", 0x1600, 0x8009}, | ||
| 191 | {"D/K-PAL-NICAM", 0x0E80, 0x8009}, | ||
| 192 | {"D/K-PAL-MONO", 0x1478, 0x8009}, | ||
| 193 | {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, | ||
| 194 | {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, | ||
| 195 | {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, | ||
| 196 | {"L-SECAM-NICAM", 0x8E82, 0x0009}, | ||
| 197 | {"L'-SECAM-NICAM", 0x8E82, 0x4009}, | ||
| 198 | {"DTV6", 0x00C0, 0x8002}, | ||
| 199 | {"DTV8", 0x00C0, 0x800B}, | ||
| 200 | {"DTV7/8", 0x00C0, 0x801B}, | ||
| 201 | {"DTV7", 0x00C0, 0x8007}, | ||
| 202 | {"FM Radio-INPUT2", 0x9802, 0x9002}, | ||
| 203 | {"FM Radio-INPUT1", 0x0208, 0x9002}, | ||
| 204 | {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} | ||
| 205 | }; | ||
| 206 | |||
| 207 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); | ||
| 208 | static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); | ||
| 209 | static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); | ||
| 210 | static int xc5000_TunerReset(struct dvb_frontend *fe); | ||
| 211 | |||
| 212 | static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) | ||
| 213 | { | ||
| 214 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, | ||
| 215 | .flags = 0, .buf = buf, .len = len }; | ||
| 216 | |||
| 217 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { | ||
| 218 | printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); | ||
| 219 | return XC_RESULT_I2C_WRITE_FAILURE; | ||
| 220 | } | ||
| 221 | return XC_RESULT_SUCCESS; | ||
| 222 | } | ||
| 223 | |||
| 224 | #if 0 | ||
| 225 | /* This routine is never used because the only time we read data from the | ||
| 226 | i2c bus is when we read registers, and we want that to be an atomic i2c | ||
| 227 | transaction in case we are on a multi-master bus */ | ||
| 228 | static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) | ||
| 229 | { | ||
| 230 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, | ||
| 231 | .flags = I2C_M_RD, .buf = buf, .len = len }; | ||
| 232 | |||
| 233 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { | ||
| 234 | printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); | ||
| 235 | return -EREMOTEIO; | ||
| 236 | } | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | #endif | ||
| 240 | |||
| 241 | static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) | ||
| 242 | { | ||
| 243 | u8 buf[2] = { reg >> 8, reg & 0xff }; | ||
| 244 | u8 bval[2] = { 0, 0 }; | ||
| 245 | struct i2c_msg msg[2] = { | ||
| 246 | { .addr = priv->i2c_props.addr, | ||
| 247 | .flags = 0, .buf = &buf[0], .len = 2 }, | ||
| 248 | { .addr = priv->i2c_props.addr, | ||
| 249 | .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, | ||
| 250 | }; | ||
| 251 | |||
| 252 | if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { | ||
| 253 | printk(KERN_WARNING "xc5000: I2C read failed\n"); | ||
| 254 | return -EREMOTEIO; | ||
| 255 | } | ||
| 256 | |||
| 257 | *val = (bval[0] << 8) | bval[1]; | ||
| 258 | return XC_RESULT_SUCCESS; | ||
| 259 | } | ||
| 260 | |||
| 261 | static void xc_wait(int wait_ms) | ||
| 262 | { | ||
| 263 | msleep(wait_ms); | ||
| 264 | } | ||
| 265 | |||
| 266 | static int xc5000_TunerReset(struct dvb_frontend *fe) | ||
| 267 | { | ||
| 268 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 269 | int ret; | ||
| 270 | |||
| 271 | dprintk(1, "%s()\n", __func__); | ||
| 272 | |||
| 273 | if (fe->callback) { | ||
| 274 | ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? | ||
| 275 | fe->dvb->priv : | ||
| 276 | priv->i2c_props.adap->algo_data, | ||
| 277 | DVB_FRONTEND_COMPONENT_TUNER, | ||
| 278 | XC5000_TUNER_RESET, 0); | ||
| 279 | if (ret) { | ||
| 280 | printk(KERN_ERR "xc5000: reset failed\n"); | ||
| 281 | return XC_RESULT_RESET_FAILURE; | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); | ||
| 285 | return XC_RESULT_RESET_FAILURE; | ||
| 286 | } | ||
| 287 | return XC_RESULT_SUCCESS; | ||
| 288 | } | ||
| 289 | |||
| 290 | static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) | ||
| 291 | { | ||
| 292 | u8 buf[4]; | ||
| 293 | int WatchDogTimer = 100; | ||
| 294 | int result; | ||
| 295 | |||
| 296 | buf[0] = (regAddr >> 8) & 0xFF; | ||
| 297 | buf[1] = regAddr & 0xFF; | ||
| 298 | buf[2] = (i2cData >> 8) & 0xFF; | ||
| 299 | buf[3] = i2cData & 0xFF; | ||
| 300 | result = xc_send_i2c_data(priv, buf, 4); | ||
| 301 | if (result == XC_RESULT_SUCCESS) { | ||
| 302 | /* wait for busy flag to clear */ | ||
| 303 | while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { | ||
| 304 | result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); | ||
| 305 | if (result == XC_RESULT_SUCCESS) { | ||
| 306 | if ((buf[0] == 0) && (buf[1] == 0)) { | ||
| 307 | /* busy flag cleared */ | ||
| 308 | break; | ||
| 309 | } else { | ||
| 310 | xc_wait(5); /* wait 5 ms */ | ||
| 311 | WatchDogTimer--; | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | if (WatchDogTimer < 0) | ||
| 317 | result = XC_RESULT_I2C_WRITE_FAILURE; | ||
| 318 | |||
| 319 | return result; | ||
| 320 | } | ||
| 321 | |||
| 322 | static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) | ||
| 323 | { | ||
| 324 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 325 | |||
| 326 | int i, nbytes_to_send, result; | ||
| 327 | unsigned int len, pos, index; | ||
| 328 | u8 buf[XC_MAX_I2C_WRITE_LENGTH]; | ||
| 329 | |||
| 330 | index = 0; | ||
| 331 | while ((i2c_sequence[index] != 0xFF) || | ||
| 332 | (i2c_sequence[index + 1] != 0xFF)) { | ||
| 333 | len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; | ||
| 334 | if (len == 0x0000) { | ||
| 335 | /* RESET command */ | ||
| 336 | result = xc5000_TunerReset(fe); | ||
| 337 | index += 2; | ||
| 338 | if (result != XC_RESULT_SUCCESS) | ||
| 339 | return result; | ||
| 340 | } else if (len & 0x8000) { | ||
| 341 | /* WAIT command */ | ||
| 342 | xc_wait(len & 0x7FFF); | ||
| 343 | index += 2; | ||
| 344 | } else { | ||
| 345 | /* Send i2c data whilst ensuring individual transactions | ||
| 346 | * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. | ||
| 347 | */ | ||
| 348 | index += 2; | ||
| 349 | buf[0] = i2c_sequence[index]; | ||
| 350 | buf[1] = i2c_sequence[index + 1]; | ||
| 351 | pos = 2; | ||
| 352 | while (pos < len) { | ||
| 353 | if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) | ||
| 354 | nbytes_to_send = | ||
| 355 | XC_MAX_I2C_WRITE_LENGTH; | ||
| 356 | else | ||
| 357 | nbytes_to_send = (len - pos + 2); | ||
| 358 | for (i = 2; i < nbytes_to_send; i++) { | ||
| 359 | buf[i] = i2c_sequence[index + pos + | ||
| 360 | i - 2]; | ||
| 361 | } | ||
| 362 | result = xc_send_i2c_data(priv, buf, | ||
| 363 | nbytes_to_send); | ||
| 364 | |||
| 365 | if (result != XC_RESULT_SUCCESS) | ||
| 366 | return result; | ||
| 367 | |||
| 368 | pos += nbytes_to_send - 2; | ||
| 369 | } | ||
| 370 | index += len; | ||
| 371 | } | ||
| 372 | } | ||
| 373 | return XC_RESULT_SUCCESS; | ||
| 374 | } | ||
| 375 | |||
| 376 | static int xc_initialize(struct xc5000_priv *priv) | ||
| 377 | { | ||
| 378 | dprintk(1, "%s()\n", __func__); | ||
| 379 | return xc_write_reg(priv, XREG_INIT, 0); | ||
| 380 | } | ||
| 381 | |||
| 382 | static int xc_SetTVStandard(struct xc5000_priv *priv, | ||
| 383 | u16 VideoMode, u16 AudioMode) | ||
| 384 | { | ||
| 385 | int ret; | ||
| 386 | dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); | ||
| 387 | dprintk(1, "%s() Standard = %s\n", | ||
| 388 | __func__, | ||
| 389 | XC5000_Standard[priv->video_standard].Name); | ||
| 390 | |||
| 391 | ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); | ||
| 392 | if (ret == XC_RESULT_SUCCESS) | ||
| 393 | ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); | ||
| 394 | |||
| 395 | return ret; | ||
| 396 | } | ||
| 397 | |||
| 398 | static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) | ||
| 399 | { | ||
| 400 | dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, | ||
| 401 | rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); | ||
| 402 | |||
| 403 | if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { | ||
| 404 | rf_mode = XC_RF_MODE_CABLE; | ||
| 405 | printk(KERN_ERR | ||
| 406 | "%s(), Invalid mode, defaulting to CABLE", | ||
| 407 | __func__); | ||
| 408 | } | ||
| 409 | return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); | ||
| 410 | } | ||
| 411 | |||
| 412 | static const struct dvb_tuner_ops xc5000_tuner_ops; | ||
| 413 | |||
| 414 | static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) | ||
| 415 | { | ||
| 416 | u16 freq_code; | ||
| 417 | |||
| 418 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
| 419 | |||
| 420 | if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || | ||
| 421 | (freq_hz < xc5000_tuner_ops.info.frequency_min)) | ||
| 422 | return XC_RESULT_OUT_OF_RANGE; | ||
| 423 | |||
| 424 | freq_code = (u16)(freq_hz / 15625); | ||
| 425 | |||
| 426 | /* Starting in firmware version 1.1.44, Xceive recommends using the | ||
| 427 | FINERFREQ for all normal tuning (the doc indicates reg 0x03 should | ||
| 428 | only be used for fast scanning for channel lock) */ | ||
| 429 | return xc_write_reg(priv, XREG_FINERFREQ, freq_code); | ||
| 430 | } | ||
| 431 | |||
| 432 | |||
| 433 | static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) | ||
| 434 | { | ||
| 435 | u32 freq_code = (freq_khz * 1024)/1000; | ||
| 436 | dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", | ||
| 437 | __func__, freq_khz, freq_code); | ||
| 438 | |||
| 439 | return xc_write_reg(priv, XREG_IF_OUT, freq_code); | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) | ||
| 444 | { | ||
| 445 | return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); | ||
| 446 | } | ||
| 447 | |||
| 448 | static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) | ||
| 449 | { | ||
| 450 | int result; | ||
| 451 | u16 regData; | ||
| 452 | u32 tmp; | ||
| 453 | |||
| 454 | result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); | ||
| 455 | if (result != XC_RESULT_SUCCESS) | ||
| 456 | return result; | ||
| 457 | |||
| 458 | tmp = (u32)regData; | ||
| 459 | (*freq_error_hz) = (tmp * 15625) / 1000; | ||
| 460 | return result; | ||
| 461 | } | ||
| 462 | |||
| 463 | static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) | ||
| 464 | { | ||
| 465 | return xc5000_readreg(priv, XREG_LOCK, lock_status); | ||
| 466 | } | ||
| 467 | |||
| 468 | static int xc_get_version(struct xc5000_priv *priv, | ||
| 469 | u8 *hw_majorversion, u8 *hw_minorversion, | ||
| 470 | u8 *fw_majorversion, u8 *fw_minorversion) | ||
| 471 | { | ||
| 472 | u16 data; | ||
| 473 | int result; | ||
| 474 | |||
| 475 | result = xc5000_readreg(priv, XREG_VERSION, &data); | ||
| 476 | if (result != XC_RESULT_SUCCESS) | ||
| 477 | return result; | ||
| 478 | |||
| 479 | (*hw_majorversion) = (data >> 12) & 0x0F; | ||
| 480 | (*hw_minorversion) = (data >> 8) & 0x0F; | ||
| 481 | (*fw_majorversion) = (data >> 4) & 0x0F; | ||
| 482 | (*fw_minorversion) = data & 0x0F; | ||
| 483 | |||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) | ||
| 488 | { | ||
| 489 | return xc5000_readreg(priv, XREG_BUILD, buildrev); | ||
| 490 | } | ||
| 491 | |||
| 492 | static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) | ||
| 493 | { | ||
| 494 | u16 regData; | ||
| 495 | int result; | ||
| 496 | |||
| 497 | result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); | ||
| 498 | if (result != XC_RESULT_SUCCESS) | ||
| 499 | return result; | ||
| 500 | |||
| 501 | (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; | ||
| 502 | return result; | ||
| 503 | } | ||
| 504 | |||
| 505 | static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) | ||
| 506 | { | ||
| 507 | return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); | ||
| 508 | } | ||
| 509 | |||
| 510 | static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) | ||
| 511 | { | ||
| 512 | return xc5000_readreg(priv, XREG_QUALITY, quality); | ||
| 513 | } | ||
| 514 | |||
| 515 | static u16 WaitForLock(struct xc5000_priv *priv) | ||
| 516 | { | ||
| 517 | u16 lockState = 0; | ||
| 518 | int watchDogCount = 40; | ||
| 519 | |||
| 520 | while ((lockState == 0) && (watchDogCount > 0)) { | ||
| 521 | xc_get_lock_status(priv, &lockState); | ||
| 522 | if (lockState != 1) { | ||
| 523 | xc_wait(5); | ||
| 524 | watchDogCount--; | ||
| 525 | } | ||
| 526 | } | ||
| 527 | return lockState; | ||
| 528 | } | ||
| 529 | |||
| 530 | #define XC_TUNE_ANALOG 0 | ||
| 531 | #define XC_TUNE_DIGITAL 1 | ||
| 532 | static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) | ||
| 533 | { | ||
| 534 | int found = 0; | ||
| 535 | |||
| 536 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
| 537 | |||
| 538 | if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) | ||
| 539 | return 0; | ||
| 540 | |||
| 541 | if (mode == XC_TUNE_ANALOG) { | ||
| 542 | if (WaitForLock(priv) == 1) | ||
| 543 | found = 1; | ||
| 544 | } | ||
| 545 | |||
| 546 | return found; | ||
| 547 | } | ||
| 548 | |||
| 549 | |||
| 550 | static int xc5000_fwupload(struct dvb_frontend *fe) | ||
| 551 | { | ||
| 552 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 553 | const struct firmware *fw; | ||
| 554 | int ret; | ||
| 555 | |||
| 556 | /* request the firmware, this will block and timeout */ | ||
| 557 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", | ||
| 558 | XC5000_DEFAULT_FIRMWARE); | ||
| 559 | |||
| 560 | ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, | ||
| 561 | priv->i2c_props.adap->dev.parent); | ||
| 562 | if (ret) { | ||
| 563 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); | ||
| 564 | ret = XC_RESULT_RESET_FAILURE; | ||
| 565 | goto out; | ||
| 566 | } else { | ||
| 567 | printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", | ||
| 568 | fw->size); | ||
| 569 | ret = XC_RESULT_SUCCESS; | ||
| 570 | } | ||
| 571 | |||
| 572 | if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { | ||
| 573 | printk(KERN_ERR "xc5000: firmware incorrect size\n"); | ||
| 574 | ret = XC_RESULT_RESET_FAILURE; | ||
| 575 | } else { | ||
| 576 | printk(KERN_INFO "xc5000: firmware uploading...\n"); | ||
| 577 | ret = xc_load_i2c_sequence(fe, fw->data); | ||
| 578 | printk(KERN_INFO "xc5000: firmware upload complete...\n"); | ||
| 579 | } | ||
| 580 | |||
| 581 | out: | ||
| 582 | release_firmware(fw); | ||
| 583 | return ret; | ||
| 584 | } | ||
| 585 | |||
| 586 | static void xc_debug_dump(struct xc5000_priv *priv) | ||
| 587 | { | ||
| 588 | u16 adc_envelope; | ||
| 589 | u32 freq_error_hz = 0; | ||
| 590 | u16 lock_status; | ||
| 591 | u32 hsync_freq_hz = 0; | ||
| 592 | u16 frame_lines; | ||
| 593 | u16 quality; | ||
| 594 | u8 hw_majorversion = 0, hw_minorversion = 0; | ||
| 595 | u8 fw_majorversion = 0, fw_minorversion = 0; | ||
| 596 | u16 fw_buildversion = 0; | ||
| 597 | |||
| 598 | /* Wait for stats to stabilize. | ||
| 599 | * Frame Lines needs two frame times after initial lock | ||
| 600 | * before it is valid. | ||
| 601 | */ | ||
| 602 | xc_wait(100); | ||
| 603 | |||
| 604 | xc_get_ADC_Envelope(priv, &adc_envelope); | ||
| 605 | dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); | ||
| 606 | |||
| 607 | xc_get_frequency_error(priv, &freq_error_hz); | ||
| 608 | dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); | ||
| 609 | |||
| 610 | xc_get_lock_status(priv, &lock_status); | ||
| 611 | dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", | ||
| 612 | lock_status); | ||
| 613 | |||
| 614 | xc_get_version(priv, &hw_majorversion, &hw_minorversion, | ||
| 615 | &fw_majorversion, &fw_minorversion); | ||
| 616 | xc_get_buildversion(priv, &fw_buildversion); | ||
| 617 | dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n", | ||
| 618 | hw_majorversion, hw_minorversion, | ||
| 619 | fw_majorversion, fw_minorversion, fw_buildversion); | ||
| 620 | |||
| 621 | xc_get_hsync_freq(priv, &hsync_freq_hz); | ||
| 622 | dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); | ||
| 623 | |||
| 624 | xc_get_frame_lines(priv, &frame_lines); | ||
| 625 | dprintk(1, "*** Frame lines = %d\n", frame_lines); | ||
| 626 | |||
| 627 | xc_get_quality(priv, &quality); | ||
| 628 | dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); | ||
| 629 | } | ||
| 630 | |||
| 631 | /* | ||
| 632 | * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. | ||
| 633 | * So, the amount of the needed bandwith is given by: | ||
| 634 | * Bw = Symbol_rate * (1 + 0.15) | ||
| 635 | * As such, the maximum symbol rate supported by 6 MHz is given by: | ||
| 636 | * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds | ||
| 637 | */ | ||
| 638 | #define MAX_SYMBOL_RATE_6MHz 5217391 | ||
| 639 | |||
| 640 | static int xc5000_set_params(struct dvb_frontend *fe, | ||
| 641 | struct dvb_frontend_parameters *params) | ||
| 642 | { | ||
| 643 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 644 | int ret; | ||
| 645 | |||
| 646 | if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { | ||
| 647 | if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { | ||
| 648 | dprintk(1, "Unable to load firmware and init tuner\n"); | ||
| 649 | return -EINVAL; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); | ||
| 654 | |||
| 655 | if (fe->ops.info.type == FE_ATSC) { | ||
| 656 | dprintk(1, "%s() ATSC\n", __func__); | ||
| 657 | switch (params->u.vsb.modulation) { | ||
| 658 | case VSB_8: | ||
| 659 | case VSB_16: | ||
| 660 | dprintk(1, "%s() VSB modulation\n", __func__); | ||
| 661 | priv->rf_mode = XC_RF_MODE_AIR; | ||
| 662 | priv->freq_hz = params->frequency - 1750000; | ||
| 663 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 664 | priv->video_standard = DTV6; | ||
| 665 | break; | ||
| 666 | case QAM_64: | ||
| 667 | case QAM_256: | ||
| 668 | case QAM_AUTO: | ||
| 669 | dprintk(1, "%s() QAM modulation\n", __func__); | ||
| 670 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
| 671 | priv->freq_hz = params->frequency - 1750000; | ||
| 672 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 673 | priv->video_standard = DTV6; | ||
| 674 | break; | ||
| 675 | default: | ||
| 676 | return -EINVAL; | ||
| 677 | } | ||
| 678 | } else if (fe->ops.info.type == FE_OFDM) { | ||
| 679 | dprintk(1, "%s() OFDM\n", __func__); | ||
| 680 | switch (params->u.ofdm.bandwidth) { | ||
| 681 | case BANDWIDTH_6_MHZ: | ||
| 682 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 683 | priv->video_standard = DTV6; | ||
| 684 | priv->freq_hz = params->frequency - 1750000; | ||
| 685 | break; | ||
| 686 | case BANDWIDTH_7_MHZ: | ||
| 687 | printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); | ||
| 688 | return -EINVAL; | ||
| 689 | case BANDWIDTH_8_MHZ: | ||
| 690 | priv->bandwidth = BANDWIDTH_8_MHZ; | ||
| 691 | priv->video_standard = DTV8; | ||
| 692 | priv->freq_hz = params->frequency - 2750000; | ||
| 693 | break; | ||
| 694 | default: | ||
| 695 | printk(KERN_ERR "xc5000 bandwidth not set!\n"); | ||
| 696 | return -EINVAL; | ||
| 697 | } | ||
| 698 | priv->rf_mode = XC_RF_MODE_AIR; | ||
| 699 | } else if (fe->ops.info.type == FE_QAM) { | ||
| 700 | switch (params->u.qam.modulation) { | ||
| 701 | case QAM_256: | ||
| 702 | case QAM_AUTO: | ||
| 703 | case QAM_16: | ||
| 704 | case QAM_32: | ||
| 705 | case QAM_64: | ||
| 706 | case QAM_128: | ||
| 707 | dprintk(1, "%s() QAM modulation\n", __func__); | ||
| 708 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
| 709 | /* | ||
| 710 | * Using a 8MHz bandwidth sometimes fail | ||
| 711 | * with 6MHz-spaced channels, due to inter-carrier | ||
| 712 | * interference. So, use DTV6 firmware | ||
| 713 | */ | ||
| 714 | if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) { | ||
| 715 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 716 | priv->video_standard = DTV6; | ||
| 717 | priv->freq_hz = params->frequency - 1750000; | ||
| 718 | } else { | ||
| 719 | priv->bandwidth = BANDWIDTH_8_MHZ; | ||
| 720 | priv->video_standard = DTV7_8; | ||
| 721 | priv->freq_hz = params->frequency - 2750000; | ||
| 722 | } | ||
| 723 | break; | ||
| 724 | default: | ||
| 725 | dprintk(1, "%s() Unsupported QAM type\n", __func__); | ||
| 726 | return -EINVAL; | ||
| 727 | } | ||
| 728 | } else { | ||
| 729 | printk(KERN_ERR "xc5000 modulation type not supported!\n"); | ||
| 730 | return -EINVAL; | ||
| 731 | } | ||
| 732 | |||
| 733 | dprintk(1, "%s() frequency=%d (compensated)\n", | ||
| 734 | __func__, priv->freq_hz); | ||
| 735 | |||
| 736 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
| 737 | if (ret != XC_RESULT_SUCCESS) { | ||
| 738 | printk(KERN_ERR | ||
| 739 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
| 740 | priv->rf_mode); | ||
| 741 | return -EREMOTEIO; | ||
| 742 | } | ||
| 743 | |||
| 744 | ret = xc_SetTVStandard(priv, | ||
| 745 | XC5000_Standard[priv->video_standard].VideoMode, | ||
| 746 | XC5000_Standard[priv->video_standard].AudioMode); | ||
| 747 | if (ret != XC_RESULT_SUCCESS) { | ||
| 748 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
| 749 | return -EREMOTEIO; | ||
| 750 | } | ||
| 751 | |||
| 752 | ret = xc_set_IF_frequency(priv, priv->if_khz); | ||
| 753 | if (ret != XC_RESULT_SUCCESS) { | ||
| 754 | printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", | ||
| 755 | priv->if_khz); | ||
| 756 | return -EIO; | ||
| 757 | } | ||
| 758 | |||
| 759 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); | ||
| 760 | |||
| 761 | xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); | ||
| 762 | |||
| 763 | if (debug) | ||
| 764 | xc_debug_dump(priv); | ||
| 765 | |||
| 766 | return 0; | ||
| 767 | } | ||
| 768 | |||
| 769 | static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) | ||
| 770 | { | ||
| 771 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 772 | int ret; | ||
| 773 | u16 id; | ||
| 774 | |||
| 775 | ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); | ||
| 776 | if (ret == XC_RESULT_SUCCESS) { | ||
| 777 | if (id == XC_PRODUCT_ID_FW_NOT_LOADED) | ||
| 778 | ret = XC_RESULT_RESET_FAILURE; | ||
| 779 | else | ||
| 780 | ret = XC_RESULT_SUCCESS; | ||
| 781 | } | ||
| 782 | |||
| 783 | dprintk(1, "%s() returns %s id = 0x%x\n", __func__, | ||
| 784 | ret == XC_RESULT_SUCCESS ? "True" : "False", id); | ||
| 785 | return ret; | ||
| 786 | } | ||
| 787 | |||
| 788 | static int xc5000_set_tv_freq(struct dvb_frontend *fe, | ||
| 789 | struct analog_parameters *params) | ||
| 790 | { | ||
| 791 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 792 | int ret; | ||
| 793 | |||
| 794 | dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", | ||
| 795 | __func__, params->frequency); | ||
| 796 | |||
| 797 | /* Fix me: it could be air. */ | ||
| 798 | priv->rf_mode = params->mode; | ||
| 799 | if (params->mode > XC_RF_MODE_CABLE) | ||
| 800 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
| 801 | |||
| 802 | /* params->frequency is in units of 62.5khz */ | ||
| 803 | priv->freq_hz = params->frequency * 62500; | ||
| 804 | |||
| 805 | /* FIX ME: Some video standards may have several possible audio | ||
| 806 | standards. We simply default to one of them here. | ||
| 807 | */ | ||
| 808 | if (params->std & V4L2_STD_MN) { | ||
| 809 | /* default to BTSC audio standard */ | ||
| 810 | priv->video_standard = MN_NTSC_PAL_BTSC; | ||
| 811 | goto tune_channel; | ||
| 812 | } | ||
| 813 | |||
| 814 | if (params->std & V4L2_STD_PAL_BG) { | ||
| 815 | /* default to NICAM audio standard */ | ||
| 816 | priv->video_standard = BG_PAL_NICAM; | ||
| 817 | goto tune_channel; | ||
| 818 | } | ||
| 819 | |||
| 820 | if (params->std & V4L2_STD_PAL_I) { | ||
| 821 | /* default to NICAM audio standard */ | ||
| 822 | priv->video_standard = I_PAL_NICAM; | ||
| 823 | goto tune_channel; | ||
| 824 | } | ||
| 825 | |||
| 826 | if (params->std & V4L2_STD_PAL_DK) { | ||
| 827 | /* default to NICAM audio standard */ | ||
| 828 | priv->video_standard = DK_PAL_NICAM; | ||
| 829 | goto tune_channel; | ||
| 830 | } | ||
| 831 | |||
| 832 | if (params->std & V4L2_STD_SECAM_DK) { | ||
| 833 | /* default to A2 DK1 audio standard */ | ||
| 834 | priv->video_standard = DK_SECAM_A2DK1; | ||
| 835 | goto tune_channel; | ||
| 836 | } | ||
| 837 | |||
| 838 | if (params->std & V4L2_STD_SECAM_L) { | ||
| 839 | priv->video_standard = L_SECAM_NICAM; | ||
| 840 | goto tune_channel; | ||
| 841 | } | ||
| 842 | |||
| 843 | if (params->std & V4L2_STD_SECAM_LC) { | ||
| 844 | priv->video_standard = LC_SECAM_NICAM; | ||
| 845 | goto tune_channel; | ||
| 846 | } | ||
| 847 | |||
| 848 | tune_channel: | ||
| 849 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
| 850 | if (ret != XC_RESULT_SUCCESS) { | ||
| 851 | printk(KERN_ERR | ||
| 852 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
| 853 | priv->rf_mode); | ||
| 854 | return -EREMOTEIO; | ||
| 855 | } | ||
| 856 | |||
| 857 | ret = xc_SetTVStandard(priv, | ||
| 858 | XC5000_Standard[priv->video_standard].VideoMode, | ||
| 859 | XC5000_Standard[priv->video_standard].AudioMode); | ||
| 860 | if (ret != XC_RESULT_SUCCESS) { | ||
| 861 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
| 862 | return -EREMOTEIO; | ||
| 863 | } | ||
| 864 | |||
| 865 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); | ||
| 866 | |||
| 867 | xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); | ||
| 868 | |||
| 869 | if (debug) | ||
| 870 | xc_debug_dump(priv); | ||
| 871 | |||
| 872 | return 0; | ||
| 873 | } | ||
| 874 | |||
| 875 | static int xc5000_set_radio_freq(struct dvb_frontend *fe, | ||
| 876 | struct analog_parameters *params) | ||
| 877 | { | ||
| 878 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 879 | int ret = -EINVAL; | ||
| 880 | u8 radio_input; | ||
| 881 | |||
| 882 | dprintk(1, "%s() frequency=%d (in units of khz)\n", | ||
| 883 | __func__, params->frequency); | ||
| 884 | |||
| 885 | if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { | ||
| 886 | dprintk(1, "%s() radio input not configured\n", __func__); | ||
| 887 | return -EINVAL; | ||
| 888 | } | ||
| 889 | |||
| 890 | if (priv->radio_input == XC5000_RADIO_FM1) | ||
| 891 | radio_input = FM_Radio_INPUT1; | ||
| 892 | else if (priv->radio_input == XC5000_RADIO_FM2) | ||
| 893 | radio_input = FM_Radio_INPUT2; | ||
| 894 | else if (priv->radio_input == XC5000_RADIO_FM1_MONO) | ||
| 895 | radio_input = FM_Radio_INPUT1_MONO; | ||
| 896 | else { | ||
| 897 | dprintk(1, "%s() unknown radio input %d\n", __func__, | ||
| 898 | priv->radio_input); | ||
| 899 | return -EINVAL; | ||
| 900 | } | ||
| 901 | |||
| 902 | priv->freq_hz = params->frequency * 125 / 2; | ||
| 903 | |||
| 904 | priv->rf_mode = XC_RF_MODE_AIR; | ||
| 905 | |||
| 906 | ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, | ||
| 907 | XC5000_Standard[radio_input].AudioMode); | ||
| 908 | |||
| 909 | if (ret != XC_RESULT_SUCCESS) { | ||
| 910 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
| 911 | return -EREMOTEIO; | ||
| 912 | } | ||
| 913 | |||
| 914 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
| 915 | if (ret != XC_RESULT_SUCCESS) { | ||
| 916 | printk(KERN_ERR | ||
| 917 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
| 918 | priv->rf_mode); | ||
| 919 | return -EREMOTEIO; | ||
| 920 | } | ||
| 921 | |||
| 922 | if ((priv->radio_input == XC5000_RADIO_FM1) || | ||
| 923 | (priv->radio_input == XC5000_RADIO_FM2)) | ||
| 924 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); | ||
| 925 | else if (priv->radio_input == XC5000_RADIO_FM1_MONO) | ||
| 926 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); | ||
| 927 | |||
| 928 | xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); | ||
| 929 | |||
| 930 | return 0; | ||
| 931 | } | ||
| 932 | |||
| 933 | static int xc5000_set_analog_params(struct dvb_frontend *fe, | ||
| 934 | struct analog_parameters *params) | ||
| 935 | { | ||
| 936 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 937 | int ret = -EINVAL; | ||
| 938 | |||
| 939 | if (priv->i2c_props.adap == NULL) | ||
| 940 | return -EINVAL; | ||
| 941 | |||
| 942 | if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { | ||
| 943 | if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { | ||
| 944 | dprintk(1, "Unable to load firmware and init tuner\n"); | ||
| 945 | return -EINVAL; | ||
| 946 | } | ||
| 947 | } | ||
| 948 | |||
| 949 | switch (params->mode) { | ||
| 950 | case V4L2_TUNER_RADIO: | ||
| 951 | ret = xc5000_set_radio_freq(fe, params); | ||
| 952 | break; | ||
| 953 | case V4L2_TUNER_ANALOG_TV: | ||
| 954 | case V4L2_TUNER_DIGITAL_TV: | ||
| 955 | ret = xc5000_set_tv_freq(fe, params); | ||
| 956 | break; | ||
| 957 | } | ||
| 958 | |||
| 959 | return ret; | ||
| 960 | } | ||
| 961 | |||
| 962 | |||
| 963 | static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) | ||
| 964 | { | ||
| 965 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 966 | dprintk(1, "%s()\n", __func__); | ||
| 967 | *freq = priv->freq_hz; | ||
| 968 | return 0; | ||
| 969 | } | ||
| 970 | |||
| 971 | static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
| 972 | { | ||
| 973 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 974 | dprintk(1, "%s()\n", __func__); | ||
| 975 | |||
| 976 | *bw = priv->bandwidth; | ||
| 977 | return 0; | ||
| 978 | } | ||
| 979 | |||
| 980 | static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) | ||
| 981 | { | ||
| 982 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 983 | u16 lock_status = 0; | ||
| 984 | |||
| 985 | xc_get_lock_status(priv, &lock_status); | ||
| 986 | |||
| 987 | dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); | ||
| 988 | |||
| 989 | *status = lock_status; | ||
| 990 | |||
| 991 | return 0; | ||
| 992 | } | ||
| 993 | |||
| 994 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) | ||
| 995 | { | ||
| 996 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 997 | int ret = 0; | ||
| 998 | |||
| 999 | if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { | ||
| 1000 | ret = xc5000_fwupload(fe); | ||
| 1001 | if (ret != XC_RESULT_SUCCESS) | ||
| 1002 | return ret; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | /* Start the tuner self-calibration process */ | ||
| 1006 | ret |= xc_initialize(priv); | ||
| 1007 | |||
| 1008 | /* Wait for calibration to complete. | ||
| 1009 | * We could continue but XC5000 will clock stretch subsequent | ||
| 1010 | * I2C transactions until calibration is complete. This way we | ||
| 1011 | * don't have to rely on clock stretching working. | ||
| 1012 | */ | ||
| 1013 | xc_wait(100); | ||
| 1014 | |||
| 1015 | /* Default to "CABLE" mode */ | ||
| 1016 | ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); | ||
| 1017 | |||
| 1018 | return ret; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | static int xc5000_sleep(struct dvb_frontend *fe) | ||
| 1022 | { | ||
| 1023 | int ret; | ||
| 1024 | |||
| 1025 | dprintk(1, "%s()\n", __func__); | ||
| 1026 | |||
| 1027 | /* Avoid firmware reload on slow devices */ | ||
| 1028 | if (no_poweroff) | ||
| 1029 | return 0; | ||
| 1030 | |||
| 1031 | /* According to Xceive technical support, the "powerdown" register | ||
| 1032 | was removed in newer versions of the firmware. The "supported" | ||
| 1033 | way to sleep the tuner is to pull the reset pin low for 10ms */ | ||
| 1034 | ret = xc5000_TunerReset(fe); | ||
| 1035 | if (ret != XC_RESULT_SUCCESS) { | ||
| 1036 | printk(KERN_ERR | ||
| 1037 | "xc5000: %s() unable to shutdown tuner\n", | ||
| 1038 | __func__); | ||
| 1039 | return -EREMOTEIO; | ||
| 1040 | } else | ||
| 1041 | return XC_RESULT_SUCCESS; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | static int xc5000_init(struct dvb_frontend *fe) | ||
| 1045 | { | ||
| 1046 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 1047 | dprintk(1, "%s()\n", __func__); | ||
| 1048 | |||
| 1049 | if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { | ||
| 1050 | printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); | ||
| 1051 | return -EREMOTEIO; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | if (debug) | ||
| 1055 | xc_debug_dump(priv); | ||
| 1056 | |||
| 1057 | return 0; | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | static int xc5000_release(struct dvb_frontend *fe) | ||
| 1061 | { | ||
| 1062 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 1063 | |||
| 1064 | dprintk(1, "%s()\n", __func__); | ||
| 1065 | |||
| 1066 | mutex_lock(&xc5000_list_mutex); | ||
| 1067 | |||
| 1068 | if (priv) | ||
| 1069 | hybrid_tuner_release_state(priv); | ||
| 1070 | |||
| 1071 | mutex_unlock(&xc5000_list_mutex); | ||
| 1072 | |||
| 1073 | fe->tuner_priv = NULL; | ||
| 1074 | |||
| 1075 | return 0; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
| 1079 | { | ||
| 1080 | struct xc5000_priv *priv = fe->tuner_priv; | ||
| 1081 | struct xc5000_config *p = priv_cfg; | ||
| 1082 | |||
| 1083 | dprintk(1, "%s()\n", __func__); | ||
| 1084 | |||
| 1085 | if (p->if_khz) | ||
| 1086 | priv->if_khz = p->if_khz; | ||
| 1087 | |||
| 1088 | if (p->radio_input) | ||
| 1089 | priv->radio_input = p->radio_input; | ||
| 1090 | |||
| 1091 | return 0; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | |||
| 1095 | static const struct dvb_tuner_ops xc5000_tuner_ops = { | ||
| 1096 | .info = { | ||
| 1097 | .name = "Xceive XC5000", | ||
| 1098 | .frequency_min = 1000000, | ||
| 1099 | .frequency_max = 1023000000, | ||
| 1100 | .frequency_step = 50000, | ||
| 1101 | }, | ||
| 1102 | |||
| 1103 | .release = xc5000_release, | ||
| 1104 | .init = xc5000_init, | ||
| 1105 | .sleep = xc5000_sleep, | ||
| 1106 | |||
| 1107 | .set_config = xc5000_set_config, | ||
| 1108 | .set_params = xc5000_set_params, | ||
| 1109 | .set_analog_params = xc5000_set_analog_params, | ||
| 1110 | .get_frequency = xc5000_get_frequency, | ||
| 1111 | .get_bandwidth = xc5000_get_bandwidth, | ||
| 1112 | .get_status = xc5000_get_status | ||
| 1113 | }; | ||
| 1114 | |||
| 1115 | struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | ||
| 1116 | struct i2c_adapter *i2c, | ||
| 1117 | const struct xc5000_config *cfg) | ||
| 1118 | { | ||
| 1119 | struct xc5000_priv *priv = NULL; | ||
| 1120 | int instance; | ||
| 1121 | u16 id = 0; | ||
| 1122 | |||
| 1123 | dprintk(1, "%s(%d-%04x)\n", __func__, | ||
| 1124 | i2c ? i2c_adapter_id(i2c) : -1, | ||
| 1125 | cfg ? cfg->i2c_address : -1); | ||
| 1126 | |||
| 1127 | mutex_lock(&xc5000_list_mutex); | ||
| 1128 | |||
| 1129 | instance = hybrid_tuner_request_state(struct xc5000_priv, priv, | ||
| 1130 | hybrid_tuner_instance_list, | ||
| 1131 | i2c, cfg->i2c_address, "xc5000"); | ||
| 1132 | switch (instance) { | ||
| 1133 | case 0: | ||
| 1134 | goto fail; | ||
| 1135 | break; | ||
| 1136 | case 1: | ||
| 1137 | /* new tuner instance */ | ||
| 1138 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
| 1139 | fe->tuner_priv = priv; | ||
| 1140 | break; | ||
| 1141 | default: | ||
| 1142 | /* existing tuner instance */ | ||
| 1143 | fe->tuner_priv = priv; | ||
| 1144 | break; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | if (priv->if_khz == 0) { | ||
| 1148 | /* If the IF hasn't been set yet, use the value provided by | ||
| 1149 | the caller (occurs in hybrid devices where the analog | ||
| 1150 | call to xc5000_attach occurs before the digital side) */ | ||
| 1151 | priv->if_khz = cfg->if_khz; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | if (priv->radio_input == 0) | ||
| 1155 | priv->radio_input = cfg->radio_input; | ||
| 1156 | |||
| 1157 | /* Check if firmware has been loaded. It is possible that another | ||
| 1158 | instance of the driver has loaded the firmware. | ||
| 1159 | */ | ||
| 1160 | if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) | ||
| 1161 | goto fail; | ||
| 1162 | |||
| 1163 | switch (id) { | ||
| 1164 | case XC_PRODUCT_ID_FW_LOADED: | ||
| 1165 | printk(KERN_INFO | ||
| 1166 | "xc5000: Successfully identified at address 0x%02x\n", | ||
| 1167 | cfg->i2c_address); | ||
| 1168 | printk(KERN_INFO | ||
| 1169 | "xc5000: Firmware has been loaded previously\n"); | ||
| 1170 | break; | ||
| 1171 | case XC_PRODUCT_ID_FW_NOT_LOADED: | ||
| 1172 | printk(KERN_INFO | ||
| 1173 | "xc5000: Successfully identified at address 0x%02x\n", | ||
| 1174 | cfg->i2c_address); | ||
| 1175 | printk(KERN_INFO | ||
| 1176 | "xc5000: Firmware has not been loaded previously\n"); | ||
| 1177 | break; | ||
| 1178 | default: | ||
| 1179 | printk(KERN_ERR | ||
| 1180 | "xc5000: Device not found at addr 0x%02x (0x%x)\n", | ||
| 1181 | cfg->i2c_address, id); | ||
| 1182 | goto fail; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | mutex_unlock(&xc5000_list_mutex); | ||
| 1186 | |||
| 1187 | memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, | ||
| 1188 | sizeof(struct dvb_tuner_ops)); | ||
| 1189 | |||
| 1190 | return fe; | ||
| 1191 | fail: | ||
| 1192 | mutex_unlock(&xc5000_list_mutex); | ||
| 1193 | |||
| 1194 | xc5000_release(fe); | ||
| 1195 | return NULL; | ||
| 1196 | } | ||
| 1197 | EXPORT_SYMBOL(xc5000_attach); | ||
| 1198 | |||
| 1199 | MODULE_AUTHOR("Steven Toth"); | ||
| 1200 | MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); | ||
| 1201 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h new file mode 100644 index 00000000000..e2957451b53 --- /dev/null +++ b/drivers/media/common/tuners/xc5000.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
| 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 | #ifndef __XC5000_H__ | ||
| 23 | #define __XC5000_H__ | ||
| 24 | |||
| 25 | #include <linux/firmware.h> | ||
| 26 | |||
| 27 | struct dvb_frontend; | ||
| 28 | struct i2c_adapter; | ||
| 29 | |||
| 30 | struct xc5000_config { | ||
| 31 | u8 i2c_address; | ||
| 32 | u32 if_khz; | ||
| 33 | u8 radio_input; | ||
| 34 | }; | ||
| 35 | |||
| 36 | /* xc5000 callback command */ | ||
| 37 | #define XC5000_TUNER_RESET 0 | ||
| 38 | |||
| 39 | /* Possible Radio inputs */ | ||
| 40 | #define XC5000_RADIO_NOT_CONFIGURED 0 | ||
| 41 | #define XC5000_RADIO_FM1 1 | ||
| 42 | #define XC5000_RADIO_FM2 2 | ||
| 43 | #define XC5000_RADIO_FM1_MONO 3 | ||
| 44 | |||
| 45 | /* For each bridge framework, when it attaches either analog or digital, | ||
| 46 | * it has to store a reference back to its _core equivalent structure, | ||
| 47 | * so that it can service the hardware by steering gpio's etc. | ||
| 48 | * Each bridge implementation is different so cast devptr accordingly. | ||
| 49 | * The xc5000 driver cares not for this value, other than ensuring | ||
| 50 | * it's passed back to a bridge during tuner_callback(). | ||
| 51 | */ | ||
| 52 | |||
| 53 | #if defined(CONFIG_MEDIA_TUNER_XC5000) || \ | ||
| 54 | (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) | ||
| 55 | extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | ||
| 56 | struct i2c_adapter *i2c, | ||
| 57 | const struct xc5000_config *cfg); | ||
| 58 | #else | ||
| 59 | static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | ||
| 60 | struct i2c_adapter *i2c, | ||
| 61 | const struct xc5000_config *cfg) | ||
| 62 | { | ||
| 63 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 64 | return NULL; | ||
| 65 | } | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #endif | ||
