Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/common/tuners/max2165.c
15112 views
1
/*
2
* Driver for Maxim MAX2165 silicon tuner
3
*
4
* Copyright (c) 2009 David T. L. Wong <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
*
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
*/
21
22
#include <linux/module.h>
23
#include <linux/moduleparam.h>
24
#include <linux/videodev2.h>
25
#include <linux/delay.h>
26
#include <linux/dvb/frontend.h>
27
#include <linux/i2c.h>
28
#include <linux/slab.h>
29
30
#include "dvb_frontend.h"
31
32
#include "max2165.h"
33
#include "max2165_priv.h"
34
#include "tuner-i2c.h"
35
36
#define dprintk(args...) \
37
do { \
38
if (debug) \
39
printk(KERN_DEBUG "max2165: " args); \
40
} while (0)
41
42
static int debug;
43
module_param(debug, int, 0644);
44
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
45
46
static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
47
{
48
int ret;
49
u8 buf[] = { reg, data };
50
struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
51
52
msg.addr = priv->config->i2c_address;
53
54
if (debug >= 2)
55
dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
56
57
ret = i2c_transfer(priv->i2c, &msg, 1);
58
59
if (ret != 1)
60
dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
61
__func__, reg, data, ret);
62
63
return (ret != 1) ? -EIO : 0;
64
}
65
66
static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
67
{
68
int ret;
69
u8 dev_addr = priv->config->i2c_address;
70
71
u8 b0[] = { reg };
72
u8 b1[] = { 0 };
73
struct i2c_msg msg[] = {
74
{ .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 },
75
{ .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 },
76
};
77
78
ret = i2c_transfer(priv->i2c, msg, 2);
79
if (ret != 2) {
80
dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
81
return -EIO;
82
}
83
84
*p_data = b1[0];
85
if (debug >= 2)
86
dprintk("%s: reg=0x%02X, data=0x%02X\n",
87
__func__, reg, b1[0]);
88
return 0;
89
}
90
91
static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg,
92
u8 mask, u8 data)
93
{
94
int ret;
95
u8 v;
96
97
data &= mask;
98
ret = max2165_read_reg(priv, reg, &v);
99
if (ret != 0)
100
return ret;
101
v &= ~mask;
102
v |= data;
103
ret = max2165_write_reg(priv, reg, v);
104
105
return ret;
106
}
107
108
static int max2165_read_rom_table(struct max2165_priv *priv)
109
{
110
u8 dat[3];
111
int i;
112
113
for (i = 0; i < 3; i++) {
114
max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1);
115
max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]);
116
}
117
118
priv->tf_ntch_low_cfg = dat[0] >> 4;
119
priv->tf_ntch_hi_cfg = dat[0] & 0x0F;
120
priv->tf_balun_low_ref = dat[1] & 0x0F;
121
priv->tf_balun_hi_ref = dat[1] >> 4;
122
priv->bb_filter_7mhz_cfg = dat[2] & 0x0F;
123
priv->bb_filter_8mhz_cfg = dat[2] >> 4;
124
125
dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg);
126
dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg);
127
dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref);
128
dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref);
129
dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg);
130
dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg);
131
132
return 0;
133
}
134
135
static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/)
136
{
137
u8 v;
138
139
v = (osc / 2);
140
if (v == 2)
141
v = 0x7;
142
else
143
v -= 8;
144
145
max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v);
146
147
return 0;
148
}
149
150
static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
151
{
152
u8 val;
153
154
if (bw == BANDWIDTH_8_MHZ)
155
val = priv->bb_filter_8mhz_cfg;
156
else
157
val = priv->bb_filter_7mhz_cfg;
158
159
max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4);
160
161
return 0;
162
}
163
164
int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
165
{
166
u32 remainder;
167
u32 q, f = 0;
168
int i;
169
170
if (0 == divisor)
171
return -1;
172
173
q = dividend / divisor;
174
remainder = dividend - q * divisor;
175
176
for (i = 0; i < 31; i++) {
177
remainder <<= 1;
178
if (remainder >= divisor) {
179
f += 1;
180
remainder -= divisor;
181
}
182
f <<= 1;
183
}
184
185
*quotient = q;
186
*fraction = f;
187
188
return 0;
189
}
190
191
static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
192
{
193
u8 tf;
194
u8 tf_ntch;
195
u32 t;
196
u32 quotient, fraction;
197
198
/* Set PLL divider according to RF frequency */
199
fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
200
&quotient, &fraction);
201
202
/* 20-bit fraction */
203
fraction >>= 12;
204
205
max2165_write_reg(priv, REG_NDIV_INT, quotient);
206
max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16);
207
max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8);
208
max2165_write_reg(priv, REG_NDIV_FRAC0, fraction);
209
210
/* Norch Filter */
211
tf_ntch = (freq < 725000000) ?
212
priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg;
213
214
/* Tracking filter balun */
215
t = priv->tf_balun_low_ref;
216
t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref)
217
* (freq / 1000 - 470000) / (780000 - 470000);
218
219
tf = t;
220
dprintk("tf = %X\n", tf);
221
tf |= tf_ntch << 4;
222
223
max2165_write_reg(priv, REG_TRACK_FILTER, tf);
224
225
return 0;
226
}
227
228
static void max2165_debug_status(struct max2165_priv *priv)
229
{
230
u8 status, autotune;
231
u8 auto_vco_success, auto_vco_active;
232
u8 pll_locked;
233
u8 dc_offset_low, dc_offset_hi;
234
u8 signal_lv_over_threshold;
235
u8 vco, vco_sub_band, adc;
236
237
max2165_read_reg(priv, REG_STATUS, &status);
238
max2165_read_reg(priv, REG_AUTOTUNE, &autotune);
239
240
auto_vco_success = (status >> 6) & 0x01;
241
auto_vco_active = (status >> 5) & 0x01;
242
pll_locked = (status >> 4) & 0x01;
243
dc_offset_low = (status >> 3) & 0x01;
244
dc_offset_hi = (status >> 2) & 0x01;
245
signal_lv_over_threshold = status & 0x01;
246
247
vco = autotune >> 6;
248
vco_sub_band = (autotune >> 3) & 0x7;
249
adc = autotune & 0x7;
250
251
dprintk("auto VCO active: %d, auto VCO success: %d\n",
252
auto_vco_active, auto_vco_success);
253
dprintk("PLL locked: %d\n", pll_locked);
254
dprintk("DC offset low: %d, DC offset high: %d\n",
255
dc_offset_low, dc_offset_hi);
256
dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold);
257
dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
258
}
259
260
static int max2165_set_params(struct dvb_frontend *fe,
261
struct dvb_frontend_parameters *params)
262
{
263
struct max2165_priv *priv = fe->tuner_priv;
264
int ret;
265
266
dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency);
267
if (fe->ops.info.type == FE_ATSC) {
268
return -EINVAL;
269
} else if (fe->ops.info.type == FE_OFDM) {
270
dprintk("%s() OFDM\n", __func__);
271
switch (params->u.ofdm.bandwidth) {
272
case BANDWIDTH_6_MHZ:
273
return -EINVAL;
274
case BANDWIDTH_7_MHZ:
275
case BANDWIDTH_8_MHZ:
276
priv->frequency = params->frequency;
277
priv->bandwidth = params->u.ofdm.bandwidth;
278
break;
279
default:
280
printk(KERN_ERR "MAX2165 bandwidth not set!\n");
281
return -EINVAL;
282
}
283
} else {
284
printk(KERN_ERR "MAX2165 modulation type not supported!\n");
285
return -EINVAL;
286
}
287
288
dprintk("%s() frequency=%d\n", __func__, priv->frequency);
289
290
if (fe->ops.i2c_gate_ctrl)
291
fe->ops.i2c_gate_ctrl(fe, 1);
292
max2165_set_bandwidth(priv, priv->bandwidth);
293
ret = max2165_set_rf(priv, priv->frequency);
294
mdelay(50);
295
max2165_debug_status(priv);
296
if (fe->ops.i2c_gate_ctrl)
297
fe->ops.i2c_gate_ctrl(fe, 0);
298
299
if (ret != 0)
300
return -EREMOTEIO;
301
302
return 0;
303
}
304
305
static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq)
306
{
307
struct max2165_priv *priv = fe->tuner_priv;
308
dprintk("%s()\n", __func__);
309
*freq = priv->frequency;
310
return 0;
311
}
312
313
static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
314
{
315
struct max2165_priv *priv = fe->tuner_priv;
316
dprintk("%s()\n", __func__);
317
318
*bw = priv->bandwidth;
319
return 0;
320
}
321
322
static int max2165_get_status(struct dvb_frontend *fe, u32 *status)
323
{
324
struct max2165_priv *priv = fe->tuner_priv;
325
u16 lock_status = 0;
326
327
dprintk("%s()\n", __func__);
328
329
if (fe->ops.i2c_gate_ctrl)
330
fe->ops.i2c_gate_ctrl(fe, 1);
331
332
max2165_debug_status(priv);
333
*status = lock_status;
334
335
if (fe->ops.i2c_gate_ctrl)
336
fe->ops.i2c_gate_ctrl(fe, 0);
337
338
return 0;
339
}
340
341
static int max2165_sleep(struct dvb_frontend *fe)
342
{
343
dprintk("%s()\n", __func__);
344
return 0;
345
}
346
347
static int max2165_init(struct dvb_frontend *fe)
348
{
349
struct max2165_priv *priv = fe->tuner_priv;
350
dprintk("%s()\n", __func__);
351
352
if (fe->ops.i2c_gate_ctrl)
353
fe->ops.i2c_gate_ctrl(fe, 1);
354
355
/* Setup initial values */
356
/* Fractional Mode on */
357
max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18);
358
/* LNA on */
359
max2165_write_reg(priv, REG_LNA, 0x01);
360
max2165_write_reg(priv, REG_PLL_CFG, 0x7A);
361
max2165_write_reg(priv, REG_TEST, 0x08);
362
max2165_write_reg(priv, REG_SHUTDOWN, 0x40);
363
max2165_write_reg(priv, REG_VCO_CTRL, 0x84);
364
max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3);
365
max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75);
366
max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00);
367
max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00);
368
369
max2165_set_osc(priv, priv->config->osc_clk);
370
371
max2165_read_rom_table(priv);
372
373
max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ);
374
375
if (fe->ops.i2c_gate_ctrl)
376
fe->ops.i2c_gate_ctrl(fe, 0);
377
378
return 0;
379
}
380
381
static int max2165_release(struct dvb_frontend *fe)
382
{
383
struct max2165_priv *priv = fe->tuner_priv;
384
dprintk("%s()\n", __func__);
385
386
kfree(priv);
387
fe->tuner_priv = NULL;
388
389
return 0;
390
}
391
392
static const struct dvb_tuner_ops max2165_tuner_ops = {
393
.info = {
394
.name = "Maxim MAX2165",
395
.frequency_min = 470000000,
396
.frequency_max = 780000000,
397
.frequency_step = 50000,
398
},
399
400
.release = max2165_release,
401
.init = max2165_init,
402
.sleep = max2165_sleep,
403
404
.set_params = max2165_set_params,
405
.set_analog_params = NULL,
406
.get_frequency = max2165_get_frequency,
407
.get_bandwidth = max2165_get_bandwidth,
408
.get_status = max2165_get_status
409
};
410
411
struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
412
struct i2c_adapter *i2c,
413
struct max2165_config *cfg)
414
{
415
struct max2165_priv *priv = NULL;
416
417
dprintk("%s(%d-%04x)\n", __func__,
418
i2c ? i2c_adapter_id(i2c) : -1,
419
cfg ? cfg->i2c_address : -1);
420
421
priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL);
422
if (priv == NULL)
423
return NULL;
424
425
memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops,
426
sizeof(struct dvb_tuner_ops));
427
428
priv->config = cfg;
429
priv->i2c = i2c;
430
fe->tuner_priv = priv;
431
432
max2165_init(fe);
433
max2165_debug_status(priv);
434
435
return fe;
436
}
437
EXPORT_SYMBOL(max2165_attach);
438
439
MODULE_AUTHOR("David T. L. Wong <[email protected]>");
440
MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
441
MODULE_LICENSE("GPL");
442
443