xref: /linux/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24c66c920SMichael Krufky /*
34c66c920SMichael Krufky  *  mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
44c66c920SMichael Krufky  *
508e10972SMichael Krufky  *  Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
64c66c920SMichael Krufky  */
74c66c920SMichael Krufky 
84c66c920SMichael Krufky #include "mxl111sf-tuner.h"
94c66c920SMichael Krufky #include "mxl111sf-phy.h"
104c66c920SMichael Krufky #include "mxl111sf-reg.h"
114c66c920SMichael Krufky 
124c66c920SMichael Krufky /* debug */
134c66c920SMichael Krufky static int mxl111sf_tuner_debug;
144c66c920SMichael Krufky module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
154c66c920SMichael Krufky MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
164c66c920SMichael Krufky 
174c66c920SMichael Krufky #define mxl_dbg(fmt, arg...) \
184c66c920SMichael Krufky 	if (mxl111sf_tuner_debug) \
194c66c920SMichael Krufky 		mxl_printk(KERN_DEBUG, fmt, ##arg)
204c66c920SMichael Krufky 
214c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
224c66c920SMichael Krufky 
234c66c920SMichael Krufky struct mxl111sf_tuner_state {
244c66c920SMichael Krufky 	struct mxl111sf_state *mxl_state;
254c66c920SMichael Krufky 
2640205163SJulia Lawall 	const struct mxl111sf_tuner_config *cfg;
274c66c920SMichael Krufky 
28f7901f9bSMichael Krufky 	enum mxl_if_freq if_freq;
29f7901f9bSMichael Krufky 
304c66c920SMichael Krufky 	u32 frequency;
314c66c920SMichael Krufky 	u32 bandwidth;
324c66c920SMichael Krufky };
334c66c920SMichael Krufky 
mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state * state,u8 addr,u8 * data)344c66c920SMichael Krufky static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
354c66c920SMichael Krufky 				   u8 addr, u8 *data)
364c66c920SMichael Krufky {
374c66c920SMichael Krufky 	return (state->cfg->read_reg) ?
384c66c920SMichael Krufky 		state->cfg->read_reg(state->mxl_state, addr, data) :
394c66c920SMichael Krufky 		-EINVAL;
404c66c920SMichael Krufky }
414c66c920SMichael Krufky 
mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state * state,u8 addr,u8 data)424c66c920SMichael Krufky static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
434c66c920SMichael Krufky 				    u8 addr, u8 data)
444c66c920SMichael Krufky {
454c66c920SMichael Krufky 	return (state->cfg->write_reg) ?
464c66c920SMichael Krufky 		state->cfg->write_reg(state->mxl_state, addr, data) :
474c66c920SMichael Krufky 		-EINVAL;
484c66c920SMichael Krufky }
494c66c920SMichael Krufky 
mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state * state,struct mxl111sf_reg_ctrl_info * ctrl_reg_info)504c66c920SMichael Krufky static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
514c66c920SMichael Krufky 			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
524c66c920SMichael Krufky {
534c66c920SMichael Krufky 	return (state->cfg->program_regs) ?
544c66c920SMichael Krufky 		state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
554c66c920SMichael Krufky 		-EINVAL;
564c66c920SMichael Krufky }
574c66c920SMichael Krufky 
mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state * state,int onoff)584c66c920SMichael Krufky static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
594c66c920SMichael Krufky 					  int onoff)
604c66c920SMichael Krufky {
614c66c920SMichael Krufky 	return (state->cfg->top_master_ctrl) ?
624c66c920SMichael Krufky 		state->cfg->top_master_ctrl(state->mxl_state, onoff) :
634c66c920SMichael Krufky 		-EINVAL;
644c66c920SMichael Krufky }
654c66c920SMichael Krufky 
664c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
674c66c920SMichael Krufky 
684c66c920SMichael Krufky static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
694c66c920SMichael Krufky 	{0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
704c66c920SMichael Krufky 			       DIG_MODEINDEX, _A, _CSF, */
714c66c920SMichael Krufky 	{0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
724c66c920SMichael Krufky 	{0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
734c66c920SMichael Krufky 	{0,    0,    0}
744c66c920SMichael Krufky };
754c66c920SMichael Krufky 
764c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
774c66c920SMichael Krufky 
mxl111sf_calc_phy_tune_regs(u32 freq,u8 bw)784c66c920SMichael Krufky static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
794c66c920SMichael Krufky 								  u8 bw)
804c66c920SMichael Krufky {
814c66c920SMichael Krufky 	u8 filt_bw;
824c66c920SMichael Krufky 
834c66c920SMichael Krufky 	/* set channel bandwidth */
844c66c920SMichael Krufky 	switch (bw) {
854c66c920SMichael Krufky 	case 0: /* ATSC */
864c66c920SMichael Krufky 		filt_bw = 25;
874c66c920SMichael Krufky 		break;
884c66c920SMichael Krufky 	case 1: /* QAM */
894c66c920SMichael Krufky 		filt_bw = 69;
904c66c920SMichael Krufky 		break;
914c66c920SMichael Krufky 	case 6:
924c66c920SMichael Krufky 		filt_bw = 21;
934c66c920SMichael Krufky 		break;
944c66c920SMichael Krufky 	case 7:
954c66c920SMichael Krufky 		filt_bw = 42;
964c66c920SMichael Krufky 		break;
974c66c920SMichael Krufky 	case 8:
984c66c920SMichael Krufky 		filt_bw = 63;
994c66c920SMichael Krufky 		break;
1004c66c920SMichael Krufky 	default:
101c778edb5SHans Verkuil 		pr_err("%s: invalid bandwidth setting!", __func__);
1024c66c920SMichael Krufky 		return NULL;
1034c66c920SMichael Krufky 	}
1044c66c920SMichael Krufky 
1054c66c920SMichael Krufky 	/* calculate RF channel */
1064c66c920SMichael Krufky 	freq /= 1000000;
1074c66c920SMichael Krufky 
1084c66c920SMichael Krufky 	freq *= 64;
1094c66c920SMichael Krufky #if 0
1104c66c920SMichael Krufky 	/* do round */
1114c66c920SMichael Krufky 	freq += 0.5;
1124c66c920SMichael Krufky #endif
1134c66c920SMichael Krufky 	/* set bandwidth */
1144c66c920SMichael Krufky 	mxl_phy_tune_rf[0].data = filt_bw;
1154c66c920SMichael Krufky 
1164c66c920SMichael Krufky 	/* set RF */
1174c66c920SMichael Krufky 	mxl_phy_tune_rf[1].data = (freq & 0xff);
1184c66c920SMichael Krufky 	mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
1194c66c920SMichael Krufky 
1204c66c920SMichael Krufky 	/* start tune */
1214c66c920SMichael Krufky 	return mxl_phy_tune_rf;
1224c66c920SMichael Krufky }
1234c66c920SMichael Krufky 
mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state * state)1244c66c920SMichael Krufky static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
1254c66c920SMichael Krufky {
1264c66c920SMichael Krufky 	int ret;
1274c66c920SMichael Krufky 	u8 ctrl;
1284c66c920SMichael Krufky #if 0
1294c66c920SMichael Krufky 	u16 iffcw;
1304c66c920SMichael Krufky 	u32 if_freq;
1314c66c920SMichael Krufky #endif
1324c66c920SMichael Krufky 	mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
1334c66c920SMichael Krufky 		state->cfg->invert_spectrum, state->cfg->if_freq);
1344c66c920SMichael Krufky 
1354c66c920SMichael Krufky 	/* set IF polarity */
1364c66c920SMichael Krufky 	ctrl = state->cfg->invert_spectrum;
1374c66c920SMichael Krufky 
1384c66c920SMichael Krufky 	ctrl |= state->cfg->if_freq;
1394c66c920SMichael Krufky 
1404c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
1414c66c920SMichael Krufky 	if (mxl_fail(ret))
1424c66c920SMichael Krufky 		goto fail;
1434c66c920SMichael Krufky 
1444c66c920SMichael Krufky #if 0
1454c66c920SMichael Krufky 	if_freq /= 1000000;
1464c66c920SMichael Krufky 
1474c66c920SMichael Krufky 	/* do round */
1484c66c920SMichael Krufky 	if_freq += 0.5;
1494c66c920SMichael Krufky 
1504c66c920SMichael Krufky 	if (MXL_IF_LO == state->cfg->if_freq) {
1514c66c920SMichael Krufky 		ctrl = 0x08;
1524c66c920SMichael Krufky 		iffcw = (u16)(if_freq / (108 * 4096));
1534c66c920SMichael Krufky 	} else if (MXL_IF_HI == state->cfg->if_freq) {
1544c66c920SMichael Krufky 		ctrl = 0x08;
1554c66c920SMichael Krufky 		iffcw = (u16)(if_freq / (216 * 4096));
1564c66c920SMichael Krufky 	} else {
1574c66c920SMichael Krufky 		ctrl = 0;
1584c66c920SMichael Krufky 		iffcw = 0;
1594c66c920SMichael Krufky 	}
1604c66c920SMichael Krufky 
1614c66c920SMichael Krufky 	ctrl |= (iffcw >> 8);
1624c66c920SMichael Krufky #endif
1634c66c920SMichael Krufky 	ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
1644c66c920SMichael Krufky 	if (mxl_fail(ret))
1654c66c920SMichael Krufky 		goto fail;
1664c66c920SMichael Krufky 
1674c66c920SMichael Krufky 	ctrl &= 0xf0;
1684c66c920SMichael Krufky 	ctrl |= 0x90;
1694c66c920SMichael Krufky 
1704c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
1714c66c920SMichael Krufky 	if (mxl_fail(ret))
1724c66c920SMichael Krufky 		goto fail;
1734c66c920SMichael Krufky 
1744c66c920SMichael Krufky #if 0
1754c66c920SMichael Krufky 	ctrl = iffcw & 0x00ff;
1764c66c920SMichael Krufky #endif
1774c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
178f7901f9bSMichael Krufky 	if (mxl_fail(ret))
179f7901f9bSMichael Krufky 		goto fail;
180f7901f9bSMichael Krufky 
181f7901f9bSMichael Krufky 	state->if_freq = state->cfg->if_freq;
1824c66c920SMichael Krufky fail:
1834c66c920SMichael Krufky 	return ret;
1844c66c920SMichael Krufky }
1854c66c920SMichael Krufky 
mxl1x1sf_tune_rf(struct dvb_frontend * fe,u32 freq,u8 bw)1864c66c920SMichael Krufky static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
1874c66c920SMichael Krufky {
1884c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
1894c66c920SMichael Krufky 	static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
1904c66c920SMichael Krufky 	int ret;
1914c66c920SMichael Krufky 	u8 mxl_mode;
1924c66c920SMichael Krufky 
1934c66c920SMichael Krufky 	mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
1944c66c920SMichael Krufky 
1954c66c920SMichael Krufky 	/* stop tune */
1964c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
1974c66c920SMichael Krufky 	if (mxl_fail(ret))
1984c66c920SMichael Krufky 		goto fail;
1994c66c920SMichael Krufky 
2004c66c920SMichael Krufky 	/* check device mode */
2014c66c920SMichael Krufky 	ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
2024c66c920SMichael Krufky 	if (mxl_fail(ret))
2034c66c920SMichael Krufky 		goto fail;
2044c66c920SMichael Krufky 
2054c66c920SMichael Krufky 	/* Fill out registers for channel tune */
2064c66c920SMichael Krufky 	reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
2074c66c920SMichael Krufky 	if (!reg_ctrl_array)
2084c66c920SMichael Krufky 		return -EINVAL;
2094c66c920SMichael Krufky 
2104c66c920SMichael Krufky 	ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
2114c66c920SMichael Krufky 	if (mxl_fail(ret))
2124c66c920SMichael Krufky 		goto fail;
2134c66c920SMichael Krufky 
2144c66c920SMichael Krufky 	if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
2154c66c920SMichael Krufky 		/* IF tuner mode only */
2164c66c920SMichael Krufky 		mxl1x1sf_tuner_top_master_ctrl(state, 0);
2174c66c920SMichael Krufky 		mxl1x1sf_tuner_top_master_ctrl(state, 1);
2184c66c920SMichael Krufky 		mxl1x1sf_tuner_set_if_output_freq(state);
2194c66c920SMichael Krufky 	}
2204c66c920SMichael Krufky 
2214c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
2224c66c920SMichael Krufky 	if (mxl_fail(ret))
2234c66c920SMichael Krufky 		goto fail;
2244c66c920SMichael Krufky 
2254c66c920SMichael Krufky 	if (state->cfg->ant_hunt)
2264c66c920SMichael Krufky 		state->cfg->ant_hunt(fe);
2274c66c920SMichael Krufky fail:
2284c66c920SMichael Krufky 	return ret;
2294c66c920SMichael Krufky }
2304c66c920SMichael Krufky 
mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state * state,int * rf_synth_lock,int * ref_synth_lock)2314c66c920SMichael Krufky static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
2324c66c920SMichael Krufky 					  int *rf_synth_lock,
2334c66c920SMichael Krufky 					  int *ref_synth_lock)
2344c66c920SMichael Krufky {
2354c66c920SMichael Krufky 	int ret;
2364c66c920SMichael Krufky 	u8 data;
2374c66c920SMichael Krufky 
2384c66c920SMichael Krufky 	*rf_synth_lock = 0;
2394c66c920SMichael Krufky 	*ref_synth_lock = 0;
2404c66c920SMichael Krufky 
2414c66c920SMichael Krufky 	ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
2424c66c920SMichael Krufky 	if (mxl_fail(ret))
2434c66c920SMichael Krufky 		goto fail;
2444c66c920SMichael Krufky 
2454c66c920SMichael Krufky 	*ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
2464c66c920SMichael Krufky 	*rf_synth_lock  = ((data & 0x0c) == 0x0c) ? 1 : 0;
2474c66c920SMichael Krufky fail:
2484c66c920SMichael Krufky 	return ret;
2494c66c920SMichael Krufky }
2504c66c920SMichael Krufky 
2514c66c920SMichael Krufky #if 0
2524c66c920SMichael Krufky static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
2534c66c920SMichael Krufky 					 int onoff)
2544c66c920SMichael Krufky {
2554c66c920SMichael Krufky 	return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
2564c66c920SMichael Krufky 					onoff ? 1 : 0);
2574c66c920SMichael Krufky }
2584c66c920SMichael Krufky #endif
2594c66c920SMichael Krufky 
2604c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
2614c66c920SMichael Krufky 
mxl111sf_tuner_set_params(struct dvb_frontend * fe)26214d24d14SMauro Carvalho Chehab static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
2634c66c920SMichael Krufky {
26493ce675cSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
26593ce675cSMauro Carvalho Chehab 	u32 delsys  = c->delivery_system;
2664c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
2674c66c920SMichael Krufky 	int ret;
2684c66c920SMichael Krufky 	u8 bw;
2694c66c920SMichael Krufky 
2704c66c920SMichael Krufky 	mxl_dbg("()");
2714c66c920SMichael Krufky 
27293ce675cSMauro Carvalho Chehab 	switch (delsys) {
27393ce675cSMauro Carvalho Chehab 	case SYS_ATSC:
2744ef70775SMichael Krufky 	case SYS_ATSCMH:
2754c66c920SMichael Krufky 		bw = 0; /* ATSC */
2764c66c920SMichael Krufky 		break;
27793ce675cSMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_B:
2784c66c920SMichael Krufky 		bw = 1; /* US CABLE */
2794c66c920SMichael Krufky 		break;
28093ce675cSMauro Carvalho Chehab 	case SYS_DVBT:
28193ce675cSMauro Carvalho Chehab 		switch (c->bandwidth_hz) {
28293ce675cSMauro Carvalho Chehab 		case 6000000:
2834c66c920SMichael Krufky 			bw = 6;
2844c66c920SMichael Krufky 			break;
28593ce675cSMauro Carvalho Chehab 		case 7000000:
2864c66c920SMichael Krufky 			bw = 7;
2874c66c920SMichael Krufky 			break;
28893ce675cSMauro Carvalho Chehab 		case 8000000:
2894c66c920SMichael Krufky 			bw = 8;
2904c66c920SMichael Krufky 			break;
2914c66c920SMichael Krufky 		default:
292c778edb5SHans Verkuil 			pr_err("%s: bandwidth not set!", __func__);
2934c66c920SMichael Krufky 			return -EINVAL;
2944c66c920SMichael Krufky 		}
29593ce675cSMauro Carvalho Chehab 		break;
29693ce675cSMauro Carvalho Chehab 	default:
297c778edb5SHans Verkuil 		pr_err("%s: modulation type not supported!", __func__);
2984c66c920SMichael Krufky 		return -EINVAL;
2994c66c920SMichael Krufky 	}
30093ce675cSMauro Carvalho Chehab 	ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
3014c66c920SMichael Krufky 	if (mxl_fail(ret))
3024c66c920SMichael Krufky 		goto fail;
3034c66c920SMichael Krufky 
30493ce675cSMauro Carvalho Chehab 	state->frequency = c->frequency;
305c6f56e7dSMauro Carvalho Chehab 	state->bandwidth = c->bandwidth_hz;
3064c66c920SMichael Krufky fail:
3074c66c920SMichael Krufky 	return ret;
3084c66c920SMichael Krufky }
3094c66c920SMichael Krufky 
3104c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
3114c66c920SMichael Krufky 
3124c66c920SMichael Krufky #if 0
3134c66c920SMichael Krufky static int mxl111sf_tuner_init(struct dvb_frontend *fe)
3144c66c920SMichael Krufky {
3154c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
3164c66c920SMichael Krufky 	int ret;
3174c66c920SMichael Krufky 
3184c66c920SMichael Krufky 	/* wake from standby handled by usb driver */
3194c66c920SMichael Krufky 
3204c66c920SMichael Krufky 	return ret;
3214c66c920SMichael Krufky }
3224c66c920SMichael Krufky 
3234c66c920SMichael Krufky static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
3244c66c920SMichael Krufky {
3254c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
3264c66c920SMichael Krufky 	int ret;
3274c66c920SMichael Krufky 
3284c66c920SMichael Krufky 	/* enter standby mode handled by usb driver */
3294c66c920SMichael Krufky 
3304c66c920SMichael Krufky 	return ret;
3314c66c920SMichael Krufky }
3324c66c920SMichael Krufky #endif
3334c66c920SMichael Krufky 
3344c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
3354c66c920SMichael Krufky 
mxl111sf_tuner_get_status(struct dvb_frontend * fe,u32 * status)3364c66c920SMichael Krufky static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
3374c66c920SMichael Krufky {
3384c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
3394c66c920SMichael Krufky 	int rf_locked, ref_locked, ret;
3404c66c920SMichael Krufky 
3414c66c920SMichael Krufky 	*status = 0;
3424c66c920SMichael Krufky 
3434c66c920SMichael Krufky 	ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
3444c66c920SMichael Krufky 	if (mxl_fail(ret))
3454c66c920SMichael Krufky 		goto fail;
3464c66c920SMichael Krufky 	mxl_info("%s%s", rf_locked ? "rf locked " : "",
3474c66c920SMichael Krufky 		 ref_locked ? "ref locked" : "");
3484c66c920SMichael Krufky 
3494c66c920SMichael Krufky 	if ((rf_locked) || (ref_locked))
3504c66c920SMichael Krufky 		*status |= TUNER_STATUS_LOCKED;
3514c66c920SMichael Krufky fail:
3524c66c920SMichael Krufky 	return ret;
3534c66c920SMichael Krufky }
3544c66c920SMichael Krufky 
mxl111sf_get_rf_strength(struct dvb_frontend * fe,u16 * strength)3554c66c920SMichael Krufky static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
3564c66c920SMichael Krufky {
3574c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
3584c66c920SMichael Krufky 	u8 val1, val2;
3594c66c920SMichael Krufky 	int ret;
3604c66c920SMichael Krufky 
3614c66c920SMichael Krufky 	*strength = 0;
3624c66c920SMichael Krufky 
3634c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
3644c66c920SMichael Krufky 	if (mxl_fail(ret))
3654c66c920SMichael Krufky 		goto fail;
3664c66c920SMichael Krufky 	ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
3674c66c920SMichael Krufky 	if (mxl_fail(ret))
3684c66c920SMichael Krufky 		goto fail;
3694c66c920SMichael Krufky 	ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
3704c66c920SMichael Krufky 	if (mxl_fail(ret))
3714c66c920SMichael Krufky 		goto fail;
3724c66c920SMichael Krufky 
3734c66c920SMichael Krufky 	*strength = val1 | ((val2 & 0x07) << 8);
3744c66c920SMichael Krufky fail:
3754c66c920SMichael Krufky 	ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
3764c66c920SMichael Krufky 	mxl_fail(ret);
3774c66c920SMichael Krufky 
3784c66c920SMichael Krufky 	return ret;
3794c66c920SMichael Krufky }
3804c66c920SMichael Krufky 
3814c66c920SMichael Krufky /* ------------------------------------------------------------------------ */
3824c66c920SMichael Krufky 
mxl111sf_tuner_get_frequency(struct dvb_frontend * fe,u32 * frequency)3834c66c920SMichael Krufky static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
3844c66c920SMichael Krufky {
3854c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
3864c66c920SMichael Krufky 	*frequency = state->frequency;
3874c66c920SMichael Krufky 	return 0;
3884c66c920SMichael Krufky }
3894c66c920SMichael Krufky 
mxl111sf_tuner_get_bandwidth(struct dvb_frontend * fe,u32 * bandwidth)3904c66c920SMichael Krufky static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
3914c66c920SMichael Krufky {
3924c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
3934c66c920SMichael Krufky 	*bandwidth = state->bandwidth;
3944c66c920SMichael Krufky 	return 0;
3954c66c920SMichael Krufky }
3964c66c920SMichael Krufky 
mxl111sf_tuner_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)397f7901f9bSMichael Krufky static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
398f7901f9bSMichael Krufky 					   u32 *frequency)
399f7901f9bSMichael Krufky {
400f7901f9bSMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
401f7901f9bSMichael Krufky 
402f7901f9bSMichael Krufky 	*frequency = 0;
403f7901f9bSMichael Krufky 
404f7901f9bSMichael Krufky 	switch (state->if_freq) {
405f7901f9bSMichael Krufky 	case MXL_IF_4_0:   /* 4.0   MHz */
406f7901f9bSMichael Krufky 		*frequency = 4000000;
407f7901f9bSMichael Krufky 		break;
408f7901f9bSMichael Krufky 	case MXL_IF_4_5:   /* 4.5   MHz */
409f7901f9bSMichael Krufky 		*frequency = 4500000;
410f7901f9bSMichael Krufky 		break;
411f7901f9bSMichael Krufky 	case MXL_IF_4_57:  /* 4.57  MHz */
412f7901f9bSMichael Krufky 		*frequency = 4570000;
413f7901f9bSMichael Krufky 		break;
414f7901f9bSMichael Krufky 	case MXL_IF_5_0:   /* 5.0   MHz */
415f7901f9bSMichael Krufky 		*frequency = 5000000;
416f7901f9bSMichael Krufky 		break;
417f7901f9bSMichael Krufky 	case MXL_IF_5_38:  /* 5.38  MHz */
418f7901f9bSMichael Krufky 		*frequency = 5380000;
419f7901f9bSMichael Krufky 		break;
420f7901f9bSMichael Krufky 	case MXL_IF_6_0:   /* 6.0   MHz */
421f7901f9bSMichael Krufky 		*frequency = 6000000;
422f7901f9bSMichael Krufky 		break;
423f7901f9bSMichael Krufky 	case MXL_IF_6_28:  /* 6.28  MHz */
424f7901f9bSMichael Krufky 		*frequency = 6280000;
425f7901f9bSMichael Krufky 		break;
426f7901f9bSMichael Krufky 	case MXL_IF_7_2:   /* 7.2   MHz */
427f7901f9bSMichael Krufky 		*frequency = 7200000;
428f7901f9bSMichael Krufky 		break;
429f7901f9bSMichael Krufky 	case MXL_IF_35_25: /* 35.25 MHz */
430f7901f9bSMichael Krufky 		*frequency = 35250000;
431f7901f9bSMichael Krufky 		break;
432f7901f9bSMichael Krufky 	case MXL_IF_36:    /* 36    MHz */
433f7901f9bSMichael Krufky 		*frequency = 36000000;
434f7901f9bSMichael Krufky 		break;
435f7901f9bSMichael Krufky 	case MXL_IF_36_15: /* 36.15 MHz */
436f7901f9bSMichael Krufky 		*frequency = 36150000;
437f7901f9bSMichael Krufky 		break;
438f7901f9bSMichael Krufky 	case MXL_IF_44:    /* 44    MHz */
439f7901f9bSMichael Krufky 		*frequency = 44000000;
440f7901f9bSMichael Krufky 		break;
441f7901f9bSMichael Krufky 	}
442f7901f9bSMichael Krufky 	return 0;
443f7901f9bSMichael Krufky }
444f7901f9bSMichael Krufky 
mxl111sf_tuner_release(struct dvb_frontend * fe)445194ced7aSMax Kellermann static void mxl111sf_tuner_release(struct dvb_frontend *fe)
4464c66c920SMichael Krufky {
4474c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = fe->tuner_priv;
4484c66c920SMichael Krufky 	mxl_dbg("()");
4494c66c920SMichael Krufky 	kfree(state);
4504c66c920SMichael Krufky 	fe->tuner_priv = NULL;
4514c66c920SMichael Krufky }
4524c66c920SMichael Krufky 
4534c66c920SMichael Krufky /* ------------------------------------------------------------------------- */
4544c66c920SMichael Krufky 
45556e247a5SJulia Lawall static const struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
4564c66c920SMichael Krufky 	.info = {
4574c66c920SMichael Krufky 		.name = "MaxLinear MxL111SF",
4584c66c920SMichael Krufky #if 0
459a3f90c75SMauro Carvalho Chehab 		.frequency_min_hz  = ,
460a3f90c75SMauro Carvalho Chehab 		.frequency_max_hz  = ,
461a3f90c75SMauro Carvalho Chehab 		.frequency_step_hz = ,
4624c66c920SMichael Krufky #endif
4634c66c920SMichael Krufky 	},
4644c66c920SMichael Krufky #if 0
4654c66c920SMichael Krufky 	.init              = mxl111sf_tuner_init,
4664c66c920SMichael Krufky 	.sleep             = mxl111sf_tuner_sleep,
4674c66c920SMichael Krufky #endif
4684c66c920SMichael Krufky 	.set_params        = mxl111sf_tuner_set_params,
4694c66c920SMichael Krufky 	.get_status        = mxl111sf_tuner_get_status,
4704c66c920SMichael Krufky 	.get_rf_strength   = mxl111sf_get_rf_strength,
4714c66c920SMichael Krufky 	.get_frequency     = mxl111sf_tuner_get_frequency,
4724c66c920SMichael Krufky 	.get_bandwidth     = mxl111sf_tuner_get_bandwidth,
473f7901f9bSMichael Krufky 	.get_if_frequency  = mxl111sf_tuner_get_if_frequency,
4744c66c920SMichael Krufky 	.release           = mxl111sf_tuner_release,
4754c66c920SMichael Krufky };
4764c66c920SMichael Krufky 
mxl111sf_tuner_attach(struct dvb_frontend * fe,struct mxl111sf_state * mxl_state,const struct mxl111sf_tuner_config * cfg)4774c66c920SMichael Krufky struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
4784c66c920SMichael Krufky 				struct mxl111sf_state *mxl_state,
47940205163SJulia Lawall 				const struct mxl111sf_tuner_config *cfg)
4804c66c920SMichael Krufky {
4814c66c920SMichael Krufky 	struct mxl111sf_tuner_state *state = NULL;
4824c66c920SMichael Krufky 
4834c66c920SMichael Krufky 	mxl_dbg("()");
4844c66c920SMichael Krufky 
4854c66c920SMichael Krufky 	state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
4864c66c920SMichael Krufky 	if (state == NULL)
4874c66c920SMichael Krufky 		return NULL;
4884c66c920SMichael Krufky 
4894c66c920SMichael Krufky 	state->mxl_state = mxl_state;
4904c66c920SMichael Krufky 	state->cfg = cfg;
4914c66c920SMichael Krufky 
4924c66c920SMichael Krufky 	memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
4934c66c920SMichael Krufky 	       sizeof(struct dvb_tuner_ops));
4944c66c920SMichael Krufky 
4954c66c920SMichael Krufky 	fe->tuner_priv = state;
4964c66c920SMichael Krufky 	return fe;
4974c66c920SMichael Krufky }
4984c66c920SMichael Krufky EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
4994c66c920SMichael Krufky 
5004c66c920SMichael Krufky MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
50108e10972SMichael Krufky MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
5024c66c920SMichael Krufky MODULE_LICENSE("GPL");
5034c66c920SMichael Krufky MODULE_VERSION("0.1");
504