1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 22ccf5a99SIgor M. Liplianin /* 32ccf5a99SIgor M. Liplianin * Driver for Zarlink ZL10039 DVB-S tuner 42ccf5a99SIgor M. Liplianin * 52ccf5a99SIgor M. Liplianin * Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za> 62ccf5a99SIgor M. Liplianin */ 72ccf5a99SIgor M. Liplianin 82ccf5a99SIgor M. Liplianin #include <linux/module.h> 92ccf5a99SIgor M. Liplianin #include <linux/init.h> 102ccf5a99SIgor M. Liplianin #include <linux/string.h> 112ccf5a99SIgor M. Liplianin #include <linux/slab.h> 122ccf5a99SIgor M. Liplianin #include <linux/dvb/frontend.h> 132ccf5a99SIgor M. Liplianin 14fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 152ccf5a99SIgor M. Liplianin #include "zl10039.h" 162ccf5a99SIgor M. Liplianin 172ccf5a99SIgor M. Liplianin static int debug; 182ccf5a99SIgor M. Liplianin 198393796dSMauro Carvalho Chehab /* Max transfer size done by I2C transfer functions */ 208393796dSMauro Carvalho Chehab #define MAX_XFER_SIZE 64 218393796dSMauro Carvalho Chehab 222ccf5a99SIgor M. Liplianin #define dprintk(args...) \ 232ccf5a99SIgor M. Liplianin do { \ 242ccf5a99SIgor M. Liplianin if (debug) \ 252ccf5a99SIgor M. Liplianin printk(KERN_DEBUG args); \ 262ccf5a99SIgor M. Liplianin } while (0) 272ccf5a99SIgor M. Liplianin 282ccf5a99SIgor M. Liplianin enum zl10039_model_id { 292ccf5a99SIgor M. Liplianin ID_ZL10039 = 1 302ccf5a99SIgor M. Liplianin }; 312ccf5a99SIgor M. Liplianin 322ccf5a99SIgor M. Liplianin struct zl10039_state { 332ccf5a99SIgor M. Liplianin struct i2c_adapter *i2c; 342ccf5a99SIgor M. Liplianin u8 i2c_addr; 352ccf5a99SIgor M. Liplianin u8 id; 362ccf5a99SIgor M. Liplianin }; 372ccf5a99SIgor M. Liplianin 382ccf5a99SIgor M. Liplianin enum zl10039_reg_addr { 392ccf5a99SIgor M. Liplianin PLL0 = 0, 402ccf5a99SIgor M. Liplianin PLL1, 412ccf5a99SIgor M. Liplianin PLL2, 422ccf5a99SIgor M. Liplianin PLL3, 432ccf5a99SIgor M. Liplianin RFFE, 442ccf5a99SIgor M. Liplianin BASE0, 452ccf5a99SIgor M. Liplianin BASE1, 462ccf5a99SIgor M. Liplianin BASE2, 472ccf5a99SIgor M. Liplianin LO0, 482ccf5a99SIgor M. Liplianin LO1, 492ccf5a99SIgor M. Liplianin LO2, 502ccf5a99SIgor M. Liplianin LO3, 512ccf5a99SIgor M. Liplianin LO4, 522ccf5a99SIgor M. Liplianin LO5, 532ccf5a99SIgor M. Liplianin LO6, 542ccf5a99SIgor M. Liplianin GENERAL 552ccf5a99SIgor M. Liplianin }; 562ccf5a99SIgor M. Liplianin 572ccf5a99SIgor M. Liplianin static int zl10039_read(const struct zl10039_state *state, 582ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, u8 *buf, 592ccf5a99SIgor M. Liplianin const size_t count) 602ccf5a99SIgor M. Liplianin { 612ccf5a99SIgor M. Liplianin u8 regbuf[] = { reg }; 622ccf5a99SIgor M. Liplianin struct i2c_msg msg[] = { 632ccf5a99SIgor M. Liplianin {/* Write register address */ 642ccf5a99SIgor M. Liplianin .addr = state->i2c_addr, 652ccf5a99SIgor M. Liplianin .flags = 0, 662ccf5a99SIgor M. Liplianin .buf = regbuf, 672ccf5a99SIgor M. Liplianin .len = 1, 682ccf5a99SIgor M. Liplianin }, {/* Read count bytes */ 692ccf5a99SIgor M. Liplianin .addr = state->i2c_addr, 702ccf5a99SIgor M. Liplianin .flags = I2C_M_RD, 712ccf5a99SIgor M. Liplianin .buf = buf, 722ccf5a99SIgor M. Liplianin .len = count, 732ccf5a99SIgor M. Liplianin }, 742ccf5a99SIgor M. Liplianin }; 752ccf5a99SIgor M. Liplianin 762ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 772ccf5a99SIgor M. Liplianin 782ccf5a99SIgor M. Liplianin if (i2c_transfer(state->i2c, msg, 2) != 2) { 792ccf5a99SIgor M. Liplianin dprintk("%s: i2c read error\n", __func__); 802ccf5a99SIgor M. Liplianin return -EREMOTEIO; 812ccf5a99SIgor M. Liplianin } 822ccf5a99SIgor M. Liplianin 832ccf5a99SIgor M. Liplianin return 0; /* Success */ 842ccf5a99SIgor M. Liplianin } 852ccf5a99SIgor M. Liplianin 862ccf5a99SIgor M. Liplianin static int zl10039_write(struct zl10039_state *state, 872ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, const u8 *src, 882ccf5a99SIgor M. Liplianin const size_t count) 892ccf5a99SIgor M. Liplianin { 908393796dSMauro Carvalho Chehab u8 buf[MAX_XFER_SIZE]; 912ccf5a99SIgor M. Liplianin struct i2c_msg msg = { 922ccf5a99SIgor M. Liplianin .addr = state->i2c_addr, 932ccf5a99SIgor M. Liplianin .flags = 0, 942ccf5a99SIgor M. Liplianin .buf = buf, 952ccf5a99SIgor M. Liplianin .len = count + 1, 962ccf5a99SIgor M. Liplianin }; 972ccf5a99SIgor M. Liplianin 988393796dSMauro Carvalho Chehab if (1 + count > sizeof(buf)) { 998393796dSMauro Carvalho Chehab printk(KERN_WARNING 10035f30f36SMauro Carvalho Chehab "%s: i2c wr reg=%04x: len=%zu is too big!\n", 1018393796dSMauro Carvalho Chehab KBUILD_MODNAME, reg, count); 1028393796dSMauro Carvalho Chehab return -EINVAL; 1038393796dSMauro Carvalho Chehab } 1048393796dSMauro Carvalho Chehab 1052ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1062ccf5a99SIgor M. Liplianin /* Write register address and data in one go */ 1072ccf5a99SIgor M. Liplianin buf[0] = reg; 1082ccf5a99SIgor M. Liplianin memcpy(&buf[1], src, count); 1092ccf5a99SIgor M. Liplianin if (i2c_transfer(state->i2c, &msg, 1) != 1) { 1102ccf5a99SIgor M. Liplianin dprintk("%s: i2c write error\n", __func__); 1112ccf5a99SIgor M. Liplianin return -EREMOTEIO; 1122ccf5a99SIgor M. Liplianin } 1132ccf5a99SIgor M. Liplianin 1142ccf5a99SIgor M. Liplianin return 0; /* Success */ 1152ccf5a99SIgor M. Liplianin } 1162ccf5a99SIgor M. Liplianin 1172ccf5a99SIgor M. Liplianin static inline int zl10039_readreg(struct zl10039_state *state, 1182ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, u8 *val) 1192ccf5a99SIgor M. Liplianin { 1202ccf5a99SIgor M. Liplianin return zl10039_read(state, reg, val, 1); 1212ccf5a99SIgor M. Liplianin } 1222ccf5a99SIgor M. Liplianin 1232ccf5a99SIgor M. Liplianin static inline int zl10039_writereg(struct zl10039_state *state, 1242ccf5a99SIgor M. Liplianin const enum zl10039_reg_addr reg, 1252ccf5a99SIgor M. Liplianin const u8 val) 1262ccf5a99SIgor M. Liplianin { 1273cd890dbSArnd Bergmann const u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */ 1283cd890dbSArnd Bergmann 1293cd890dbSArnd Bergmann return zl10039_write(state, reg, &tmp, 1); 1302ccf5a99SIgor M. Liplianin } 1312ccf5a99SIgor M. Liplianin 1322ccf5a99SIgor M. Liplianin static int zl10039_init(struct dvb_frontend *fe) 1332ccf5a99SIgor M. Liplianin { 1342ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 1352ccf5a99SIgor M. Liplianin int ret; 1362ccf5a99SIgor M. Liplianin 1372ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1382ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1392ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 1402ccf5a99SIgor M. Liplianin /* Reset logic */ 1412ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, GENERAL, 0x40); 1422ccf5a99SIgor M. Liplianin if (ret < 0) { 1434bd69e7bSMauro Carvalho Chehab dprintk("Note: i2c write error normal when resetting the tuner\n"); 1442ccf5a99SIgor M. Liplianin } 1452ccf5a99SIgor M. Liplianin /* Wake up */ 1462ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, GENERAL, 0x01); 1472ccf5a99SIgor M. Liplianin if (ret < 0) { 1482ccf5a99SIgor M. Liplianin dprintk("Tuner power up failed\n"); 1492ccf5a99SIgor M. Liplianin return ret; 1502ccf5a99SIgor M. Liplianin } 1512ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1522ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 1532ccf5a99SIgor M. Liplianin 1542ccf5a99SIgor M. Liplianin return 0; 1552ccf5a99SIgor M. Liplianin } 1562ccf5a99SIgor M. Liplianin 1572ccf5a99SIgor M. Liplianin static int zl10039_sleep(struct dvb_frontend *fe) 1582ccf5a99SIgor M. Liplianin { 1592ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 1602ccf5a99SIgor M. Liplianin int ret; 1612ccf5a99SIgor M. Liplianin 1622ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1632ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1642ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 1652ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, GENERAL, 0x80); 1662ccf5a99SIgor M. Liplianin if (ret < 0) { 1672ccf5a99SIgor M. Liplianin dprintk("Tuner sleep failed\n"); 1682ccf5a99SIgor M. Liplianin return ret; 1692ccf5a99SIgor M. Liplianin } 1702ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 1712ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 1722ccf5a99SIgor M. Liplianin 1732ccf5a99SIgor M. Liplianin return 0; 1742ccf5a99SIgor M. Liplianin } 1752ccf5a99SIgor M. Liplianin 17614d24d14SMauro Carvalho Chehab static int zl10039_set_params(struct dvb_frontend *fe) 1772ccf5a99SIgor M. Liplianin { 1788579881bSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1792ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 1802ccf5a99SIgor M. Liplianin u8 buf[6]; 1812ccf5a99SIgor M. Liplianin u8 bf; 1822ccf5a99SIgor M. Liplianin u32 fbw; 1832ccf5a99SIgor M. Liplianin u32 div; 1842ccf5a99SIgor M. Liplianin int ret; 1852ccf5a99SIgor M. Liplianin 1862ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 1872ccf5a99SIgor M. Liplianin dprintk("Set frequency = %d, symbol rate = %d\n", 1888579881bSMauro Carvalho Chehab c->frequency, c->symbol_rate); 1892ccf5a99SIgor M. Liplianin 1902ccf5a99SIgor M. Liplianin /* Assumed 10.111 MHz crystal oscillator */ 1912ccf5a99SIgor M. Liplianin /* Cancelled num/den 80 to prevent overflow */ 1928579881bSMauro Carvalho Chehab div = (c->frequency * 1000) / 126387; 1938579881bSMauro Carvalho Chehab fbw = (c->symbol_rate * 27) / 32000; 1942ccf5a99SIgor M. Liplianin /* Cancelled num/den 10 to prevent overflow */ 1952ccf5a99SIgor M. Liplianin bf = ((fbw * 5088) / 1011100) - 1; 1962ccf5a99SIgor M. Liplianin 1972ccf5a99SIgor M. Liplianin /*PLL divider*/ 1982ccf5a99SIgor M. Liplianin buf[0] = (div >> 8) & 0x7f; 1992ccf5a99SIgor M. Liplianin buf[1] = (div >> 0) & 0xff; 2002ccf5a99SIgor M. Liplianin /*Reference divider*/ 2012ccf5a99SIgor M. Liplianin /* Select reference ratio of 80 */ 2022ccf5a99SIgor M. Liplianin buf[2] = 0x1D; 2032ccf5a99SIgor M. Liplianin /*PLL test modes*/ 2042ccf5a99SIgor M. Liplianin buf[3] = 0x40; 2052ccf5a99SIgor M. Liplianin /*RF Control register*/ 2062ccf5a99SIgor M. Liplianin buf[4] = 0x6E; /* Bypass enable */ 2072ccf5a99SIgor M. Liplianin /*Baseband filter cutoff */ 2082ccf5a99SIgor M. Liplianin buf[5] = bf; 2092ccf5a99SIgor M. Liplianin 2102ccf5a99SIgor M. Liplianin /* Open i2c gate */ 2112ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2122ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 2132ccf5a99SIgor M. Liplianin /* BR = 10, Enable filter adjustment */ 2142ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, BASE1, 0x0A); 2152ccf5a99SIgor M. Liplianin if (ret < 0) 2162ccf5a99SIgor M. Liplianin goto error; 2172ccf5a99SIgor M. Liplianin /* Write new config values */ 2182ccf5a99SIgor M. Liplianin ret = zl10039_write(state, PLL0, buf, sizeof(buf)); 2192ccf5a99SIgor M. Liplianin if (ret < 0) 2202ccf5a99SIgor M. Liplianin goto error; 2212ccf5a99SIgor M. Liplianin /* BR = 10, Disable filter adjustment */ 2222ccf5a99SIgor M. Liplianin ret = zl10039_writereg(state, BASE1, 0x6A); 2232ccf5a99SIgor M. Liplianin if (ret < 0) 2242ccf5a99SIgor M. Liplianin goto error; 2252ccf5a99SIgor M. Liplianin 2262ccf5a99SIgor M. Liplianin /* Close i2c gate */ 2272ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2282ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 2292ccf5a99SIgor M. Liplianin return 0; 2302ccf5a99SIgor M. Liplianin error: 2312ccf5a99SIgor M. Liplianin dprintk("Error setting tuner\n"); 2322ccf5a99SIgor M. Liplianin return ret; 2332ccf5a99SIgor M. Liplianin } 2342ccf5a99SIgor M. Liplianin 235194ced7aSMax Kellermann static void zl10039_release(struct dvb_frontend *fe) 2362ccf5a99SIgor M. Liplianin { 2372ccf5a99SIgor M. Liplianin struct zl10039_state *state = fe->tuner_priv; 2382ccf5a99SIgor M. Liplianin 2392ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 2402ccf5a99SIgor M. Liplianin kfree(state); 2412ccf5a99SIgor M. Liplianin fe->tuner_priv = NULL; 2422ccf5a99SIgor M. Liplianin } 2432ccf5a99SIgor M. Liplianin 24414c4bf3cSJulia Lawall static const struct dvb_tuner_ops zl10039_ops = { 2452ccf5a99SIgor M. Liplianin .release = zl10039_release, 2462ccf5a99SIgor M. Liplianin .init = zl10039_init, 2472ccf5a99SIgor M. Liplianin .sleep = zl10039_sleep, 2482ccf5a99SIgor M. Liplianin .set_params = zl10039_set_params, 2492ccf5a99SIgor M. Liplianin }; 2502ccf5a99SIgor M. Liplianin 2512ccf5a99SIgor M. Liplianin struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, 2522ccf5a99SIgor M. Liplianin u8 i2c_addr, struct i2c_adapter *i2c) 2532ccf5a99SIgor M. Liplianin { 2542ccf5a99SIgor M. Liplianin struct zl10039_state *state = NULL; 2552ccf5a99SIgor M. Liplianin 2562ccf5a99SIgor M. Liplianin dprintk("%s\n", __func__); 2572ccf5a99SIgor M. Liplianin state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL); 2582ccf5a99SIgor M. Liplianin if (state == NULL) 2592ccf5a99SIgor M. Liplianin goto error; 2602ccf5a99SIgor M. Liplianin 2612ccf5a99SIgor M. Liplianin state->i2c = i2c; 2622ccf5a99SIgor M. Liplianin state->i2c_addr = i2c_addr; 2632ccf5a99SIgor M. Liplianin 2642ccf5a99SIgor M. Liplianin /* Open i2c gate */ 2652ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2662ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 1); 2672ccf5a99SIgor M. Liplianin /* check if this is a valid tuner */ 2682ccf5a99SIgor M. Liplianin if (zl10039_readreg(state, GENERAL, &state->id) < 0) { 2692ccf5a99SIgor M. Liplianin /* Close i2c gate */ 2702ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2712ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 2722ccf5a99SIgor M. Liplianin goto error; 2732ccf5a99SIgor M. Liplianin } 2742ccf5a99SIgor M. Liplianin /* Close i2c gate */ 2752ccf5a99SIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 2762ccf5a99SIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 2772ccf5a99SIgor M. Liplianin 2782ccf5a99SIgor M. Liplianin state->id = state->id & 0x0f; 2792ccf5a99SIgor M. Liplianin switch (state->id) { 2802ccf5a99SIgor M. Liplianin case ID_ZL10039: 281cc1e6315SMauro Carvalho Chehab strscpy(fe->ops.tuner_ops.info.name, 282cc1e6315SMauro Carvalho Chehab "Zarlink ZL10039 DVB-S tuner", 283cc1e6315SMauro Carvalho Chehab sizeof(fe->ops.tuner_ops.info.name)); 2842ccf5a99SIgor M. Liplianin break; 2852ccf5a99SIgor M. Liplianin default: 2862ccf5a99SIgor M. Liplianin dprintk("Chip ID=%x does not match a known type\n", state->id); 2872ccf5a99SIgor M. Liplianin goto error; 2882ccf5a99SIgor M. Liplianin } 2892ccf5a99SIgor M. Liplianin 2902ccf5a99SIgor M. Liplianin memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops)); 2912ccf5a99SIgor M. Liplianin fe->tuner_priv = state; 2922ccf5a99SIgor M. Liplianin dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr); 2932ccf5a99SIgor M. Liplianin return fe; 2942ccf5a99SIgor M. Liplianin error: 2952ccf5a99SIgor M. Liplianin kfree(state); 2962ccf5a99SIgor M. Liplianin return NULL; 2972ccf5a99SIgor M. Liplianin } 2982ccf5a99SIgor M. Liplianin EXPORT_SYMBOL(zl10039_attach); 2992ccf5a99SIgor M. Liplianin 3002ccf5a99SIgor M. Liplianin module_param(debug, int, 0644); 3012ccf5a99SIgor M. Liplianin MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 3022ccf5a99SIgor M. Liplianin MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver"); 3032ccf5a99SIgor M. Liplianin MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>"); 3042ccf5a99SIgor M. Liplianin MODULE_LICENSE("GPL"); 305