162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * budget-ci.c: driver for the SAA7146 based Budget DVB cards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Compiled from various sources by Michael Hunold <michael@mihu.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM> 862306a36Sopenharmony_ci * partially based on the Siemens DVB driver by Ralph+Marcus Metzler 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * the project's page is at https://linuxtv.org 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/errno.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/interrupt.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <media/rc-core.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "budget.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <media/dvb_ca_en50221.h> 2562306a36Sopenharmony_ci#include "stv0299.h" 2662306a36Sopenharmony_ci#include "stv0297.h" 2762306a36Sopenharmony_ci#include "tda1004x.h" 2862306a36Sopenharmony_ci#include "stb0899_drv.h" 2962306a36Sopenharmony_ci#include "stb0899_reg.h" 3062306a36Sopenharmony_ci#include "stb0899_cfg.h" 3162306a36Sopenharmony_ci#include "stb6100.h" 3262306a36Sopenharmony_ci#include "stb6100_cfg.h" 3362306a36Sopenharmony_ci#include "lnbp21.h" 3462306a36Sopenharmony_ci#include "bsbe1.h" 3562306a36Sopenharmony_ci#include "bsru6.h" 3662306a36Sopenharmony_ci#include "tda1002x.h" 3762306a36Sopenharmony_ci#include "tda827x.h" 3862306a36Sopenharmony_ci#include "bsbe1-d01a.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define MODULE_NAME "budget_ci" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * Regarding DEBIADDR_IR: 4462306a36Sopenharmony_ci * Some CI modules hang if random addresses are read. 4562306a36Sopenharmony_ci * Using address 0x4000 for the IR read means that we 4662306a36Sopenharmony_ci * use the same address as for CI version, which should 4762306a36Sopenharmony_ci * be a safe default. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci#define DEBIADDR_IR 0x4000 5062306a36Sopenharmony_ci#define DEBIADDR_CICONTROL 0x0000 5162306a36Sopenharmony_ci#define DEBIADDR_CIVERSION 0x4000 5262306a36Sopenharmony_ci#define DEBIADDR_IO 0x1000 5362306a36Sopenharmony_ci#define DEBIADDR_ATTR 0x3000 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define CICONTROL_RESET 0x01 5662306a36Sopenharmony_ci#define CICONTROL_ENABLETS 0x02 5762306a36Sopenharmony_ci#define CICONTROL_CAMDETECT 0x08 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define DEBICICTL 0x00420000 6062306a36Sopenharmony_ci#define DEBICICAM 0x02420000 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define SLOTSTATUS_NONE 1 6362306a36Sopenharmony_ci#define SLOTSTATUS_PRESENT 2 6462306a36Sopenharmony_ci#define SLOTSTATUS_RESET 4 6562306a36Sopenharmony_ci#define SLOTSTATUS_READY 8 6662306a36Sopenharmony_ci#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* RC5 device wildcard */ 6962306a36Sopenharmony_ci#define IR_DEVICE_ANY 255 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int rc5_device = -1; 7262306a36Sopenharmony_cimodule_param(rc5_device, int, 0644); 7362306a36Sopenharmony_ciMODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int ir_debug; 7662306a36Sopenharmony_cimodule_param(ir_debug, int, 0644); 7762306a36Sopenharmony_ciMODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct budget_ci_ir { 8262306a36Sopenharmony_ci struct rc_dev *dev; 8362306a36Sopenharmony_ci struct tasklet_struct msp430_irq_tasklet; 8462306a36Sopenharmony_ci char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ 8562306a36Sopenharmony_ci char phys[32]; 8662306a36Sopenharmony_ci int rc5_device; 8762306a36Sopenharmony_ci u32 ir_key; 8862306a36Sopenharmony_ci bool have_command; 8962306a36Sopenharmony_ci bool full_rc5; /* Outputs a full RC5 code */ 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct budget_ci { 9362306a36Sopenharmony_ci struct budget budget; 9462306a36Sopenharmony_ci struct tasklet_struct ciintf_irq_tasklet; 9562306a36Sopenharmony_ci int slot_status; 9662306a36Sopenharmony_ci int ci_irq; 9762306a36Sopenharmony_ci struct dvb_ca_en50221 ca; 9862306a36Sopenharmony_ci struct budget_ci_ir ir; 9962306a36Sopenharmony_ci u8 tuner_pll_address; /* used for philips_tdm1316l configs */ 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void msp430_ir_interrupt(struct tasklet_struct *t) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet); 10562306a36Sopenharmony_ci struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); 10662306a36Sopenharmony_ci struct rc_dev *dev = budget_ci->ir.dev; 10762306a36Sopenharmony_ci u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* 11062306a36Sopenharmony_ci * The msp430 chip can generate two different bytes, command and device 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * type1: X1CCCCCC, C = command bits (0 - 63) 11362306a36Sopenharmony_ci * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Each signal from the remote control can generate one or more command 11662306a36Sopenharmony_ci * bytes and one or more device bytes. For the repeated bytes, the 11762306a36Sopenharmony_ci * highest bit (X) is set. The first command byte is always generated 11862306a36Sopenharmony_ci * before the first device byte. Other than that, no specific order 11962306a36Sopenharmony_ci * seems to apply. To make life interesting, bytes can also be lost. 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Only when we have a command and device byte, a keypress is 12262306a36Sopenharmony_ci * generated. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (ir_debug) 12662306a36Sopenharmony_ci printk("budget_ci: received byte 0x%02x\n", command); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Remove repeat bit, we use every command */ 12962306a36Sopenharmony_ci command = command & 0x7f; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Is this a RC5 command byte? */ 13262306a36Sopenharmony_ci if (command & 0x40) { 13362306a36Sopenharmony_ci budget_ci->ir.have_command = true; 13462306a36Sopenharmony_ci budget_ci->ir.ir_key = command & 0x3f; 13562306a36Sopenharmony_ci return; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* It's a RC5 device byte */ 13962306a36Sopenharmony_ci if (!budget_ci->ir.have_command) 14062306a36Sopenharmony_ci return; 14162306a36Sopenharmony_ci budget_ci->ir.have_command = false; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && 14462306a36Sopenharmony_ci budget_ci->ir.rc5_device != (command & 0x1f)) 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (budget_ci->ir.full_rc5) { 14862306a36Sopenharmony_ci rc_keydown(dev, RC_PROTO_RC5, 14962306a36Sopenharmony_ci RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key), 15062306a36Sopenharmony_ci !!(command & 0x20)); 15162306a36Sopenharmony_ci return; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* FIXME: We should generate complete scancodes for all devices */ 15562306a36Sopenharmony_ci rc_keydown(dev, RC_PROTO_UNKNOWN, budget_ci->ir.ir_key, 15662306a36Sopenharmony_ci !!(command & 0x20)); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic int msp430_ir_init(struct budget_ci *budget_ci) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 16262306a36Sopenharmony_ci struct rc_dev *dev; 16362306a36Sopenharmony_ci int error; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci dev = rc_allocate_device(RC_DRIVER_SCANCODE); 16662306a36Sopenharmony_ci if (!dev) { 16762306a36Sopenharmony_ci printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); 16862306a36Sopenharmony_ci return -ENOMEM; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), 17262306a36Sopenharmony_ci "Budget-CI dvb ir receiver %s", saa->name); 17362306a36Sopenharmony_ci snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys), 17462306a36Sopenharmony_ci "pci-%s/ir0", pci_name(saa->pci)); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci dev->driver_name = MODULE_NAME; 17762306a36Sopenharmony_ci dev->device_name = budget_ci->ir.name; 17862306a36Sopenharmony_ci dev->input_phys = budget_ci->ir.phys; 17962306a36Sopenharmony_ci dev->input_id.bustype = BUS_PCI; 18062306a36Sopenharmony_ci dev->input_id.version = 1; 18162306a36Sopenharmony_ci if (saa->pci->subsystem_vendor) { 18262306a36Sopenharmony_ci dev->input_id.vendor = saa->pci->subsystem_vendor; 18362306a36Sopenharmony_ci dev->input_id.product = saa->pci->subsystem_device; 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci dev->input_id.vendor = saa->pci->vendor; 18662306a36Sopenharmony_ci dev->input_id.product = saa->pci->device; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci dev->dev.parent = &saa->pci->dev; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (rc5_device < 0) 19162306a36Sopenharmony_ci budget_ci->ir.rc5_device = IR_DEVICE_ANY; 19262306a36Sopenharmony_ci else 19362306a36Sopenharmony_ci budget_ci->ir.rc5_device = rc5_device; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Select keymap and address */ 19662306a36Sopenharmony_ci switch (budget_ci->budget.dev->pci->subsystem_device) { 19762306a36Sopenharmony_ci case 0x100c: 19862306a36Sopenharmony_ci case 0x100f: 19962306a36Sopenharmony_ci case 0x1011: 20062306a36Sopenharmony_ci case 0x1012: 20162306a36Sopenharmony_ci /* The hauppauge keymap is a superset of these remotes */ 20262306a36Sopenharmony_ci dev->map_name = RC_MAP_HAUPPAUGE; 20362306a36Sopenharmony_ci budget_ci->ir.full_rc5 = true; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (rc5_device < 0) 20662306a36Sopenharmony_ci budget_ci->ir.rc5_device = 0x1f; 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci case 0x1010: 20962306a36Sopenharmony_ci case 0x1017: 21062306a36Sopenharmony_ci case 0x1019: 21162306a36Sopenharmony_ci case 0x101a: 21262306a36Sopenharmony_ci case 0x101b: 21362306a36Sopenharmony_ci /* for the Technotrend 1500 bundled remote */ 21462306a36Sopenharmony_ci dev->map_name = RC_MAP_TT_1500; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci default: 21762306a36Sopenharmony_ci /* unknown remote */ 21862306a36Sopenharmony_ci dev->map_name = RC_MAP_BUDGET_CI_OLD; 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci if (!budget_ci->ir.full_rc5) 22262306a36Sopenharmony_ci dev->scancode_mask = 0xff; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci error = rc_register_device(dev); 22562306a36Sopenharmony_ci if (error) { 22662306a36Sopenharmony_ci printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); 22762306a36Sopenharmony_ci rc_free_device(dev); 22862306a36Sopenharmony_ci return error; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci budget_ci->ir.dev = dev; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci tasklet_setup(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci SAA7146_IER_ENABLE(saa, MASK_06); 23662306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void msp430_ir_deinit(struct budget_ci *budget_ci) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci SAA7146_IER_DISABLE(saa, MASK_06); 24662306a36Sopenharmony_ci saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); 24762306a36Sopenharmony_ci tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci rc_unregister_device(budget_ci->ir.dev); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (slot != 0) 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, 26062306a36Sopenharmony_ci DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (slot != 0) 26862306a36Sopenharmony_ci return -EINVAL; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, 27162306a36Sopenharmony_ci DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (slot != 0) 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, 28262306a36Sopenharmony_ci DEBIADDR_IO | (address & 3), 1, 1, 0); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (slot != 0) 29062306a36Sopenharmony_ci return -EINVAL; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, 29362306a36Sopenharmony_ci DEBIADDR_IO | (address & 3), 1, value, 1, 0); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 29962306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (slot != 0) 30262306a36Sopenharmony_ci return -EINVAL; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (budget_ci->ci_irq) { 30562306a36Sopenharmony_ci // trigger on RISING edge during reset so we know when READY is re-asserted 30662306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_RESET; 30962306a36Sopenharmony_ci ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); 31062306a36Sopenharmony_ci msleep(1); 31162306a36Sopenharmony_ci ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 31262306a36Sopenharmony_ci CICONTROL_RESET, 1, 0); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); 31562306a36Sopenharmony_ci ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 32262306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (slot != 0) 32562306a36Sopenharmony_ci return -EINVAL; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); 32862306a36Sopenharmony_ci ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 33562306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 33662306a36Sopenharmony_ci int tmp; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (slot != 0) 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); 34462306a36Sopenharmony_ci ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 34562306a36Sopenharmony_ci tmp | CICONTROL_ENABLETS, 1, 0); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void ciintf_interrupt(struct tasklet_struct *t) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct budget_ci *budget_ci = from_tasklet(budget_ci, t, 35462306a36Sopenharmony_ci ciintf_irq_tasklet); 35562306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 35662306a36Sopenharmony_ci unsigned int flags; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci // ensure we don't get spurious IRQs during initialisation 35962306a36Sopenharmony_ci if (!budget_ci->budget.ci_present) 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci // read the CAM status 36362306a36Sopenharmony_ci flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); 36462306a36Sopenharmony_ci if (flags & CICONTROL_CAMDETECT) { 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci // GPIO should be set to trigger on falling edge if a CAM is present 36762306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (budget_ci->slot_status & SLOTSTATUS_NONE) { 37062306a36Sopenharmony_ci // CAM insertion IRQ 37162306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_PRESENT; 37262306a36Sopenharmony_ci dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, 37362306a36Sopenharmony_ci DVB_CA_EN50221_CAMCHANGE_INSERTED); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { 37662306a36Sopenharmony_ci // CAM ready (reset completed) 37762306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_READY; 37862306a36Sopenharmony_ci dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci } else if (budget_ci->slot_status & SLOTSTATUS_READY) { 38162306a36Sopenharmony_ci // FR/DA IRQ 38262306a36Sopenharmony_ci dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } else { 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci // trigger on rising edge if a CAM is not present - when a CAM is inserted, we 38762306a36Sopenharmony_ci // only want to get the IRQ when it sets READY. If we trigger on the falling edge, 38862306a36Sopenharmony_ci // the CAM might not actually be ready yet. 38962306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci // generate a CAM removal IRQ if we haven't already 39262306a36Sopenharmony_ci if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { 39362306a36Sopenharmony_ci // CAM removal IRQ 39462306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_NONE; 39562306a36Sopenharmony_ci dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, 39662306a36Sopenharmony_ci DVB_CA_EN50221_CAMCHANGE_REMOVED); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct budget_ci *budget_ci = ca->data; 40462306a36Sopenharmony_ci unsigned int flags; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci // ensure we don't get spurious IRQs during initialisation 40762306a36Sopenharmony_ci if (!budget_ci->budget.ci_present) 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci // read the CAM status 41162306a36Sopenharmony_ci flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); 41262306a36Sopenharmony_ci if (flags & CICONTROL_CAMDETECT) { 41362306a36Sopenharmony_ci // mark it as present if it wasn't before 41462306a36Sopenharmony_ci if (budget_ci->slot_status & SLOTSTATUS_NONE) { 41562306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_PRESENT; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci // during a RESET, we check if we can read from IO memory to see when CAM is ready 41962306a36Sopenharmony_ci if (budget_ci->slot_status & SLOTSTATUS_RESET) { 42062306a36Sopenharmony_ci if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { 42162306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_READY; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_NONE; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (budget_ci->slot_status != SLOTSTATUS_NONE) { 42962306a36Sopenharmony_ci if (budget_ci->slot_status & SLOTSTATUS_READY) { 43062306a36Sopenharmony_ci return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci return DVB_CA_EN50221_POLL_CAM_PRESENT; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int ciintf_init(struct budget_ci *budget_ci) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 44162306a36Sopenharmony_ci int flags; 44262306a36Sopenharmony_ci int result; 44362306a36Sopenharmony_ci int ci_version; 44462306a36Sopenharmony_ci int ca_flags; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci // enable DEBI pins 44962306a36Sopenharmony_ci saa7146_write(saa, MC1, MASK_27 | MASK_11); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci // test if it is there 45262306a36Sopenharmony_ci ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); 45362306a36Sopenharmony_ci if ((ci_version & 0xa0) != 0xa0) { 45462306a36Sopenharmony_ci result = -ENODEV; 45562306a36Sopenharmony_ci goto error; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci // determine whether a CAM is present or not 45962306a36Sopenharmony_ci flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); 46062306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_NONE; 46162306a36Sopenharmony_ci if (flags & CICONTROL_CAMDETECT) 46262306a36Sopenharmony_ci budget_ci->slot_status = SLOTSTATUS_PRESENT; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci // version 0xa2 of the CI firmware doesn't generate interrupts 46562306a36Sopenharmony_ci if (ci_version == 0xa2) { 46662306a36Sopenharmony_ci ca_flags = 0; 46762306a36Sopenharmony_ci budget_ci->ci_irq = 0; 46862306a36Sopenharmony_ci } else { 46962306a36Sopenharmony_ci ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | 47062306a36Sopenharmony_ci DVB_CA_EN50221_FLAG_IRQ_FR | 47162306a36Sopenharmony_ci DVB_CA_EN50221_FLAG_IRQ_DA; 47262306a36Sopenharmony_ci budget_ci->ci_irq = 1; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci // register CI interface 47662306a36Sopenharmony_ci budget_ci->ca.owner = THIS_MODULE; 47762306a36Sopenharmony_ci budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; 47862306a36Sopenharmony_ci budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; 47962306a36Sopenharmony_ci budget_ci->ca.read_cam_control = ciintf_read_cam_control; 48062306a36Sopenharmony_ci budget_ci->ca.write_cam_control = ciintf_write_cam_control; 48162306a36Sopenharmony_ci budget_ci->ca.slot_reset = ciintf_slot_reset; 48262306a36Sopenharmony_ci budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; 48362306a36Sopenharmony_ci budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; 48462306a36Sopenharmony_ci budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; 48562306a36Sopenharmony_ci budget_ci->ca.data = budget_ci; 48662306a36Sopenharmony_ci if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, 48762306a36Sopenharmony_ci &budget_ci->ca, 48862306a36Sopenharmony_ci ca_flags, 1)) != 0) { 48962306a36Sopenharmony_ci printk("budget_ci: CI interface detected, but initialisation failed.\n"); 49062306a36Sopenharmony_ci goto error; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci // Setup CI slot IRQ 49462306a36Sopenharmony_ci if (budget_ci->ci_irq) { 49562306a36Sopenharmony_ci tasklet_setup(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt); 49662306a36Sopenharmony_ci if (budget_ci->slot_status != SLOTSTATUS_NONE) { 49762306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); 49862306a36Sopenharmony_ci } else { 49962306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci SAA7146_IER_ENABLE(saa, MASK_03); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci // enable interface 50562306a36Sopenharmony_ci ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 50662306a36Sopenharmony_ci CICONTROL_RESET, 1, 0); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci // success! 50962306a36Sopenharmony_ci printk("budget_ci: CI interface initialised\n"); 51062306a36Sopenharmony_ci budget_ci->budget.ci_present = 1; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci // forge a fake CI IRQ so the CAM state is setup correctly 51362306a36Sopenharmony_ci if (budget_ci->ci_irq) { 51462306a36Sopenharmony_ci flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; 51562306a36Sopenharmony_ci if (budget_ci->slot_status != SLOTSTATUS_NONE) 51662306a36Sopenharmony_ci flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; 51762306a36Sopenharmony_ci dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cierror: 52362306a36Sopenharmony_ci saa7146_write(saa, MC1, MASK_27); 52462306a36Sopenharmony_ci return result; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void ciintf_deinit(struct budget_ci *budget_ci) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci // disable CI interrupts 53262306a36Sopenharmony_ci if (budget_ci->ci_irq) { 53362306a36Sopenharmony_ci SAA7146_IER_DISABLE(saa, MASK_03); 53462306a36Sopenharmony_ci saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); 53562306a36Sopenharmony_ci tasklet_kill(&budget_ci->ciintf_irq_tasklet); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci // reset interface 53962306a36Sopenharmony_ci ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); 54062306a36Sopenharmony_ci msleep(1); 54162306a36Sopenharmony_ci ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 54262306a36Sopenharmony_ci CICONTROL_RESET, 1, 0); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci // disable TS data stream to CI interface 54562306a36Sopenharmony_ci saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci // release the CA device 54862306a36Sopenharmony_ci dvb_ca_en50221_release(&budget_ci->ca); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci // disable DEBI pins 55162306a36Sopenharmony_ci saa7146_write(saa, MC1, MASK_27); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct budget_ci *budget_ci = dev->ext_priv; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (*isr & MASK_06) 56162306a36Sopenharmony_ci tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (*isr & MASK_10) 56462306a36Sopenharmony_ci ttpci_budget_irq10_handler(dev, isr); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) 56762306a36Sopenharmony_ci tasklet_schedule(&budget_ci->ciintf_irq_tasklet); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic u8 philips_su1278_tt_inittab[] = { 57162306a36Sopenharmony_ci 0x01, 0x0f, 57262306a36Sopenharmony_ci 0x02, 0x30, 57362306a36Sopenharmony_ci 0x03, 0x00, 57462306a36Sopenharmony_ci 0x04, 0x5b, 57562306a36Sopenharmony_ci 0x05, 0x85, 57662306a36Sopenharmony_ci 0x06, 0x02, 57762306a36Sopenharmony_ci 0x07, 0x00, 57862306a36Sopenharmony_ci 0x08, 0x02, 57962306a36Sopenharmony_ci 0x09, 0x00, 58062306a36Sopenharmony_ci 0x0C, 0x01, 58162306a36Sopenharmony_ci 0x0D, 0x81, 58262306a36Sopenharmony_ci 0x0E, 0x44, 58362306a36Sopenharmony_ci 0x0f, 0x14, 58462306a36Sopenharmony_ci 0x10, 0x3c, 58562306a36Sopenharmony_ci 0x11, 0x84, 58662306a36Sopenharmony_ci 0x12, 0xda, 58762306a36Sopenharmony_ci 0x13, 0x97, 58862306a36Sopenharmony_ci 0x14, 0x95, 58962306a36Sopenharmony_ci 0x15, 0xc9, 59062306a36Sopenharmony_ci 0x16, 0x19, 59162306a36Sopenharmony_ci 0x17, 0x8c, 59262306a36Sopenharmony_ci 0x18, 0x59, 59362306a36Sopenharmony_ci 0x19, 0xf8, 59462306a36Sopenharmony_ci 0x1a, 0xfe, 59562306a36Sopenharmony_ci 0x1c, 0x7f, 59662306a36Sopenharmony_ci 0x1d, 0x00, 59762306a36Sopenharmony_ci 0x1e, 0x00, 59862306a36Sopenharmony_ci 0x1f, 0x50, 59962306a36Sopenharmony_ci 0x20, 0x00, 60062306a36Sopenharmony_ci 0x21, 0x00, 60162306a36Sopenharmony_ci 0x22, 0x00, 60262306a36Sopenharmony_ci 0x23, 0x00, 60362306a36Sopenharmony_ci 0x28, 0x00, 60462306a36Sopenharmony_ci 0x29, 0x28, 60562306a36Sopenharmony_ci 0x2a, 0x14, 60662306a36Sopenharmony_ci 0x2b, 0x0f, 60762306a36Sopenharmony_ci 0x2c, 0x09, 60862306a36Sopenharmony_ci 0x2d, 0x09, 60962306a36Sopenharmony_ci 0x31, 0x1f, 61062306a36Sopenharmony_ci 0x32, 0x19, 61162306a36Sopenharmony_ci 0x33, 0xfc, 61262306a36Sopenharmony_ci 0x34, 0x93, 61362306a36Sopenharmony_ci 0xff, 0xff 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci stv0299_writereg(fe, 0x0e, 0x44); 61962306a36Sopenharmony_ci if (srate >= 10000000) { 62062306a36Sopenharmony_ci stv0299_writereg(fe, 0x13, 0x97); 62162306a36Sopenharmony_ci stv0299_writereg(fe, 0x14, 0x95); 62262306a36Sopenharmony_ci stv0299_writereg(fe, 0x15, 0xc9); 62362306a36Sopenharmony_ci stv0299_writereg(fe, 0x17, 0x8c); 62462306a36Sopenharmony_ci stv0299_writereg(fe, 0x1a, 0xfe); 62562306a36Sopenharmony_ci stv0299_writereg(fe, 0x1c, 0x7f); 62662306a36Sopenharmony_ci stv0299_writereg(fe, 0x2d, 0x09); 62762306a36Sopenharmony_ci } else { 62862306a36Sopenharmony_ci stv0299_writereg(fe, 0x13, 0x99); 62962306a36Sopenharmony_ci stv0299_writereg(fe, 0x14, 0x8d); 63062306a36Sopenharmony_ci stv0299_writereg(fe, 0x15, 0xce); 63162306a36Sopenharmony_ci stv0299_writereg(fe, 0x17, 0x43); 63262306a36Sopenharmony_ci stv0299_writereg(fe, 0x1a, 0x1d); 63362306a36Sopenharmony_ci stv0299_writereg(fe, 0x1c, 0x12); 63462306a36Sopenharmony_ci stv0299_writereg(fe, 0x2d, 0x05); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci stv0299_writereg(fe, 0x0e, 0x23); 63762306a36Sopenharmony_ci stv0299_writereg(fe, 0x0f, 0x94); 63862306a36Sopenharmony_ci stv0299_writereg(fe, 0x10, 0x39); 63962306a36Sopenharmony_ci stv0299_writereg(fe, 0x15, 0xc9); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); 64262306a36Sopenharmony_ci stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); 64362306a36Sopenharmony_ci stv0299_writereg(fe, 0x21, (ratio) & 0xf0); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return 0; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 65162306a36Sopenharmony_ci struct budget_ci *budget_ci = fe->dvb->priv; 65262306a36Sopenharmony_ci u32 div; 65362306a36Sopenharmony_ci u8 buf[4]; 65462306a36Sopenharmony_ci struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if ((p->frequency < 950000) || (p->frequency > 2150000)) 65762306a36Sopenharmony_ci return -EINVAL; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci div = (p->frequency + (500 - 1)) / 500; /* round correctly */ 66062306a36Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 66162306a36Sopenharmony_ci buf[1] = div & 0xff; 66262306a36Sopenharmony_ci buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; 66362306a36Sopenharmony_ci buf[3] = 0x20; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (p->symbol_rate < 4000000) 66662306a36Sopenharmony_ci buf[3] |= 1; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (p->frequency < 1250000) 66962306a36Sopenharmony_ci buf[3] |= 0; 67062306a36Sopenharmony_ci else if (p->frequency < 1550000) 67162306a36Sopenharmony_ci buf[3] |= 0x40; 67262306a36Sopenharmony_ci else if (p->frequency < 2050000) 67362306a36Sopenharmony_ci buf[3] |= 0x80; 67462306a36Sopenharmony_ci else if (p->frequency < 2150000) 67562306a36Sopenharmony_ci buf[3] |= 0xC0; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 67862306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 67962306a36Sopenharmony_ci if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) 68062306a36Sopenharmony_ci return -EIO; 68162306a36Sopenharmony_ci return 0; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic const struct stv0299_config philips_su1278_tt_config = { 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci .demod_address = 0x68, 68762306a36Sopenharmony_ci .inittab = philips_su1278_tt_inittab, 68862306a36Sopenharmony_ci .mclk = 64000000UL, 68962306a36Sopenharmony_ci .invert = 0, 69062306a36Sopenharmony_ci .skip_reinit = 1, 69162306a36Sopenharmony_ci .lock_output = STV0299_LOCKOUTPUT_1, 69262306a36Sopenharmony_ci .volt13_op0_op1 = STV0299_VOLT13_OP1, 69362306a36Sopenharmony_ci .min_delay_ms = 50, 69462306a36Sopenharmony_ci .set_symbol_rate = philips_su1278_tt_set_symbol_rate, 69562306a36Sopenharmony_ci}; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct budget_ci *budget_ci = fe->dvb->priv; 70262306a36Sopenharmony_ci static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; 70362306a36Sopenharmony_ci static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; 70462306a36Sopenharmony_ci struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = 70562306a36Sopenharmony_ci sizeof(td1316_init) }; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci // setup PLL configuration 70862306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 70962306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 71062306a36Sopenharmony_ci if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) 71162306a36Sopenharmony_ci return -EIO; 71262306a36Sopenharmony_ci msleep(1); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci // disable the mc44BC374c (do not check for errors) 71562306a36Sopenharmony_ci tuner_msg.addr = 0x65; 71662306a36Sopenharmony_ci tuner_msg.buf = disable_mc44BC374c; 71762306a36Sopenharmony_ci tuner_msg.len = sizeof(disable_mc44BC374c); 71862306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 71962306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 72062306a36Sopenharmony_ci if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { 72162306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 72262306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 72362306a36Sopenharmony_ci i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 73262306a36Sopenharmony_ci struct budget_ci *budget_ci = fe->dvb->priv; 73362306a36Sopenharmony_ci u8 tuner_buf[4]; 73462306a36Sopenharmony_ci struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; 73562306a36Sopenharmony_ci int tuner_frequency = 0; 73662306a36Sopenharmony_ci u8 band, cp, filter; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci // determine charge pump 73962306a36Sopenharmony_ci tuner_frequency = p->frequency + 36130000; 74062306a36Sopenharmony_ci if (tuner_frequency < 87000000) 74162306a36Sopenharmony_ci return -EINVAL; 74262306a36Sopenharmony_ci else if (tuner_frequency < 130000000) 74362306a36Sopenharmony_ci cp = 3; 74462306a36Sopenharmony_ci else if (tuner_frequency < 160000000) 74562306a36Sopenharmony_ci cp = 5; 74662306a36Sopenharmony_ci else if (tuner_frequency < 200000000) 74762306a36Sopenharmony_ci cp = 6; 74862306a36Sopenharmony_ci else if (tuner_frequency < 290000000) 74962306a36Sopenharmony_ci cp = 3; 75062306a36Sopenharmony_ci else if (tuner_frequency < 420000000) 75162306a36Sopenharmony_ci cp = 5; 75262306a36Sopenharmony_ci else if (tuner_frequency < 480000000) 75362306a36Sopenharmony_ci cp = 6; 75462306a36Sopenharmony_ci else if (tuner_frequency < 620000000) 75562306a36Sopenharmony_ci cp = 3; 75662306a36Sopenharmony_ci else if (tuner_frequency < 830000000) 75762306a36Sopenharmony_ci cp = 5; 75862306a36Sopenharmony_ci else if (tuner_frequency < 895000000) 75962306a36Sopenharmony_ci cp = 7; 76062306a36Sopenharmony_ci else 76162306a36Sopenharmony_ci return -EINVAL; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci // determine band 76462306a36Sopenharmony_ci if (p->frequency < 49000000) 76562306a36Sopenharmony_ci return -EINVAL; 76662306a36Sopenharmony_ci else if (p->frequency < 159000000) 76762306a36Sopenharmony_ci band = 1; 76862306a36Sopenharmony_ci else if (p->frequency < 444000000) 76962306a36Sopenharmony_ci band = 2; 77062306a36Sopenharmony_ci else if (p->frequency < 861000000) 77162306a36Sopenharmony_ci band = 4; 77262306a36Sopenharmony_ci else 77362306a36Sopenharmony_ci return -EINVAL; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci // setup PLL filter and TDA9889 77662306a36Sopenharmony_ci switch (p->bandwidth_hz) { 77762306a36Sopenharmony_ci case 6000000: 77862306a36Sopenharmony_ci tda1004x_writereg(fe, 0x0C, 0x14); 77962306a36Sopenharmony_ci filter = 0; 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci case 7000000: 78362306a36Sopenharmony_ci tda1004x_writereg(fe, 0x0C, 0x80); 78462306a36Sopenharmony_ci filter = 0; 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci case 8000000: 78862306a36Sopenharmony_ci tda1004x_writereg(fe, 0x0C, 0x14); 78962306a36Sopenharmony_ci filter = 1; 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci default: 79362306a36Sopenharmony_ci return -EINVAL; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci // calculate divisor 79762306a36Sopenharmony_ci // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) 79862306a36Sopenharmony_ci tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci // setup tuner buffer 80162306a36Sopenharmony_ci tuner_buf[0] = tuner_frequency >> 8; 80262306a36Sopenharmony_ci tuner_buf[1] = tuner_frequency & 0xff; 80362306a36Sopenharmony_ci tuner_buf[2] = 0xca; 80462306a36Sopenharmony_ci tuner_buf[3] = (cp << 5) | (filter << 3) | band; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 80762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 80862306a36Sopenharmony_ci if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) 80962306a36Sopenharmony_ci return -EIO; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci msleep(1); 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, 81662306a36Sopenharmony_ci const struct firmware **fw, char *name) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct budget_ci *budget_ci = fe->dvb->priv; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic struct tda1004x_config philips_tdm1316l_config = { 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci .demod_address = 0x8, 82662306a36Sopenharmony_ci .invert = 0, 82762306a36Sopenharmony_ci .invert_oclk = 0, 82862306a36Sopenharmony_ci .xtal_freq = TDA10046_XTAL_4M, 82962306a36Sopenharmony_ci .agc_config = TDA10046_AGC_DEFAULT, 83062306a36Sopenharmony_ci .if_freq = TDA10046_FREQ_3617, 83162306a36Sopenharmony_ci .request_firmware = philips_tdm1316l_request_firmware, 83262306a36Sopenharmony_ci}; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic struct tda1004x_config philips_tdm1316l_config_invert = { 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci .demod_address = 0x8, 83762306a36Sopenharmony_ci .invert = 1, 83862306a36Sopenharmony_ci .invert_oclk = 0, 83962306a36Sopenharmony_ci .xtal_freq = TDA10046_XTAL_4M, 84062306a36Sopenharmony_ci .agc_config = TDA10046_AGC_DEFAULT, 84162306a36Sopenharmony_ci .if_freq = TDA10046_FREQ_3617, 84262306a36Sopenharmony_ci .request_firmware = philips_tdm1316l_request_firmware, 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 84862306a36Sopenharmony_ci struct budget_ci *budget_ci = fe->dvb->priv; 84962306a36Sopenharmony_ci u8 tuner_buf[5]; 85062306a36Sopenharmony_ci struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, 85162306a36Sopenharmony_ci .flags = 0, 85262306a36Sopenharmony_ci .buf = tuner_buf, 85362306a36Sopenharmony_ci .len = sizeof(tuner_buf) }; 85462306a36Sopenharmony_ci int tuner_frequency = 0; 85562306a36Sopenharmony_ci u8 band, cp, filter; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci // determine charge pump 85862306a36Sopenharmony_ci tuner_frequency = p->frequency + 36125000; 85962306a36Sopenharmony_ci if (tuner_frequency < 87000000) 86062306a36Sopenharmony_ci return -EINVAL; 86162306a36Sopenharmony_ci else if (tuner_frequency < 130000000) { 86262306a36Sopenharmony_ci cp = 3; 86362306a36Sopenharmony_ci band = 1; 86462306a36Sopenharmony_ci } else if (tuner_frequency < 160000000) { 86562306a36Sopenharmony_ci cp = 5; 86662306a36Sopenharmony_ci band = 1; 86762306a36Sopenharmony_ci } else if (tuner_frequency < 200000000) { 86862306a36Sopenharmony_ci cp = 6; 86962306a36Sopenharmony_ci band = 1; 87062306a36Sopenharmony_ci } else if (tuner_frequency < 290000000) { 87162306a36Sopenharmony_ci cp = 3; 87262306a36Sopenharmony_ci band = 2; 87362306a36Sopenharmony_ci } else if (tuner_frequency < 420000000) { 87462306a36Sopenharmony_ci cp = 5; 87562306a36Sopenharmony_ci band = 2; 87662306a36Sopenharmony_ci } else if (tuner_frequency < 480000000) { 87762306a36Sopenharmony_ci cp = 6; 87862306a36Sopenharmony_ci band = 2; 87962306a36Sopenharmony_ci } else if (tuner_frequency < 620000000) { 88062306a36Sopenharmony_ci cp = 3; 88162306a36Sopenharmony_ci band = 4; 88262306a36Sopenharmony_ci } else if (tuner_frequency < 830000000) { 88362306a36Sopenharmony_ci cp = 5; 88462306a36Sopenharmony_ci band = 4; 88562306a36Sopenharmony_ci } else if (tuner_frequency < 895000000) { 88662306a36Sopenharmony_ci cp = 7; 88762306a36Sopenharmony_ci band = 4; 88862306a36Sopenharmony_ci } else 88962306a36Sopenharmony_ci return -EINVAL; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci // assume PLL filter should always be 8MHz for the moment. 89262306a36Sopenharmony_ci filter = 1; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci // calculate divisor 89562306a36Sopenharmony_ci tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci // setup tuner buffer 89862306a36Sopenharmony_ci tuner_buf[0] = tuner_frequency >> 8; 89962306a36Sopenharmony_ci tuner_buf[1] = tuner_frequency & 0xff; 90062306a36Sopenharmony_ci tuner_buf[2] = 0xc8; 90162306a36Sopenharmony_ci tuner_buf[3] = (cp << 5) | (filter << 3) | band; 90262306a36Sopenharmony_ci tuner_buf[4] = 0x80; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 90562306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 90662306a36Sopenharmony_ci if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) 90762306a36Sopenharmony_ci return -EIO; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci msleep(50); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 91262306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 91362306a36Sopenharmony_ci if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) 91462306a36Sopenharmony_ci return -EIO; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci msleep(1); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci return 0; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic u8 dvbc_philips_tdm1316l_inittab[] = { 92262306a36Sopenharmony_ci 0x80, 0x01, 92362306a36Sopenharmony_ci 0x80, 0x00, 92462306a36Sopenharmony_ci 0x81, 0x01, 92562306a36Sopenharmony_ci 0x81, 0x00, 92662306a36Sopenharmony_ci 0x00, 0x09, 92762306a36Sopenharmony_ci 0x01, 0x69, 92862306a36Sopenharmony_ci 0x03, 0x00, 92962306a36Sopenharmony_ci 0x04, 0x00, 93062306a36Sopenharmony_ci 0x07, 0x00, 93162306a36Sopenharmony_ci 0x08, 0x00, 93262306a36Sopenharmony_ci 0x20, 0x00, 93362306a36Sopenharmony_ci 0x21, 0x40, 93462306a36Sopenharmony_ci 0x22, 0x00, 93562306a36Sopenharmony_ci 0x23, 0x00, 93662306a36Sopenharmony_ci 0x24, 0x40, 93762306a36Sopenharmony_ci 0x25, 0x88, 93862306a36Sopenharmony_ci 0x30, 0xff, 93962306a36Sopenharmony_ci 0x31, 0x00, 94062306a36Sopenharmony_ci 0x32, 0xff, 94162306a36Sopenharmony_ci 0x33, 0x00, 94262306a36Sopenharmony_ci 0x34, 0x50, 94362306a36Sopenharmony_ci 0x35, 0x7f, 94462306a36Sopenharmony_ci 0x36, 0x00, 94562306a36Sopenharmony_ci 0x37, 0x20, 94662306a36Sopenharmony_ci 0x38, 0x00, 94762306a36Sopenharmony_ci 0x40, 0x1c, 94862306a36Sopenharmony_ci 0x41, 0xff, 94962306a36Sopenharmony_ci 0x42, 0x29, 95062306a36Sopenharmony_ci 0x43, 0x20, 95162306a36Sopenharmony_ci 0x44, 0xff, 95262306a36Sopenharmony_ci 0x45, 0x00, 95362306a36Sopenharmony_ci 0x46, 0x00, 95462306a36Sopenharmony_ci 0x49, 0x04, 95562306a36Sopenharmony_ci 0x4a, 0x00, 95662306a36Sopenharmony_ci 0x4b, 0x7b, 95762306a36Sopenharmony_ci 0x52, 0x30, 95862306a36Sopenharmony_ci 0x55, 0xae, 95962306a36Sopenharmony_ci 0x56, 0x47, 96062306a36Sopenharmony_ci 0x57, 0xe1, 96162306a36Sopenharmony_ci 0x58, 0x3a, 96262306a36Sopenharmony_ci 0x5a, 0x1e, 96362306a36Sopenharmony_ci 0x5b, 0x34, 96462306a36Sopenharmony_ci 0x60, 0x00, 96562306a36Sopenharmony_ci 0x63, 0x00, 96662306a36Sopenharmony_ci 0x64, 0x00, 96762306a36Sopenharmony_ci 0x65, 0x00, 96862306a36Sopenharmony_ci 0x66, 0x00, 96962306a36Sopenharmony_ci 0x67, 0x00, 97062306a36Sopenharmony_ci 0x68, 0x00, 97162306a36Sopenharmony_ci 0x69, 0x00, 97262306a36Sopenharmony_ci 0x6a, 0x02, 97362306a36Sopenharmony_ci 0x6b, 0x00, 97462306a36Sopenharmony_ci 0x70, 0xff, 97562306a36Sopenharmony_ci 0x71, 0x00, 97662306a36Sopenharmony_ci 0x72, 0x00, 97762306a36Sopenharmony_ci 0x73, 0x00, 97862306a36Sopenharmony_ci 0x74, 0x0c, 97962306a36Sopenharmony_ci 0x80, 0x00, 98062306a36Sopenharmony_ci 0x81, 0x00, 98162306a36Sopenharmony_ci 0x82, 0x00, 98262306a36Sopenharmony_ci 0x83, 0x00, 98362306a36Sopenharmony_ci 0x84, 0x04, 98462306a36Sopenharmony_ci 0x85, 0x80, 98562306a36Sopenharmony_ci 0x86, 0x24, 98662306a36Sopenharmony_ci 0x87, 0x78, 98762306a36Sopenharmony_ci 0x88, 0x10, 98862306a36Sopenharmony_ci 0x89, 0x00, 98962306a36Sopenharmony_ci 0x90, 0x01, 99062306a36Sopenharmony_ci 0x91, 0x01, 99162306a36Sopenharmony_ci 0xa0, 0x04, 99262306a36Sopenharmony_ci 0xa1, 0x00, 99362306a36Sopenharmony_ci 0xa2, 0x00, 99462306a36Sopenharmony_ci 0xb0, 0x91, 99562306a36Sopenharmony_ci 0xb1, 0x0b, 99662306a36Sopenharmony_ci 0xc0, 0x53, 99762306a36Sopenharmony_ci 0xc1, 0x70, 99862306a36Sopenharmony_ci 0xc2, 0x12, 99962306a36Sopenharmony_ci 0xd0, 0x00, 100062306a36Sopenharmony_ci 0xd1, 0x00, 100162306a36Sopenharmony_ci 0xd2, 0x00, 100262306a36Sopenharmony_ci 0xd3, 0x00, 100362306a36Sopenharmony_ci 0xd4, 0x00, 100462306a36Sopenharmony_ci 0xd5, 0x00, 100562306a36Sopenharmony_ci 0xde, 0x00, 100662306a36Sopenharmony_ci 0xdf, 0x00, 100762306a36Sopenharmony_ci 0x61, 0x38, 100862306a36Sopenharmony_ci 0x62, 0x0a, 100962306a36Sopenharmony_ci 0x53, 0x13, 101062306a36Sopenharmony_ci 0x59, 0x08, 101162306a36Sopenharmony_ci 0xff, 0xff, 101262306a36Sopenharmony_ci}; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic struct stv0297_config dvbc_philips_tdm1316l_config = { 101562306a36Sopenharmony_ci .demod_address = 0x1c, 101662306a36Sopenharmony_ci .inittab = dvbc_philips_tdm1316l_inittab, 101762306a36Sopenharmony_ci .invert = 0, 101862306a36Sopenharmony_ci .stop_during_read = 1, 101962306a36Sopenharmony_ci}; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic struct tda10023_config tda10023_config = { 102262306a36Sopenharmony_ci .demod_address = 0xc, 102362306a36Sopenharmony_ci .invert = 0, 102462306a36Sopenharmony_ci .xtal = 16000000, 102562306a36Sopenharmony_ci .pll_m = 11, 102662306a36Sopenharmony_ci .pll_p = 3, 102762306a36Sopenharmony_ci .pll_n = 1, 102862306a36Sopenharmony_ci .deltaf = 0xa511, 102962306a36Sopenharmony_ci}; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic struct tda827x_config tda827x_config = { 103262306a36Sopenharmony_ci .config = 0, 103362306a36Sopenharmony_ci}; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci/* TT S2-3200 DVB-S (STB0899) Inittab */ 103662306a36Sopenharmony_cistatic const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci { STB0899_DEV_ID , 0x81 }, 103962306a36Sopenharmony_ci { STB0899_DISCNTRL1 , 0x32 }, 104062306a36Sopenharmony_ci { STB0899_DISCNTRL2 , 0x80 }, 104162306a36Sopenharmony_ci { STB0899_DISRX_ST0 , 0x04 }, 104262306a36Sopenharmony_ci { STB0899_DISRX_ST1 , 0x00 }, 104362306a36Sopenharmony_ci { STB0899_DISPARITY , 0x00 }, 104462306a36Sopenharmony_ci { STB0899_DISSTATUS , 0x20 }, 104562306a36Sopenharmony_ci { STB0899_DISF22 , 0x8c }, 104662306a36Sopenharmony_ci { STB0899_DISF22RX , 0x9a }, 104762306a36Sopenharmony_ci { STB0899_SYSREG , 0x0b }, 104862306a36Sopenharmony_ci { STB0899_ACRPRESC , 0x11 }, 104962306a36Sopenharmony_ci { STB0899_ACRDIV1 , 0x0a }, 105062306a36Sopenharmony_ci { STB0899_ACRDIV2 , 0x05 }, 105162306a36Sopenharmony_ci { STB0899_DACR1 , 0x00 }, 105262306a36Sopenharmony_ci { STB0899_DACR2 , 0x00 }, 105362306a36Sopenharmony_ci { STB0899_OUTCFG , 0x00 }, 105462306a36Sopenharmony_ci { STB0899_MODECFG , 0x00 }, 105562306a36Sopenharmony_ci { STB0899_IRQSTATUS_3 , 0x30 }, 105662306a36Sopenharmony_ci { STB0899_IRQSTATUS_2 , 0x00 }, 105762306a36Sopenharmony_ci { STB0899_IRQSTATUS_1 , 0x00 }, 105862306a36Sopenharmony_ci { STB0899_IRQSTATUS_0 , 0x00 }, 105962306a36Sopenharmony_ci { STB0899_IRQMSK_3 , 0xf3 }, 106062306a36Sopenharmony_ci { STB0899_IRQMSK_2 , 0xfc }, 106162306a36Sopenharmony_ci { STB0899_IRQMSK_1 , 0xff }, 106262306a36Sopenharmony_ci { STB0899_IRQMSK_0 , 0xff }, 106362306a36Sopenharmony_ci { STB0899_IRQCFG , 0x00 }, 106462306a36Sopenharmony_ci { STB0899_I2CCFG , 0x88 }, 106562306a36Sopenharmony_ci { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ 106662306a36Sopenharmony_ci { STB0899_IOPVALUE5 , 0x00 }, 106762306a36Sopenharmony_ci { STB0899_IOPVALUE4 , 0x20 }, 106862306a36Sopenharmony_ci { STB0899_IOPVALUE3 , 0xc9 }, 106962306a36Sopenharmony_ci { STB0899_IOPVALUE2 , 0x90 }, 107062306a36Sopenharmony_ci { STB0899_IOPVALUE1 , 0x40 }, 107162306a36Sopenharmony_ci { STB0899_IOPVALUE0 , 0x00 }, 107262306a36Sopenharmony_ci { STB0899_GPIO00CFG , 0x82 }, 107362306a36Sopenharmony_ci { STB0899_GPIO01CFG , 0x82 }, 107462306a36Sopenharmony_ci { STB0899_GPIO02CFG , 0x82 }, 107562306a36Sopenharmony_ci { STB0899_GPIO03CFG , 0x82 }, 107662306a36Sopenharmony_ci { STB0899_GPIO04CFG , 0x82 }, 107762306a36Sopenharmony_ci { STB0899_GPIO05CFG , 0x82 }, 107862306a36Sopenharmony_ci { STB0899_GPIO06CFG , 0x82 }, 107962306a36Sopenharmony_ci { STB0899_GPIO07CFG , 0x82 }, 108062306a36Sopenharmony_ci { STB0899_GPIO08CFG , 0x82 }, 108162306a36Sopenharmony_ci { STB0899_GPIO09CFG , 0x82 }, 108262306a36Sopenharmony_ci { STB0899_GPIO10CFG , 0x82 }, 108362306a36Sopenharmony_ci { STB0899_GPIO11CFG , 0x82 }, 108462306a36Sopenharmony_ci { STB0899_GPIO12CFG , 0x82 }, 108562306a36Sopenharmony_ci { STB0899_GPIO13CFG , 0x82 }, 108662306a36Sopenharmony_ci { STB0899_GPIO14CFG , 0x82 }, 108762306a36Sopenharmony_ci { STB0899_GPIO15CFG , 0x82 }, 108862306a36Sopenharmony_ci { STB0899_GPIO16CFG , 0x82 }, 108962306a36Sopenharmony_ci { STB0899_GPIO17CFG , 0x82 }, 109062306a36Sopenharmony_ci { STB0899_GPIO18CFG , 0x82 }, 109162306a36Sopenharmony_ci { STB0899_GPIO19CFG , 0x82 }, 109262306a36Sopenharmony_ci { STB0899_GPIO20CFG , 0x82 }, 109362306a36Sopenharmony_ci { STB0899_SDATCFG , 0xb8 }, 109462306a36Sopenharmony_ci { STB0899_SCLTCFG , 0xba }, 109562306a36Sopenharmony_ci { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ 109662306a36Sopenharmony_ci { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ 109762306a36Sopenharmony_ci { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ 109862306a36Sopenharmony_ci { STB0899_DIRCLKCFG , 0x82 }, 109962306a36Sopenharmony_ci { STB0899_CLKOUT27CFG , 0x7e }, 110062306a36Sopenharmony_ci { STB0899_STDBYCFG , 0x82 }, 110162306a36Sopenharmony_ci { STB0899_CS0CFG , 0x82 }, 110262306a36Sopenharmony_ci { STB0899_CS1CFG , 0x82 }, 110362306a36Sopenharmony_ci { STB0899_DISEQCOCFG , 0x20 }, 110462306a36Sopenharmony_ci { STB0899_GPIO32CFG , 0x82 }, 110562306a36Sopenharmony_ci { STB0899_GPIO33CFG , 0x82 }, 110662306a36Sopenharmony_ci { STB0899_GPIO34CFG , 0x82 }, 110762306a36Sopenharmony_ci { STB0899_GPIO35CFG , 0x82 }, 110862306a36Sopenharmony_ci { STB0899_GPIO36CFG , 0x82 }, 110962306a36Sopenharmony_ci { STB0899_GPIO37CFG , 0x82 }, 111062306a36Sopenharmony_ci { STB0899_GPIO38CFG , 0x82 }, 111162306a36Sopenharmony_ci { STB0899_GPIO39CFG , 0x82 }, 111262306a36Sopenharmony_ci { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ 111362306a36Sopenharmony_ci { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ 111462306a36Sopenharmony_ci { STB0899_FILTCTRL , 0x00 }, 111562306a36Sopenharmony_ci { STB0899_SYSCTRL , 0x00 }, 111662306a36Sopenharmony_ci { STB0899_STOPCLK1 , 0x20 }, 111762306a36Sopenharmony_ci { STB0899_STOPCLK2 , 0x00 }, 111862306a36Sopenharmony_ci { STB0899_INTBUFSTATUS , 0x00 }, 111962306a36Sopenharmony_ci { STB0899_INTBUFCTRL , 0x0a }, 112062306a36Sopenharmony_ci { 0xffff , 0xff }, 112162306a36Sopenharmony_ci}; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_cistatic const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { 112462306a36Sopenharmony_ci { STB0899_DEMOD , 0x00 }, 112562306a36Sopenharmony_ci { STB0899_RCOMPC , 0xc9 }, 112662306a36Sopenharmony_ci { STB0899_AGC1CN , 0x41 }, 112762306a36Sopenharmony_ci { STB0899_AGC1REF , 0x10 }, 112862306a36Sopenharmony_ci { STB0899_RTC , 0x7a }, 112962306a36Sopenharmony_ci { STB0899_TMGCFG , 0x4e }, 113062306a36Sopenharmony_ci { STB0899_AGC2REF , 0x34 }, 113162306a36Sopenharmony_ci { STB0899_TLSR , 0x84 }, 113262306a36Sopenharmony_ci { STB0899_CFD , 0xc7 }, 113362306a36Sopenharmony_ci { STB0899_ACLC , 0x87 }, 113462306a36Sopenharmony_ci { STB0899_BCLC , 0x94 }, 113562306a36Sopenharmony_ci { STB0899_EQON , 0x41 }, 113662306a36Sopenharmony_ci { STB0899_LDT , 0xdd }, 113762306a36Sopenharmony_ci { STB0899_LDT2 , 0xc9 }, 113862306a36Sopenharmony_ci { STB0899_EQUALREF , 0xb4 }, 113962306a36Sopenharmony_ci { STB0899_TMGRAMP , 0x10 }, 114062306a36Sopenharmony_ci { STB0899_TMGTHD , 0x30 }, 114162306a36Sopenharmony_ci { STB0899_IDCCOMP , 0xfb }, 114262306a36Sopenharmony_ci { STB0899_QDCCOMP , 0x03 }, 114362306a36Sopenharmony_ci { STB0899_POWERI , 0x3b }, 114462306a36Sopenharmony_ci { STB0899_POWERQ , 0x3d }, 114562306a36Sopenharmony_ci { STB0899_RCOMP , 0x81 }, 114662306a36Sopenharmony_ci { STB0899_AGCIQIN , 0x80 }, 114762306a36Sopenharmony_ci { STB0899_AGC2I1 , 0x04 }, 114862306a36Sopenharmony_ci { STB0899_AGC2I2 , 0xf5 }, 114962306a36Sopenharmony_ci { STB0899_TLIR , 0x25 }, 115062306a36Sopenharmony_ci { STB0899_RTF , 0x80 }, 115162306a36Sopenharmony_ci { STB0899_DSTATUS , 0x00 }, 115262306a36Sopenharmony_ci { STB0899_LDI , 0xca }, 115362306a36Sopenharmony_ci { STB0899_CFRM , 0xf1 }, 115462306a36Sopenharmony_ci { STB0899_CFRL , 0xf3 }, 115562306a36Sopenharmony_ci { STB0899_NIRM , 0x2a }, 115662306a36Sopenharmony_ci { STB0899_NIRL , 0x05 }, 115762306a36Sopenharmony_ci { STB0899_ISYMB , 0x17 }, 115862306a36Sopenharmony_ci { STB0899_QSYMB , 0xfa }, 115962306a36Sopenharmony_ci { STB0899_SFRH , 0x2f }, 116062306a36Sopenharmony_ci { STB0899_SFRM , 0x68 }, 116162306a36Sopenharmony_ci { STB0899_SFRL , 0x40 }, 116262306a36Sopenharmony_ci { STB0899_SFRUPH , 0x2f }, 116362306a36Sopenharmony_ci { STB0899_SFRUPM , 0x68 }, 116462306a36Sopenharmony_ci { STB0899_SFRUPL , 0x40 }, 116562306a36Sopenharmony_ci { STB0899_EQUAI1 , 0xfd }, 116662306a36Sopenharmony_ci { STB0899_EQUAQ1 , 0x04 }, 116762306a36Sopenharmony_ci { STB0899_EQUAI2 , 0x0f }, 116862306a36Sopenharmony_ci { STB0899_EQUAQ2 , 0xff }, 116962306a36Sopenharmony_ci { STB0899_EQUAI3 , 0xdf }, 117062306a36Sopenharmony_ci { STB0899_EQUAQ3 , 0xfa }, 117162306a36Sopenharmony_ci { STB0899_EQUAI4 , 0x37 }, 117262306a36Sopenharmony_ci { STB0899_EQUAQ4 , 0x0d }, 117362306a36Sopenharmony_ci { STB0899_EQUAI5 , 0xbd }, 117462306a36Sopenharmony_ci { STB0899_EQUAQ5 , 0xf7 }, 117562306a36Sopenharmony_ci { STB0899_DSTATUS2 , 0x00 }, 117662306a36Sopenharmony_ci { STB0899_VSTATUS , 0x00 }, 117762306a36Sopenharmony_ci { STB0899_VERROR , 0xff }, 117862306a36Sopenharmony_ci { STB0899_IQSWAP , 0x2a }, 117962306a36Sopenharmony_ci { STB0899_ECNT1M , 0x00 }, 118062306a36Sopenharmony_ci { STB0899_ECNT1L , 0x00 }, 118162306a36Sopenharmony_ci { STB0899_ECNT2M , 0x00 }, 118262306a36Sopenharmony_ci { STB0899_ECNT2L , 0x00 }, 118362306a36Sopenharmony_ci { STB0899_ECNT3M , 0x00 }, 118462306a36Sopenharmony_ci { STB0899_ECNT3L , 0x00 }, 118562306a36Sopenharmony_ci { STB0899_FECAUTO1 , 0x06 }, 118662306a36Sopenharmony_ci { STB0899_FECM , 0x01 }, 118762306a36Sopenharmony_ci { STB0899_VTH12 , 0xf0 }, 118862306a36Sopenharmony_ci { STB0899_VTH23 , 0xa0 }, 118962306a36Sopenharmony_ci { STB0899_VTH34 , 0x78 }, 119062306a36Sopenharmony_ci { STB0899_VTH56 , 0x4e }, 119162306a36Sopenharmony_ci { STB0899_VTH67 , 0x48 }, 119262306a36Sopenharmony_ci { STB0899_VTH78 , 0x38 }, 119362306a36Sopenharmony_ci { STB0899_PRVIT , 0xff }, 119462306a36Sopenharmony_ci { STB0899_VITSYNC , 0x19 }, 119562306a36Sopenharmony_ci { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ 119662306a36Sopenharmony_ci { STB0899_TSULC , 0x42 }, 119762306a36Sopenharmony_ci { STB0899_RSLLC , 0x40 }, 119862306a36Sopenharmony_ci { STB0899_TSLPL , 0x12 }, 119962306a36Sopenharmony_ci { STB0899_TSCFGH , 0x0c }, 120062306a36Sopenharmony_ci { STB0899_TSCFGM , 0x00 }, 120162306a36Sopenharmony_ci { STB0899_TSCFGL , 0x0c }, 120262306a36Sopenharmony_ci { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ 120362306a36Sopenharmony_ci { STB0899_RSSYNCDEL , 0x00 }, 120462306a36Sopenharmony_ci { STB0899_TSINHDELH , 0x02 }, 120562306a36Sopenharmony_ci { STB0899_TSINHDELM , 0x00 }, 120662306a36Sopenharmony_ci { STB0899_TSINHDELL , 0x00 }, 120762306a36Sopenharmony_ci { STB0899_TSLLSTKM , 0x00 }, 120862306a36Sopenharmony_ci { STB0899_TSLLSTKL , 0x00 }, 120962306a36Sopenharmony_ci { STB0899_TSULSTKM , 0x00 }, 121062306a36Sopenharmony_ci { STB0899_TSULSTKL , 0xab }, 121162306a36Sopenharmony_ci { STB0899_PCKLENUL , 0x00 }, 121262306a36Sopenharmony_ci { STB0899_PCKLENLL , 0xcc }, 121362306a36Sopenharmony_ci { STB0899_RSPCKLEN , 0xcc }, 121462306a36Sopenharmony_ci { STB0899_TSSTATUS , 0x80 }, 121562306a36Sopenharmony_ci { STB0899_ERRCTRL1 , 0xb6 }, 121662306a36Sopenharmony_ci { STB0899_ERRCTRL2 , 0x96 }, 121762306a36Sopenharmony_ci { STB0899_ERRCTRL3 , 0x89 }, 121862306a36Sopenharmony_ci { STB0899_DMONMSK1 , 0x27 }, 121962306a36Sopenharmony_ci { STB0899_DMONMSK0 , 0x03 }, 122062306a36Sopenharmony_ci { STB0899_DEMAPVIT , 0x5c }, 122162306a36Sopenharmony_ci { STB0899_PLPARM , 0x1f }, 122262306a36Sopenharmony_ci { STB0899_PDELCTRL , 0x48 }, 122362306a36Sopenharmony_ci { STB0899_PDELCTRL2 , 0x00 }, 122462306a36Sopenharmony_ci { STB0899_BBHCTRL1 , 0x00 }, 122562306a36Sopenharmony_ci { STB0899_BBHCTRL2 , 0x00 }, 122662306a36Sopenharmony_ci { STB0899_HYSTTHRESH , 0x77 }, 122762306a36Sopenharmony_ci { STB0899_MATCSTM , 0x00 }, 122862306a36Sopenharmony_ci { STB0899_MATCSTL , 0x00 }, 122962306a36Sopenharmony_ci { STB0899_UPLCSTM , 0x00 }, 123062306a36Sopenharmony_ci { STB0899_UPLCSTL , 0x00 }, 123162306a36Sopenharmony_ci { STB0899_DFLCSTM , 0x00 }, 123262306a36Sopenharmony_ci { STB0899_DFLCSTL , 0x00 }, 123362306a36Sopenharmony_ci { STB0899_SYNCCST , 0x00 }, 123462306a36Sopenharmony_ci { STB0899_SYNCDCSTM , 0x00 }, 123562306a36Sopenharmony_ci { STB0899_SYNCDCSTL , 0x00 }, 123662306a36Sopenharmony_ci { STB0899_ISI_ENTRY , 0x00 }, 123762306a36Sopenharmony_ci { STB0899_ISI_BIT_EN , 0x00 }, 123862306a36Sopenharmony_ci { STB0899_MATSTRM , 0x00 }, 123962306a36Sopenharmony_ci { STB0899_MATSTRL , 0x00 }, 124062306a36Sopenharmony_ci { STB0899_UPLSTRM , 0x00 }, 124162306a36Sopenharmony_ci { STB0899_UPLSTRL , 0x00 }, 124262306a36Sopenharmony_ci { STB0899_DFLSTRM , 0x00 }, 124362306a36Sopenharmony_ci { STB0899_DFLSTRL , 0x00 }, 124462306a36Sopenharmony_ci { STB0899_SYNCSTR , 0x00 }, 124562306a36Sopenharmony_ci { STB0899_SYNCDSTRM , 0x00 }, 124662306a36Sopenharmony_ci { STB0899_SYNCDSTRL , 0x00 }, 124762306a36Sopenharmony_ci { STB0899_CFGPDELSTATUS1 , 0x10 }, 124862306a36Sopenharmony_ci { STB0899_CFGPDELSTATUS2 , 0x00 }, 124962306a36Sopenharmony_ci { STB0899_BBFERRORM , 0x00 }, 125062306a36Sopenharmony_ci { STB0899_BBFERRORL , 0x00 }, 125162306a36Sopenharmony_ci { STB0899_UPKTERRORM , 0x00 }, 125262306a36Sopenharmony_ci { STB0899_UPKTERRORL , 0x00 }, 125362306a36Sopenharmony_ci { 0xffff , 0xff }, 125462306a36Sopenharmony_ci}; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic struct stb0899_config tt3200_config = { 125762306a36Sopenharmony_ci .init_dev = tt3200_stb0899_s1_init_1, 125862306a36Sopenharmony_ci .init_s2_demod = stb0899_s2_init_2, 125962306a36Sopenharmony_ci .init_s1_demod = tt3200_stb0899_s1_init_3, 126062306a36Sopenharmony_ci .init_s2_fec = stb0899_s2_init_4, 126162306a36Sopenharmony_ci .init_tst = stb0899_s1_init_5, 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci .postproc = NULL, 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci .demod_address = 0x68, 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci .xtal_freq = 27000000, 126862306a36Sopenharmony_ci .inversion = IQ_SWAP_ON, 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci .lo_clk = 76500000, 127162306a36Sopenharmony_ci .hi_clk = 99000000, 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci .esno_ave = STB0899_DVBS2_ESNO_AVE, 127462306a36Sopenharmony_ci .esno_quant = STB0899_DVBS2_ESNO_QUANT, 127562306a36Sopenharmony_ci .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, 127662306a36Sopenharmony_ci .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, 127762306a36Sopenharmony_ci .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, 127862306a36Sopenharmony_ci .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, 127962306a36Sopenharmony_ci .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, 128062306a36Sopenharmony_ci .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, 128162306a36Sopenharmony_ci .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, 128462306a36Sopenharmony_ci .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, 128562306a36Sopenharmony_ci .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, 128662306a36Sopenharmony_ci .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci .tuner_get_frequency = stb6100_get_frequency, 128962306a36Sopenharmony_ci .tuner_set_frequency = stb6100_set_frequency, 129062306a36Sopenharmony_ci .tuner_set_bandwidth = stb6100_set_bandwidth, 129162306a36Sopenharmony_ci .tuner_get_bandwidth = stb6100_get_bandwidth, 129262306a36Sopenharmony_ci .tuner_set_rfsiggain = NULL 129362306a36Sopenharmony_ci}; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic struct stb6100_config tt3200_stb6100_config = { 129662306a36Sopenharmony_ci .tuner_address = 0x60, 129762306a36Sopenharmony_ci .refclock = 27000000, 129862306a36Sopenharmony_ci}; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic void frontend_init(struct budget_ci *budget_ci) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci switch (budget_ci->budget.dev->pci->subsystem_device) { 130362306a36Sopenharmony_ci case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) 130462306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = 130562306a36Sopenharmony_ci dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); 130662306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 130762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; 130862306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; 130962306a36Sopenharmony_ci break; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci break; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) 131462306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = 131562306a36Sopenharmony_ci dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); 131662306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 131762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; 131862306a36Sopenharmony_ci break; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci break; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) 132362306a36Sopenharmony_ci budget_ci->tuner_pll_address = 0x61; 132462306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = 132562306a36Sopenharmony_ci dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); 132662306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 132762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; 132862306a36Sopenharmony_ci break; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci break; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) 133362306a36Sopenharmony_ci budget_ci->tuner_pll_address = 0x63; 133462306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = 133562306a36Sopenharmony_ci dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); 133662306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 133762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; 133862306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci break; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) 134462306a36Sopenharmony_ci budget_ci->tuner_pll_address = 0x60; 134562306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = 134662306a36Sopenharmony_ci dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); 134762306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 134862306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; 134962306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; 135062306a36Sopenharmony_ci break; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci break; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci case 0x1017: // TT S-1500 PCI 135562306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); 135662306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 135762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; 135862306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; 136162306a36Sopenharmony_ci if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { 136262306a36Sopenharmony_ci printk("%s: No LNBP21 found!\n", __func__); 136362306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 136462306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci break; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ 137062306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); 137162306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 137262306a36Sopenharmony_ci if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { 137362306a36Sopenharmony_ci printk(KERN_ERR "%s: No tda827x found!\n", __func__); 137462306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 137562306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci break; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */ 138162306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap); 138262306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 138362306a36Sopenharmony_ci if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) { 138462306a36Sopenharmony_ci if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { 138562306a36Sopenharmony_ci printk(KERN_ERR "%s: No LNBP21 found!\n", __func__); 138662306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 138762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci } else { 139062306a36Sopenharmony_ci printk(KERN_ERR "%s: No STB6000 found!\n", __func__); 139162306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 139262306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci break; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci case 0x1019: // TT S2-3200 PCI 139862306a36Sopenharmony_ci /* 139962306a36Sopenharmony_ci * NOTE! on some STB0899 versions, the internal PLL takes a longer time 140062306a36Sopenharmony_ci * to settle, aka LOCK. On the older revisions of the chip, we don't see 140162306a36Sopenharmony_ci * this, as a result on the newer chips the entire clock tree, will not 140262306a36Sopenharmony_ci * be stable after a freshly POWER 'ed up situation. 140362306a36Sopenharmony_ci * In this case, we should RESET the STB0899 (Active LOW) and wait for 140462306a36Sopenharmony_ci * PLL stabilization. 140562306a36Sopenharmony_ci * 140662306a36Sopenharmony_ci * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is 140762306a36Sopenharmony_ci * connected to the SAA7146 GPIO, GPIO2, Pin 142 140862306a36Sopenharmony_ci */ 140962306a36Sopenharmony_ci /* Reset Demodulator */ 141062306a36Sopenharmony_ci saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); 141162306a36Sopenharmony_ci /* Wait for everything to die */ 141262306a36Sopenharmony_ci msleep(50); 141362306a36Sopenharmony_ci /* Pull it up out of Reset state */ 141462306a36Sopenharmony_ci saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); 141562306a36Sopenharmony_ci /* Wait for PLL to stabilize */ 141662306a36Sopenharmony_ci msleep(250); 141762306a36Sopenharmony_ci /* 141862306a36Sopenharmony_ci * PLL state should be stable now. Ideally, we should check 141962306a36Sopenharmony_ci * for PLL LOCK status. But well, never mind! 142062306a36Sopenharmony_ci */ 142162306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); 142262306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 142362306a36Sopenharmony_ci if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { 142462306a36Sopenharmony_ci if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { 142562306a36Sopenharmony_ci printk("%s: No LNBP21 found!\n", __func__); 142662306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 142762306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci } else { 143062306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 143162306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci break; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend == NULL) { 143962306a36Sopenharmony_ci printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", 144062306a36Sopenharmony_ci budget_ci->budget.dev->pci->vendor, 144162306a36Sopenharmony_ci budget_ci->budget.dev->pci->device, 144262306a36Sopenharmony_ci budget_ci->budget.dev->pci->subsystem_vendor, 144362306a36Sopenharmony_ci budget_ci->budget.dev->pci->subsystem_device); 144462306a36Sopenharmony_ci } else { 144562306a36Sopenharmony_ci if (dvb_register_frontend 144662306a36Sopenharmony_ci (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { 144762306a36Sopenharmony_ci printk("budget-ci: Frontend registration failed!\n"); 144862306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 144962306a36Sopenharmony_ci budget_ci->budget.dvb_frontend = NULL; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci} 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_cistatic int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct budget_ci *budget_ci; 145762306a36Sopenharmony_ci int err; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL); 146062306a36Sopenharmony_ci if (!budget_ci) { 146162306a36Sopenharmony_ci err = -ENOMEM; 146262306a36Sopenharmony_ci goto out1; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci dprintk(2, "budget_ci: %p\n", budget_ci); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci dev->ext_priv = budget_ci; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, 147062306a36Sopenharmony_ci adapter_nr); 147162306a36Sopenharmony_ci if (err) 147262306a36Sopenharmony_ci goto out2; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci err = msp430_ir_init(budget_ci); 147562306a36Sopenharmony_ci if (err) 147662306a36Sopenharmony_ci goto out3; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci ciintf_init(budget_ci); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci budget_ci->budget.dvb_adapter.priv = budget_ci; 148162306a36Sopenharmony_ci frontend_init(budget_ci); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci ttpci_budget_init_hooks(&budget_ci->budget); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci return 0; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ciout3: 148862306a36Sopenharmony_ci ttpci_budget_deinit(&budget_ci->budget); 148962306a36Sopenharmony_ciout2: 149062306a36Sopenharmony_ci kfree(budget_ci); 149162306a36Sopenharmony_ciout1: 149262306a36Sopenharmony_ci return err; 149362306a36Sopenharmony_ci} 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_cistatic int budget_ci_detach(struct saa7146_dev *dev) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci struct budget_ci *budget_ci = dev->ext_priv; 149862306a36Sopenharmony_ci struct saa7146_dev *saa = budget_ci->budget.dev; 149962306a36Sopenharmony_ci int err; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (budget_ci->budget.ci_present) 150262306a36Sopenharmony_ci ciintf_deinit(budget_ci); 150362306a36Sopenharmony_ci msp430_ir_deinit(budget_ci); 150462306a36Sopenharmony_ci if (budget_ci->budget.dvb_frontend) { 150562306a36Sopenharmony_ci dvb_unregister_frontend(budget_ci->budget.dvb_frontend); 150662306a36Sopenharmony_ci dvb_frontend_detach(budget_ci->budget.dvb_frontend); 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci err = ttpci_budget_deinit(&budget_ci->budget); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci // disable frontend and CI interface 151162306a36Sopenharmony_ci saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci kfree(budget_ci); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci return err; 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cistatic struct saa7146_extension budget_extension; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT); 152162306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); 152262306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); 152362306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); 152462306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); 152562306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); 152662306a36Sopenharmony_ciMAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); 152762306a36Sopenharmony_ciMAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic const struct pci_device_id pci_tbl[] = { 153062306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), 153162306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), 153262306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), 153362306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), 153462306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), 153562306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), 153662306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), 153762306a36Sopenharmony_ci MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), 153862306a36Sopenharmony_ci MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), 153962306a36Sopenharmony_ci { 154062306a36Sopenharmony_ci .vendor = 0, 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci}; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pci_tbl); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistatic struct saa7146_extension budget_extension = { 154762306a36Sopenharmony_ci .name = "budget_ci dvb", 154862306a36Sopenharmony_ci .flags = SAA7146_USE_I2C_IRQ, 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci .module = THIS_MODULE, 155162306a36Sopenharmony_ci .pci_tbl = &pci_tbl[0], 155262306a36Sopenharmony_ci .attach = budget_ci_attach, 155362306a36Sopenharmony_ci .detach = budget_ci_detach, 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci .irq_mask = MASK_03 | MASK_06 | MASK_10, 155662306a36Sopenharmony_ci .irq_func = budget_ci_irq, 155762306a36Sopenharmony_ci}; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic int __init budget_ci_init(void) 156062306a36Sopenharmony_ci{ 156162306a36Sopenharmony_ci return saa7146_register_extension(&budget_extension); 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic void __exit budget_ci_exit(void) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci saa7146_unregister_extension(&budget_extension); 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cimodule_init(budget_ci_init); 157062306a36Sopenharmony_cimodule_exit(budget_ci_exit); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 157362306a36Sopenharmony_ciMODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); 157462306a36Sopenharmony_ciMODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards w/ CI-module produced by Siemens, Technotrend, Hauppauge"); 1575