18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "mc44s803.h" 178c2ecf20Sopenharmony_ci#include "mc44s803_priv.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define mc_printk(level, format, arg...) \ 208c2ecf20Sopenharmony_ci printk(level "mc44s803: " format , ## arg) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Writes a single register */ 238c2ecf20Sopenharmony_cistatic int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci u8 buf[3]; 268c2ecf20Sopenharmony_ci struct i2c_msg msg = { 278c2ecf20Sopenharmony_ci .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 288c2ecf20Sopenharmony_ci }; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci buf[0] = (val & 0xff0000) >> 16; 318c2ecf20Sopenharmony_ci buf[1] = (val & 0xff00) >> 8; 328c2ecf20Sopenharmony_ci buf[2] = (val & 0xff); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c, &msg, 1) != 1) { 358c2ecf20Sopenharmony_ci mc_printk(KERN_WARNING, "I2C write failed\n"); 368c2ecf20Sopenharmony_ci return -EREMOTEIO; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Reads a single register */ 428c2ecf20Sopenharmony_cistatic int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u32 wval; 458c2ecf20Sopenharmony_ci u8 buf[3]; 468c2ecf20Sopenharmony_ci int ret; 478c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 488c2ecf20Sopenharmony_ci { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, 498c2ecf20Sopenharmony_ci .buf = buf, .len = 3 }, 508c2ecf20Sopenharmony_ci }; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | 538c2ecf20Sopenharmony_ci MC44S803_REG_SM(reg, MC44S803_D); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ret = mc44s803_writereg(priv, wval); 568c2ecf20Sopenharmony_ci if (ret) 578c2ecf20Sopenharmony_ci return ret; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c, msg, 1) != 1) { 608c2ecf20Sopenharmony_ci mc_printk(KERN_WARNING, "I2C read failed\n"); 618c2ecf20Sopenharmony_ci return -EREMOTEIO; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void mc44s803_release(struct dvb_frontend *fe) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct mc44s803_priv *priv = fe->tuner_priv; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 748c2ecf20Sopenharmony_ci kfree(priv); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int mc44s803_init(struct dvb_frontend *fe) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct mc44s803_priv *priv = fe->tuner_priv; 808c2ecf20Sopenharmony_ci u32 val; 818c2ecf20Sopenharmony_ci int err; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 848c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Reset chip */ 878c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | 888c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_RS); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 918c2ecf20Sopenharmony_ci if (err) 928c2ecf20Sopenharmony_ci goto exit; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 978c2ecf20Sopenharmony_ci if (err) 988c2ecf20Sopenharmony_ci goto exit; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Power Up and Start Osc */ 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | 1038c2ecf20Sopenharmony_ci MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | 1048c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_OSCSEL); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1078c2ecf20Sopenharmony_ci if (err) 1088c2ecf20Sopenharmony_ci goto exit; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | 1118c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x200, MC44S803_POWER); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1148c2ecf20Sopenharmony_ci if (err) 1158c2ecf20Sopenharmony_ci goto exit; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci msleep(10); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | 1208c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x40, MC44S803_REFOSC) | 1218c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_OSCSEL); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1248c2ecf20Sopenharmony_ci if (err) 1258c2ecf20Sopenharmony_ci goto exit; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci msleep(20); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Setup Mixer */ 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | 1328c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_TRI_STATE) | 1338c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1368c2ecf20Sopenharmony_ci if (err) 1378c2ecf20Sopenharmony_ci goto exit; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* Setup Cirquit Adjust */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | 1428c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_G1) | 1438c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_G3) | 1448c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | 1458c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_G6) | 1468c2ecf20Sopenharmony_ci MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | 1478c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x3, MC44S803_LP) | 1488c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_CLRF) | 1498c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_CLIF); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1528c2ecf20Sopenharmony_ci if (err) 1538c2ecf20Sopenharmony_ci goto exit; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | 1568c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_G1) | 1578c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_G3) | 1588c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | 1598c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_G6) | 1608c2ecf20Sopenharmony_ci MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | 1618c2ecf20Sopenharmony_ci MC44S803_REG_SM(0x3, MC44S803_LP); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1648c2ecf20Sopenharmony_ci if (err) 1658c2ecf20Sopenharmony_ci goto exit; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* Setup Digtune */ 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | 1708c2ecf20Sopenharmony_ci MC44S803_REG_SM(3, MC44S803_XOD); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1738c2ecf20Sopenharmony_ci if (err) 1748c2ecf20Sopenharmony_ci goto exit; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* Setup AGC */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | 1798c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_AT1) | 1808c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_AT2) | 1818c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | 1828c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | 1838c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_LNA0); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 1868c2ecf20Sopenharmony_ci if (err) 1878c2ecf20Sopenharmony_ci goto exit; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1908c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciexit: 1948c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1958c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci mc_printk(KERN_WARNING, "I/O Error\n"); 1988c2ecf20Sopenharmony_ci return err; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int mc44s803_set_params(struct dvb_frontend *fe) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct mc44s803_priv *priv = fe->tuner_priv; 2048c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 2058c2ecf20Sopenharmony_ci u32 r1, r2, n1, n2, lo1, lo2, freq, val; 2068c2ecf20Sopenharmony_ci int err; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci priv->frequency = c->frequency; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci r1 = MC44S803_OSC / 1000000; 2118c2ecf20Sopenharmony_ci r2 = MC44S803_OSC / 100000; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000; 2148c2ecf20Sopenharmony_ci freq = MC44S803_OSC / r1 * n1; 2158c2ecf20Sopenharmony_ci lo1 = ((60 * n1) + (r1 / 2)) / r1; 2168c2ecf20Sopenharmony_ci freq = freq - c->frequency; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci n2 = (freq - MC44S803_IF2 + 50000) / 100000; 2198c2ecf20Sopenharmony_ci lo2 = ((60 * n2) + (r2 / 2)) / r2; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2228c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | 2258c2ecf20Sopenharmony_ci MC44S803_REG_SM(r1-1, MC44S803_R1) | 2268c2ecf20Sopenharmony_ci MC44S803_REG_SM(r2-1, MC44S803_R2) | 2278c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_REFBUF_EN); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 2308c2ecf20Sopenharmony_ci if (err) 2318c2ecf20Sopenharmony_ci goto exit; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | 2348c2ecf20Sopenharmony_ci MC44S803_REG_SM(n1-2, MC44S803_LO1); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 2378c2ecf20Sopenharmony_ci if (err) 2388c2ecf20Sopenharmony_ci goto exit; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | 2418c2ecf20Sopenharmony_ci MC44S803_REG_SM(n2-2, MC44S803_LO2); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 2448c2ecf20Sopenharmony_ci if (err) 2458c2ecf20Sopenharmony_ci goto exit; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | 2488c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_DA) | 2498c2ecf20Sopenharmony_ci MC44S803_REG_SM(lo1, MC44S803_LO_REF) | 2508c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_AT); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 2538c2ecf20Sopenharmony_ci if (err) 2548c2ecf20Sopenharmony_ci goto exit; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | 2578c2ecf20Sopenharmony_ci MC44S803_REG_SM(2, MC44S803_DA) | 2588c2ecf20Sopenharmony_ci MC44S803_REG_SM(lo2, MC44S803_LO_REF) | 2598c2ecf20Sopenharmony_ci MC44S803_REG_SM(1, MC44S803_AT); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci err = mc44s803_writereg(priv, val); 2628c2ecf20Sopenharmony_ci if (err) 2638c2ecf20Sopenharmony_ci goto exit; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2668c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciexit: 2718c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2728c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci mc_printk(KERN_WARNING, "I/O Error\n"); 2758c2ecf20Sopenharmony_ci return err; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct mc44s803_priv *priv = fe->tuner_priv; 2818c2ecf20Sopenharmony_ci *frequency = priv->frequency; 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int mc44s803_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci *frequency = MC44S803_IF2; /* 36.125 MHz */ 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops mc44s803_tuner_ops = { 2928c2ecf20Sopenharmony_ci .info = { 2938c2ecf20Sopenharmony_ci .name = "Freescale MC44S803", 2948c2ecf20Sopenharmony_ci .frequency_min_hz = 48 * MHz, 2958c2ecf20Sopenharmony_ci .frequency_max_hz = 1000 * MHz, 2968c2ecf20Sopenharmony_ci .frequency_step_hz = 100 * kHz, 2978c2ecf20Sopenharmony_ci }, 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci .release = mc44s803_release, 3008c2ecf20Sopenharmony_ci .init = mc44s803_init, 3018c2ecf20Sopenharmony_ci .set_params = mc44s803_set_params, 3028c2ecf20Sopenharmony_ci .get_frequency = mc44s803_get_frequency, 3038c2ecf20Sopenharmony_ci .get_if_frequency = mc44s803_get_if_frequency, 3048c2ecf20Sopenharmony_ci}; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* This functions tries to identify a MC44S803 tuner by reading the ID 3078c2ecf20Sopenharmony_ci register. This is hasty. */ 3088c2ecf20Sopenharmony_cistruct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, 3098c2ecf20Sopenharmony_ci struct i2c_adapter *i2c, struct mc44s803_config *cfg) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct mc44s803_priv *priv; 3128c2ecf20Sopenharmony_ci u32 reg; 3138c2ecf20Sopenharmony_ci u8 id; 3148c2ecf20Sopenharmony_ci int ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci reg = 0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); 3198c2ecf20Sopenharmony_ci if (priv == NULL) 3208c2ecf20Sopenharmony_ci return NULL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci priv->cfg = cfg; 3238c2ecf20Sopenharmony_ci priv->i2c = i2c; 3248c2ecf20Sopenharmony_ci priv->fe = fe; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3278c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); 3308c2ecf20Sopenharmony_ci if (ret) 3318c2ecf20Sopenharmony_ci goto error; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci id = MC44S803_REG_MS(reg, MC44S803_ID); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (id != 0x14) { 3368c2ecf20Sopenharmony_ci mc_printk(KERN_ERR, "unsupported ID (%x should be 0x14)\n", 3378c2ecf20Sopenharmony_ci id); 3388c2ecf20Sopenharmony_ci goto error; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); 3428c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, 3438c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3488c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return fe; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cierror: 3538c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3548c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci kfree(priv); 3578c2ecf20Sopenharmony_ci return NULL; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mc44s803_attach); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jochen Friedrich"); 3628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); 3638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 364