1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for Maxim MAX2165 silicon tuner
5 * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
8 #include <linux/module.h>
9 #include <linux/moduleparam.h>
10 #include <linux/videodev2.h>
11 #include <linux/delay.h>
12 #include <linux/dvb/frontend.h>
13 #include <linux/i2c.h>
14 #include <linux/slab.h>
16 #include <media/dvb_frontend.h>
19 #include "max2165_priv.h"
20 #include "tuner-i2c.h"
22 #define dprintk(args...) \
25 printk(KERN_DEBUG "max2165: " args); \
29 module_param(debug
, int, 0644);
30 MODULE_PARM_DESC(debug
, "Turn on/off debugging (default:off).");
32 static int max2165_write_reg(struct max2165_priv
*priv
, u8 reg
, u8 data
)
35 u8 buf
[] = { reg
, data
};
36 struct i2c_msg msg
= { .flags
= 0, .buf
= buf
, .len
= 2 };
38 msg
.addr
= priv
->config
->i2c_address
;
41 dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__
, reg
, data
);
43 ret
= i2c_transfer(priv
->i2c
, &msg
, 1);
46 dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
47 __func__
, reg
, data
, ret
);
49 return (ret
!= 1) ? -EIO
: 0;
52 static int max2165_read_reg(struct max2165_priv
*priv
, u8 reg
, u8
*p_data
)
55 u8 dev_addr
= priv
->config
->i2c_address
;
59 struct i2c_msg msg
[] = {
60 { .addr
= dev_addr
, .flags
= 0, .buf
= b0
, .len
= 1 },
61 { .addr
= dev_addr
, .flags
= I2C_M_RD
, .buf
= b1
, .len
= 1 },
64 ret
= i2c_transfer(priv
->i2c
, msg
, 2);
66 dprintk("%s: error reg=0x%x, ret=%i\n", __func__
, reg
, ret
);
72 dprintk("%s: reg=0x%02X, data=0x%02X\n",
73 __func__
, reg
, b1
[0]);
77 static int max2165_mask_write_reg(struct max2165_priv
*priv
, u8 reg
,
84 ret
= max2165_read_reg(priv
, reg
, &v
);
89 ret
= max2165_write_reg(priv
, reg
, v
);
94 static int max2165_read_rom_table(struct max2165_priv
*priv
)
99 for (i
= 0; i
< 3; i
++) {
100 max2165_write_reg(priv
, REG_ROM_TABLE_ADDR
, i
+ 1);
101 max2165_read_reg(priv
, REG_ROM_TABLE_DATA
, &dat
[i
]);
104 priv
->tf_ntch_low_cfg
= dat
[0] >> 4;
105 priv
->tf_ntch_hi_cfg
= dat
[0] & 0x0F;
106 priv
->tf_balun_low_ref
= dat
[1] & 0x0F;
107 priv
->tf_balun_hi_ref
= dat
[1] >> 4;
108 priv
->bb_filter_7mhz_cfg
= dat
[2] & 0x0F;
109 priv
->bb_filter_8mhz_cfg
= dat
[2] >> 4;
111 dprintk("tf_ntch_low_cfg = 0x%X\n", priv
->tf_ntch_low_cfg
);
112 dprintk("tf_ntch_hi_cfg = 0x%X\n", priv
->tf_ntch_hi_cfg
);
113 dprintk("tf_balun_low_ref = 0x%X\n", priv
->tf_balun_low_ref
);
114 dprintk("tf_balun_hi_ref = 0x%X\n", priv
->tf_balun_hi_ref
);
115 dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv
->bb_filter_7mhz_cfg
);
116 dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv
->bb_filter_8mhz_cfg
);
121 static int max2165_set_osc(struct max2165_priv
*priv
, u8 osc
/*MHz*/)
131 max2165_mask_write_reg(priv
, REG_PLL_CFG
, 0x07, v
);
136 static int max2165_set_bandwidth(struct max2165_priv
*priv
, u32 bw
)
141 val
= priv
->bb_filter_8mhz_cfg
;
143 val
= priv
->bb_filter_7mhz_cfg
;
145 max2165_mask_write_reg(priv
, REG_BASEBAND_CTRL
, 0xF0, val
<< 4);
150 static int fixpt_div32(u32 dividend
, u32 divisor
, u32
*quotient
, u32
*fraction
)
159 q
= dividend
/ divisor
;
160 remainder
= dividend
- q
* divisor
;
162 for (i
= 0; i
< 31; i
++) {
164 if (remainder
>= divisor
) {
166 remainder
-= divisor
;
177 static int max2165_set_rf(struct max2165_priv
*priv
, u32 freq
)
182 u32 quotient
, fraction
;
185 /* Set PLL divider according to RF frequency */
186 ret
= fixpt_div32(freq
/ 1000, priv
->config
->osc_clk
* 1000,
187 "ient
, &fraction
);
191 /* 20-bit fraction */
194 max2165_write_reg(priv
, REG_NDIV_INT
, quotient
);
195 max2165_mask_write_reg(priv
, REG_NDIV_FRAC2
, 0x0F, fraction
>> 16);
196 max2165_write_reg(priv
, REG_NDIV_FRAC1
, fraction
>> 8);
197 max2165_write_reg(priv
, REG_NDIV_FRAC0
, fraction
);
200 tf_ntch
= (freq
< 725000000) ?
201 priv
->tf_ntch_low_cfg
: priv
->tf_ntch_hi_cfg
;
203 /* Tracking filter balun */
204 t
= priv
->tf_balun_low_ref
;
205 t
+= (priv
->tf_balun_hi_ref
- priv
->tf_balun_low_ref
)
206 * (freq
/ 1000 - 470000) / (780000 - 470000);
209 dprintk("tf = %X\n", tf
);
212 max2165_write_reg(priv
, REG_TRACK_FILTER
, tf
);
217 static void max2165_debug_status(struct max2165_priv
*priv
)
220 u8 auto_vco_success
, auto_vco_active
;
222 u8 dc_offset_low
, dc_offset_hi
;
223 u8 signal_lv_over_threshold
;
224 u8 vco
, vco_sub_band
, adc
;
226 max2165_read_reg(priv
, REG_STATUS
, &status
);
227 max2165_read_reg(priv
, REG_AUTOTUNE
, &autotune
);
229 auto_vco_success
= (status
>> 6) & 0x01;
230 auto_vco_active
= (status
>> 5) & 0x01;
231 pll_locked
= (status
>> 4) & 0x01;
232 dc_offset_low
= (status
>> 3) & 0x01;
233 dc_offset_hi
= (status
>> 2) & 0x01;
234 signal_lv_over_threshold
= status
& 0x01;
237 vco_sub_band
= (autotune
>> 3) & 0x7;
238 adc
= autotune
& 0x7;
240 dprintk("auto VCO active: %d, auto VCO success: %d\n",
241 auto_vco_active
, auto_vco_success
);
242 dprintk("PLL locked: %d\n", pll_locked
);
243 dprintk("DC offset low: %d, DC offset high: %d\n",
244 dc_offset_low
, dc_offset_hi
);
245 dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold
);
246 dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco
, vco_sub_band
, adc
);
249 static int max2165_set_params(struct dvb_frontend
*fe
)
251 struct max2165_priv
*priv
= fe
->tuner_priv
;
252 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
255 switch (c
->bandwidth_hz
) {
258 priv
->frequency
= c
->frequency
;
261 printk(KERN_INFO
"MAX2165: bandwidth %d Hz not supported.\n",
266 dprintk("%s() frequency=%d\n", __func__
, c
->frequency
);
268 if (fe
->ops
.i2c_gate_ctrl
)
269 fe
->ops
.i2c_gate_ctrl(fe
, 1);
270 max2165_set_bandwidth(priv
, c
->bandwidth_hz
);
271 ret
= max2165_set_rf(priv
, priv
->frequency
);
273 max2165_debug_status(priv
);
274 if (fe
->ops
.i2c_gate_ctrl
)
275 fe
->ops
.i2c_gate_ctrl(fe
, 0);
283 static int max2165_get_frequency(struct dvb_frontend
*fe
, u32
*freq
)
285 struct max2165_priv
*priv
= fe
->tuner_priv
;
286 dprintk("%s()\n", __func__
);
287 *freq
= priv
->frequency
;
291 static int max2165_get_bandwidth(struct dvb_frontend
*fe
, u32
*bw
)
293 struct max2165_priv
*priv
= fe
->tuner_priv
;
294 dprintk("%s()\n", __func__
);
296 *bw
= priv
->bandwidth
;
300 static int max2165_get_status(struct dvb_frontend
*fe
, u32
*status
)
302 struct max2165_priv
*priv
= fe
->tuner_priv
;
305 dprintk("%s()\n", __func__
);
307 if (fe
->ops
.i2c_gate_ctrl
)
308 fe
->ops
.i2c_gate_ctrl(fe
, 1);
310 max2165_debug_status(priv
);
311 *status
= lock_status
;
313 if (fe
->ops
.i2c_gate_ctrl
)
314 fe
->ops
.i2c_gate_ctrl(fe
, 0);
319 static int max2165_sleep(struct dvb_frontend
*fe
)
321 dprintk("%s()\n", __func__
);
325 static int max2165_init(struct dvb_frontend
*fe
)
327 struct max2165_priv
*priv
= fe
->tuner_priv
;
328 dprintk("%s()\n", __func__
);
330 if (fe
->ops
.i2c_gate_ctrl
)
331 fe
->ops
.i2c_gate_ctrl(fe
, 1);
333 /* Setup initial values */
334 /* Fractional Mode on */
335 max2165_write_reg(priv
, REG_NDIV_FRAC2
, 0x18);
337 max2165_write_reg(priv
, REG_LNA
, 0x01);
338 max2165_write_reg(priv
, REG_PLL_CFG
, 0x7A);
339 max2165_write_reg(priv
, REG_TEST
, 0x08);
340 max2165_write_reg(priv
, REG_SHUTDOWN
, 0x40);
341 max2165_write_reg(priv
, REG_VCO_CTRL
, 0x84);
342 max2165_write_reg(priv
, REG_BASEBAND_CTRL
, 0xC3);
343 max2165_write_reg(priv
, REG_DC_OFFSET_CTRL
, 0x75);
344 max2165_write_reg(priv
, REG_DC_OFFSET_DAC
, 0x00);
345 max2165_write_reg(priv
, REG_ROM_TABLE_ADDR
, 0x00);
347 max2165_set_osc(priv
, priv
->config
->osc_clk
);
349 max2165_read_rom_table(priv
);
351 max2165_set_bandwidth(priv
, 8000000);
353 if (fe
->ops
.i2c_gate_ctrl
)
354 fe
->ops
.i2c_gate_ctrl(fe
, 0);
359 static void max2165_release(struct dvb_frontend
*fe
)
361 struct max2165_priv
*priv
= fe
->tuner_priv
;
362 dprintk("%s()\n", __func__
);
365 fe
->tuner_priv
= NULL
;
368 static const struct dvb_tuner_ops max2165_tuner_ops
= {
370 .name
= "Maxim MAX2165",
371 .frequency_min_hz
= 470 * MHz
,
372 .frequency_max_hz
= 862 * MHz
,
373 .frequency_step_hz
= 50 * kHz
,
376 .release
= max2165_release
,
377 .init
= max2165_init
,
378 .sleep
= max2165_sleep
,
380 .set_params
= max2165_set_params
,
381 .set_analog_params
= NULL
,
382 .get_frequency
= max2165_get_frequency
,
383 .get_bandwidth
= max2165_get_bandwidth
,
384 .get_status
= max2165_get_status
387 struct dvb_frontend
*max2165_attach(struct dvb_frontend
*fe
,
388 struct i2c_adapter
*i2c
,
389 struct max2165_config
*cfg
)
391 struct max2165_priv
*priv
= NULL
;
393 dprintk("%s(%d-%04x)\n", __func__
,
394 i2c
? i2c_adapter_id(i2c
) : -1,
395 cfg
? cfg
->i2c_address
: -1);
397 priv
= kzalloc(sizeof(struct max2165_priv
), GFP_KERNEL
);
401 memcpy(&fe
->ops
.tuner_ops
, &max2165_tuner_ops
,
402 sizeof(struct dvb_tuner_ops
));
406 fe
->tuner_priv
= priv
;
409 max2165_debug_status(priv
);
413 EXPORT_SYMBOL(max2165_attach
);
415 MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
416 MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
417 MODULE_LICENSE("GPL");