]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/media/dvb/frontends/dib7000m.c
V4L/DVB (4524): Initial commit for the DiB7000M-demod
[karo-tx-linux.git] / drivers / media / dvb / frontends / dib7000m.c
1 /*
2  * Linux-DVB Driver for DiBcom's DiB7000M and
3  *              first generation DiB7000P-demodulator-family.
4  *
5  * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
6  *
7  * This program is free software; you can redistribute it and/or
8  *      modify it under the terms of the GNU General Public License as
9  *      published by the Free Software Foundation, version 2.
10  */
11 #include <linux/kernel.h>
12 #include <linux/i2c.h>
13
14 #include "dvb_frontend.h"
15
16 #include "dib7000m.h"
17
18 static int debug;
19 module_param(debug, int, 0644);
20 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
21
22 #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
23
24 struct dib7000m_state {
25         struct dvb_frontend demod;
26     struct dib7000m_config cfg;
27
28         u8 i2c_addr;
29         struct i2c_adapter   *i2c_adap;
30
31         struct dibx000_i2c_master i2c_master;
32
33 /* offset is 1 in case of the 7000MC */
34         u8 reg_offs;
35
36         u16 wbd_ref;
37
38         u8 current_band;
39         fe_bandwidth_t current_bandwidth;
40         struct dibx000_agc_config *current_agc;
41         u32 timf[9];
42
43         u16 revision;
44 };
45
46 static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
47 {
48         u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
49         u8 rb[2];
50         struct i2c_msg msg[2] = {
51                 { .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
52                 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
53         };
54
55         if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
56                 dprintk("i2c read error on %d\n",reg);
57
58         return (rb[0] << 8) | rb[1];
59 }
60
61 /*
62 static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
63 {
64         u8 b[4] = {
65                 (reg >> 8) & 0xff, reg & 0xff,
66                 (val >> 8) & 0xff, val & 0xff,
67         };
68         struct i2c_msg msg = {
69                 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
70         };
71         return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
72 }
73 */
74
75 static int dib7000m_get_frontend(struct dvb_frontend* fe,
76                                 struct dvb_frontend_parameters *fep)
77 {
78         struct dib7000m_state *state = fe->demodulator_priv;
79         u16 tps = dib7000m_read_word(state,480);
80
81         fep->inversion = INVERSION_AUTO;
82
83         fep->u.ofdm.bandwidth = state->current_bandwidth;
84
85         switch ((tps >> 8) & 0x2) {
86                 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
87                 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
88                 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
89         }
90
91         switch (tps & 0x3) {
92                 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
93                 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
94                 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
95                 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
96         }
97
98         switch ((tps >> 14) & 0x3) {
99                 case 0: fep->u.ofdm.constellation = QPSK; break;
100                 case 1: fep->u.ofdm.constellation = QAM_16; break;
101                 case 2:
102                 default: fep->u.ofdm.constellation = QAM_64; break;
103         }
104
105         /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
106         /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
107
108         fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
109         switch ((tps >> 5) & 0x7) {
110                 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
111                 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
112                 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
113                 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
114                 case 7:
115                 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
116
117         }
118
119         switch ((tps >> 2) & 0x7) {
120                 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
121                 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
122                 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
123                 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
124                 case 7:
125                 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
126         }
127
128         /* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
129
130         return 0;
131 }
132
133 static int dib7000m_set_frontend(struct dvb_frontend* fe,
134                                 struct dvb_frontend_parameters *fep)
135 {
136         return 0;
137 }
138
139 static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
140 {
141         struct dib7000m_state *state = fe->demodulator_priv;
142         u16 lock = dib7000m_read_word(state, 509);
143
144         *stat = 0;
145
146         if (lock & 0x8000)
147                 *stat |= FE_HAS_SIGNAL;
148         if (lock & 0x3000)
149                 *stat |= FE_HAS_CARRIER;
150         if (lock & 0x0100)
151                 *stat |= FE_HAS_VITERBI;
152         if (lock & 0x0010)
153                 *stat |= FE_HAS_SYNC;
154         if (lock & 0x0008)
155                 *stat |= FE_HAS_LOCK;
156
157         return 0;
158 }
159
160 static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
161 {
162         struct dib7000m_state *state = fe->demodulator_priv;
163         *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
164         return 0;
165 }
166
167 static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
168 {
169         struct dib7000m_state *state = fe->demodulator_priv;
170         *unc = dib7000m_read_word(state, 534);
171         return 0;
172 }
173
174 static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
175 {
176         struct dib7000m_state *state = fe->demodulator_priv;
177         u16 val = dib7000m_read_word(state, 390);
178         *strength = 65535 - val;
179         return 0;
180 }
181
182 static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
183 {
184         *snr = 0x0000;
185         return 0;
186 }
187
188 static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
189 {
190         tune->min_delay_ms = 1000;
191         return 0;
192 }
193
194 static int dib7000m_init(struct dvb_frontend *fe)
195 {
196         return 0;
197 }
198
199 static int dib7000m_sleep(struct dvb_frontend *fe)
200 {
201         return 0;
202 }
203
204 static void dib7000m_release(struct dvb_frontend *fe)
205 { }
206
207 static struct dvb_frontend_ops dib7000m_ops = {
208         .info = {
209                 .name = "DiBcom 7000MA/MB/PA/PB/MC",
210                 .type = FE_OFDM,
211                 .frequency_min      = 44250000,
212                 .frequency_max      = 867250000,
213                 .frequency_stepsize = 62500,
214                 .caps = FE_CAN_INVERSION_AUTO |
215                         FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
216                         FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
217                         FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
218                         FE_CAN_TRANSMISSION_MODE_AUTO |
219                         FE_CAN_GUARD_INTERVAL_AUTO |
220                         FE_CAN_RECOVER |
221                         FE_CAN_HIERARCHY_AUTO,
222         },
223
224         .release              = dib7000m_release,
225
226         .init                 = dib7000m_init,
227         .sleep                = dib7000m_sleep,
228
229         .set_frontend         = dib7000m_set_frontend,
230         .get_tune_settings    = dib7000m_fe_get_tune_settings,
231         .get_frontend         = dib7000m_get_frontend,
232
233         .read_status          = dib7000m_read_status,
234         .read_ber             = dib7000m_read_ber,
235         .read_signal_strength = dib7000m_read_signal_strength,
236         .read_snr             = dib7000m_read_snr,
237         .read_ucblocks        = dib7000m_read_unc_blocks,
238 };
239
240 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
241 MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
242 MODULE_LICENSE("GPL");