162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/i2c.h> 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci#include <linux/videodev2.h> 1162306a36Sopenharmony_ci#include "tuner-i2c.h" 1262306a36Sopenharmony_ci#include "mxl5007t.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic DEFINE_MUTEX(mxl5007t_list_mutex); 1562306a36Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic int mxl5007t_debug; 1862306a36Sopenharmony_cimodule_param_named(debug, mxl5007t_debug, int, 0644); 1962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "set debug level"); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define mxl_printk(kern, fmt, arg...) \ 2462306a36Sopenharmony_ci printk(kern "%s: " fmt "\n", __func__, ##arg) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define mxl_err(fmt, arg...) \ 2762306a36Sopenharmony_ci mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define mxl_warn(fmt, arg...) \ 3062306a36Sopenharmony_ci mxl_printk(KERN_WARNING, fmt, ##arg) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define mxl_info(fmt, arg...) \ 3362306a36Sopenharmony_ci mxl_printk(KERN_INFO, fmt, ##arg) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define mxl_debug(fmt, arg...) \ 3662306a36Sopenharmony_ci({ \ 3762306a36Sopenharmony_ci if (mxl5007t_debug) \ 3862306a36Sopenharmony_ci mxl_printk(KERN_DEBUG, fmt, ##arg); \ 3962306a36Sopenharmony_ci}) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define mxl_fail(ret) \ 4262306a36Sopenharmony_ci({ \ 4362306a36Sopenharmony_ci int __ret; \ 4462306a36Sopenharmony_ci __ret = (ret < 0); \ 4562306a36Sopenharmony_ci if (__ret) \ 4662306a36Sopenharmony_ci mxl_printk(KERN_ERR, "error %d on line %d", \ 4762306a36Sopenharmony_ci ret, __LINE__); \ 4862306a36Sopenharmony_ci __ret; \ 4962306a36Sopenharmony_ci}) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cienum mxl5007t_mode { 5462306a36Sopenharmony_ci MxL_MODE_ISDBT = 0, 5562306a36Sopenharmony_ci MxL_MODE_DVBT = 1, 5662306a36Sopenharmony_ci MxL_MODE_ATSC = 2, 5762306a36Sopenharmony_ci MxL_MODE_CABLE = 0x10, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cienum mxl5007t_chip_version { 6162306a36Sopenharmony_ci MxL_UNKNOWN_ID = 0x00, 6262306a36Sopenharmony_ci MxL_5007_V1_F1 = 0x11, 6362306a36Sopenharmony_ci MxL_5007_V1_F2 = 0x12, 6462306a36Sopenharmony_ci MxL_5007_V4 = 0x14, 6562306a36Sopenharmony_ci MxL_5007_V2_100_F1 = 0x21, 6662306a36Sopenharmony_ci MxL_5007_V2_100_F2 = 0x22, 6762306a36Sopenharmony_ci MxL_5007_V2_200_F1 = 0x23, 6862306a36Sopenharmony_ci MxL_5007_V2_200_F2 = 0x24, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct reg_pair_t { 7262306a36Sopenharmony_ci u8 reg; 7362306a36Sopenharmony_ci u8 val; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic struct reg_pair_t init_tab[] = { 7962306a36Sopenharmony_ci { 0x02, 0x06 }, 8062306a36Sopenharmony_ci { 0x03, 0x48 }, 8162306a36Sopenharmony_ci { 0x05, 0x04 }, 8262306a36Sopenharmony_ci { 0x06, 0x10 }, 8362306a36Sopenharmony_ci { 0x2e, 0x15 }, /* OVERRIDE */ 8462306a36Sopenharmony_ci { 0x30, 0x10 }, /* OVERRIDE */ 8562306a36Sopenharmony_ci { 0x45, 0x58 }, /* OVERRIDE */ 8662306a36Sopenharmony_ci { 0x48, 0x19 }, /* OVERRIDE */ 8762306a36Sopenharmony_ci { 0x52, 0x03 }, /* OVERRIDE */ 8862306a36Sopenharmony_ci { 0x53, 0x44 }, /* OVERRIDE */ 8962306a36Sopenharmony_ci { 0x6a, 0x4b }, /* OVERRIDE */ 9062306a36Sopenharmony_ci { 0x76, 0x00 }, /* OVERRIDE */ 9162306a36Sopenharmony_ci { 0x78, 0x18 }, /* OVERRIDE */ 9262306a36Sopenharmony_ci { 0x7a, 0x17 }, /* OVERRIDE */ 9362306a36Sopenharmony_ci { 0x85, 0x06 }, /* OVERRIDE */ 9462306a36Sopenharmony_ci { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ 9562306a36Sopenharmony_ci { 0, 0 } 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct reg_pair_t init_tab_cable[] = { 9962306a36Sopenharmony_ci { 0x02, 0x06 }, 10062306a36Sopenharmony_ci { 0x03, 0x48 }, 10162306a36Sopenharmony_ci { 0x05, 0x04 }, 10262306a36Sopenharmony_ci { 0x06, 0x10 }, 10362306a36Sopenharmony_ci { 0x09, 0x3f }, 10462306a36Sopenharmony_ci { 0x0a, 0x3f }, 10562306a36Sopenharmony_ci { 0x0b, 0x3f }, 10662306a36Sopenharmony_ci { 0x2e, 0x15 }, /* OVERRIDE */ 10762306a36Sopenharmony_ci { 0x30, 0x10 }, /* OVERRIDE */ 10862306a36Sopenharmony_ci { 0x45, 0x58 }, /* OVERRIDE */ 10962306a36Sopenharmony_ci { 0x48, 0x19 }, /* OVERRIDE */ 11062306a36Sopenharmony_ci { 0x52, 0x03 }, /* OVERRIDE */ 11162306a36Sopenharmony_ci { 0x53, 0x44 }, /* OVERRIDE */ 11262306a36Sopenharmony_ci { 0x6a, 0x4b }, /* OVERRIDE */ 11362306a36Sopenharmony_ci { 0x76, 0x00 }, /* OVERRIDE */ 11462306a36Sopenharmony_ci { 0x78, 0x18 }, /* OVERRIDE */ 11562306a36Sopenharmony_ci { 0x7a, 0x17 }, /* OVERRIDE */ 11662306a36Sopenharmony_ci { 0x85, 0x06 }, /* OVERRIDE */ 11762306a36Sopenharmony_ci { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ 11862306a36Sopenharmony_ci { 0, 0 } 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic struct reg_pair_t reg_pair_rftune[] = { 12462306a36Sopenharmony_ci { 0x0f, 0x00 }, /* abort tune */ 12562306a36Sopenharmony_ci { 0x0c, 0x15 }, 12662306a36Sopenharmony_ci { 0x0d, 0x40 }, 12762306a36Sopenharmony_ci { 0x0e, 0x0e }, 12862306a36Sopenharmony_ci { 0x1f, 0x87 }, /* OVERRIDE */ 12962306a36Sopenharmony_ci { 0x20, 0x1f }, /* OVERRIDE */ 13062306a36Sopenharmony_ci { 0x21, 0x87 }, /* OVERRIDE */ 13162306a36Sopenharmony_ci { 0x22, 0x1f }, /* OVERRIDE */ 13262306a36Sopenharmony_ci { 0x80, 0x01 }, /* freq dependent */ 13362306a36Sopenharmony_ci { 0x0f, 0x01 }, /* start tune */ 13462306a36Sopenharmony_ci { 0, 0 } 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct mxl5007t_state { 14062306a36Sopenharmony_ci struct list_head hybrid_tuner_instance_list; 14162306a36Sopenharmony_ci struct tuner_i2c_props i2c_props; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci struct mutex lock; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci struct mxl5007t_config *config; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci enum mxl5007t_chip_version chip_id; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; 15062306a36Sopenharmony_ci struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; 15162306a36Sopenharmony_ci struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci enum mxl5007t_if_freq if_freq; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci u32 frequency; 15662306a36Sopenharmony_ci u32 bandwidth; 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* called by _init and _rftun to manipulate the register arrays */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci unsigned int i = 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci while (reg_pair[i].reg || reg_pair[i].val) { 16862306a36Sopenharmony_ci if (reg_pair[i].reg == reg) { 16962306a36Sopenharmony_ci reg_pair[i].val &= ~mask; 17062306a36Sopenharmony_ci reg_pair[i].val |= val; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci i++; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void copy_reg_bits(struct reg_pair_t *reg_pair1, 17862306a36Sopenharmony_ci struct reg_pair_t *reg_pair2) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci unsigned int i, j; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci i = j = 0; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci while (reg_pair1[i].reg || reg_pair1[i].val) { 18562306a36Sopenharmony_ci while (reg_pair2[j].reg || reg_pair2[j].val) { 18662306a36Sopenharmony_ci if (reg_pair1[i].reg != reg_pair2[j].reg) { 18762306a36Sopenharmony_ci j++; 18862306a36Sopenharmony_ci continue; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci reg_pair2[j].val = reg_pair1[i].val; 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci i++; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void mxl5007t_set_mode_bits(struct mxl5007t_state *state, 20062306a36Sopenharmony_ci enum mxl5007t_mode mode, 20162306a36Sopenharmony_ci s32 if_diff_out_level) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci switch (mode) { 20462306a36Sopenharmony_ci case MxL_MODE_ATSC: 20562306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci case MxL_MODE_DVBT: 20862306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci case MxL_MODE_ISDBT: 21162306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci case MxL_MODE_CABLE: 21462306a36Sopenharmony_ci set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); 21562306a36Sopenharmony_ci set_reg_bits(state->tab_init_cable, 0x0a, 0xff, 21662306a36Sopenharmony_ci 8 - if_diff_out_level); 21762306a36Sopenharmony_ci set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci default: 22062306a36Sopenharmony_ci mxl_fail(-EINVAL); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, 22562306a36Sopenharmony_ci enum mxl5007t_if_freq if_freq, 22662306a36Sopenharmony_ci int invert_if) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci u8 val; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci switch (if_freq) { 23162306a36Sopenharmony_ci case MxL_IF_4_MHZ: 23262306a36Sopenharmony_ci val = 0x00; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci case MxL_IF_4_5_MHZ: 23562306a36Sopenharmony_ci val = 0x02; 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci case MxL_IF_4_57_MHZ: 23862306a36Sopenharmony_ci val = 0x03; 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci case MxL_IF_5_MHZ: 24162306a36Sopenharmony_ci val = 0x04; 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci case MxL_IF_5_38_MHZ: 24462306a36Sopenharmony_ci val = 0x05; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case MxL_IF_6_MHZ: 24762306a36Sopenharmony_ci val = 0x06; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case MxL_IF_6_28_MHZ: 25062306a36Sopenharmony_ci val = 0x07; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci case MxL_IF_9_1915_MHZ: 25362306a36Sopenharmony_ci val = 0x08; 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case MxL_IF_35_25_MHZ: 25662306a36Sopenharmony_ci val = 0x09; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci case MxL_IF_36_15_MHZ: 25962306a36Sopenharmony_ci val = 0x0a; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci case MxL_IF_44_MHZ: 26262306a36Sopenharmony_ci val = 0x0b; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci default: 26562306a36Sopenharmony_ci mxl_fail(-EINVAL); 26662306a36Sopenharmony_ci return; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x02, 0x0f, val); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* set inverted IF or normal IF */ 27162306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci state->if_freq = if_freq; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, 27762306a36Sopenharmony_ci enum mxl5007t_xtal_freq xtal_freq) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci switch (xtal_freq) { 28062306a36Sopenharmony_ci case MxL_XTAL_16_MHZ: 28162306a36Sopenharmony_ci /* select xtal freq & ref freq */ 28262306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); 28362306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case MxL_XTAL_20_MHZ: 28662306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); 28762306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case MxL_XTAL_20_25_MHZ: 29062306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); 29162306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci case MxL_XTAL_20_48_MHZ: 29462306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); 29562306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci case MxL_XTAL_24_MHZ: 29862306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); 29962306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci case MxL_XTAL_25_MHZ: 30262306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); 30362306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci case MxL_XTAL_25_14_MHZ: 30662306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); 30762306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case MxL_XTAL_27_MHZ: 31062306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); 31162306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci case MxL_XTAL_28_8_MHZ: 31462306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); 31562306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci case MxL_XTAL_32_MHZ: 31862306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); 31962306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci case MxL_XTAL_40_MHZ: 32262306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); 32362306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case MxL_XTAL_44_MHZ: 32662306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); 32762306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case MxL_XTAL_48_MHZ: 33062306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); 33162306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci case MxL_XTAL_49_3811_MHZ: 33462306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); 33562306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci default: 33862306a36Sopenharmony_ci mxl_fail(-EINVAL); 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, 34462306a36Sopenharmony_ci enum mxl5007t_mode mode) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct mxl5007t_config *cfg = state->config; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); 34962306a36Sopenharmony_ci memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); 35262306a36Sopenharmony_ci mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); 35362306a36Sopenharmony_ci mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); 35662306a36Sopenharmony_ci set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (mode >= MxL_MODE_CABLE) { 35962306a36Sopenharmony_ci copy_reg_bits(state->tab_init, state->tab_init_cable); 36062306a36Sopenharmony_ci return state->tab_init_cable; 36162306a36Sopenharmony_ci } else 36262306a36Sopenharmony_ci return state->tab_init; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cienum mxl5007t_bw_mhz { 36862306a36Sopenharmony_ci MxL_BW_6MHz = 6, 36962306a36Sopenharmony_ci MxL_BW_7MHz = 7, 37062306a36Sopenharmony_ci MxL_BW_8MHz = 8, 37162306a36Sopenharmony_ci}; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void mxl5007t_set_bw_bits(struct mxl5007t_state *state, 37462306a36Sopenharmony_ci enum mxl5007t_bw_mhz bw) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci u8 val; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci switch (bw) { 37962306a36Sopenharmony_ci case MxL_BW_6MHz: 38062306a36Sopenharmony_ci val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, 38162306a36Sopenharmony_ci * and DIG_MODEINDEX_CSF */ 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case MxL_BW_7MHz: 38462306a36Sopenharmony_ci val = 0x2a; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case MxL_BW_8MHz: 38762306a36Sopenharmony_ci val = 0x3f; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci default: 39062306a36Sopenharmony_ci mxl_fail(-EINVAL); 39162306a36Sopenharmony_ci return; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic struct 39762306a36Sopenharmony_cireg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, 39862306a36Sopenharmony_ci u32 rf_freq, enum mxl5007t_bw_mhz bw) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci u32 dig_rf_freq = 0; 40162306a36Sopenharmony_ci u32 temp; 40262306a36Sopenharmony_ci u32 frac_divider = 1000000; 40362306a36Sopenharmony_ci unsigned int i; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci mxl5007t_set_bw_bits(state, bw); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Convert RF frequency into 16 bits => 41062306a36Sopenharmony_ci * 10 bit integer (MHz) + 6 bit fraction */ 41162306a36Sopenharmony_ci dig_rf_freq = rf_freq / MHz; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci temp = rf_freq % MHz; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 41662306a36Sopenharmony_ci dig_rf_freq <<= 1; 41762306a36Sopenharmony_ci frac_divider /= 2; 41862306a36Sopenharmony_ci if (temp > frac_divider) { 41962306a36Sopenharmony_ci temp -= frac_divider; 42062306a36Sopenharmony_ci dig_rf_freq++; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* add to have shift center point by 7.8124 kHz */ 42562306a36Sopenharmony_ci if (temp > 7812) 42662306a36Sopenharmony_ci dig_rf_freq++; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); 42962306a36Sopenharmony_ci set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (rf_freq >= 333000000) 43262306a36Sopenharmony_ci set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return state->tab_rftune; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci u8 buf[] = { reg, val }; 44262306a36Sopenharmony_ci struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, 44362306a36Sopenharmony_ci .buf = buf, .len = 2 }; 44462306a36Sopenharmony_ci int ret; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci ret = i2c_transfer(state->i2c_props.adap, &msg, 1); 44762306a36Sopenharmony_ci if (ret != 1) { 44862306a36Sopenharmony_ci mxl_err("failed!"); 44962306a36Sopenharmony_ci return -EREMOTEIO; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic int mxl5007t_write_regs(struct mxl5007t_state *state, 45562306a36Sopenharmony_ci struct reg_pair_t *reg_pair) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci unsigned int i = 0; 45862306a36Sopenharmony_ci int ret = 0; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { 46162306a36Sopenharmony_ci ret = mxl5007t_write_reg(state, 46262306a36Sopenharmony_ci reg_pair[i].reg, reg_pair[i].val); 46362306a36Sopenharmony_ci i++; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci u8 buf[2] = { 0xfb, reg }; 47162306a36Sopenharmony_ci struct i2c_msg msg[] = { 47262306a36Sopenharmony_ci { .addr = state->i2c_props.addr, .flags = 0, 47362306a36Sopenharmony_ci .buf = buf, .len = 2 }, 47462306a36Sopenharmony_ci { .addr = state->i2c_props.addr, .flags = I2C_M_RD, 47562306a36Sopenharmony_ci .buf = val, .len = 1 }, 47662306a36Sopenharmony_ci }; 47762306a36Sopenharmony_ci int ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ret = i2c_transfer(state->i2c_props.adap, msg, 2); 48062306a36Sopenharmony_ci if (ret != 2) { 48162306a36Sopenharmony_ci mxl_err("failed!"); 48262306a36Sopenharmony_ci return -EREMOTEIO; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int mxl5007t_soft_reset(struct mxl5007t_state *state) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci u8 d = 0xff; 49062306a36Sopenharmony_ci struct i2c_msg msg = { 49162306a36Sopenharmony_ci .addr = state->i2c_props.addr, .flags = 0, 49262306a36Sopenharmony_ci .buf = &d, .len = 1 49362306a36Sopenharmony_ci }; 49462306a36Sopenharmony_ci int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (ret != 1) { 49762306a36Sopenharmony_ci mxl_err("failed!"); 49862306a36Sopenharmony_ci return -EREMOTEIO; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic int mxl5007t_tuner_init(struct mxl5007t_state *state, 50462306a36Sopenharmony_ci enum mxl5007t_mode mode) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct reg_pair_t *init_regs; 50762306a36Sopenharmony_ci int ret; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* calculate initialization reg array */ 51062306a36Sopenharmony_ci init_regs = mxl5007t_calc_init_regs(state, mode); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ret = mxl5007t_write_regs(state, init_regs); 51362306a36Sopenharmony_ci if (mxl_fail(ret)) 51462306a36Sopenharmony_ci goto fail; 51562306a36Sopenharmony_ci mdelay(1); 51662306a36Sopenharmony_cifail: 51762306a36Sopenharmony_ci return ret; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, 52162306a36Sopenharmony_ci enum mxl5007t_bw_mhz bw) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct reg_pair_t *rf_tune_regs; 52462306a36Sopenharmony_ci int ret; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* calculate channel change reg array */ 52762306a36Sopenharmony_ci rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci ret = mxl5007t_write_regs(state, rf_tune_regs); 53062306a36Sopenharmony_ci if (mxl_fail(ret)) 53162306a36Sopenharmony_ci goto fail; 53262306a36Sopenharmony_ci msleep(3); 53362306a36Sopenharmony_cifail: 53462306a36Sopenharmony_ci return ret; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int mxl5007t_synth_lock_status(struct mxl5007t_state *state, 54062306a36Sopenharmony_ci int *rf_locked, int *ref_locked) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci u8 d; 54362306a36Sopenharmony_ci int ret; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci *rf_locked = 0; 54662306a36Sopenharmony_ci *ref_locked = 0; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ret = mxl5007t_read_reg(state, 0xd8, &d); 54962306a36Sopenharmony_ci if (mxl_fail(ret)) 55062306a36Sopenharmony_ci goto fail; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if ((d & 0x0c) == 0x0c) 55362306a36Sopenharmony_ci *rf_locked = 1; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if ((d & 0x03) == 0x03) 55662306a36Sopenharmony_ci *ref_locked = 1; 55762306a36Sopenharmony_cifail: 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 56662306a36Sopenharmony_ci int rf_locked, ref_locked, ret; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci *status = 0; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 57162306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); 57462306a36Sopenharmony_ci if (mxl_fail(ret)) 57562306a36Sopenharmony_ci goto fail; 57662306a36Sopenharmony_ci mxl_debug("%s%s", rf_locked ? "rf locked " : "", 57762306a36Sopenharmony_ci ref_locked ? "ref locked" : ""); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if ((rf_locked) || (ref_locked)) 58062306a36Sopenharmony_ci *status |= TUNER_STATUS_LOCKED; 58162306a36Sopenharmony_cifail: 58262306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 58362306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return ret; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int mxl5007t_set_params(struct dvb_frontend *fe) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 59362306a36Sopenharmony_ci u32 delsys = c->delivery_system; 59462306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 59562306a36Sopenharmony_ci enum mxl5007t_bw_mhz bw; 59662306a36Sopenharmony_ci enum mxl5007t_mode mode; 59762306a36Sopenharmony_ci int ret; 59862306a36Sopenharmony_ci u32 freq = c->frequency; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci switch (delsys) { 60162306a36Sopenharmony_ci case SYS_ATSC: 60262306a36Sopenharmony_ci mode = MxL_MODE_ATSC; 60362306a36Sopenharmony_ci bw = MxL_BW_6MHz; 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci case SYS_DVBC_ANNEX_B: 60662306a36Sopenharmony_ci mode = MxL_MODE_CABLE; 60762306a36Sopenharmony_ci bw = MxL_BW_6MHz; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case SYS_DVBT: 61062306a36Sopenharmony_ci case SYS_DVBT2: 61162306a36Sopenharmony_ci mode = MxL_MODE_DVBT; 61262306a36Sopenharmony_ci switch (c->bandwidth_hz) { 61362306a36Sopenharmony_ci case 6000000: 61462306a36Sopenharmony_ci bw = MxL_BW_6MHz; 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci case 7000000: 61762306a36Sopenharmony_ci bw = MxL_BW_7MHz; 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case 8000000: 62062306a36Sopenharmony_ci bw = MxL_BW_8MHz; 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci default: 62362306a36Sopenharmony_ci return -EINVAL; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci default: 62762306a36Sopenharmony_ci mxl_err("modulation type not supported!"); 62862306a36Sopenharmony_ci return -EINVAL; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 63262306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mutex_lock(&state->lock); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = mxl5007t_tuner_init(state, mode); 63762306a36Sopenharmony_ci if (mxl_fail(ret)) 63862306a36Sopenharmony_ci goto fail; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ret = mxl5007t_tuner_rf_tune(state, freq, bw); 64162306a36Sopenharmony_ci if (mxl_fail(ret)) 64262306a36Sopenharmony_ci goto fail; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci state->frequency = freq; 64562306a36Sopenharmony_ci state->bandwidth = c->bandwidth_hz; 64662306a36Sopenharmony_cifail: 64762306a36Sopenharmony_ci mutex_unlock(&state->lock); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 65062306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic int mxl5007t_init(struct dvb_frontend *fe) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 66062306a36Sopenharmony_ci int ret; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 66362306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* wake from standby */ 66662306a36Sopenharmony_ci ret = mxl5007t_write_reg(state, 0x01, 0x01); 66762306a36Sopenharmony_ci mxl_fail(ret); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 67062306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return ret; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic int mxl5007t_sleep(struct dvb_frontend *fe) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 67862306a36Sopenharmony_ci int ret; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 68162306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* enter standby mode */ 68462306a36Sopenharmony_ci ret = mxl5007t_write_reg(state, 0x01, 0x00); 68562306a36Sopenharmony_ci mxl_fail(ret); 68662306a36Sopenharmony_ci ret = mxl5007t_write_reg(state, 0x0f, 0x00); 68762306a36Sopenharmony_ci mxl_fail(ret); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 69062306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return ret; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 70062306a36Sopenharmony_ci *frequency = state->frequency; 70162306a36Sopenharmony_ci return 0; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 70762306a36Sopenharmony_ci *bandwidth = state->bandwidth; 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci *frequency = 0; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci switch (state->if_freq) { 71862306a36Sopenharmony_ci case MxL_IF_4_MHZ: 71962306a36Sopenharmony_ci *frequency = 4000000; 72062306a36Sopenharmony_ci break; 72162306a36Sopenharmony_ci case MxL_IF_4_5_MHZ: 72262306a36Sopenharmony_ci *frequency = 4500000; 72362306a36Sopenharmony_ci break; 72462306a36Sopenharmony_ci case MxL_IF_4_57_MHZ: 72562306a36Sopenharmony_ci *frequency = 4570000; 72662306a36Sopenharmony_ci break; 72762306a36Sopenharmony_ci case MxL_IF_5_MHZ: 72862306a36Sopenharmony_ci *frequency = 5000000; 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci case MxL_IF_5_38_MHZ: 73162306a36Sopenharmony_ci *frequency = 5380000; 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci case MxL_IF_6_MHZ: 73462306a36Sopenharmony_ci *frequency = 6000000; 73562306a36Sopenharmony_ci break; 73662306a36Sopenharmony_ci case MxL_IF_6_28_MHZ: 73762306a36Sopenharmony_ci *frequency = 6280000; 73862306a36Sopenharmony_ci break; 73962306a36Sopenharmony_ci case MxL_IF_9_1915_MHZ: 74062306a36Sopenharmony_ci *frequency = 9191500; 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case MxL_IF_35_25_MHZ: 74362306a36Sopenharmony_ci *frequency = 35250000; 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case MxL_IF_36_15_MHZ: 74662306a36Sopenharmony_ci *frequency = 36150000; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case MxL_IF_44_MHZ: 74962306a36Sopenharmony_ci *frequency = 44000000; 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic void mxl5007t_release(struct dvb_frontend *fe) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct mxl5007t_state *state = fe->tuner_priv; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci mutex_lock(&mxl5007t_list_mutex); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (state) 76262306a36Sopenharmony_ci hybrid_tuner_release_state(state); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci mutex_unlock(&mxl5007t_list_mutex); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci fe->tuner_priv = NULL; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic const struct dvb_tuner_ops mxl5007t_tuner_ops = { 77262306a36Sopenharmony_ci .info = { 77362306a36Sopenharmony_ci .name = "MaxLinear MxL5007T", 77462306a36Sopenharmony_ci }, 77562306a36Sopenharmony_ci .init = mxl5007t_init, 77662306a36Sopenharmony_ci .sleep = mxl5007t_sleep, 77762306a36Sopenharmony_ci .set_params = mxl5007t_set_params, 77862306a36Sopenharmony_ci .get_status = mxl5007t_get_status, 77962306a36Sopenharmony_ci .get_frequency = mxl5007t_get_frequency, 78062306a36Sopenharmony_ci .get_bandwidth = mxl5007t_get_bandwidth, 78162306a36Sopenharmony_ci .release = mxl5007t_release, 78262306a36Sopenharmony_ci .get_if_frequency = mxl5007t_get_if_frequency, 78362306a36Sopenharmony_ci}; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int mxl5007t_get_chip_id(struct mxl5007t_state *state) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci char *name; 78862306a36Sopenharmony_ci int ret; 78962306a36Sopenharmony_ci u8 id; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ret = mxl5007t_read_reg(state, 0xd9, &id); 79262306a36Sopenharmony_ci if (mxl_fail(ret)) 79362306a36Sopenharmony_ci goto fail; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci switch (id) { 79662306a36Sopenharmony_ci case MxL_5007_V1_F1: 79762306a36Sopenharmony_ci name = "MxL5007.v1.f1"; 79862306a36Sopenharmony_ci break; 79962306a36Sopenharmony_ci case MxL_5007_V1_F2: 80062306a36Sopenharmony_ci name = "MxL5007.v1.f2"; 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci case MxL_5007_V2_100_F1: 80362306a36Sopenharmony_ci name = "MxL5007.v2.100.f1"; 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci case MxL_5007_V2_100_F2: 80662306a36Sopenharmony_ci name = "MxL5007.v2.100.f2"; 80762306a36Sopenharmony_ci break; 80862306a36Sopenharmony_ci case MxL_5007_V2_200_F1: 80962306a36Sopenharmony_ci name = "MxL5007.v2.200.f1"; 81062306a36Sopenharmony_ci break; 81162306a36Sopenharmony_ci case MxL_5007_V2_200_F2: 81262306a36Sopenharmony_ci name = "MxL5007.v2.200.f2"; 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci case MxL_5007_V4: 81562306a36Sopenharmony_ci name = "MxL5007T.v4"; 81662306a36Sopenharmony_ci break; 81762306a36Sopenharmony_ci default: 81862306a36Sopenharmony_ci name = "MxL5007T"; 81962306a36Sopenharmony_ci printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); 82062306a36Sopenharmony_ci id = MxL_UNKNOWN_ID; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci state->chip_id = id; 82362306a36Sopenharmony_ci mxl_info("%s detected @ %d-%04x", name, 82462306a36Sopenharmony_ci i2c_adapter_id(state->i2c_props.adap), 82562306a36Sopenharmony_ci state->i2c_props.addr); 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_cifail: 82862306a36Sopenharmony_ci mxl_warn("unable to identify device @ %d-%04x", 82962306a36Sopenharmony_ci i2c_adapter_id(state->i2c_props.adap), 83062306a36Sopenharmony_ci state->i2c_props.addr); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci state->chip_id = MxL_UNKNOWN_ID; 83362306a36Sopenharmony_ci return ret; 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistruct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, 83762306a36Sopenharmony_ci struct i2c_adapter *i2c, u8 addr, 83862306a36Sopenharmony_ci struct mxl5007t_config *cfg) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct mxl5007t_state *state = NULL; 84162306a36Sopenharmony_ci int instance, ret; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci mutex_lock(&mxl5007t_list_mutex); 84462306a36Sopenharmony_ci instance = hybrid_tuner_request_state(struct mxl5007t_state, state, 84562306a36Sopenharmony_ci hybrid_tuner_instance_list, 84662306a36Sopenharmony_ci i2c, addr, "mxl5007t"); 84762306a36Sopenharmony_ci switch (instance) { 84862306a36Sopenharmony_ci case 0: 84962306a36Sopenharmony_ci goto fail; 85062306a36Sopenharmony_ci case 1: 85162306a36Sopenharmony_ci /* new tuner instance */ 85262306a36Sopenharmony_ci state->config = cfg; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci mutex_init(&state->lock); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 85762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci ret = mxl5007t_get_chip_id(state); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 86262306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* check return value of mxl5007t_get_chip_id */ 86562306a36Sopenharmony_ci if (mxl_fail(ret)) 86662306a36Sopenharmony_ci goto fail; 86762306a36Sopenharmony_ci break; 86862306a36Sopenharmony_ci default: 86962306a36Sopenharmony_ci /* existing tuner instance */ 87062306a36Sopenharmony_ci break; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 87462306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci ret = mxl5007t_soft_reset(state); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 87962306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (mxl_fail(ret)) 88262306a36Sopenharmony_ci goto fail; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 88562306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci ret = mxl5007t_write_reg(state, 0x04, 88862306a36Sopenharmony_ci state->config->loop_thru_enable); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 89162306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (mxl_fail(ret)) 89462306a36Sopenharmony_ci goto fail; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci fe->tuner_priv = state; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci mutex_unlock(&mxl5007t_list_mutex); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, 90162306a36Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci return fe; 90462306a36Sopenharmony_cifail: 90562306a36Sopenharmony_ci mutex_unlock(&mxl5007t_list_mutex); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci mxl5007t_release(fe); 90862306a36Sopenharmony_ci return NULL; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mxl5007t_attach); 91162306a36Sopenharmony_ciMODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); 91262306a36Sopenharmony_ciMODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); 91362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 91462306a36Sopenharmony_ciMODULE_VERSION("0.2"); 915