12ccf5a99SIgor M. Liplianin /* 22ccf5a99SIgor M. Liplianin * Driver for Zarlink ZL10039 DVB-S tuner 32ccf5a99SIgor M. Liplianin * 42ccf5a99SIgor M. Liplianin * Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za> 52ccf5a99SIgor M. Liplianin * 62ccf5a99SIgor M. Liplianin * This program is free software; you can redistribute it and/or modify 72ccf5a99SIgor M. Liplianin * it under the terms of the GNU General Public License as published by 82ccf5a99SIgor M. Liplianin * the Free Software Foundation; either version 2 of the License, or 92ccf5a99SIgor M. Liplianin * (at your option) any later version. 102ccf5a99SIgor M. Liplianin * 112ccf5a99SIgor M. Liplianin * This program is distributed in the hope that it will be useful, 122ccf5a99SIgor M. Liplianin * but WITHOUT ANY WARRANTY; without even the implied warranty of 132ccf5a99SIgor M. Liplianin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 142ccf5a99SIgor M. Liplianin * 152ccf5a99SIgor M. Liplianin * GNU General Public License for more details. 162ccf5a99SIgor M. Liplianin * 172ccf5a99SIgor M. Liplianin * You should have received a copy of the GNU General Public License 182ccf5a99SIgor M. Liplianin * along with this program; if not, write to the Free Software 192ccf5a99SIgor M. Liplianin * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 202ccf5a99SIgor M. Liplianin */ 212ccf5a99SIgor M. Liplianin 222ccf5a99SIgor M. Liplianin #include <linux/module.h> 232ccf5a99SIgor M. Liplianin #include <linux/init.h> 242ccf5a99SIgor M. Liplianin #include <linux/string.h> 252ccf5a99SIgor M. Liplianin #include <linux/slab.h> 262ccf5a99SIgor M. Liplianin #include <linux/dvb/frontend.h> 272ccf5a99SIgor M. Liplianin 282ccf5a99SIgor M. Liplianin #include "dvb_frontend.h" 292ccf5a99SIgor M. Liplianin #include "zl10039.h" 302ccf5a99SIgor M. Liplianin 312ccf5a99SIgor M. Liplianin static int debug; 322ccf5a99SIgor M. Liplianin 338393796dSMauro Carvalho Chehab /* Max transfer size done by I2C transfer functions */ 348393796dSMauro Carvalho Chehab #define MAX_XFER_SIZE 64 358393796dSMauro Carvalho Chehab 362ccf5a99SIgor M. Liplianin #define dprintk(args...) \ 372ccf5a99SIgor M. Liplianin do { \ 382ccf5a99SIgor M. Liplianin if (debug) \ 392ccf5a99SIgor M. Liplianin printk(KERN_DEBUG args); \ 402ccf5a99SIgor M. Liplianin } while (0) 412ccf5a99SIgor M. Liplianin 422ccf5a99SIgor M. Liplianin enum zl10039_model_id { 432ccf5a99SIgor M. Liplianin ID_ZL10039 = 1 442ccf5a99SIgor M. Liplianin }; 452ccf5a99SIgor M. Liplianin 462ccf5a99SIgor M. Liplianin struct zl10039_state { 472ccf5a99SIgor M. Liplianin struct i2c_adapter *i2c; 482ccf5a99SIgor M. Liplianin u8 i2c_addr; 492ccf5a99SIgor M. Liplianin u8 id; 502ccf5a99SIgor M. Liplianin }; 512ccf5a99SIgor M. Liplianin 522ccf5a99SIgor M. Liplianin enum zl10039_reg_addr { 532ccf5a99SIgor M. Liplianin PLL0 = 0, 542ccf5a99SIgor M. Liplianin PLL1, 552ccf5a99SIgor M. Liplianin PLL2, 562ccf5a99SIgor M. Liplianin PLL3, 572ccf5a99SIgor M. Liplianin RFFE, 582ccf5a99SIgor M. Liplianin BASE0, 592ccf5a99SIgor M. Liplianin BASE1, 602ccf5a99SIgor M. Liplianin BASE2, 612ccf5a99SIgor M. Liplianin LO0, 622ccf5a99SIgor M. Liplianin LO1, 632ccf5a99SIgor M. Liplianin LO2, 642ccf5a99SIgor M. Liplianin LO3, 652ccf5a99SIgor M. Liplianin LO4, 662ccf5a99SIgor M. Liplianin LO5, 672ccf5a99SIgor M. Liplianin LO6, 682ccf5a99SIgor M. Liplianin GENERAL 692ccf5a99SIgor M. Liplianin }; 702ccf5a99SIgor M. Liplianin 712ccf5a99SIgor M. Liplianin static int zl10039_read(const struct zl10039_state *state, 722ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, u8 *buf, 732ccf5a99SIgor M. Liplianin const size_t count) 742ccf5a99SIgor M. Liplianin { 752ccf5a99SIgor M. Liplianin u8 regbuf[] = { reg }; 762ccf5a99SIgor M. Liplianin struct i2c_msg msg[] = { 772ccf5a99SIgor M. Liplianin {/* Write register address */ 782ccf5a99SIgor M. Liplianin .addr = state->i2c_addr, 792ccf5a99SIgor M. Liplianin .flags = 0, 802ccf5a99SIgor M. Liplianin .buf = regbuf, 812ccf5a99SIgor M. Liplianin .len = 1, 822ccf5a99SIgor M. Liplianin }, {/* Read count bytes */ 832ccf5a99SIgor M. Liplianin .addr = state->i2c_addr, 842ccf5a99SIgor M. Liplianin .flags = I2C_M_RD, 852ccf5a99SIgor M. Liplianin .buf = buf, 862ccf5a99SIgor M. Liplianin .len = count, 872ccf5a99SIgor M. Liplianin }, 882ccf5a99SIgor M. Liplianin }; 892ccf5a99SIgor M. Liplianin 902ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 912ccf5a99SIgor M. Liplianin 922ccf5a99SIgor M. Liplianin if (i2c_transfer(state->i2c, msg, 2) != 2) { 932ccf5a99SIgor M. Liplianin dprintk("%s: i2c read error\n", __func__); 942ccf5a99SIgor M. Liplianin return -EREMOTEIO; 952ccf5a99SIgor M. Liplianin } 962ccf5a99SIgor M. Liplianin 972ccf5a99SIgor M. Liplianin return 0; /* Success */ 982ccf5a99SIgor M. Liplianin } 992ccf5a99SIgor M. Liplianin 1002ccf5a99SIgor M. Liplianin static int zl10039_write(struct zl10039_state *state, 1012ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, const u8 *src, 1022ccf5a99SIgor M. Liplianin const size_t count) 1032ccf5a99SIgor M. Liplianin { 1048393796dSMauro Carvalho Chehab u8 buf[MAX_XFER_SIZE]; 1052ccf5a99SIgor M. Liplianin struct i2c_msg msg = { 1062ccf5a99SIgor M. Liplianin .addr = state->i2c_addr, 1072ccf5a99SIgor M. Liplianin .flags = 0, 1082ccf5a99SIgor M. Liplianin .buf = buf, 1092ccf5a99SIgor M. Liplianin .len = count + 1, 1102ccf5a99SIgor M. Liplianin }; 1112ccf5a99SIgor M. Liplianin 1128393796dSMauro Carvalho Chehab if (1 + count > sizeof(buf)) { 1138393796dSMauro Carvalho Chehab printk(KERN_WARNING 11435f30f36SMauro Carvalho Chehab "%s: i2c wr reg=%04x: len=%zu is too big!\n", 1158393796dSMauro Carvalho Chehab KBUILD_MODNAME, reg, count); 1168393796dSMauro Carvalho Chehab return -EINVAL; 1178393796dSMauro Carvalho Chehab } 1188393796dSMauro Carvalho Chehab 1192ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1202ccf5a99SIgor M. Liplianin /* Write register address and data in one go */ 1212ccf5a99SIgor M. Liplianin buf[0] = reg; 1222ccf5a99SIgor M. Liplianin memcpy(&buf[1], src, count); 1232ccf5a99SIgor M. Liplianin if (i2c_transfer(state->i2c, &msg, 1) != 1) { 1242ccf5a99SIgor M. Liplianin dprintk("%s: i2c write error\n", __func__); 1252ccf5a99SIgor M. Liplianin return -EREMOTEIO; 1262ccf5a99SIgor M. Liplianin } 1272ccf5a99SIgor M. Liplianin 1282ccf5a99SIgor M. Liplianin return 0; /* Success */ 1292ccf5a99SIgor M. Liplianin } 1302ccf5a99SIgor M. Liplianin 1312ccf5a99SIgor M. Liplianin static inline int zl10039_readreg(struct zl10039_state *state, 1322ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, u8 *val) 1332ccf5a99SIgor M. Liplianin { 1342ccf5a99SIgor M. Liplianin return zl10039_read(state, reg, val, 1); 1352ccf5a99SIgor M. Liplianin } 1362ccf5a99SIgor M. Liplianin 1372ccf5a99SIgor M. Liplianin static inline int zl10039_writereg(struct zl10039_state *state, 1382ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, 1392ccf5a99SIgor M. Liplianin const u8 val) 1402ccf5a99SIgor M. Liplianin { 1412ccf5a99SIgor M. Liplianin return zl10039_write(state, reg, &val, 1); 1422ccf5a99SIgor M. Liplianin } 1432ccf5a99SIgor M. Liplianin 1442ccf5a99SIgor M. Liplianin static int zl10039_init(struct dvb_frontend *fe) 1452ccf5a99SIgor M. Liplianin { 1462ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 1472ccf5a99SIgor M. Liplianin int ret; 1482ccf5a99SIgor M. Liplianin 1492ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1502ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1512ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 1522ccf5a99SIgor M. Liplianin /* Reset logic */ 1532ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, GENERAL, 0x40); 1542ccf5a99SIgor M. Liplianin if (ret < 0) { 1554bd69e7bSMauro Carvalho Chehab dprintk("Note: i2c write error normal when resetting the tuner\n"); 1562ccf5a99SIgor M. Liplianin } 1572ccf5a99SIgor M. Liplianin /* Wake up */ 1582ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, GENERAL, 0x01); 1592ccf5a99SIgor M. Liplianin if (ret < 0) { 1602ccf5a99SIgor M. Liplianin dprintk("Tuner power up failed\n"); 1612ccf5a99SIgor M. Liplianin return ret; 1622ccf5a99SIgor M. Liplianin } 1632ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1642ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 1652ccf5a99SIgor M. Liplianin 1662ccf5a99SIgor M. Liplianin return 0; 1672ccf5a99SIgor M. Liplianin } 1682ccf5a99SIgor M. Liplianin 1692ccf5a99SIgor M. Liplianin static int zl10039_sleep(struct dvb_frontend *fe) 1702ccf5a99SIgor M. Liplianin { 1712ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 1722ccf5a99SIgor M. Liplianin int ret; 1732ccf5a99SIgor M. Liplianin 1742ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1752ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1762ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 1772ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, GENERAL, 0x80); 1782ccf5a99SIgor M. Liplianin if (ret < 0) { 1792ccf5a99SIgor M. Liplianin dprintk("Tuner sleep failed\n"); 1802ccf5a99SIgor M. Liplianin return ret; 1812ccf5a99SIgor M. Liplianin } 1822ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1832ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 1842ccf5a99SIgor M. Liplianin 1852ccf5a99SIgor M. Liplianin return 0; 1862ccf5a99SIgor M. Liplianin } 1872ccf5a99SIgor M. Liplianin 18814d24d14SMauro Carvalho Chehab static int zl10039_set_params(struct dvb_frontend *fe) 1892ccf5a99SIgor M. Liplianin { 1908579881bSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1912ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 1922ccf5a99SIgor M. Liplianin u8 buf[6]; 1932ccf5a99SIgor M. Liplianin u8 bf; 1942ccf5a99SIgor M. Liplianin u32 fbw; 1952ccf5a99SIgor M. Liplianin u32 div; 1962ccf5a99SIgor M. Liplianin int ret; 1972ccf5a99SIgor M. Liplianin 1982ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1992ccf5a99SIgor M. Liplianin dprintk("Set frequency = %d, symbol rate = %d\n", 2008579881bSMauro Carvalho Chehab c->frequency, c->symbol_rate); 2012ccf5a99SIgor M. Liplianin 2022ccf5a99SIgor M. Liplianin /* Assumed 10.111 MHz crystal oscillator */ 2032ccf5a99SIgor M. Liplianin /* Cancelled num/den 80 to prevent overflow */ 2048579881bSMauro Carvalho Chehab div = (c->frequency * 1000) / 126387; 2058579881bSMauro Carvalho Chehab fbw = (c->symbol_rate * 27) / 32000; 2062ccf5a99SIgor M. Liplianin /* Cancelled num/den 10 to prevent overflow */ 2072ccf5a99SIgor M. Liplianin bf = ((fbw * 5088) / 1011100) - 1; 2082ccf5a99SIgor M. Liplianin 2092ccf5a99SIgor M. Liplianin /*PLL divider*/ 2102ccf5a99SIgor M. Liplianin buf[0] = (div >> 8) & 0x7f; 2112ccf5a99SIgor M. Liplianin buf[1] = (div >> 0) & 0xff; 2122ccf5a99SIgor M. Liplianin /*Reference divider*/ 2132ccf5a99SIgor M. Liplianin /* Select reference ratio of 80 */ 2142ccf5a99SIgor M. Liplianin buf[2] = 0x1D; 2152ccf5a99SIgor M. Liplianin /*PLL test modes*/ 2162ccf5a99SIgor M. Liplianin buf[3] = 0x40; 2172ccf5a99SIgor M. Liplianin /*RF Control register*/ 2182ccf5a99SIgor M. Liplianin buf[4] = 0x6E; /* Bypass enable */ 2192ccf5a99SIgor M. Liplianin /*Baseband filter cutoff */ 2202ccf5a99SIgor M. Liplianin buf[5] = bf; 2212ccf5a99SIgor M. Liplianin 2222ccf5a99SIgor M. Liplianin /* Open i2c gate */ 2232ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2242ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 2252ccf5a99SIgor M. Liplianin /* BR = 10, Enable filter adjustment */ 2262ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, BASE1, 0x0A); 2272ccf5a99SIgor M. Liplianin if (ret < 0) 2282ccf5a99SIgor M. Liplianin goto error; 2292ccf5a99SIgor M. Liplianin /* Write new config values */ 2302ccf5a99SIgor M. Liplianin ret = zl10039_write(state, PLL0, buf, sizeof(buf)); 2312ccf5a99SIgor M. Liplianin if (ret < 0) 2322ccf5a99SIgor M. Liplianin goto error; 2332ccf5a99SIgor M. Liplianin /* BR = 10, Disable filter adjustment */ 2342ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, BASE1, 0x6A); 2352ccf5a99SIgor M. Liplianin if (ret < 0) 2362ccf5a99SIgor M. Liplianin goto error; 2372ccf5a99SIgor M. Liplianin 2382ccf5a99SIgor M. Liplianin /* Close i2c gate */ 2392ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2402ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 2412ccf5a99SIgor M. Liplianin return 0; 2422ccf5a99SIgor M. Liplianin error: 2432ccf5a99SIgor M. Liplianin dprintk("Error setting tuner\n"); 2442ccf5a99SIgor M. Liplianin return ret; 2452ccf5a99SIgor M. Liplianin } 2462ccf5a99SIgor M. Liplianin 247*194ced7aSMax Kellermann static void zl10039_release(struct dvb_frontend *fe) 2482ccf5a99SIgor M. Liplianin { 2492ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 2502ccf5a99SIgor M. Liplianin 2512ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 2522ccf5a99SIgor M. Liplianin kfree(state); 2532ccf5a99SIgor M. Liplianin fe->tuner_priv = NULL; 2542ccf5a99SIgor M. Liplianin } 2552ccf5a99SIgor M. Liplianin 25614c4bf3cSJulia Lawall static const struct dvb_tuner_ops zl10039_ops = { 2572ccf5a99SIgor M. Liplianin .release = zl10039_release, 2582ccf5a99SIgor M. Liplianin .init = zl10039_init, 2592ccf5a99SIgor M. Liplianin .sleep = zl10039_sleep, 2602ccf5a99SIgor M. Liplianin .set_params = zl10039_set_params, 2612ccf5a99SIgor M. Liplianin }; 2622ccf5a99SIgor M. Liplianin 2632ccf5a99SIgor M. Liplianin struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, 2642ccf5a99SIgor M. Liplianin u8 i2c_addr, struct i2c_adapter *i2c) 2652ccf5a99SIgor M. Liplianin { 2662ccf5a99SIgor M. Liplianin struct zl10039_state *state = NULL; 2672ccf5a99SIgor M. Liplianin 2682ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 2692ccf5a99SIgor M. Liplianin state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL); 2702ccf5a99SIgor M. Liplianin if (state == NULL) 2712ccf5a99SIgor M. Liplianin goto error; 2722ccf5a99SIgor M. Liplianin 2732ccf5a99SIgor M. Liplianin state->i2c = i2c; 2742ccf5a99SIgor M. Liplianin state->i2c_addr = i2c_addr; 2752ccf5a99SIgor M. Liplianin 2762ccf5a99SIgor M. Liplianin /* Open i2c gate */ 2772ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2782ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 2792ccf5a99SIgor M. Liplianin /* check if this is a valid tuner */ 2802ccf5a99SIgor M. Liplianin if (zl10039_readreg(state, GENERAL, &state->id) < 0) { 2812ccf5a99SIgor M. Liplianin /* Close i2c gate */ 2822ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2832ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 2842ccf5a99SIgor M. Liplianin goto error; 2852ccf5a99SIgor M. Liplianin } 2862ccf5a99SIgor M. Liplianin /* Close i2c gate */ 2872ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2882ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 2892ccf5a99SIgor M. Liplianin 2902ccf5a99SIgor M. Liplianin state->id = state->id & 0x0f; 2912ccf5a99SIgor M. Liplianin switch (state->id) { 2922ccf5a99SIgor M. Liplianin case ID_ZL10039: 2932ccf5a99SIgor M. Liplianin strcpy(fe->ops.tuner_ops.info.name, 2942ccf5a99SIgor M. Liplianin "Zarlink ZL10039 DVB-S tuner"); 2952ccf5a99SIgor M. Liplianin break; 2962ccf5a99SIgor M. Liplianin default: 2972ccf5a99SIgor M. Liplianin dprintk("Chip ID=%x does not match a known type\n", state->id); 2982ccf5a99SIgor M. Liplianin goto error; 2992ccf5a99SIgor M. Liplianin } 3002ccf5a99SIgor M. Liplianin 3012ccf5a99SIgor M. Liplianin memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops)); 3022ccf5a99SIgor M. Liplianin fe->tuner_priv = state; 3032ccf5a99SIgor M. Liplianin dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr); 3042ccf5a99SIgor M. Liplianin return fe; 3052ccf5a99SIgor M. Liplianin error: 3062ccf5a99SIgor M. Liplianin kfree(state); 3072ccf5a99SIgor M. Liplianin return NULL; 3082ccf5a99SIgor M. Liplianin } 3092ccf5a99SIgor M. Liplianin EXPORT_SYMBOL(zl10039_attach); 3102ccf5a99SIgor M. Liplianin 3112ccf5a99SIgor M. Liplianin module_param(debug, int, 0644); 3122ccf5a99SIgor M. Liplianin MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 3132ccf5a99SIgor M. Liplianin MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver"); 3142ccf5a99SIgor M. Liplianin MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>"); 3152ccf5a99SIgor M. Liplianin MODULE_LICENSE("GPL"); 316