~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/media/common/tuners/tda18218.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * NXP TDA18218HN silicon tuner driver
 
3
 *
 
4
 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
 
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
 *    GNU General Public License for more details.
 
15
 *
 
16
 *    You should have received a copy of the GNU General Public License
 
17
 *    along with this program; if not, write to the Free Software
 
18
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#include "tda18218.h"
 
22
#include "tda18218_priv.h"
 
23
 
 
24
static int debug;
 
25
module_param(debug, int, 0644);
 
26
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
27
 
 
28
/* write multiple registers */
 
29
static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
 
30
{
 
31
        int ret = 0;
 
32
        u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
 
33
        struct i2c_msg msg[1] = {
 
34
                {
 
35
                        .addr = priv->cfg->i2c_address,
 
36
                        .flags = 0,
 
37
                        .buf = buf,
 
38
                }
 
39
        };
 
40
 
 
41
        msg_len_max = priv->cfg->i2c_wr_max - 1;
 
42
        quotient = len / msg_len_max;
 
43
        remainder = len % msg_len_max;
 
44
        msg_len = msg_len_max;
 
45
        for (i = 0; (i <= quotient && remainder); i++) {
 
46
                if (i == quotient)  /* set len of the last msg */
 
47
                        msg_len = remainder;
 
48
 
 
49
                msg[0].len = msg_len + 1;
 
50
                buf[0] = reg + i * msg_len_max;
 
51
                memcpy(&buf[1], &val[i * msg_len_max], msg_len);
 
52
 
 
53
                ret = i2c_transfer(priv->i2c, msg, 1);
 
54
                if (ret != 1)
 
55
                        break;
 
56
        }
 
57
 
 
58
        if (ret == 1) {
 
59
                ret = 0;
 
60
        } else {
 
61
                warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
 
62
                ret = -EREMOTEIO;
 
63
        }
 
64
 
 
65
        return ret;
 
66
}
 
67
 
 
68
/* read multiple registers */
 
69
static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
 
70
{
 
71
        int ret;
 
72
        u8 buf[reg+len]; /* we must start read always from reg 0x00 */
 
73
        struct i2c_msg msg[2] = {
 
74
                {
 
75
                        .addr = priv->cfg->i2c_address,
 
76
                        .flags = 0,
 
77
                        .len = 1,
 
78
                        .buf = "\x00",
 
79
                }, {
 
80
                        .addr = priv->cfg->i2c_address,
 
81
                        .flags = I2C_M_RD,
 
82
                        .len = sizeof(buf),
 
83
                        .buf = buf,
 
84
                }
 
85
        };
 
86
 
 
87
        ret = i2c_transfer(priv->i2c, msg, 2);
 
88
        if (ret == 2) {
 
89
                memcpy(val, &buf[reg], len);
 
90
                ret = 0;
 
91
        } else {
 
92
                warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
 
93
                ret = -EREMOTEIO;
 
94
        }
 
95
 
 
96
        return ret;
 
97
}
 
98
 
 
99
/* write single register */
 
100
static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
 
101
{
 
102
        return tda18218_wr_regs(priv, reg, &val, 1);
 
103
}
 
104
 
 
105
/* read single register */
 
106
 
 
107
static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
 
108
{
 
109
        return tda18218_rd_regs(priv, reg, val, 1);
 
110
}
 
111
 
 
112
static int tda18218_set_params(struct dvb_frontend *fe,
 
113
        struct dvb_frontend_parameters *params)
 
