Path: blob/master/drivers/media/common/tuners/mt2131.c
15112 views
/*1* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"2*3* Copyright (c) 2006 Steven Toth <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13*14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.19*/2021#include <linux/module.h>22#include <linux/delay.h>23#include <linux/dvb/frontend.h>24#include <linux/i2c.h>25#include <linux/slab.h>2627#include "dvb_frontend.h"2829#include "mt2131.h"30#include "mt2131_priv.h"3132static int debug;33module_param(debug, int, 0644);34MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");3536#define dprintk(level,fmt, arg...) if (debug >= level) \37printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)3839static u8 mt2131_config1[] = {400x01,410x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,420x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,430x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,440xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x0045};4647static u8 mt2131_config2[] = {480x10,490x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x0450};5152static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)53{54struct i2c_msg msg[2] = {55{ .addr = priv->cfg->i2c_address, .flags = 0,56.buf = ®, .len = 1 },57{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,58.buf = val, .len = 1 },59};6061if (i2c_transfer(priv->i2c, msg, 2) != 2) {62printk(KERN_WARNING "mt2131 I2C read failed\n");63return -EREMOTEIO;64}65return 0;66}6768static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)69{70u8 buf[2] = { reg, val };71struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,72.buf = buf, .len = 2 };7374if (i2c_transfer(priv->i2c, &msg, 1) != 1) {75printk(KERN_WARNING "mt2131 I2C write failed\n");76return -EREMOTEIO;77}78return 0;79}8081static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)82{83struct i2c_msg msg = { .addr = priv->cfg->i2c_address,84.flags = 0, .buf = buf, .len = len };8586if (i2c_transfer(priv->i2c, &msg, 1) != 1) {87printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",88(int)len);89return -EREMOTEIO;90}91return 0;92}9394static int mt2131_set_params(struct dvb_frontend *fe,95struct dvb_frontend_parameters *params)96{97struct mt2131_priv *priv;98int ret=0, i;99u32 freq;100u8 if_band_center;101u32 f_lo1, f_lo2;102u32 div1, num1, div2, num2;103u8 b[8];104u8 lockval = 0;105106priv = fe->tuner_priv;107if (fe->ops.info.type == FE_OFDM)108priv->bandwidth = params->u.ofdm.bandwidth;109else110priv->bandwidth = 0;111112freq = params->frequency / 1000; // Hz -> kHz113dprintk(1, "%s() freq=%d\n", __func__, freq);114115f_lo1 = freq + MT2131_IF1 * 1000;116f_lo1 = (f_lo1 / 250) * 250;117f_lo2 = f_lo1 - freq - MT2131_IF2;118119priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000;120121/* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */122num1 = f_lo1 * 64 / (MT2131_FREF / 128);123div1 = num1 / 8192;124num1 &= 0x1fff;125126/* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */127num2 = f_lo2 * 64 / (MT2131_FREF / 128);128div2 = num2 / 8192;129num2 &= 0x1fff;130131if (freq <= 82500) if_band_center = 0x00; else132if (freq <= 137500) if_band_center = 0x01; else133if (freq <= 192500) if_band_center = 0x02; else134if (freq <= 247500) if_band_center = 0x03; else135if (freq <= 302500) if_band_center = 0x04; else136if (freq <= 357500) if_band_center = 0x05; else137if (freq <= 412500) if_band_center = 0x06; else138if (freq <= 467500) if_band_center = 0x07; else139if (freq <= 522500) if_band_center = 0x08; else140if (freq <= 577500) if_band_center = 0x09; else141if (freq <= 632500) if_band_center = 0x0A; else142if (freq <= 687500) if_band_center = 0x0B; else143if (freq <= 742500) if_band_center = 0x0C; else144if (freq <= 797500) if_band_center = 0x0D; else145if (freq <= 852500) if_band_center = 0x0E; else146if (freq <= 907500) if_band_center = 0x0F; else147if (freq <= 962500) if_band_center = 0x10; else148if (freq <= 1017500) if_band_center = 0x11; else149if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;150151b[0] = 1;152b[1] = (num1 >> 5) & 0xFF;153b[2] = (num1 & 0x1F);154b[3] = div1;155b[4] = (num2 >> 5) & 0xFF;156b[5] = num2 & 0x1F;157b[6] = div2;158159dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);160dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center);161dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);162dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n",163(int)div1, (int)num1, (int)div2, (int)num2);164dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",165(int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],166(int)b[6]);167168ret = mt2131_writeregs(priv,b,7);169if (ret < 0)170return ret;171172mt2131_writereg(priv, 0x0b, if_band_center);173174/* Wait for lock */175i = 0;176do {177mt2131_readreg(priv, 0x08, &lockval);178if ((lockval & 0x88) == 0x88)179break;180msleep(4);181i++;182} while (i < 10);183184return ret;185}186187static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)188{189struct mt2131_priv *priv = fe->tuner_priv;190dprintk(1, "%s()\n", __func__);191*frequency = priv->frequency;192return 0;193}194195static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)196{197struct mt2131_priv *priv = fe->tuner_priv;198dprintk(1, "%s()\n", __func__);199*bandwidth = priv->bandwidth;200return 0;201}202203static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)204{205struct mt2131_priv *priv = fe->tuner_priv;206u8 lock_status = 0;207u8 afc_status = 0;208209*status = 0;210211mt2131_readreg(priv, 0x08, &lock_status);212if ((lock_status & 0x88) == 0x88)213*status = TUNER_STATUS_LOCKED;214215mt2131_readreg(priv, 0x09, &afc_status);216dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",217__func__, lock_status, afc_status);218219return 0;220}221222static int mt2131_init(struct dvb_frontend *fe)223{224struct mt2131_priv *priv = fe->tuner_priv;225int ret;226dprintk(1, "%s()\n", __func__);227228if ((ret = mt2131_writeregs(priv, mt2131_config1,229sizeof(mt2131_config1))) < 0)230return ret;231232mt2131_writereg(priv, 0x0b, 0x09);233mt2131_writereg(priv, 0x15, 0x47);234mt2131_writereg(priv, 0x07, 0xf2);235mt2131_writereg(priv, 0x0b, 0x01);236237if ((ret = mt2131_writeregs(priv, mt2131_config2,238sizeof(mt2131_config2))) < 0)239return ret;240241return ret;242}243244static int mt2131_release(struct dvb_frontend *fe)245{246dprintk(1, "%s()\n", __func__);247kfree(fe->tuner_priv);248fe->tuner_priv = NULL;249return 0;250}251252static const struct dvb_tuner_ops mt2131_tuner_ops = {253.info = {254.name = "Microtune MT2131",255.frequency_min = 48000000,256.frequency_max = 860000000,257.frequency_step = 50000,258},259260.release = mt2131_release,261.init = mt2131_init,262263.set_params = mt2131_set_params,264.get_frequency = mt2131_get_frequency,265.get_bandwidth = mt2131_get_bandwidth,266.get_status = mt2131_get_status267};268269struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,270struct i2c_adapter *i2c,271struct mt2131_config *cfg, u16 if1)272{273struct mt2131_priv *priv = NULL;274u8 id = 0;275276dprintk(1, "%s()\n", __func__);277278priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);279if (priv == NULL)280return NULL;281282priv->cfg = cfg;283priv->bandwidth = 6000000; /* 6MHz */284priv->i2c = i2c;285286if (mt2131_readreg(priv, 0, &id) != 0) {287kfree(priv);288return NULL;289}290if ( (id != 0x3E) && (id != 0x3F) ) {291printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",292cfg->i2c_address);293kfree(priv);294return NULL;295}296297printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",298cfg->i2c_address);299memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,300sizeof(struct dvb_tuner_ops));301302fe->tuner_priv = priv;303return fe;304}305EXPORT_SYMBOL(mt2131_attach);306307MODULE_AUTHOR("Steven Toth");308MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");309MODULE_LICENSE("GPL");310311/*312* Local variables:313* c-basic-offset: 8314*/315316317