162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * budget-av.c: driver for the SAA7146 based Budget DVB cards 462306a36Sopenharmony_ci * with analog video in 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Compiled from various sources by Michael Hunold <michael@mihu.de> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> & 962306a36Sopenharmony_ci * Andrew de Quincey <adq_dvb@lidskialf.net> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Copyright (C) 1999-2002 Ralph Metzler 1462306a36Sopenharmony_ci * & Marcus Metzler for convergence integrated media GmbH 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * the project's page is at https://linuxtv.org 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "budget.h" 2262306a36Sopenharmony_ci#include "stv0299.h" 2362306a36Sopenharmony_ci#include "stb0899_drv.h" 2462306a36Sopenharmony_ci#include "stb0899_reg.h" 2562306a36Sopenharmony_ci#include "stb0899_cfg.h" 2662306a36Sopenharmony_ci#include "tda8261.h" 2762306a36Sopenharmony_ci#include "tda8261_cfg.h" 2862306a36Sopenharmony_ci#include "tda1002x.h" 2962306a36Sopenharmony_ci#include "tda1004x.h" 3062306a36Sopenharmony_ci#include "tua6100.h" 3162306a36Sopenharmony_ci#include "dvb-pll.h" 3262306a36Sopenharmony_ci#include <media/drv-intf/saa7146_vv.h> 3362306a36Sopenharmony_ci#include <linux/module.h> 3462306a36Sopenharmony_ci#include <linux/etherdevice.h> 3562306a36Sopenharmony_ci#include <linux/errno.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci#include <linux/interrupt.h> 3862306a36Sopenharmony_ci#include <linux/input.h> 3962306a36Sopenharmony_ci#include <linux/spinlock.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <media/dvb_ca_en50221.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define DEBICICAM 0x02420000 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SLOTSTATUS_NONE 1 4662306a36Sopenharmony_ci#define SLOTSTATUS_PRESENT 2 4762306a36Sopenharmony_ci#define SLOTSTATUS_RESET 4 4862306a36Sopenharmony_ci#define SLOTSTATUS_READY 8 4962306a36Sopenharmony_ci#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct budget_av { 5462306a36Sopenharmony_ci struct budget budget; 5562306a36Sopenharmony_ci struct video_device vd; 5662306a36Sopenharmony_ci int cur_input; 5762306a36Sopenharmony_ci int has_saa7113; 5862306a36Sopenharmony_ci struct tasklet_struct ciintf_irq_tasklet; 5962306a36Sopenharmony_ci int slot_status; 6062306a36Sopenharmony_ci struct dvb_ca_en50221 ca; 6162306a36Sopenharmony_ci u8 reinitialise_demod:1; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* GPIO Connections: 6862306a36Sopenharmony_ci * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! 6962306a36Sopenharmony_ci * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory 7062306a36Sopenharmony_ci * 2 - CI Card Enable (Active Low) 7162306a36Sopenharmony_ci * 3 - CI Card Detect 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/**************************************************************************** 7562306a36Sopenharmony_ci * INITIALIZATION 7662306a36Sopenharmony_ci ****************************************************************************/ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci u8 mm1[] = { 0x00 }; 8162306a36Sopenharmony_ci u8 mm2[] = { 0x00 }; 8262306a36Sopenharmony_ci struct i2c_msg msgs[2]; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci msgs[0].flags = 0; 8562306a36Sopenharmony_ci msgs[1].flags = I2C_M_RD; 8662306a36Sopenharmony_ci msgs[0].addr = msgs[1].addr = id / 2; 8762306a36Sopenharmony_ci mm1[0] = reg; 8862306a36Sopenharmony_ci msgs[0].len = 1; 8962306a36Sopenharmony_ci msgs[1].len = 1; 9062306a36Sopenharmony_ci msgs[0].buf = mm1; 9162306a36Sopenharmony_ci msgs[1].buf = mm2; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci i2c_transfer(i2c, msgs, 2); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return mm2[0]; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci u8 mm1[] = { reg }; 10162306a36Sopenharmony_ci struct i2c_msg msgs[2] = { 10262306a36Sopenharmony_ci {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, 10362306a36Sopenharmony_ci {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} 10462306a36Sopenharmony_ci }; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (i2c_transfer(i2c, msgs, 2) != 2) 10762306a36Sopenharmony_ci return -EIO; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci u8 msg[2] = { reg, val }; 11562306a36Sopenharmony_ci struct i2c_msg msgs; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci msgs.flags = 0; 11862306a36Sopenharmony_ci msgs.addr = id / 2; 11962306a36Sopenharmony_ci msgs.len = 2; 12062306a36Sopenharmony_ci msgs.buf = msg; 12162306a36Sopenharmony_ci return i2c_transfer(i2c, &msgs, 1); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 12762306a36Sopenharmony_ci int result; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (slot != 0) 13062306a36Sopenharmony_ci return -EINVAL; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); 13362306a36Sopenharmony_ci udelay(1); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); 13662306a36Sopenharmony_ci if (result == -ETIMEDOUT) { 13762306a36Sopenharmony_ci ciintf_slot_shutdown(ca, slot); 13862306a36Sopenharmony_ci pr_info("cam ejected 1\n"); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci return result; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 14662306a36Sopenharmony_ci int result; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (slot != 0) 14962306a36Sopenharmony_ci return -EINVAL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); 15262306a36Sopenharmony_ci udelay(1); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); 15562306a36Sopenharmony_ci if (result == -ETIMEDOUT) { 15662306a36Sopenharmony_ci ciintf_slot_shutdown(ca, slot); 15762306a36Sopenharmony_ci pr_info("cam ejected 2\n"); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci return result; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 16562306a36Sopenharmony_ci int result; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (slot != 0) 16862306a36Sopenharmony_ci return -EINVAL; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); 17162306a36Sopenharmony_ci udelay(1); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); 17462306a36Sopenharmony_ci if (result == -ETIMEDOUT) { 17562306a36Sopenharmony_ci ciintf_slot_shutdown(ca, slot); 17662306a36Sopenharmony_ci pr_info("cam ejected 3\n"); 17762306a36Sopenharmony_ci return -ETIMEDOUT; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci return result; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 18562306a36Sopenharmony_ci int result; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (slot != 0) 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); 19162306a36Sopenharmony_ci udelay(1); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); 19462306a36Sopenharmony_ci if (result == -ETIMEDOUT) { 19562306a36Sopenharmony_ci ciintf_slot_shutdown(ca, slot); 19662306a36Sopenharmony_ci pr_info("cam ejected 5\n"); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci return result; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 20462306a36Sopenharmony_ci struct saa7146_dev *saa = budget_av->budget.dev; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (slot != 0) 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci dprintk(1, "ciintf_slot_reset\n"); 21062306a36Sopenharmony_ci budget_av->slot_status = SLOTSTATUS_RESET; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ 21562306a36Sopenharmony_ci msleep(2); 21662306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ 21762306a36Sopenharmony_ci msleep(20); /* 20 ms Vcc settling time */ 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ 22062306a36Sopenharmony_ci ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); 22162306a36Sopenharmony_ci msleep(20); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* reinitialise the frontend if necessary */ 22462306a36Sopenharmony_ci if (budget_av->reinitialise_demod) 22562306a36Sopenharmony_ci dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 23362306a36Sopenharmony_ci struct saa7146_dev *saa = budget_av->budget.dev; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (slot != 0) 23662306a36Sopenharmony_ci return -EINVAL; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci dprintk(1, "ciintf_slot_shutdown\n"); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); 24162306a36Sopenharmony_ci budget_av->slot_status = SLOTSTATUS_NONE; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 24962306a36Sopenharmony_ci struct saa7146_dev *saa = budget_av->budget.dev; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (slot != 0) 25262306a36Sopenharmony_ci return -EINVAL; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct budget_av *budget_av = ca->data; 26462306a36Sopenharmony_ci struct saa7146_dev *saa = budget_av->budget.dev; 26562306a36Sopenharmony_ci int result; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (slot != 0) 26862306a36Sopenharmony_ci return -EINVAL; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* test the card detect line - needs to be done carefully 27162306a36Sopenharmony_ci * since it never goes high for some CAMs on this interface (e.g. topuptv) */ 27262306a36Sopenharmony_ci if (budget_av->slot_status == SLOTSTATUS_NONE) { 27362306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); 27462306a36Sopenharmony_ci udelay(1); 27562306a36Sopenharmony_ci if (saa7146_read(saa, PSR) & MASK_06) { 27662306a36Sopenharmony_ci if (budget_av->slot_status == SLOTSTATUS_NONE) { 27762306a36Sopenharmony_ci budget_av->slot_status = SLOTSTATUS_PRESENT; 27862306a36Sopenharmony_ci pr_info("cam inserted A\n"); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* We also try and read from IO memory to work round the above detection bug. If 28562306a36Sopenharmony_ci * there is no CAM, we will get a timeout. Only done if there is no cam 28662306a36Sopenharmony_ci * present, since this test actually breaks some cams :( 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * if the CI interface is not open, we also do the above test since we 28962306a36Sopenharmony_ci * don't care if the cam has problems - we'll be resetting it on open() anyway */ 29062306a36Sopenharmony_ci if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { 29162306a36Sopenharmony_ci saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); 29262306a36Sopenharmony_ci result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); 29362306a36Sopenharmony_ci if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { 29462306a36Sopenharmony_ci budget_av->slot_status = SLOTSTATUS_PRESENT; 29562306a36Sopenharmony_ci pr_info("cam inserted B\n"); 29662306a36Sopenharmony_ci } else if (result < 0) { 29762306a36Sopenharmony_ci if (budget_av->slot_status != SLOTSTATUS_NONE) { 29862306a36Sopenharmony_ci ciintf_slot_shutdown(ca, slot); 29962306a36Sopenharmony_ci pr_info("cam ejected 5\n"); 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* read from attribute memory in reset/ready state to know when the CAM is ready */ 30662306a36Sopenharmony_ci if (budget_av->slot_status == SLOTSTATUS_RESET) { 30762306a36Sopenharmony_ci result = ciintf_read_attribute_mem(ca, slot, 0); 30862306a36Sopenharmony_ci if (result == 0x1d) { 30962306a36Sopenharmony_ci budget_av->slot_status = SLOTSTATUS_READY; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* work out correct return code */ 31462306a36Sopenharmony_ci if (budget_av->slot_status != SLOTSTATUS_NONE) { 31562306a36Sopenharmony_ci if (budget_av->slot_status & SLOTSTATUS_READY) { 31662306a36Sopenharmony_ci return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci return DVB_CA_EN50221_POLL_CAM_PRESENT; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int ciintf_init(struct budget_av *budget_av) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct saa7146_dev *saa = budget_av->budget.dev; 32662306a36Sopenharmony_ci int result; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); 33162306a36Sopenharmony_ci saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); 33262306a36Sopenharmony_ci saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); 33362306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Enable DEBI pins */ 33662306a36Sopenharmony_ci saa7146_write(saa, MC1, MASK_27 | MASK_11); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* register CI interface */ 33962306a36Sopenharmony_ci budget_av->ca.owner = THIS_MODULE; 34062306a36Sopenharmony_ci budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; 34162306a36Sopenharmony_ci budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; 34262306a36Sopenharmony_ci budget_av->ca.read_cam_control = ciintf_read_cam_control; 34362306a36Sopenharmony_ci budget_av->ca.write_cam_control = ciintf_write_cam_control; 34462306a36Sopenharmony_ci budget_av->ca.slot_reset = ciintf_slot_reset; 34562306a36Sopenharmony_ci budget_av->ca.slot_shutdown = ciintf_slot_shutdown; 34662306a36Sopenharmony_ci budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; 34762306a36Sopenharmony_ci budget_av->ca.poll_slot_status = ciintf_poll_slot_status; 34862306a36Sopenharmony_ci budget_av->ca.data = budget_av; 34962306a36Sopenharmony_ci budget_av->budget.ci_present = 1; 35062306a36Sopenharmony_ci budget_av->slot_status = SLOTSTATUS_NONE; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, 35362306a36Sopenharmony_ci &budget_av->ca, 0, 1)) != 0) { 35462306a36Sopenharmony_ci pr_err("ci initialisation failed\n"); 35562306a36Sopenharmony_ci goto error; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci pr_info("ci interface initialised\n"); 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cierror: 36262306a36Sopenharmony_ci saa7146_write(saa, MC1, MASK_27); 36362306a36Sopenharmony_ci return result; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void ciintf_deinit(struct budget_av *budget_av) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct saa7146_dev *saa = budget_av->budget.dev; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); 37162306a36Sopenharmony_ci saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); 37262306a36Sopenharmony_ci saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); 37362306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* release the CA device */ 37662306a36Sopenharmony_ci dvb_ca_en50221_release(&budget_av->ca); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* disable DEBI pins */ 37962306a36Sopenharmony_ci saa7146_write(saa, MC1, MASK_27); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic const u8 saa7113_tab[] = { 38462306a36Sopenharmony_ci 0x01, 0x08, 38562306a36Sopenharmony_ci 0x02, 0xc0, 38662306a36Sopenharmony_ci 0x03, 0x33, 38762306a36Sopenharmony_ci 0x04, 0x00, 38862306a36Sopenharmony_ci 0x05, 0x00, 38962306a36Sopenharmony_ci 0x06, 0xeb, 39062306a36Sopenharmony_ci 0x07, 0xe0, 39162306a36Sopenharmony_ci 0x08, 0x28, 39262306a36Sopenharmony_ci 0x09, 0x00, 39362306a36Sopenharmony_ci 0x0a, 0x80, 39462306a36Sopenharmony_ci 0x0b, 0x47, 39562306a36Sopenharmony_ci 0x0c, 0x40, 39662306a36Sopenharmony_ci 0x0d, 0x00, 39762306a36Sopenharmony_ci 0x0e, 0x01, 39862306a36Sopenharmony_ci 0x0f, 0x44, 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci 0x10, 0x08, 40162306a36Sopenharmony_ci 0x11, 0x0c, 40262306a36Sopenharmony_ci 0x12, 0x7b, 40362306a36Sopenharmony_ci 0x13, 0x00, 40462306a36Sopenharmony_ci 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci 0x57, 0xff, 40762306a36Sopenharmony_ci 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, 40862306a36Sopenharmony_ci 0x5b, 0x83, 0x5e, 0x00, 40962306a36Sopenharmony_ci 0xff 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int saa7113_init(struct budget_av *budget_av) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct budget *budget = &budget_av->budget; 41562306a36Sopenharmony_ci struct saa7146_dev *saa = budget->dev; 41662306a36Sopenharmony_ci const u8 *data = saa7113_tab; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); 41962306a36Sopenharmony_ci msleep(200); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { 42262306a36Sopenharmony_ci dprintk(1, "saa7113 not found on KNC card\n"); 42362306a36Sopenharmony_ci return -ENODEV; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci dprintk(1, "saa7113 detected and initializing\n"); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci while (*data != 0xff) { 42962306a36Sopenharmony_ci i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); 43062306a36Sopenharmony_ci data += 2; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int saa7113_setinput(struct budget_av *budget_av, int input) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct budget *budget = &budget_av->budget; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (1 != budget_av->has_saa7113) 44362306a36Sopenharmony_ci return -ENODEV; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (input == 1) { 44662306a36Sopenharmony_ci i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); 44762306a36Sopenharmony_ci i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); 44862306a36Sopenharmony_ci } else if (input == 0) { 44962306a36Sopenharmony_ci i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); 45062306a36Sopenharmony_ci i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); 45162306a36Sopenharmony_ci } else 45262306a36Sopenharmony_ci return -EINVAL; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci budget_av->cur_input = input; 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci u8 aclk = 0; 46262306a36Sopenharmony_ci u8 bclk = 0; 46362306a36Sopenharmony_ci u8 m1; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci aclk = 0xb5; 46662306a36Sopenharmony_ci if (srate < 2000000) 46762306a36Sopenharmony_ci bclk = 0x86; 46862306a36Sopenharmony_ci else if (srate < 5000000) 46962306a36Sopenharmony_ci bclk = 0x89; 47062306a36Sopenharmony_ci else if (srate < 15000000) 47162306a36Sopenharmony_ci bclk = 0x8f; 47262306a36Sopenharmony_ci else if (srate < 45000000) 47362306a36Sopenharmony_ci bclk = 0x95; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci m1 = 0x14; 47662306a36Sopenharmony_ci if (srate < 4000000) 47762306a36Sopenharmony_ci m1 = 0x10; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci stv0299_writereg(fe, 0x13, aclk); 48062306a36Sopenharmony_ci stv0299_writereg(fe, 0x14, bclk); 48162306a36Sopenharmony_ci stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); 48262306a36Sopenharmony_ci stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); 48362306a36Sopenharmony_ci stv0299_writereg(fe, 0x21, (ratio) & 0xf0); 48462306a36Sopenharmony_ci stv0299_writereg(fe, 0x0f, 0x80 | m1); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 49262306a36Sopenharmony_ci u32 div; 49362306a36Sopenharmony_ci u8 buf[4]; 49462306a36Sopenharmony_ci struct budget *budget = fe->dvb->priv; 49562306a36Sopenharmony_ci struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if ((c->frequency < 950000) || (c->frequency > 2150000)) 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci div = (c->frequency + (125 - 1)) / 125; /* round correctly */ 50162306a36Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 50262306a36Sopenharmony_ci buf[1] = div & 0xff; 50362306a36Sopenharmony_ci buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; 50462306a36Sopenharmony_ci buf[3] = 0x20; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (c->symbol_rate < 4000000) 50762306a36Sopenharmony_ci buf[3] |= 1; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (c->frequency < 1250000) 51062306a36Sopenharmony_ci buf[3] |= 0; 51162306a36Sopenharmony_ci else if (c->frequency < 1550000) 51262306a36Sopenharmony_ci buf[3] |= 0x40; 51362306a36Sopenharmony_ci else if (c->frequency < 2050000) 51462306a36Sopenharmony_ci buf[3] |= 0x80; 51562306a36Sopenharmony_ci else if (c->frequency < 2150000) 51662306a36Sopenharmony_ci buf[3] |= 0xC0; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 51962306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 52062306a36Sopenharmony_ci if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) 52162306a36Sopenharmony_ci return -EIO; 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic u8 typhoon_cinergy1200s_inittab[] = { 52662306a36Sopenharmony_ci 0x01, 0x15, 52762306a36Sopenharmony_ci 0x02, 0x30, 52862306a36Sopenharmony_ci 0x03, 0x00, 52962306a36Sopenharmony_ci 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ 53062306a36Sopenharmony_ci 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ 53162306a36Sopenharmony_ci 0x06, 0x40, /* DAC not used, set to high impendance mode */ 53262306a36Sopenharmony_ci 0x07, 0x00, /* DAC LSB */ 53362306a36Sopenharmony_ci 0x08, 0x40, /* DiSEqC off */ 53462306a36Sopenharmony_ci 0x09, 0x00, /* FIFO */ 53562306a36Sopenharmony_ci 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ 53662306a36Sopenharmony_ci 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ 53762306a36Sopenharmony_ci 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 53862306a36Sopenharmony_ci 0x10, 0x3f, // AGC2 0x3d 53962306a36Sopenharmony_ci 0x11, 0x84, 54062306a36Sopenharmony_ci 0x12, 0xb9, 54162306a36Sopenharmony_ci 0x15, 0xc9, // lock detector threshold 54262306a36Sopenharmony_ci 0x16, 0x00, 54362306a36Sopenharmony_ci 0x17, 0x00, 54462306a36Sopenharmony_ci 0x18, 0x00, 54562306a36Sopenharmony_ci 0x19, 0x00, 54662306a36Sopenharmony_ci 0x1a, 0x00, 54762306a36Sopenharmony_ci 0x1f, 0x50, 54862306a36Sopenharmony_ci 0x20, 0x00, 54962306a36Sopenharmony_ci 0x21, 0x00, 55062306a36Sopenharmony_ci 0x22, 0x00, 55162306a36Sopenharmony_ci 0x23, 0x00, 55262306a36Sopenharmony_ci 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 55362306a36Sopenharmony_ci 0x29, 0x1e, // 1/2 threshold 55462306a36Sopenharmony_ci 0x2a, 0x14, // 2/3 threshold 55562306a36Sopenharmony_ci 0x2b, 0x0f, // 3/4 threshold 55662306a36Sopenharmony_ci 0x2c, 0x09, // 5/6 threshold 55762306a36Sopenharmony_ci 0x2d, 0x05, // 7/8 threshold 55862306a36Sopenharmony_ci 0x2e, 0x01, 55962306a36Sopenharmony_ci 0x31, 0x1f, // test all FECs 56062306a36Sopenharmony_ci 0x32, 0x19, // viterbi and synchro search 56162306a36Sopenharmony_ci 0x33, 0xfc, // rs control 56262306a36Sopenharmony_ci 0x34, 0x93, // error control 56362306a36Sopenharmony_ci 0x0f, 0x92, 56462306a36Sopenharmony_ci 0xff, 0xff 56562306a36Sopenharmony_ci}; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic const struct stv0299_config typhoon_config = { 56862306a36Sopenharmony_ci .demod_address = 0x68, 56962306a36Sopenharmony_ci .inittab = typhoon_cinergy1200s_inittab, 57062306a36Sopenharmony_ci .mclk = 88000000UL, 57162306a36Sopenharmony_ci .invert = 0, 57262306a36Sopenharmony_ci .skip_reinit = 0, 57362306a36Sopenharmony_ci .lock_output = STV0299_LOCKOUTPUT_1, 57462306a36Sopenharmony_ci .volt13_op0_op1 = STV0299_VOLT13_OP0, 57562306a36Sopenharmony_ci .min_delay_ms = 100, 57662306a36Sopenharmony_ci .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, 57762306a36Sopenharmony_ci}; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic const struct stv0299_config cinergy_1200s_config = { 58162306a36Sopenharmony_ci .demod_address = 0x68, 58262306a36Sopenharmony_ci .inittab = typhoon_cinergy1200s_inittab, 58362306a36Sopenharmony_ci .mclk = 88000000UL, 58462306a36Sopenharmony_ci .invert = 0, 58562306a36Sopenharmony_ci .skip_reinit = 0, 58662306a36Sopenharmony_ci .lock_output = STV0299_LOCKOUTPUT_0, 58762306a36Sopenharmony_ci .volt13_op0_op1 = STV0299_VOLT13_OP0, 58862306a36Sopenharmony_ci .min_delay_ms = 100, 58962306a36Sopenharmony_ci .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, 59062306a36Sopenharmony_ci}; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic const struct stv0299_config cinergy_1200s_1894_0010_config = { 59362306a36Sopenharmony_ci .demod_address = 0x68, 59462306a36Sopenharmony_ci .inittab = typhoon_cinergy1200s_inittab, 59562306a36Sopenharmony_ci .mclk = 88000000UL, 59662306a36Sopenharmony_ci .invert = 1, 59762306a36Sopenharmony_ci .skip_reinit = 0, 59862306a36Sopenharmony_ci .lock_output = STV0299_LOCKOUTPUT_1, 59962306a36Sopenharmony_ci .volt13_op0_op1 = STV0299_VOLT13_OP0, 60062306a36Sopenharmony_ci .min_delay_ms = 100, 60162306a36Sopenharmony_ci .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, 60262306a36Sopenharmony_ci}; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int philips_cu1216_tuner_set_params(struct dvb_frontend *fe) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 60762306a36Sopenharmony_ci struct budget *budget = fe->dvb->priv; 60862306a36Sopenharmony_ci u8 buf[6]; 60962306a36Sopenharmony_ci struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; 61062306a36Sopenharmony_ci int i; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci#define CU1216_IF 36125000 61362306a36Sopenharmony_ci#define TUNER_MUL 62500 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 61862306a36Sopenharmony_ci buf[1] = div & 0xff; 61962306a36Sopenharmony_ci buf[2] = 0xce; 62062306a36Sopenharmony_ci buf[3] = (c->frequency < 150000000 ? 0x01 : 62162306a36Sopenharmony_ci c->frequency < 445000000 ? 0x02 : 0x04); 62262306a36Sopenharmony_ci buf[4] = 0xde; 62362306a36Sopenharmony_ci buf[5] = 0x20; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 62662306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 62762306a36Sopenharmony_ci if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) 62862306a36Sopenharmony_ci return -EIO; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* wait for the pll lock */ 63162306a36Sopenharmony_ci msg.flags = I2C_M_RD; 63262306a36Sopenharmony_ci msg.len = 1; 63362306a36Sopenharmony_ci for (i = 0; i < 20; i++) { 63462306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 63562306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 63662306a36Sopenharmony_ci if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci msleep(10); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* switch the charge pump to the lower current */ 64262306a36Sopenharmony_ci msg.flags = 0; 64362306a36Sopenharmony_ci msg.len = 2; 64462306a36Sopenharmony_ci msg.buf = &buf[2]; 64562306a36Sopenharmony_ci buf[2] &= ~0x40; 64662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 64762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 64862306a36Sopenharmony_ci if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) 64962306a36Sopenharmony_ci return -EIO; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic struct tda1002x_config philips_cu1216_config = { 65562306a36Sopenharmony_ci .demod_address = 0x0c, 65662306a36Sopenharmony_ci .invert = 1, 65762306a36Sopenharmony_ci}; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic struct tda1002x_config philips_cu1216_config_altaddress = { 66062306a36Sopenharmony_ci .demod_address = 0x0d, 66162306a36Sopenharmony_ci .invert = 0, 66262306a36Sopenharmony_ci}; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic struct tda10023_config philips_cu1216_tda10023_config = { 66562306a36Sopenharmony_ci .demod_address = 0x0c, 66662306a36Sopenharmony_ci .invert = 1, 66762306a36Sopenharmony_ci}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic int philips_tu1216_tuner_init(struct dvb_frontend *fe) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct budget *budget = fe->dvb->priv; 67262306a36Sopenharmony_ci static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; 67362306a36Sopenharmony_ci struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci // setup PLL configuration 67662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 67762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 67862306a36Sopenharmony_ci if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) 67962306a36Sopenharmony_ci return -EIO; 68062306a36Sopenharmony_ci msleep(1); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return 0; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int philips_tu1216_tuner_set_params(struct dvb_frontend *fe) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 68862306a36Sopenharmony_ci struct budget *budget = fe->dvb->priv; 68962306a36Sopenharmony_ci u8 tuner_buf[4]; 69062306a36Sopenharmony_ci struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = 69162306a36Sopenharmony_ci sizeof(tuner_buf) }; 69262306a36Sopenharmony_ci int tuner_frequency = 0; 69362306a36Sopenharmony_ci u8 band, cp, filter; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci // determine charge pump 69662306a36Sopenharmony_ci tuner_frequency = c->frequency + 36166000; 69762306a36Sopenharmony_ci if (tuner_frequency < 87000000) 69862306a36Sopenharmony_ci return -EINVAL; 69962306a36Sopenharmony_ci else if (tuner_frequency < 130000000) 70062306a36Sopenharmony_ci cp = 3; 70162306a36Sopenharmony_ci else if (tuner_frequency < 160000000) 70262306a36Sopenharmony_ci cp = 5; 70362306a36Sopenharmony_ci else if (tuner_frequency < 200000000) 70462306a36Sopenharmony_ci cp = 6; 70562306a36Sopenharmony_ci else if (tuner_frequency < 290000000) 70662306a36Sopenharmony_ci cp = 3; 70762306a36Sopenharmony_ci else if (tuner_frequency < 420000000) 70862306a36Sopenharmony_ci cp = 5; 70962306a36Sopenharmony_ci else if (tuner_frequency < 480000000) 71062306a36Sopenharmony_ci cp = 6; 71162306a36Sopenharmony_ci else if (tuner_frequency < 620000000) 71262306a36Sopenharmony_ci cp = 3; 71362306a36Sopenharmony_ci else if (tuner_frequency < 830000000) 71462306a36Sopenharmony_ci cp = 5; 71562306a36Sopenharmony_ci else if (tuner_frequency < 895000000) 71662306a36Sopenharmony_ci cp = 7; 71762306a36Sopenharmony_ci else 71862306a36Sopenharmony_ci return -EINVAL; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci // determine band 72162306a36Sopenharmony_ci if (c->frequency < 49000000) 72262306a36Sopenharmony_ci return -EINVAL; 72362306a36Sopenharmony_ci else if (c->frequency < 161000000) 72462306a36Sopenharmony_ci band = 1; 72562306a36Sopenharmony_ci else if (c->frequency < 444000000) 72662306a36Sopenharmony_ci band = 2; 72762306a36Sopenharmony_ci else if (c->frequency < 861000000) 72862306a36Sopenharmony_ci band = 4; 72962306a36Sopenharmony_ci else 73062306a36Sopenharmony_ci return -EINVAL; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci // setup PLL filter 73362306a36Sopenharmony_ci switch (c->bandwidth_hz) { 73462306a36Sopenharmony_ci case 6000000: 73562306a36Sopenharmony_ci filter = 0; 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci case 7000000: 73962306a36Sopenharmony_ci filter = 0; 74062306a36Sopenharmony_ci break; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci case 8000000: 74362306a36Sopenharmony_ci filter = 1; 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci default: 74762306a36Sopenharmony_ci return -EINVAL; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci // calculate divisor 75162306a36Sopenharmony_ci // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) 75262306a36Sopenharmony_ci tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci // setup tuner buffer 75562306a36Sopenharmony_ci tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; 75662306a36Sopenharmony_ci tuner_buf[1] = tuner_frequency & 0xff; 75762306a36Sopenharmony_ci tuner_buf[2] = 0xca; 75862306a36Sopenharmony_ci tuner_buf[3] = (cp << 5) | (filter << 3) | band; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 76162306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 76262306a36Sopenharmony_ci if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) 76362306a36Sopenharmony_ci return -EIO; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci msleep(1); 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int philips_tu1216_request_firmware(struct dvb_frontend *fe, 77062306a36Sopenharmony_ci const struct firmware **fw, char *name) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct budget *budget = fe->dvb->priv; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return request_firmware(fw, name, &budget->dev->pci->dev); 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic struct tda1004x_config philips_tu1216_config = { 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci .demod_address = 0x8, 78062306a36Sopenharmony_ci .invert = 1, 78162306a36Sopenharmony_ci .invert_oclk = 1, 78262306a36Sopenharmony_ci .xtal_freq = TDA10046_XTAL_4M, 78362306a36Sopenharmony_ci .agc_config = TDA10046_AGC_DEFAULT, 78462306a36Sopenharmony_ci .if_freq = TDA10046_FREQ_3617, 78562306a36Sopenharmony_ci .request_firmware = philips_tu1216_request_firmware, 78662306a36Sopenharmony_ci}; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic u8 philips_sd1878_inittab[] = { 78962306a36Sopenharmony_ci 0x01, 0x15, 79062306a36Sopenharmony_ci 0x02, 0x30, 79162306a36Sopenharmony_ci 0x03, 0x00, 79262306a36Sopenharmony_ci 0x04, 0x7d, 79362306a36Sopenharmony_ci 0x05, 0x35, 79462306a36Sopenharmony_ci 0x06, 0x40, 79562306a36Sopenharmony_ci 0x07, 0x00, 79662306a36Sopenharmony_ci 0x08, 0x43, 79762306a36Sopenharmony_ci 0x09, 0x02, 79862306a36Sopenharmony_ci 0x0C, 0x51, 79962306a36Sopenharmony_ci 0x0D, 0x82, 80062306a36Sopenharmony_ci 0x0E, 0x23, 80162306a36Sopenharmony_ci 0x10, 0x3f, 80262306a36Sopenharmony_ci 0x11, 0x84, 80362306a36Sopenharmony_ci 0x12, 0xb9, 80462306a36Sopenharmony_ci 0x15, 0xc9, 80562306a36Sopenharmony_ci 0x16, 0x19, 80662306a36Sopenharmony_ci 0x17, 0x8c, 80762306a36Sopenharmony_ci 0x18, 0x59, 80862306a36Sopenharmony_ci 0x19, 0xf8, 80962306a36Sopenharmony_ci 0x1a, 0xfe, 81062306a36Sopenharmony_ci 0x1c, 0x7f, 81162306a36Sopenharmony_ci 0x1d, 0x00, 81262306a36Sopenharmony_ci 0x1e, 0x00, 81362306a36Sopenharmony_ci 0x1f, 0x50, 81462306a36Sopenharmony_ci 0x20, 0x00, 81562306a36Sopenharmony_ci 0x21, 0x00, 81662306a36Sopenharmony_ci 0x22, 0x00, 81762306a36Sopenharmony_ci 0x23, 0x00, 81862306a36Sopenharmony_ci 0x28, 0x00, 81962306a36Sopenharmony_ci 0x29, 0x28, 82062306a36Sopenharmony_ci 0x2a, 0x14, 82162306a36Sopenharmony_ci 0x2b, 0x0f, 82262306a36Sopenharmony_ci 0x2c, 0x09, 82362306a36Sopenharmony_ci 0x2d, 0x09, 82462306a36Sopenharmony_ci 0x31, 0x1f, 82562306a36Sopenharmony_ci 0x32, 0x19, 82662306a36Sopenharmony_ci 0x33, 0xfc, 82762306a36Sopenharmony_ci 0x34, 0x93, 82862306a36Sopenharmony_ci 0xff, 0xff 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, 83262306a36Sopenharmony_ci u32 srate, u32 ratio) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci u8 aclk = 0; 83562306a36Sopenharmony_ci u8 bclk = 0; 83662306a36Sopenharmony_ci u8 m1; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci aclk = 0xb5; 83962306a36Sopenharmony_ci if (srate < 2000000) 84062306a36Sopenharmony_ci bclk = 0x86; 84162306a36Sopenharmony_ci else if (srate < 5000000) 84262306a36Sopenharmony_ci bclk = 0x89; 84362306a36Sopenharmony_ci else if (srate < 15000000) 84462306a36Sopenharmony_ci bclk = 0x8f; 84562306a36Sopenharmony_ci else if (srate < 45000000) 84662306a36Sopenharmony_ci bclk = 0x95; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci m1 = 0x14; 84962306a36Sopenharmony_ci if (srate < 4000000) 85062306a36Sopenharmony_ci m1 = 0x10; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci stv0299_writereg(fe, 0x0e, 0x23); 85362306a36Sopenharmony_ci stv0299_writereg(fe, 0x0f, 0x94); 85462306a36Sopenharmony_ci stv0299_writereg(fe, 0x10, 0x39); 85562306a36Sopenharmony_ci stv0299_writereg(fe, 0x13, aclk); 85662306a36Sopenharmony_ci stv0299_writereg(fe, 0x14, bclk); 85762306a36Sopenharmony_ci stv0299_writereg(fe, 0x15, 0xc9); 85862306a36Sopenharmony_ci stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); 85962306a36Sopenharmony_ci stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); 86062306a36Sopenharmony_ci stv0299_writereg(fe, 0x21, (ratio) & 0xf0); 86162306a36Sopenharmony_ci stv0299_writereg(fe, 0x0f, 0x80 | m1); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic const struct stv0299_config philips_sd1878_config = { 86762306a36Sopenharmony_ci .demod_address = 0x68, 86862306a36Sopenharmony_ci .inittab = philips_sd1878_inittab, 86962306a36Sopenharmony_ci .mclk = 88000000UL, 87062306a36Sopenharmony_ci .invert = 0, 87162306a36Sopenharmony_ci .skip_reinit = 0, 87262306a36Sopenharmony_ci .lock_output = STV0299_LOCKOUTPUT_1, 87362306a36Sopenharmony_ci .volt13_op0_op1 = STV0299_VOLT13_OP0, 87462306a36Sopenharmony_ci .min_delay_ms = 100, 87562306a36Sopenharmony_ci .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, 87662306a36Sopenharmony_ci}; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci/* KNC1 DVB-S (STB0899) Inittab */ 87962306a36Sopenharmony_cistatic const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci { STB0899_DEV_ID , 0x81 }, 88262306a36Sopenharmony_ci { STB0899_DISCNTRL1 , 0x32 }, 88362306a36Sopenharmony_ci { STB0899_DISCNTRL2 , 0x80 }, 88462306a36Sopenharmony_ci { STB0899_DISRX_ST0 , 0x04 }, 88562306a36Sopenharmony_ci { STB0899_DISRX_ST1 , 0x00 }, 88662306a36Sopenharmony_ci { STB0899_DISPARITY , 0x00 }, 88762306a36Sopenharmony_ci { STB0899_DISSTATUS , 0x20 }, 88862306a36Sopenharmony_ci { STB0899_DISF22 , 0x8c }, 88962306a36Sopenharmony_ci { STB0899_DISF22RX , 0x9a }, 89062306a36Sopenharmony_ci { STB0899_SYSREG , 0x0b }, 89162306a36Sopenharmony_ci { STB0899_ACRPRESC , 0x11 }, 89262306a36Sopenharmony_ci { STB0899_ACRDIV1 , 0x0a }, 89362306a36Sopenharmony_ci { STB0899_ACRDIV2 , 0x05 }, 89462306a36Sopenharmony_ci { STB0899_DACR1 , 0x00 }, 89562306a36Sopenharmony_ci { STB0899_DACR2 , 0x00 }, 89662306a36Sopenharmony_ci { STB0899_OUTCFG , 0x00 }, 89762306a36Sopenharmony_ci { STB0899_MODECFG , 0x00 }, 89862306a36Sopenharmony_ci { STB0899_IRQSTATUS_3 , 0x30 }, 89962306a36Sopenharmony_ci { STB0899_IRQSTATUS_2 , 0x00 }, 90062306a36Sopenharmony_ci { STB0899_IRQSTATUS_1 , 0x00 }, 90162306a36Sopenharmony_ci { STB0899_IRQSTATUS_0 , 0x00 }, 90262306a36Sopenharmony_ci { STB0899_IRQMSK_3 , 0xf3 }, 90362306a36Sopenharmony_ci { STB0899_IRQMSK_2 , 0xfc }, 90462306a36Sopenharmony_ci { STB0899_IRQMSK_1 , 0xff }, 90562306a36Sopenharmony_ci { STB0899_IRQMSK_0 , 0xff }, 90662306a36Sopenharmony_ci { STB0899_IRQCFG , 0x00 }, 90762306a36Sopenharmony_ci { STB0899_I2CCFG , 0x88 }, 90862306a36Sopenharmony_ci { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ 90962306a36Sopenharmony_ci { STB0899_IOPVALUE5 , 0x00 }, 91062306a36Sopenharmony_ci { STB0899_IOPVALUE4 , 0x20 }, 91162306a36Sopenharmony_ci { STB0899_IOPVALUE3 , 0xc9 }, 91262306a36Sopenharmony_ci { STB0899_IOPVALUE2 , 0x90 }, 91362306a36Sopenharmony_ci { STB0899_IOPVALUE1 , 0x40 }, 91462306a36Sopenharmony_ci { STB0899_IOPVALUE0 , 0x00 }, 91562306a36Sopenharmony_ci { STB0899_GPIO00CFG , 0x82 }, 91662306a36Sopenharmony_ci { STB0899_GPIO01CFG , 0x82 }, 91762306a36Sopenharmony_ci { STB0899_GPIO02CFG , 0x82 }, 91862306a36Sopenharmony_ci { STB0899_GPIO03CFG , 0x82 }, 91962306a36Sopenharmony_ci { STB0899_GPIO04CFG , 0x82 }, 92062306a36Sopenharmony_ci { STB0899_GPIO05CFG , 0x82 }, 92162306a36Sopenharmony_ci { STB0899_GPIO06CFG , 0x82 }, 92262306a36Sopenharmony_ci { STB0899_GPIO07CFG , 0x82 }, 92362306a36Sopenharmony_ci { STB0899_GPIO08CFG , 0x82 }, 92462306a36Sopenharmony_ci { STB0899_GPIO09CFG , 0x82 }, 92562306a36Sopenharmony_ci { STB0899_GPIO10CFG , 0x82 }, 92662306a36Sopenharmony_ci { STB0899_GPIO11CFG , 0x82 }, 92762306a36Sopenharmony_ci { STB0899_GPIO12CFG , 0x82 }, 92862306a36Sopenharmony_ci { STB0899_GPIO13CFG , 0x82 }, 92962306a36Sopenharmony_ci { STB0899_GPIO14CFG , 0x82 }, 93062306a36Sopenharmony_ci { STB0899_GPIO15CFG , 0x82 }, 93162306a36Sopenharmony_ci { STB0899_GPIO16CFG , 0x82 }, 93262306a36Sopenharmony_ci { STB0899_GPIO17CFG , 0x82 }, 93362306a36Sopenharmony_ci { STB0899_GPIO18CFG , 0x82 }, 93462306a36Sopenharmony_ci { STB0899_GPIO19CFG , 0x82 }, 93562306a36Sopenharmony_ci { STB0899_GPIO20CFG , 0x82 }, 93662306a36Sopenharmony_ci { STB0899_SDATCFG , 0xb8 }, 93762306a36Sopenharmony_ci { STB0899_SCLTCFG , 0xba }, 93862306a36Sopenharmony_ci { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ 93962306a36Sopenharmony_ci { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ 94062306a36Sopenharmony_ci { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ 94162306a36Sopenharmony_ci { STB0899_DIRCLKCFG , 0x82 }, 94262306a36Sopenharmony_ci { STB0899_CLKOUT27CFG , 0x7e }, 94362306a36Sopenharmony_ci { STB0899_STDBYCFG , 0x82 }, 94462306a36Sopenharmony_ci { STB0899_CS0CFG , 0x82 }, 94562306a36Sopenharmony_ci { STB0899_CS1CFG , 0x82 }, 94662306a36Sopenharmony_ci { STB0899_DISEQCOCFG , 0x20 }, 94762306a36Sopenharmony_ci { STB0899_GPIO32CFG , 0x82 }, 94862306a36Sopenharmony_ci { STB0899_GPIO33CFG , 0x82 }, 94962306a36Sopenharmony_ci { STB0899_GPIO34CFG , 0x82 }, 95062306a36Sopenharmony_ci { STB0899_GPIO35CFG , 0x82 }, 95162306a36Sopenharmony_ci { STB0899_GPIO36CFG , 0x82 }, 95262306a36Sopenharmony_ci { STB0899_GPIO37CFG , 0x82 }, 95362306a36Sopenharmony_ci { STB0899_GPIO38CFG , 0x82 }, 95462306a36Sopenharmony_ci { STB0899_GPIO39CFG , 0x82 }, 95562306a36Sopenharmony_ci { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ 95662306a36Sopenharmony_ci { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ 95762306a36Sopenharmony_ci { STB0899_FILTCTRL , 0x00 }, 95862306a36Sopenharmony_ci { STB0899_SYSCTRL , 0x00 }, 95962306a36Sopenharmony_ci { STB0899_STOPCLK1 , 0x20 }, 96062306a36Sopenharmony_ci { STB0899_STOPCLK2 , 0x00 }, 96162306a36Sopenharmony_ci { STB0899_INTBUFSTATUS , 0x00 }, 96262306a36Sopenharmony_ci { STB0899_INTBUFCTRL , 0x0a }, 96362306a36Sopenharmony_ci { 0xffff , 0xff }, 96462306a36Sopenharmony_ci}; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { 96762306a36Sopenharmony_ci { STB0899_DEMOD , 0x00 }, 96862306a36Sopenharmony_ci { STB0899_RCOMPC , 0xc9 }, 96962306a36Sopenharmony_ci { STB0899_AGC1CN , 0x41 }, 97062306a36Sopenharmony_ci { STB0899_AGC1REF , 0x08 }, 97162306a36Sopenharmony_ci { STB0899_RTC , 0x7a }, 97262306a36Sopenharmony_ci { STB0899_TMGCFG , 0x4e }, 97362306a36Sopenharmony_ci { STB0899_AGC2REF , 0x33 }, 97462306a36Sopenharmony_ci { STB0899_TLSR , 0x84 }, 97562306a36Sopenharmony_ci { STB0899_CFD , 0xee }, 97662306a36Sopenharmony_ci { STB0899_ACLC , 0x87 }, 97762306a36Sopenharmony_ci { STB0899_BCLC , 0x94 }, 97862306a36Sopenharmony_ci { STB0899_EQON , 0x41 }, 97962306a36Sopenharmony_ci { STB0899_LDT , 0xdd }, 98062306a36Sopenharmony_ci { STB0899_LDT2 , 0xc9 }, 98162306a36Sopenharmony_ci { STB0899_EQUALREF , 0xb4 }, 98262306a36Sopenharmony_ci { STB0899_TMGRAMP , 0x10 }, 98362306a36Sopenharmony_ci { STB0899_TMGTHD , 0x30 }, 98462306a36Sopenharmony_ci { STB0899_IDCCOMP , 0xfb }, 98562306a36Sopenharmony_ci { STB0899_QDCCOMP , 0x03 }, 98662306a36Sopenharmony_ci { STB0899_POWERI , 0x3b }, 98762306a36Sopenharmony_ci { STB0899_POWERQ , 0x3d }, 98862306a36Sopenharmony_ci { STB0899_RCOMP , 0x81 }, 98962306a36Sopenharmony_ci { STB0899_AGCIQIN , 0x80 }, 99062306a36Sopenharmony_ci { STB0899_AGC2I1 , 0x04 }, 99162306a36Sopenharmony_ci { STB0899_AGC2I2 , 0xf5 }, 99262306a36Sopenharmony_ci { STB0899_TLIR , 0x25 }, 99362306a36Sopenharmony_ci { STB0899_RTF , 0x80 }, 99462306a36Sopenharmony_ci { STB0899_DSTATUS , 0x00 }, 99562306a36Sopenharmony_ci { STB0899_LDI , 0xca }, 99662306a36Sopenharmony_ci { STB0899_CFRM , 0xf1 }, 99762306a36Sopenharmony_ci { STB0899_CFRL , 0xf3 }, 99862306a36Sopenharmony_ci { STB0899_NIRM , 0x2a }, 99962306a36Sopenharmony_ci { STB0899_NIRL , 0x05 }, 100062306a36Sopenharmony_ci { STB0899_ISYMB , 0x17 }, 100162306a36Sopenharmony_ci { STB0899_QSYMB , 0xfa }, 100262306a36Sopenharmony_ci { STB0899_SFRH , 0x2f }, 100362306a36Sopenharmony_ci { STB0899_SFRM , 0x68 }, 100462306a36Sopenharmony_ci { STB0899_SFRL , 0x40 }, 100562306a36Sopenharmony_ci { STB0899_SFRUPH , 0x2f }, 100662306a36Sopenharmony_ci { STB0899_SFRUPM , 0x68 }, 100762306a36Sopenharmony_ci { STB0899_SFRUPL , 0x40 }, 100862306a36Sopenharmony_ci { STB0899_EQUAI1 , 0xfd }, 100962306a36Sopenharmony_ci { STB0899_EQUAQ1 , 0x04 }, 101062306a36Sopenharmony_ci { STB0899_EQUAI2 , 0x0f }, 101162306a36Sopenharmony_ci { STB0899_EQUAQ2 , 0xff }, 101262306a36Sopenharmony_ci { STB0899_EQUAI3 , 0xdf }, 101362306a36Sopenharmony_ci { STB0899_EQUAQ3 , 0xfa }, 101462306a36Sopenharmony_ci { STB0899_EQUAI4 , 0x37 }, 101562306a36Sopenharmony_ci { STB0899_EQUAQ4 , 0x0d }, 101662306a36Sopenharmony_ci { STB0899_EQUAI5 , 0xbd }, 101762306a36Sopenharmony_ci { STB0899_EQUAQ5 , 0xf7 }, 101862306a36Sopenharmony_ci { STB0899_DSTATUS2 , 0x00 }, 101962306a36Sopenharmony_ci { STB0899_VSTATUS , 0x00 }, 102062306a36Sopenharmony_ci { STB0899_VERROR , 0xff }, 102162306a36Sopenharmony_ci { STB0899_IQSWAP , 0x2a }, 102262306a36Sopenharmony_ci { STB0899_ECNT1M , 0x00 }, 102362306a36Sopenharmony_ci { STB0899_ECNT1L , 0x00 }, 102462306a36Sopenharmony_ci { STB0899_ECNT2M , 0x00 }, 102562306a36Sopenharmony_ci { STB0899_ECNT2L , 0x00 }, 102662306a36Sopenharmony_ci { STB0899_ECNT3M , 0x00 }, 102762306a36Sopenharmony_ci { STB0899_ECNT3L , 0x00 }, 102862306a36Sopenharmony_ci { STB0899_FECAUTO1 , 0x06 }, 102962306a36Sopenharmony_ci { STB0899_FECM , 0x01 }, 103062306a36Sopenharmony_ci { STB0899_VTH12 , 0xf0 }, 103162306a36Sopenharmony_ci { STB0899_VTH23 , 0xa0 }, 103262306a36Sopenharmony_ci { STB0899_VTH34 , 0x78 }, 103362306a36Sopenharmony_ci { STB0899_VTH56 , 0x4e }, 103462306a36Sopenharmony_ci { STB0899_VTH67 , 0x48 }, 103562306a36Sopenharmony_ci { STB0899_VTH78 , 0x38 }, 103662306a36Sopenharmony_ci { STB0899_PRVIT , 0xff }, 103762306a36Sopenharmony_ci { STB0899_VITSYNC , 0x19 }, 103862306a36Sopenharmony_ci { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ 103962306a36Sopenharmony_ci { STB0899_TSULC , 0x42 }, 104062306a36Sopenharmony_ci { STB0899_RSLLC , 0x40 }, 104162306a36Sopenharmony_ci { STB0899_TSLPL , 0x12 }, 104262306a36Sopenharmony_ci { STB0899_TSCFGH , 0x0c }, 104362306a36Sopenharmony_ci { STB0899_TSCFGM , 0x00 }, 104462306a36Sopenharmony_ci { STB0899_TSCFGL , 0x0c }, 104562306a36Sopenharmony_ci { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ 104662306a36Sopenharmony_ci { STB0899_RSSYNCDEL , 0x00 }, 104762306a36Sopenharmony_ci { STB0899_TSINHDELH , 0x02 }, 104862306a36Sopenharmony_ci { STB0899_TSINHDELM , 0x00 }, 104962306a36Sopenharmony_ci { STB0899_TSINHDELL , 0x00 }, 105062306a36Sopenharmony_ci { STB0899_TSLLSTKM , 0x00 }, 105162306a36Sopenharmony_ci { STB0899_TSLLSTKL , 0x00 }, 105262306a36Sopenharmony_ci { STB0899_TSULSTKM , 0x00 }, 105362306a36Sopenharmony_ci { STB0899_TSULSTKL , 0xab }, 105462306a36Sopenharmony_ci { STB0899_PCKLENUL , 0x00 }, 105562306a36Sopenharmony_ci { STB0899_PCKLENLL , 0xcc }, 105662306a36Sopenharmony_ci { STB0899_RSPCKLEN , 0xcc }, 105762306a36Sopenharmony_ci { STB0899_TSSTATUS , 0x80 }, 105862306a36Sopenharmony_ci { STB0899_ERRCTRL1 , 0xb6 }, 105962306a36Sopenharmony_ci { STB0899_ERRCTRL2 , 0x96 }, 106062306a36Sopenharmony_ci { STB0899_ERRCTRL3 , 0x89 }, 106162306a36Sopenharmony_ci { STB0899_DMONMSK1 , 0x27 }, 106262306a36Sopenharmony_ci { STB0899_DMONMSK0 , 0x03 }, 106362306a36Sopenharmony_ci { STB0899_DEMAPVIT , 0x5c }, 106462306a36Sopenharmony_ci { STB0899_PLPARM , 0x1f }, 106562306a36Sopenharmony_ci { STB0899_PDELCTRL , 0x48 }, 106662306a36Sopenharmony_ci { STB0899_PDELCTRL2 , 0x00 }, 106762306a36Sopenharmony_ci { STB0899_BBHCTRL1 , 0x00 }, 106862306a36Sopenharmony_ci { STB0899_BBHCTRL2 , 0x00 }, 106962306a36Sopenharmony_ci { STB0899_HYSTTHRESH , 0x77 }, 107062306a36Sopenharmony_ci { STB0899_MATCSTM , 0x00 }, 107162306a36Sopenharmony_ci { STB0899_MATCSTL , 0x00 }, 107262306a36Sopenharmony_ci { STB0899_UPLCSTM , 0x00 }, 107362306a36Sopenharmony_ci { STB0899_UPLCSTL , 0x00 }, 107462306a36Sopenharmony_ci { STB0899_DFLCSTM , 0x00 }, 107562306a36Sopenharmony_ci { STB0899_DFLCSTL , 0x00 }, 107662306a36Sopenharmony_ci { STB0899_SYNCCST , 0x00 }, 107762306a36Sopenharmony_ci { STB0899_SYNCDCSTM , 0x00 }, 107862306a36Sopenharmony_ci { STB0899_SYNCDCSTL , 0x00 }, 107962306a36Sopenharmony_ci { STB0899_ISI_ENTRY , 0x00 }, 108062306a36Sopenharmony_ci { STB0899_ISI_BIT_EN , 0x00 }, 108162306a36Sopenharmony_ci { STB0899_MATSTRM , 0x00 }, 108262306a36Sopenharmony_ci { STB0899_MATSTRL , 0x00 }, 108362306a36Sopenharmony_ci { STB0899_UPLSTRM , 0x00 }, 108462306a36Sopenharmony_ci { STB0899_UPLSTRL , 0x00 }, 108562306a36Sopenharmony_ci { STB0899_DFLSTRM , 0x00 }, 108662306a36Sopenharmony_ci { STB0899_DFLSTRL , 0x00 }, 108762306a36Sopenharmony_ci { STB0899_SYNCSTR , 0x00 }, 108862306a36Sopenharmony_ci { STB0899_SYNCDSTRM , 0x00 }, 108962306a36Sopenharmony_ci { STB0899_SYNCDSTRL , 0x00 }, 109062306a36Sopenharmony_ci { STB0899_CFGPDELSTATUS1 , 0x10 }, 109162306a36Sopenharmony_ci { STB0899_CFGPDELSTATUS2 , 0x00 }, 109262306a36Sopenharmony_ci { STB0899_BBFERRORM , 0x00 }, 109362306a36Sopenharmony_ci { STB0899_BBFERRORL , 0x00 }, 109462306a36Sopenharmony_ci { STB0899_UPKTERRORM , 0x00 }, 109562306a36Sopenharmony_ci { STB0899_UPKTERRORL , 0x00 }, 109662306a36Sopenharmony_ci { 0xffff , 0xff }, 109762306a36Sopenharmony_ci}; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci/* STB0899 demodulator config for the KNC1 and clones */ 110062306a36Sopenharmony_cistatic struct stb0899_config knc1_dvbs2_config = { 110162306a36Sopenharmony_ci .init_dev = knc1_stb0899_s1_init_1, 110262306a36Sopenharmony_ci .init_s2_demod = stb0899_s2_init_2, 110362306a36Sopenharmony_ci .init_s1_demod = knc1_stb0899_s1_init_3, 110462306a36Sopenharmony_ci .init_s2_fec = stb0899_s2_init_4, 110562306a36Sopenharmony_ci .init_tst = stb0899_s1_init_5, 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci .postproc = NULL, 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci .demod_address = 0x68, 111062306a36Sopenharmony_ci// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ 111162306a36Sopenharmony_ci .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ 111262306a36Sopenharmony_ci// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci .xtal_freq = 27000000, 111562306a36Sopenharmony_ci .inversion = IQ_SWAP_OFF, 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci .lo_clk = 76500000, 111862306a36Sopenharmony_ci .hi_clk = 90000000, 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci .esno_ave = STB0899_DVBS2_ESNO_AVE, 112162306a36Sopenharmony_ci .esno_quant = STB0899_DVBS2_ESNO_QUANT, 112262306a36Sopenharmony_ci .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, 112362306a36Sopenharmony_ci .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, 112462306a36Sopenharmony_ci .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, 112562306a36Sopenharmony_ci .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, 112662306a36Sopenharmony_ci .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, 112762306a36Sopenharmony_ci .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, 112862306a36Sopenharmony_ci .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, 113162306a36Sopenharmony_ci .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, 113262306a36Sopenharmony_ci .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, 113362306a36Sopenharmony_ci .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci .tuner_get_frequency = tda8261_get_frequency, 113662306a36Sopenharmony_ci .tuner_set_frequency = tda8261_set_frequency, 113762306a36Sopenharmony_ci .tuner_set_bandwidth = NULL, 113862306a36Sopenharmony_ci .tuner_get_bandwidth = tda8261_get_bandwidth, 113962306a36Sopenharmony_ci .tuner_set_rfsiggain = NULL 114062306a36Sopenharmony_ci}; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci/* 114362306a36Sopenharmony_ci * SD1878/SHA tuner config 114462306a36Sopenharmony_ci * 1F, Single I/P, Horizontal mount, High Sensitivity 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_cistatic const struct tda8261_config sd1878c_config = { 114762306a36Sopenharmony_ci// .name = "SD1878/SHA", 114862306a36Sopenharmony_ci .addr = 0x60, 114962306a36Sopenharmony_ci .step_size = TDA8261_STEP_1000 /* kHz */ 115062306a36Sopenharmony_ci}; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic u8 read_pwm(struct budget_av *budget_av) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci u8 b = 0xff; 115562306a36Sopenharmony_ci u8 pwm; 115662306a36Sopenharmony_ci struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, 115762306a36Sopenharmony_ci {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} 115862306a36Sopenharmony_ci }; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) 116162306a36Sopenharmony_ci || (pwm == 0xff)) 116262306a36Sopenharmony_ci pwm = 0x48; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci return pwm; 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci#define SUBID_DVBS_KNC1 0x0010 116862306a36Sopenharmony_ci#define SUBID_DVBS_KNC1_PLUS 0x0011 116962306a36Sopenharmony_ci#define SUBID_DVBS_TYPHOON 0x4f56 117062306a36Sopenharmony_ci#define SUBID_DVBS_CINERGY1200 0x1154 117162306a36Sopenharmony_ci#define SUBID_DVBS_CYNERGY1200N 0x1155 117262306a36Sopenharmony_ci#define SUBID_DVBS_TV_STAR 0x0014 117362306a36Sopenharmony_ci#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 117462306a36Sopenharmony_ci#define SUBID_DVBS_TV_STAR_CI 0x0016 117562306a36Sopenharmony_ci#define SUBID_DVBS2_KNC1 0x0018 117662306a36Sopenharmony_ci#define SUBID_DVBS2_KNC1_OEM 0x0019 117762306a36Sopenharmony_ci#define SUBID_DVBS_EASYWATCH_1 0x001a 117862306a36Sopenharmony_ci#define SUBID_DVBS_EASYWATCH_2 0x001b 117962306a36Sopenharmony_ci#define SUBID_DVBS2_EASYWATCH 0x001d 118062306a36Sopenharmony_ci#define SUBID_DVBS_EASYWATCH 0x001e 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci#define SUBID_DVBC_EASYWATCH 0x002a 118362306a36Sopenharmony_ci#define SUBID_DVBC_EASYWATCH_MK3 0x002c 118462306a36Sopenharmony_ci#define SUBID_DVBC_KNC1 0x0020 118562306a36Sopenharmony_ci#define SUBID_DVBC_KNC1_PLUS 0x0021 118662306a36Sopenharmony_ci#define SUBID_DVBC_KNC1_MK3 0x0022 118762306a36Sopenharmony_ci#define SUBID_DVBC_KNC1_TDA10024 0x0028 118862306a36Sopenharmony_ci#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 118962306a36Sopenharmony_ci#define SUBID_DVBC_CINERGY1200 0x1156 119062306a36Sopenharmony_ci#define SUBID_DVBC_CINERGY1200_MK3 0x1176 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci#define SUBID_DVBT_EASYWATCH 0x003a 119362306a36Sopenharmony_ci#define SUBID_DVBT_KNC1_PLUS 0x0031 119462306a36Sopenharmony_ci#define SUBID_DVBT_KNC1 0x0030 119562306a36Sopenharmony_ci#define SUBID_DVBT_CINERGY1200 0x1157 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic void frontend_init(struct budget_av *budget_av) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci struct saa7146_dev * saa = budget_av->budget.dev; 120062306a36Sopenharmony_ci struct dvb_frontend * fe = NULL; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* Enable / PowerON Frontend */ 120362306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* Wait for PowerON */ 120662306a36Sopenharmony_ci msleep(100); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci /* additional setup necessary for the PLUS cards */ 120962306a36Sopenharmony_ci switch (saa->pci->subsystem_device) { 121062306a36Sopenharmony_ci case SUBID_DVBS_KNC1_PLUS: 121162306a36Sopenharmony_ci case SUBID_DVBC_KNC1_PLUS: 121262306a36Sopenharmony_ci case SUBID_DVBT_KNC1_PLUS: 121362306a36Sopenharmony_ci case SUBID_DVBC_EASYWATCH: 121462306a36Sopenharmony_ci case SUBID_DVBC_KNC1_PLUS_MK3: 121562306a36Sopenharmony_ci case SUBID_DVBS2_KNC1: 121662306a36Sopenharmony_ci case SUBID_DVBS2_KNC1_OEM: 121762306a36Sopenharmony_ci case SUBID_DVBS2_EASYWATCH: 121862306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci switch (saa->pci->subsystem_device) { 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci case SUBID_DVBS_KNC1: 122562306a36Sopenharmony_ci /* 122662306a36Sopenharmony_ci * maybe that setting is needed for other dvb-s cards as well, 122762306a36Sopenharmony_ci * but so far it has been only confirmed for this type 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_ci budget_av->reinitialise_demod = 1; 123062306a36Sopenharmony_ci fallthrough; 123162306a36Sopenharmony_ci case SUBID_DVBS_KNC1_PLUS: 123262306a36Sopenharmony_ci case SUBID_DVBS_EASYWATCH_1: 123362306a36Sopenharmony_ci if (saa->pci->subsystem_vendor == 0x1894) { 123462306a36Sopenharmony_ci fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config, 123562306a36Sopenharmony_ci &budget_av->budget.i2c_adap); 123662306a36Sopenharmony_ci if (fe) { 123762306a36Sopenharmony_ci dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap); 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci } else { 124062306a36Sopenharmony_ci fe = dvb_attach(stv0299_attach, &typhoon_config, 124162306a36Sopenharmony_ci &budget_av->budget.i2c_adap); 124262306a36Sopenharmony_ci if (fe) { 124362306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci break; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci case SUBID_DVBS_TV_STAR: 124962306a36Sopenharmony_ci case SUBID_DVBS_TV_STAR_PLUS_X4: 125062306a36Sopenharmony_ci case SUBID_DVBS_TV_STAR_CI: 125162306a36Sopenharmony_ci case SUBID_DVBS_CYNERGY1200N: 125262306a36Sopenharmony_ci case SUBID_DVBS_EASYWATCH: 125362306a36Sopenharmony_ci case SUBID_DVBS_EASYWATCH_2: 125462306a36Sopenharmony_ci fe = dvb_attach(stv0299_attach, &philips_sd1878_config, 125562306a36Sopenharmony_ci &budget_av->budget.i2c_adap); 125662306a36Sopenharmony_ci if (fe) { 125762306a36Sopenharmony_ci dvb_attach(dvb_pll_attach, fe, 0x60, 125862306a36Sopenharmony_ci &budget_av->budget.i2c_adap, 125962306a36Sopenharmony_ci DVB_PLL_PHILIPS_SD1878_TDA8261); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci break; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci case SUBID_DVBS_TYPHOON: 126462306a36Sopenharmony_ci fe = dvb_attach(stv0299_attach, &typhoon_config, 126562306a36Sopenharmony_ci &budget_av->budget.i2c_adap); 126662306a36Sopenharmony_ci if (fe) { 126762306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci break; 127062306a36Sopenharmony_ci case SUBID_DVBS2_KNC1: 127162306a36Sopenharmony_ci case SUBID_DVBS2_KNC1_OEM: 127262306a36Sopenharmony_ci case SUBID_DVBS2_EASYWATCH: 127362306a36Sopenharmony_ci budget_av->reinitialise_demod = 1; 127462306a36Sopenharmony_ci if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) 127562306a36Sopenharmony_ci dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci break; 127862306a36Sopenharmony_ci case SUBID_DVBS_CINERGY1200: 127962306a36Sopenharmony_ci fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, 128062306a36Sopenharmony_ci &budget_av->budget.i2c_adap); 128162306a36Sopenharmony_ci if (fe) { 128262306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci case SUBID_DVBC_KNC1: 128762306a36Sopenharmony_ci case SUBID_DVBC_KNC1_PLUS: 128862306a36Sopenharmony_ci case SUBID_DVBC_CINERGY1200: 128962306a36Sopenharmony_ci case SUBID_DVBC_EASYWATCH: 129062306a36Sopenharmony_ci budget_av->reinitialise_demod = 1; 129162306a36Sopenharmony_ci budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; 129262306a36Sopenharmony_ci fe = dvb_attach(tda10021_attach, &philips_cu1216_config, 129362306a36Sopenharmony_ci &budget_av->budget.i2c_adap, 129462306a36Sopenharmony_ci read_pwm(budget_av)); 129562306a36Sopenharmony_ci if (fe == NULL) 129662306a36Sopenharmony_ci fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress, 129762306a36Sopenharmony_ci &budget_av->budget.i2c_adap, 129862306a36Sopenharmony_ci read_pwm(budget_av)); 129962306a36Sopenharmony_ci if (fe) { 130062306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci case SUBID_DVBC_EASYWATCH_MK3: 130562306a36Sopenharmony_ci case SUBID_DVBC_CINERGY1200_MK3: 130662306a36Sopenharmony_ci case SUBID_DVBC_KNC1_MK3: 130762306a36Sopenharmony_ci case SUBID_DVBC_KNC1_TDA10024: 130862306a36Sopenharmony_ci case SUBID_DVBC_KNC1_PLUS_MK3: 130962306a36Sopenharmony_ci budget_av->reinitialise_demod = 1; 131062306a36Sopenharmony_ci budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; 131162306a36Sopenharmony_ci fe = dvb_attach(tda10023_attach, 131262306a36Sopenharmony_ci &philips_cu1216_tda10023_config, 131362306a36Sopenharmony_ci &budget_av->budget.i2c_adap, 131462306a36Sopenharmony_ci read_pwm(budget_av)); 131562306a36Sopenharmony_ci if (fe) { 131662306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci break; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci case SUBID_DVBT_EASYWATCH: 132162306a36Sopenharmony_ci case SUBID_DVBT_KNC1: 132262306a36Sopenharmony_ci case SUBID_DVBT_KNC1_PLUS: 132362306a36Sopenharmony_ci case SUBID_DVBT_CINERGY1200: 132462306a36Sopenharmony_ci budget_av->reinitialise_demod = 1; 132562306a36Sopenharmony_ci fe = dvb_attach(tda10046_attach, &philips_tu1216_config, 132662306a36Sopenharmony_ci &budget_av->budget.i2c_adap); 132762306a36Sopenharmony_ci if (fe) { 132862306a36Sopenharmony_ci fe->ops.tuner_ops.init = philips_tu1216_tuner_init; 132962306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci break; 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (fe == NULL) { 133562306a36Sopenharmony_ci pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", 133662306a36Sopenharmony_ci saa->pci->vendor, 133762306a36Sopenharmony_ci saa->pci->device, 133862306a36Sopenharmony_ci saa->pci->subsystem_vendor, 133962306a36Sopenharmony_ci saa->pci->subsystem_device); 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci budget_av->budget.dvb_frontend = fe; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (dvb_register_frontend(&budget_av->budget.dvb_adapter, 134662306a36Sopenharmony_ci budget_av->budget.dvb_frontend)) { 134762306a36Sopenharmony_ci pr_err("Frontend registration failed!\n"); 134862306a36Sopenharmony_ci dvb_frontend_detach(budget_av->budget.dvb_frontend); 134962306a36Sopenharmony_ci budget_av->budget.dvb_frontend = NULL; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic void budget_av_irq(struct saa7146_dev *dev, u32 * isr) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct budget_av *budget_av = dev->ext_priv; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (*isr & MASK_10) 136162306a36Sopenharmony_ci ttpci_budget_irq10_handler(dev, isr); 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cistatic int budget_av_detach(struct saa7146_dev *dev) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci struct budget_av *budget_av = dev->ext_priv; 136762306a36Sopenharmony_ci int err; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci dprintk(2, "dev: %p\n", dev); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (1 == budget_av->has_saa7113) { 137262306a36Sopenharmony_ci saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci msleep(200); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci saa7146_unregister_device(&budget_av->vd, dev); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci saa7146_vv_release(dev); 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (budget_av->budget.ci_present) 138262306a36Sopenharmony_ci ciintf_deinit(budget_av); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci if (budget_av->budget.dvb_frontend != NULL) { 138562306a36Sopenharmony_ci dvb_unregister_frontend(budget_av->budget.dvb_frontend); 138662306a36Sopenharmony_ci dvb_frontend_detach(budget_av->budget.dvb_frontend); 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci err = ttpci_budget_deinit(&budget_av->budget); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci kfree(budget_av); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci return err; 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci#define KNC1_INPUTS 2 139662306a36Sopenharmony_cistatic struct v4l2_input knc1_inputs[KNC1_INPUTS] = { 139762306a36Sopenharmony_ci { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, 139862306a36Sopenharmony_ci V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, 139962306a36Sopenharmony_ci { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, 140062306a36Sopenharmony_ci V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, 140162306a36Sopenharmony_ci}; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index); 140662306a36Sopenharmony_ci if (i->index >= KNC1_INPUTS) 140762306a36Sopenharmony_ci return -EINVAL; 140862306a36Sopenharmony_ci memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); 140962306a36Sopenharmony_ci return 0; 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *fh, unsigned int *i) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci struct saa7146_dev *dev = video_drvdata(file); 141562306a36Sopenharmony_ci struct budget_av *budget_av = dev->ext_priv; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci *i = budget_av->cur_input; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci dprintk(1, "VIDIOC_G_INPUT %d\n", *i); 142062306a36Sopenharmony_ci return 0; 142162306a36Sopenharmony_ci} 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *fh, unsigned int input) 142462306a36Sopenharmony_ci{ 142562306a36Sopenharmony_ci struct saa7146_dev *dev = video_drvdata(file); 142662306a36Sopenharmony_ci struct budget_av *budget_av = dev->ext_priv; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci dprintk(1, "VIDIOC_S_INPUT %d\n", input); 142962306a36Sopenharmony_ci return saa7113_setinput(budget_av, input); 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic struct saa7146_ext_vv vv_data; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci struct budget_av *budget_av; 143762306a36Sopenharmony_ci u8 *mac; 143862306a36Sopenharmony_ci int err; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci dprintk(2, "dev: %p\n", dev); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) 144362306a36Sopenharmony_ci return -ENOMEM; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci budget_av->has_saa7113 = 0; 144662306a36Sopenharmony_ci budget_av->budget.ci_present = 0; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci dev->ext_priv = budget_av; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, 145162306a36Sopenharmony_ci adapter_nr); 145262306a36Sopenharmony_ci if (err) { 145362306a36Sopenharmony_ci kfree(budget_av); 145462306a36Sopenharmony_ci return err; 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* knc1 initialization */ 145862306a36Sopenharmony_ci saa7146_write(dev, DD1_STREAM_B, 0x04000000); 145962306a36Sopenharmony_ci saa7146_write(dev, DD1_INIT, 0x07000600); 146062306a36Sopenharmony_ci saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (saa7113_init(budget_av) == 0) { 146362306a36Sopenharmony_ci budget_av->has_saa7113 = 1; 146462306a36Sopenharmony_ci err = saa7146_vv_init(dev, &vv_data); 146562306a36Sopenharmony_ci if (err != 0) { 146662306a36Sopenharmony_ci ttpci_budget_deinit(&budget_av->budget); 146762306a36Sopenharmony_ci kfree(budget_av); 146862306a36Sopenharmony_ci ERR("cannot init vv subsystem\n"); 146962306a36Sopenharmony_ci return err; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; 147262306a36Sopenharmony_ci vv_data.vid_ops.vidioc_g_input = vidioc_g_input; 147362306a36Sopenharmony_ci vv_data.vid_ops.vidioc_s_input = vidioc_s_input; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_VIDEO))) { 147662306a36Sopenharmony_ci saa7146_vv_release(dev); 147762306a36Sopenharmony_ci ttpci_budget_deinit(&budget_av->budget); 147862306a36Sopenharmony_ci kfree(budget_av); 147962306a36Sopenharmony_ci ERR("cannot register capture v4l2 device\n"); 148062306a36Sopenharmony_ci return err; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci /* beware: this modifies dev->vv ... */ 148462306a36Sopenharmony_ci saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, 148562306a36Sopenharmony_ci SAA7146_HPS_SYNC_PORT_A); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci saa7113_setinput(budget_av, 0); 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci /* fixme: find some sane values here... */ 149162306a36Sopenharmony_ci saa7146_write(dev, PCI_BT_V1, 0x1c00101f); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci mac = budget_av->budget.dvb_adapter.proposed_mac; 149462306a36Sopenharmony_ci if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { 149562306a36Sopenharmony_ci pr_err("KNC1-%d: Could not read MAC from KNC1 card\n", 149662306a36Sopenharmony_ci budget_av->budget.dvb_adapter.num); 149762306a36Sopenharmony_ci eth_zero_addr(mac); 149862306a36Sopenharmony_ci } else { 149962306a36Sopenharmony_ci pr_info("KNC1-%d: MAC addr = %pM\n", 150062306a36Sopenharmony_ci budget_av->budget.dvb_adapter.num, mac); 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci budget_av->budget.dvb_adapter.priv = budget_av; 150462306a36Sopenharmony_ci frontend_init(budget_av); 150562306a36Sopenharmony_ci ciintf_init(budget_av); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ttpci_budget_init_hooks(&budget_av->budget); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci return 0; 151062306a36Sopenharmony_ci} 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cistatic struct saa7146_standard standard[] = { 151362306a36Sopenharmony_ci {.name = "PAL",.id = V4L2_STD_PAL, 151462306a36Sopenharmony_ci .v_offset = 0x17,.v_field = 288, 151562306a36Sopenharmony_ci .h_offset = 0x14,.h_pixels = 680, 151662306a36Sopenharmony_ci .v_max_out = 576,.h_max_out = 768 }, 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci {.name = "NTSC",.id = V4L2_STD_NTSC, 151962306a36Sopenharmony_ci .v_offset = 0x16,.v_field = 240, 152062306a36Sopenharmony_ci .h_offset = 0x06,.h_pixels = 708, 152162306a36Sopenharmony_ci .v_max_out = 480,.h_max_out = 640, }, 152262306a36Sopenharmony_ci}; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistatic struct saa7146_ext_vv vv_data = { 152562306a36Sopenharmony_ci .inputs = 2, 152662306a36Sopenharmony_ci .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 152762306a36Sopenharmony_ci .flags = 0, 152862306a36Sopenharmony_ci .stds = &standard[0], 152962306a36Sopenharmony_ci .num_stds = ARRAY_SIZE(standard), 153062306a36Sopenharmony_ci}; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cistatic struct saa7146_extension budget_extension; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); 153562306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); 153662306a36Sopenharmony_ciMAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); 153762306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); 153862306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); 153962306a36Sopenharmony_ciMAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); 154062306a36Sopenharmony_ciMAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); 154162306a36Sopenharmony_ciMAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); 154262306a36Sopenharmony_ciMAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); 154362306a36Sopenharmony_ciMAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); 154462306a36Sopenharmony_ciMAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); 154562306a36Sopenharmony_ciMAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); 154662306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); 154762306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); 154862306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); 154962306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); 155062306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024); 155162306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); 155262306a36Sopenharmony_ciMAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); 155362306a36Sopenharmony_ciMAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); 155462306a36Sopenharmony_ciMAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); 155562306a36Sopenharmony_ciMAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); 155662306a36Sopenharmony_ciMAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); 155762306a36Sopenharmony_ciMAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic const struct pci_device_id pci_tbl[] = { 156062306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), 156162306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), 156262306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), 156362306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), 156462306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), 156562306a36Sopenharmony_ci MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), 156662306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), 156762306a36Sopenharmony_ci MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), 156862306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), 156962306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), 157062306a36Sopenharmony_ci MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), 157162306a36Sopenharmony_ci MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), 157262306a36Sopenharmony_ci MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), 157362306a36Sopenharmony_ci MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), 157462306a36Sopenharmony_ci MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), 157562306a36Sopenharmony_ci MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), 157662306a36Sopenharmony_ci MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), 157762306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), 157862306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), 157962306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), 158062306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028), 158162306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), 158262306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), 158362306a36Sopenharmony_ci MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), 158462306a36Sopenharmony_ci MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), 158562306a36Sopenharmony_ci MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), 158662306a36Sopenharmony_ci MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), 158762306a36Sopenharmony_ci MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), 158862306a36Sopenharmony_ci MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), 158962306a36Sopenharmony_ci { 159062306a36Sopenharmony_ci .vendor = 0, 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci}; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pci_tbl); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_cistatic struct saa7146_extension budget_extension = { 159762306a36Sopenharmony_ci .name = "budget_av", 159862306a36Sopenharmony_ci .flags = SAA7146_USE_I2C_IRQ, 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci .pci_tbl = pci_tbl, 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci .module = THIS_MODULE, 160362306a36Sopenharmony_ci .attach = budget_av_attach, 160462306a36Sopenharmony_ci .detach = budget_av_detach, 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci .irq_mask = MASK_10, 160762306a36Sopenharmony_ci .irq_func = budget_av_irq, 160862306a36Sopenharmony_ci}; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_cistatic int __init budget_av_init(void) 161162306a36Sopenharmony_ci{ 161262306a36Sopenharmony_ci return saa7146_register_extension(&budget_extension); 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistatic void __exit budget_av_exit(void) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci saa7146_unregister_extension(&budget_extension); 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cimodule_init(budget_av_init); 162162306a36Sopenharmony_cimodule_exit(budget_av_exit); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 162462306a36Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); 162562306a36Sopenharmony_ciMODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); 1626