18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Zarlink zl10036 DVB-S silicon tuner 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Tino Reichardt 68c2ecf20Sopenharmony_ci * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci ** 98c2ecf20Sopenharmony_ci * The data sheet for this tuner can be found at: 108c2ecf20Sopenharmony_ci * http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This one is working: (at my Avermedia DVB-S Pro) 138c2ecf20Sopenharmony_ci * - zl10036 (40pin, FTA) 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * A driver for zl10038 should be very similar. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/types.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "zl10036.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int zl10036_debug; 268c2ecf20Sopenharmony_ci#define dprintk(level, args...) \ 278c2ecf20Sopenharmony_ci do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \ 288c2ecf20Sopenharmony_ci } while (0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define deb_info(args...) dprintk(0x01, args) 318c2ecf20Sopenharmony_ci#define deb_i2c(args...) dprintk(0x02, args) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct zl10036_state { 348c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 358c2ecf20Sopenharmony_ci const struct zl10036_config *config; 368c2ecf20Sopenharmony_ci u32 frequency; 378c2ecf20Sopenharmony_ci u8 br, bf; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* This driver assumes the tuner is driven by a 10.111MHz Cristal */ 428c2ecf20Sopenharmony_ci#define _XTAL 10111 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Some of the possible dividers: 458c2ecf20Sopenharmony_ci * 64, (write 0x05 to reg), freq step size 158kHz 468c2ecf20Sopenharmony_ci * 10, (write 0x0a to reg), freq step size 1.011kHz (used here) 478c2ecf20Sopenharmony_ci * 5, (write 0x09 to reg), freq step size 2.022kHz 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define _RDIV 10 518c2ecf20Sopenharmony_ci#define _RDIV_REG 0x0a 528c2ecf20Sopenharmony_ci#define _FR (_XTAL/_RDIV) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define STATUS_POR 0x80 /* Power on Reset */ 558c2ecf20Sopenharmony_ci#define STATUS_FL 0x40 /* Frequency & Phase Lock */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* read/write for zl10036 and zl10038 */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int zl10036_read_status_reg(struct zl10036_state *state) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci u8 status; 628c2ecf20Sopenharmony_ci struct i2c_msg msg[1] = { 638c2ecf20Sopenharmony_ci { .addr = state->config->tuner_address, .flags = I2C_M_RD, 648c2ecf20Sopenharmony_ci .buf = &status, .len = sizeof(status) }, 658c2ecf20Sopenharmony_ci }; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (i2c_transfer(state->i2c, msg, 1) != 1) { 688c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: i2c read failed at addr=%02x\n", 698c2ecf20Sopenharmony_ci __func__, state->config->tuner_address); 708c2ecf20Sopenharmony_ci return -EIO; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci deb_i2c("R(status): %02x [FL=%d]\n", status, 748c2ecf20Sopenharmony_ci (status & STATUS_FL) ? 1 : 0); 758c2ecf20Sopenharmony_ci if (status & STATUS_POR) 768c2ecf20Sopenharmony_ci deb_info("%s: Power-On-Reset bit enabled - need to initialize the tuner\n", 778c2ecf20Sopenharmony_ci __func__); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return status; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct i2c_msg msg[1] = { 858c2ecf20Sopenharmony_ci { .addr = state->config->tuner_address, .flags = 0, 868c2ecf20Sopenharmony_ci .buf = buf, .len = count }, 878c2ecf20Sopenharmony_ci }; 888c2ecf20Sopenharmony_ci u8 reg = 0; 898c2ecf20Sopenharmony_ci int ret; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (zl10036_debug & 0x02) { 928c2ecf20Sopenharmony_ci /* every 8bit-value satisifes this! 938c2ecf20Sopenharmony_ci * so only check for debug log */ 948c2ecf20Sopenharmony_ci if ((buf[0] & 0x80) == 0x00) 958c2ecf20Sopenharmony_ci reg = 2; 968c2ecf20Sopenharmony_ci else if ((buf[0] & 0xc0) == 0x80) 978c2ecf20Sopenharmony_ci reg = 4; 988c2ecf20Sopenharmony_ci else if ((buf[0] & 0xf0) == 0xc0) 998c2ecf20Sopenharmony_ci reg = 6; 1008c2ecf20Sopenharmony_ci else if ((buf[0] & 0xf0) == 0xd0) 1018c2ecf20Sopenharmony_ci reg = 8; 1028c2ecf20Sopenharmony_ci else if ((buf[0] & 0xf0) == 0xe0) 1038c2ecf20Sopenharmony_ci reg = 10; 1048c2ecf20Sopenharmony_ci else if ((buf[0] & 0xf0) == 0xf0) 1058c2ecf20Sopenharmony_ci reg = 12; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci deb_i2c("W(%d):", reg); 1088c2ecf20Sopenharmony_ci { 1098c2ecf20Sopenharmony_ci int i; 1108c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 1118c2ecf20Sopenharmony_ci printk(KERN_CONT " %02x", buf[i]); 1128c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 1); 1178c2ecf20Sopenharmony_ci if (ret != 1) { 1188c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret); 1198c2ecf20Sopenharmony_ci return -EIO; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void zl10036_release(struct dvb_frontend *fe) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct zl10036_state *state = fe->tuner_priv; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 1308c2ecf20Sopenharmony_ci kfree(state); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int zl10036_sleep(struct dvb_frontend *fe) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct zl10036_state *state = fe->tuner_priv; 1368c2ecf20Sopenharmony_ci u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */ 1378c2ecf20Sopenharmony_ci int ret; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci deb_info("%s\n", __func__); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1428c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = zl10036_write(state, buf, sizeof(buf)); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1478c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * register map of the ZL10036/ZL10038 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * reg[default] content 1568c2ecf20Sopenharmony_ci * 2[0x00]: 0 | N14 | N13 | N12 | N11 | N10 | N9 | N8 1578c2ecf20Sopenharmony_ci * 3[0x00]: N7 | N6 | N5 | N4 | N3 | N2 | N1 | N0 1588c2ecf20Sopenharmony_ci * 4[0x80]: 1 | 0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN 1598c2ecf20Sopenharmony_ci * 5[0x00]: P0 | C1 | C0 | R4 | R3 | R2 | R1 | R0 1608c2ecf20Sopenharmony_ci * 6[0xc0]: 1 | 1 | 0 | 0 | RSD | 0 | 0 | 0 1618c2ecf20Sopenharmony_ci * 7[0x20]: P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 | 0 1628c2ecf20Sopenharmony_ci * 8[0xdb]: 1 | 1 | 0 | 1 | 0 | CC | 1 | 1 1638c2ecf20Sopenharmony_ci * 9[0x30]: VSD | V2 | V1 | V0 | S3 | S2 | S1 | S0 1648c2ecf20Sopenharmony_ci * 10[0xe1]: 1 | 1 | 1 | 0 | 0 | LS2 | LS1 | LS0 1658c2ecf20Sopenharmony_ci * 11[0xf5]: WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE 1668c2ecf20Sopenharmony_ci * 12[0xf0]: 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 1678c2ecf20Sopenharmony_ci * 13[0x28]: PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR | TL 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int zl10036_set_frequency(struct zl10036_state *state, u32 frequency) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci u8 buf[2]; 1738c2ecf20Sopenharmony_ci u32 div, foffset; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci div = (frequency + _FR/2) / _FR; 1768c2ecf20Sopenharmony_ci state->frequency = div * _FR; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci foffset = frequency - state->frequency; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 1818c2ecf20Sopenharmony_ci buf[1] = (div >> 0) & 0xff; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__, 1848c2ecf20Sopenharmony_ci frequency, state->frequency, foffset, div); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return zl10036_write(state, buf, sizeof(buf)); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci /* fbw is measured in kHz */ 1928c2ecf20Sopenharmony_ci u8 br, bf; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci u8 buf_bf[] = { 1958c2ecf20Sopenharmony_ci 0xc0, 0x00, /* 6/7: rsd=0 bf=0 */ 1968c2ecf20Sopenharmony_ci }; 1978c2ecf20Sopenharmony_ci u8 buf_br[] = { 1988c2ecf20Sopenharmony_ci 0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/ 1998c2ecf20Sopenharmony_ci }; 2008c2ecf20Sopenharmony_ci u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* ensure correct values */ 2038c2ecf20Sopenharmony_ci if (fbw > 35000) 2048c2ecf20Sopenharmony_ci fbw = 35000; 2058c2ecf20Sopenharmony_ci if (fbw < 8000) 2068c2ecf20Sopenharmony_ci fbw = 8000; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* <= 28,82 MHz */ 2118c2ecf20Sopenharmony_ci if (fbw <= 28820) { 2128c2ecf20Sopenharmony_ci br = _BR_MAXIMUM; 2138c2ecf20Sopenharmony_ci } else { 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * f(bw)=34,6MHz f(xtal)=10.111MHz 2168c2ecf20Sopenharmony_ci * br = (10111/34600) * 63 * 1/K = 14; 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci br = ((_XTAL * 21 * 1000) / (fbw * 419)); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* ensure correct values */ 2228c2ecf20Sopenharmony_ci if (br < 4) 2238c2ecf20Sopenharmony_ci br = 4; 2248c2ecf20Sopenharmony_ci if (br > _BR_MAXIMUM) 2258c2ecf20Sopenharmony_ci br = _BR_MAXIMUM; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * k = 1.257 2298c2ecf20Sopenharmony_ci * bf = fbw/_XTAL * br * k - 1 */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci bf = (fbw * br * 1257) / (_XTAL * 1000) - 1; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* ensure correct values */ 2348c2ecf20Sopenharmony_ci if (bf > 62) 2358c2ecf20Sopenharmony_ci bf = 62; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci buf_bf[1] = (bf << 1) & 0x7e; 2388c2ecf20Sopenharmony_ci buf_br[1] = (br << 2) & 0x7c; 2398c2ecf20Sopenharmony_ci deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (br != state->br) { 2428c2ecf20Sopenharmony_ci ret = zl10036_write(state, buf_br, sizeof(buf_br)); 2438c2ecf20Sopenharmony_ci if (ret < 0) 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (bf != state->bf) { 2488c2ecf20Sopenharmony_ci ret = zl10036_write(state, buf_bf, sizeof(buf_bf)); 2498c2ecf20Sopenharmony_ci if (ret < 0) 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* time = br/(32* fxtal) */ 2538c2ecf20Sopenharmony_ci /* minimal sleep time to be calculated 2548c2ecf20Sopenharmony_ci * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */ 2558c2ecf20Sopenharmony_ci msleep(1); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = zl10036_write(state, zl10036_rsd_off, 2588c2ecf20Sopenharmony_ci sizeof(zl10036_rsd_off)); 2598c2ecf20Sopenharmony_ci if (ret < 0) 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci state->br = br; 2648c2ecf20Sopenharmony_ci state->bf = bf; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int zl10036_set_gain_params(struct zl10036_state *state, 2708c2ecf20Sopenharmony_ci int c) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci u8 buf[2]; 2738c2ecf20Sopenharmony_ci u8 rfg, ba, bg; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* default values */ 2768c2ecf20Sopenharmony_ci rfg = 0; /* enable when using an lna */ 2778c2ecf20Sopenharmony_ci ba = 1; 2788c2ecf20Sopenharmony_ci bg = 1; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* reg 4 */ 2818c2ecf20Sopenharmony_ci buf[0] = 0x80 | ((rfg << 5) & 0x20) 2828c2ecf20Sopenharmony_ci | ((ba << 3) & 0x18) | ((bg << 1) & 0x06); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (!state->config->rf_loop_enable) 2858c2ecf20Sopenharmony_ci buf[0] |= 0x01; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* P0=0 */ 2888c2ecf20Sopenharmony_ci buf[1] = _RDIV_REG | ((c << 5) & 0x60); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg); 2918c2ecf20Sopenharmony_ci return zl10036_write(state, buf, sizeof(buf)); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int zl10036_set_params(struct dvb_frontend *fe) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 2978c2ecf20Sopenharmony_ci struct zl10036_state *state = fe->tuner_priv; 2988c2ecf20Sopenharmony_ci int ret = 0; 2998c2ecf20Sopenharmony_ci u32 frequency = p->frequency; 3008c2ecf20Sopenharmony_ci u32 fbw; 3018c2ecf20Sopenharmony_ci int i; 3028c2ecf20Sopenharmony_ci u8 c; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* ensure correct values 3058c2ecf20Sopenharmony_ci * maybe redundant as core already checks this */ 3068c2ecf20Sopenharmony_ci if ((frequency < fe->ops.info.frequency_min_hz / kHz) 3078c2ecf20Sopenharmony_ci || (frequency > fe->ops.info.frequency_max_hz / kHz)) 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * alpha = 1.35 for dvb-s 3128c2ecf20Sopenharmony_ci * fBW = (alpha*symbolrate)/(2*0.8) 3138c2ecf20Sopenharmony_ci * 1.35 / (2*0.8) = 27 / 32 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci fbw = (27 * p->symbol_rate) / 32; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* scale to kHz */ 3188c2ecf20Sopenharmony_ci fbw /= 1000; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Add safe margin of 3MHz */ 3218c2ecf20Sopenharmony_ci fbw += 3000; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* setting the charge pump - guessed values */ 3248c2ecf20Sopenharmony_ci if (frequency < 950000) 3258c2ecf20Sopenharmony_ci return -EINVAL; 3268c2ecf20Sopenharmony_ci else if (frequency < 1250000) 3278c2ecf20Sopenharmony_ci c = 0; 3288c2ecf20Sopenharmony_ci else if (frequency < 1750000) 3298c2ecf20Sopenharmony_ci c = 1; 3308c2ecf20Sopenharmony_ci else if (frequency < 2175000) 3318c2ecf20Sopenharmony_ci c = 2; 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3368c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = zl10036_set_gain_params(state, c); 3398c2ecf20Sopenharmony_ci if (ret < 0) 3408c2ecf20Sopenharmony_ci goto error; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ret = zl10036_set_frequency(state, p->frequency); 3438c2ecf20Sopenharmony_ci if (ret < 0) 3448c2ecf20Sopenharmony_ci goto error; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = zl10036_set_bandwidth(state, fbw); 3478c2ecf20Sopenharmony_ci if (ret < 0) 3488c2ecf20Sopenharmony_ci goto error; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* wait for tuner lock - no idea if this is really needed */ 3518c2ecf20Sopenharmony_ci for (i = 0; i < 20; i++) { 3528c2ecf20Sopenharmony_ci ret = zl10036_read_status_reg(state); 3538c2ecf20Sopenharmony_ci if (ret < 0) 3548c2ecf20Sopenharmony_ci goto error; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* check Frequency & Phase Lock Bit */ 3578c2ecf20Sopenharmony_ci if (ret & STATUS_FL) 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci msleep(10); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cierror: 3648c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3658c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct zl10036_state *state = fe->tuner_priv; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci *frequency = state->frequency; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int zl10036_init_regs(struct zl10036_state *state) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci int ret; 3828c2ecf20Sopenharmony_ci int i; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* could also be one block from reg 2 to 13 and additional 10/11 */ 3858c2ecf20Sopenharmony_ci u8 zl10036_init_tab[][2] = { 3868c2ecf20Sopenharmony_ci { 0x04, 0x00 }, /* 2/3: div=0x400 - arbitrary value */ 3878c2ecf20Sopenharmony_ci { 0x8b, _RDIV_REG }, /* 4/5: rfg=0 ba=1 bg=1 len=? */ 3888c2ecf20Sopenharmony_ci /* p0=0 c=0 r=_RDIV_REG */ 3898c2ecf20Sopenharmony_ci { 0xc0, 0x20 }, /* 6/7: rsd=0 bf=0x10 */ 3908c2ecf20Sopenharmony_ci { 0xd3, 0x40 }, /* 8/9: from datasheet */ 3918c2ecf20Sopenharmony_ci { 0xe3, 0x5b }, /* 10/11: lock window level */ 3928c2ecf20Sopenharmony_ci { 0xf0, 0x28 }, /* 12/13: br=0xa clr=0 tl=0*/ 3938c2ecf20Sopenharmony_ci { 0xe3, 0xf9 }, /* 10/11: unlock window level */ 3948c2ecf20Sopenharmony_ci }; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* invalid values to trigger writing */ 3978c2ecf20Sopenharmony_ci state->br = 0xff; 3988c2ecf20Sopenharmony_ci state->bf = 0xff; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (!state->config->rf_loop_enable) 4018c2ecf20Sopenharmony_ci zl10036_init_tab[1][0] |= 0x01; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci deb_info("%s\n", __func__); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) { 4068c2ecf20Sopenharmony_ci ret = zl10036_write(state, zl10036_init_tab[i], 2); 4078c2ecf20Sopenharmony_ci if (ret < 0) 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int zl10036_init(struct dvb_frontend *fe) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct zl10036_state *state = fe->tuner_priv; 4178c2ecf20Sopenharmony_ci int ret = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4208c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ret = zl10036_read_status_reg(state); 4238c2ecf20Sopenharmony_ci if (ret < 0) 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Only init if Power-on-Reset bit is set? */ 4278c2ecf20Sopenharmony_ci ret = zl10036_init_regs(state); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4308c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops zl10036_tuner_ops = { 4368c2ecf20Sopenharmony_ci .info = { 4378c2ecf20Sopenharmony_ci .name = "Zarlink ZL10036", 4388c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 4398c2ecf20Sopenharmony_ci .frequency_max_hz = 2175 * MHz 4408c2ecf20Sopenharmony_ci }, 4418c2ecf20Sopenharmony_ci .init = zl10036_init, 4428c2ecf20Sopenharmony_ci .release = zl10036_release, 4438c2ecf20Sopenharmony_ci .sleep = zl10036_sleep, 4448c2ecf20Sopenharmony_ci .set_params = zl10036_set_params, 4458c2ecf20Sopenharmony_ci .get_frequency = zl10036_get_frequency, 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistruct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, 4498c2ecf20Sopenharmony_ci const struct zl10036_config *config, 4508c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct zl10036_state *state; 4538c2ecf20Sopenharmony_ci int ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!config) { 4568c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no config specified", __func__); 4578c2ecf20Sopenharmony_ci return NULL; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL); 4618c2ecf20Sopenharmony_ci if (!state) 4628c2ecf20Sopenharmony_ci return NULL; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci state->config = config; 4658c2ecf20Sopenharmony_ci state->i2c = i2c; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4688c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = zl10036_read_status_reg(state); 4718c2ecf20Sopenharmony_ci if (ret < 0) { 4728c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: No zl10036 found\n", __func__); 4738c2ecf20Sopenharmony_ci goto error; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = zl10036_init_regs(state); 4778c2ecf20Sopenharmony_ci if (ret < 0) { 4788c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: tuner initialization failed\n", 4798c2ecf20Sopenharmony_ci __func__); 4808c2ecf20Sopenharmony_ci goto error; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4848c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci fe->tuner_priv = state; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops, 4898c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 4908c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n", 4918c2ecf20Sopenharmony_ci __func__, fe->ops.tuner_ops.info.name, config->tuner_address); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return fe; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cierror: 4968c2ecf20Sopenharmony_ci kfree(state); 4978c2ecf20Sopenharmony_ci return NULL; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zl10036_attach); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cimodule_param_named(debug, zl10036_debug, int, 0644); 5028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 5038c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DVB ZL10036 driver"); 5048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tino Reichardt"); 5058c2ecf20Sopenharmony_ciMODULE_AUTHOR("Matthias Schwarzott"); 5068c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 507