xref: /linux/drivers/media/dvb-frontends/zl10039.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
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