114
{
 
115
        struct tda18218_priv *priv = fe->tuner_priv;
 
116
        int ret;
 
117
        u8 buf[3], i, BP_Filter, LP_Fc;
 
118
        u32 LO_Frac;
 
119
        /* TODO: find out correct AGC algorithm */
 
120
        u8 agc[][2] = {
 
121
                { R20_AGC11, 0x60 },
 
122
                { R23_AGC21, 0x02 },
 
123
                { R20_AGC11, 0xa0 },
 
124
                { R23_AGC21, 0x09 },
 
125
                { R20_AGC11, 0xe0 },
 
126
                { R23_AGC21, 0x0c },
 
127
                { R20_AGC11, 0x40 },
 
128
                { R23_AGC21, 0x01 },
 
129
                { R20_AGC11, 0x80 },
 
130
                { R23_AGC21, 0x08 },
 
131
                { R20_AGC11, 0xc0 },
 
132
                { R23_AGC21, 0x0b },
 
133
                { R24_AGC22, 0x1c },
 
134
                { R24_AGC22, 0x0c },
 
135
        };
 
136
 
 
137
        if (fe->ops.i2c_gate_ctrl)
 
138
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
139
 
 
140
        /* low-pass filter cut-off frequency */
 
141
        switch (params->u.ofdm.bandwidth) {
 
142
        case BANDWIDTH_6_MHZ:
 
143
                LP_Fc = 0;
 
144
                LO_Frac = params->frequency + 3000000;
 
145
                break;
 
146
        case BANDWIDTH_7_MHZ:
 
147
                LP_Fc = 1;
 
148
                LO_Frac = params->frequency + 3500000;
 
149
                break;
 
150
        case BANDWIDTH_8_MHZ:
 
151
        default:
 
152
                LP_Fc = 2;
 
153
                LO_Frac = params->frequency + 4000000;
 
154
                break;
 
155
        }
 
156
 
 
157
        /* band-pass filter */
 
158
        if (LO_Frac < 188000000)
 
159
                BP_Filter = 3;
 
160
        else if (LO_Frac < 253000000)
 
161
                BP_Filter = 4;
 
162
        else if (LO_Frac < 343000000)
 
163
                BP_Filter = 5;
 
164
        else
 
165
                BP_Filter = 6;
 
166
 
 
167
        buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
 
168
        buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
 
169
        buf[2] = priv->regs[R1C_AGC2B];
 
170
        ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
 
171
        if (ret)
 
172
                goto error;
 
173
 
 
174
        buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
 
175
        buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
 
176
        buf[2] = (LO_Frac / 1000) << 4 |
 
177
                (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
 
178
        ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
 
179
        if (ret)
 
180
                goto error;
 
181
 
 
182
        buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
 
183
        ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
 
184
        if (ret)
 
185
                goto error;
 
186
 
 
187
        buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
 
188
        ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
 
189
        if (ret)
 
190
                goto error;
 
191
 
 
192
        /* trigger AGC */
 
193
        for (i = 0; i < ARRAY_SIZE(agc); i++) {
 
194
                ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
 
195
                if (ret)
 
196
                        goto error;
 
197
        }
 
198
 
 
199
error:
 
200
        if (fe->ops.i2c_gate_ctrl)
 
201
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
202
 
 
203
        if (ret)
 
204
                dbg("%s: failed ret:%d", __func__, ret);
 
205
 
 
206
        return ret;
 
207
}
 
208
 
 
209
static int tda18218_sleep(struct dvb_frontend *fe)
 
210
{
 
211
        struct tda18218_priv *priv = fe->tuner_priv;
 
212
        int ret;
 
213
 
 
214
        if (fe->ops.i2c_gate_ctrl)
 
215
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
216
 
 
217
        /* standby */
 
218
        ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
 
219
 
 
220
        if (fe->ops.i2c_gate_ctrl)
 
221
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
222
 
 
223
        if (ret)
 
224
                dbg("%s: failed ret:%d", __func__, ret);
 
225
 
 
226
        return ret;
 
227
}
 
228
 
 
229
static int tda18218_init(struct dvb_frontend *fe)
 
230
{
 
231
        struct tda18218_priv *priv = fe->tuner_priv;
 
232
        int ret;
 
233
 
 
234
        /* TODO: calibrations */
 
235
 
 
236
        if (fe->ops.i2c_gate_ctrl)
 
237
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
238
 
 
239
        ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
 
240
 
 
241
        if (fe->ops.i2c_gate_ctrl)
 
242
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
243
 
 
244
        if (ret)
 
245
                dbg("%s: failed ret:%d", __func__, ret);
 
246
 
 
247
        return ret;
 
248
}
 
249
 
 
250
static int tda18218_release(struct dvb_frontend *fe)
 
251
{
 
252
        kfree(fe->tuner_priv);
 
253
        fe->tuner_priv = NULL;
 
254
        return 0;
 
255
}
 
256
 
 
257
static const struct dvb_tuner_ops tda18218_tuner_ops = {
 
258
        .info = {
 
259
                .name           = "NXP TDA18218",
 
260
 
 
261
                .frequency_min  = 174000000,
 
262
                .frequency_max  = 864000000,
 
263
                .frequency_step =      1000,
 
264
        },
 
265
 
 
266
        .release       = tda18218_release,
 
267
        .init          = tda18218_init,
 
268
        .sleep         = tda18218_sleep,
 
269
 
 
270
        .set_params    = tda18218_set_params,
 
271
};
 
272
 
 
273
struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
 
274
        struct i2c_adapter *i2c, struct tda18218_config *cfg)
 
275
{
 
276
        struct tda18218_priv *priv = NULL;
 
277
        u8 val;
 
278
        int ret;
 
279
        /* chip default registers values */
 
280
        static u8 def_regs[] = {
 
281
                0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
 
282
                0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
 
283
                0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
 
284
                0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
 
285
                0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
 
286
                0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
 
287
        };
 
288
 
 
289
        priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
 
290
        if (priv == NULL)
 
291
                return NULL;
 
292
 
 
293
        priv->cfg = cfg;
 
294
        priv->i2c = i2c;
 
295
        fe->tuner_priv = priv;
 
296
 
 
297
        if (fe->ops.i2c_gate_ctrl)
 
298
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
299
 
 
300
        /* check if the tuner is there */
 
301
        ret = tda18218_rd_reg(priv, R00_ID, &val);
 
302
        dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
 
303
        if (ret || val != def_regs[R00_ID]) {
 
304
                kfree(priv);
 
305
                return NULL;
 
306
        }
 
307
 
 
308
        info("NXP TDA18218HN successfully identified.");
 
309
 
 
310
        memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
 
311
                sizeof(struct dvb_tuner_ops));
 
312
        memcpy(priv->regs, def_regs, sizeof(def_regs));
 
313
 
 
314
        /* loop-through enabled chip default register values */
 
315
        if (priv->cfg->loop_through) {
 
316
                priv->regs[R17_PD1] = 0xb0;
 
317
                priv->regs[R18_PD2] = 0x59;
 
318
        }
 
319
 
 
320
        /* standby */
 
321
        ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
 
322
        if (ret)
 
323
                dbg("%s: failed ret:%d", __func__, ret);
 
324
 
 
325
        if (fe->ops.i2c_gate_ctrl)
 
326
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
327
 
 
328
        return fe;
 
329
}
 
330
EXPORT_SYMBOL(tda18218_attach);
 
331
 
 
332
MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
 
333
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 
334
MODULE_LICENSE("GPL");