100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey/** 200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Driver for Infineon tua6100 pll. 300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * (c) 2006 Andrew de Quincey 500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Based on code found in budget-av.c, which has the following: 700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Compiled from various sources by Michael Hunold <michael@mihu.de> 800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> & 1000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Andrew de Quincey <adq_dvb@lidskialf.net> 1100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 1200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> 1300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 1400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Copyright (C) 1999-2002 Ralph Metzler 1500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * & Marcus Metzler for convergence integrated media GmbH 1600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * This program is free software; you can redistribute it and/or modify 1700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * it under the terms of the GNU General Public License as published by 1800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * the Free Software Foundation; either version 2 of the License, or 1900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * (at your option) any later version. 2000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 2100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * This program is distributed in the hope that it will be useful, 2200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * but WITHOUT ANY WARRANTY; without even the implied warranty of 2300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * GNU General Public License for more details. 2500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * 2600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * You should have received a copy of the GNU General Public License 2700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * along with this program; if not, write to the Free Software 2800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey */ 3000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 3200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#include <linux/module.h> 3300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#include <linux/dvb/frontend.h> 3400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#include <asm/types.h> 3500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 3600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#include "tua6100.h" 3700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 3800be2e7c64157c845afff56f25677da706b151b6Andrew de Quinceystruct tua6100_priv { 3900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey /* i2c details */ 4000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey int i2c_address; 4100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct i2c_adapter *i2c; 4200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u32 frequency; 4300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey}; 4400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 4500be2e7c64157c845afff56f25677da706b151b6Andrew de Quinceystatic int tua6100_release(struct dvb_frontend *fe) 4600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey{ 472213918a99d6292767b6d4aae3e3f4b0520528a5Michael Krufky kfree(fe->tuner_priv); 4800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->tuner_priv = NULL; 4900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return 0; 5000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey} 5100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 5200be2e7c64157c845afff56f25677da706b151b6Andrew de Quinceystatic int tua6100_sleep(struct dvb_frontend *fe) 5300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey{ 5400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct tua6100_priv *priv = fe->tuner_priv; 5500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey int ret; 5600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u8 reg0[] = { 0x00, 0x00 }; 5700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 }; 5800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 5900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 6000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 1); 6100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { 62271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison printk("%s: i2c error\n", __func__); 6300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey } 6400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 6500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 0); 6600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 6700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return (ret == 1) ? 0 : ret; 6800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey} 6900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 7014d24d148c7521b2b88b396652e36f55d061e195Mauro Carvalho Chehabstatic int tua6100_set_params(struct dvb_frontend *fe) 7100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey{ 725918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 7300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct tua6100_priv *priv = fe->tuner_priv; 7400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u32 div; 7500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u32 prediv; 7600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u8 reg0[] = { 0x00, 0x00 }; 7700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 }; 7800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u8 reg2[] = { 0x02, 0x00, 0x00 }; 7900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 }; 8000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 }; 8100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 }; 8200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 8300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#define _R 4 8400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#define _P 32 8500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#define _ri 4000000 8600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 8700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey // setup register 0 885918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab if (c->frequency < 2000000) 8900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg0[1] = 0x03; 905918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab else 9100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg0[1] = 0x07; 9200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 9300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey // setup register 1 945918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab if (c->frequency < 1630000) 9500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[1] = 0x2c; 965918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab else 9700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[1] = 0x0c; 985918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab 9900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (_P == 64) 10000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[1] |= 0x40; 1015918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab if (c->frequency >= 1525000) 10200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[1] |= 0x80; 10300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 10400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey // register 2 10500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg2[1] = (_R >> 8) & 0x03; 10600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg2[2] = _R; 1075918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab if (c->frequency < 1455000) 10800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg2[1] |= 0x1c; 1095918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab else if (c->frequency < 1630000) 11000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg2[1] |= 0x0c; 1115918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab else 11200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg2[1] |= 0x1c; 11300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 1145918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab /* 1155918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab * The N divisor ratio (note: c->frequency is in kHz, but we 1165918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab * need it in Hz) 1175918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab */ 1185918288a422b8bbc0ebfd541d6cb9ed2c43b0b76Mauro Carvalho Chehab prediv = (c->frequency * _R) / (_ri / 1000); 11900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey div = prediv / _P; 12000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[1] |= (div >> 9) & 0x03; 12100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[2] = div >> 1; 12200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[3] = (div << 7); 12300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey priv->frequency = ((div * _P) * (_ri / 1000)) / _R; 12400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 12500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey // Finally, calculate and store the value for A 12600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey reg1[3] |= (prediv - (div*_P)) & 0x7f; 12700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 12800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#undef _R 12900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#undef _P 13000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey#undef _ri 13100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 13200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 13300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 1); 13400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (i2c_transfer(priv->i2c, &msg0, 1) != 1) 13500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return -EIO; 13600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 13700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 13800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 1); 13900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (i2c_transfer(priv->i2c, &msg2, 1) != 1) 14000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return -EIO; 14100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 14200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 14300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 1); 14400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (i2c_transfer(priv->i2c, &msg1, 1) != 1) 14500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return -EIO; 14600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 14700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 14800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 0); 14900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 15000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return 0; 15100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey} 15200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 15300be2e7c64157c845afff56f25677da706b151b6Andrew de Quinceystatic int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) 15400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey{ 15500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct tua6100_priv *priv = fe->tuner_priv; 15600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey *frequency = priv->frequency; 15700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return 0; 15800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey} 15900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 16000be2e7c64157c845afff56f25677da706b151b6Andrew de Quinceystatic struct dvb_tuner_ops tua6100_tuner_ops = { 16100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .info = { 16200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .name = "Infineon TUA6100", 16300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .frequency_min = 950000, 16400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .frequency_max = 2150000, 16500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .frequency_step = 1000, 16600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey }, 16700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .release = tua6100_release, 16800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .sleep = tua6100_sleep, 16900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .set_params = tua6100_set_params, 17000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey .get_frequency = tua6100_get_frequency, 17100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey}; 17200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 17300be2e7c64157c845afff56f25677da706b151b6Andrew de Quinceystruct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) 17400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey{ 17500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct tua6100_priv *priv = NULL; 17600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u8 b1 [] = { 0x80 }; 17700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey u8 b2 [] = { 0x00 }; 17800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 }, 17900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } }; 18000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey int ret; 18100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 18200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 18300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 1); 18400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey ret = i2c_transfer (i2c, msg, 2); 18500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (fe->ops.i2c_gate_ctrl) 18600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->ops.i2c_gate_ctrl(fe, 0); 18700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 18800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (ret != 2) 18900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return NULL; 19000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 19100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL); 19200be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey if (priv == NULL) 19300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return NULL; 19400be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 19500be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey priv->i2c_address = addr; 19600be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey priv->i2c = i2c; 19700be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 19800be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops)); 19900be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey fe->tuner_priv = priv; 20000be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey return fe; 20100be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey} 20200be2e7c64157c845afff56f25677da706b151b6Andrew de QuinceyEXPORT_SYMBOL(tua6100_attach); 20300be2e7c64157c845afff56f25677da706b151b6Andrew de Quincey 20400be2e7c64157c845afff56f25677da706b151b6Andrew de QuinceyMODULE_DESCRIPTION("DVB tua6100 driver"); 20500be2e7c64157c845afff56f25677da706b151b6Andrew de QuinceyMODULE_AUTHOR("Andrew de Quincey"); 20600be2e7c64157c845afff56f25677da706b151b6Andrew de QuinceyMODULE_LICENSE("GPL"); 207