blob: e7838926e6bc9fd723b2e6b8cebd49aaa6f3c09e [file] [log] [blame]
Olivier Greniedd316c62011-01-04 04:28:59 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family.
3 *
4 * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -030010
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
Olivier Greniedd316c62011-01-04 04:28:59 -030013#include <linux/kernel.h>
14#include <linux/i2c.h>
15#include <linux/mutex.h>
16
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050017#include <media/dvb_math.h>
18#include <media/dvb_frontend.h>
Olivier Greniedd316c62011-01-04 04:28:59 -030019
20#include "dib9000.h"
21#include "dibx000_common.h"
22
23static int debug;
24module_param(debug, int, 0644);
25MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
26
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -030027#define dprintk(fmt, arg...) do { \
28 if (debug) \
29 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
30 __func__, ##arg); \
31} while (0)
32
Olivier Greniedd316c62011-01-04 04:28:59 -030033#define MAX_NUMBER_OF_FRONTENDS 6
34
35struct i2c_device {
36 struct i2c_adapter *i2c_adap;
37 u8 i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030038 u8 *i2c_read_buffer;
39 u8 *i2c_write_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -030040};
41
Patrick Boettcher79fcce32011-08-03 12:08:21 -030042struct dib9000_pid_ctrl {
43#define DIB9000_PID_FILTER_CTRL 0
44#define DIB9000_PID_FILTER 1
45 u8 cmd;
46 u8 id;
47 u16 pid;
48 u8 onoff;
49};
50
Olivier Greniedd316c62011-01-04 04:28:59 -030051struct dib9000_state {
52 struct i2c_device i2c;
53
54 struct dibx000_i2c_master i2c_master;
55 struct i2c_adapter tuner_adap;
56 struct i2c_adapter component_bus;
57
58 u16 revision;
59 u8 reg_offs;
60
61 enum frontend_tune_state tune_state;
62 u32 status;
63 struct dvb_frontend_parametersContext channel_status;
64
65 u8 fe_id;
66
67#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff
68 u16 gpio_dir;
69#define DIB9000_GPIO_DEFAULT_VALUES 0x0000
70 u16 gpio_val;
71#define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff
72 u16 gpio_pwm_pos;
73
74 union { /* common for all chips */
75 struct {
76 u8 mobile_mode:1;
77 } host;
78
79 struct {
80 struct dib9000_fe_memory_map {
81 u16 addr;
82 u16 size;
83 } fe_mm[18];
84 u8 memcmd;
85
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -030086 struct mutex mbx_if_lock; /* to protect read/write operations */
87 struct mutex mbx_lock; /* to protect the whole mailbox handling */
Olivier Greniedd316c62011-01-04 04:28:59 -030088
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -030089 struct mutex mem_lock; /* to protect the memory accesses */
90 struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */
Olivier Greniedd316c62011-01-04 04:28:59 -030091
92#define MBX_MAX_WORDS (256 - 200 - 2)
93#define DIB9000_MSG_CACHE_SIZE 2
94 u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS];
95 u8 fw_is_running;
96 } risc;
97 } platform;
98
99 union { /* common for all platforms */
100 struct {
101 struct dib9000_config cfg;
102 } d9;
103 } chip;
104
105 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
106 u16 component_bus_speed;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300107
108 /* for the I2C transfer */
109 struct i2c_msg msg[2];
110 u8 i2c_write_buffer[255];
111 u8 i2c_read_buffer[255];
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300112 struct mutex demod_lock;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300113 u8 get_frontend_internal;
114 struct dib9000_pid_ctrl pid_ctrl[10];
115 s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
Olivier Greniedd316c62011-01-04 04:28:59 -0300116};
117
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300118static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Olivier Greniedd316c62011-01-04 04:28:59 -0300119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300120 0, 0, 0, 0, 0, 0, 0, 0
Olivier Greniedd316c62011-01-04 04:28:59 -0300121};
122
123enum dib9000_power_mode {
124 DIB9000_POWER_ALL = 0,
125
126 DIB9000_POWER_NO,
127 DIB9000_POWER_INTERF_ANALOG_AGC,
128 DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
129 DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD,
130 DIB9000_POWER_INTERFACE_ONLY,
131};
132
133enum dib9000_out_messages {
134 OUT_MSG_HBM_ACK,
135 OUT_MSG_HOST_BUF_FAIL,
136 OUT_MSG_REQ_VERSION,
137 OUT_MSG_BRIDGE_I2C_W,
138 OUT_MSG_BRIDGE_I2C_R,
139 OUT_MSG_BRIDGE_APB_W,
140 OUT_MSG_BRIDGE_APB_R,
141 OUT_MSG_SCAN_CHANNEL,
142 OUT_MSG_MONIT_DEMOD,
143 OUT_MSG_CONF_GPIO,
144 OUT_MSG_DEBUG_HELP,
145 OUT_MSG_SUBBAND_SEL,
146 OUT_MSG_ENABLE_TIME_SLICE,
147 OUT_MSG_FE_FW_DL,
148 OUT_MSG_FE_CHANNEL_SEARCH,
149 OUT_MSG_FE_CHANNEL_TUNE,
150 OUT_MSG_FE_SLEEP,
151 OUT_MSG_FE_SYNC,
152 OUT_MSG_CTL_MONIT,
153
154 OUT_MSG_CONF_SVC,
155 OUT_MSG_SET_HBM,
156 OUT_MSG_INIT_DEMOD,
157 OUT_MSG_ENABLE_DIVERSITY,
158 OUT_MSG_SET_OUTPUT_MODE,
159 OUT_MSG_SET_PRIORITARY_CHANNEL,
160 OUT_MSG_ACK_FRG,
161 OUT_MSG_INIT_PMU,
162};
163
164enum dib9000_in_messages {
165 IN_MSG_DATA,
166 IN_MSG_FRAME_INFO,
167 IN_MSG_CTL_MONIT,
168 IN_MSG_ACK_FREE_ITEM,
169 IN_MSG_DEBUG_BUF,
170 IN_MSG_MPE_MONITOR,
171 IN_MSG_RAWTS_MONITOR,
172 IN_MSG_END_BRIDGE_I2C_RW,
173 IN_MSG_END_BRIDGE_APB_RW,
174 IN_MSG_VERSION,
175 IN_MSG_END_OF_SCAN,
176 IN_MSG_MONIT_DEMOD,
177 IN_MSG_ERROR,
178 IN_MSG_FE_FW_DL_DONE,
179 IN_MSG_EVENT,
180 IN_MSG_ACK_CHANGE_SVC,
181 IN_MSG_HBM_PROF,
182};
183
184/* memory_access requests */
185#define FE_MM_W_CHANNEL 0
186#define FE_MM_W_FE_INFO 1
187#define FE_MM_RW_SYNC 2
188
189#define FE_SYNC_CHANNEL 1
190#define FE_SYNC_W_GENERIC_MONIT 2
191#define FE_SYNC_COMPONENT_ACCESS 3
192
193#define FE_MM_R_CHANNEL_SEARCH_STATE 3
194#define FE_MM_R_CHANNEL_UNION_CONTEXT 4
195#define FE_MM_R_FE_INFO 5
196#define FE_MM_R_FE_MONITOR 6
197
198#define FE_MM_W_CHANNEL_HEAD 7
199#define FE_MM_W_CHANNEL_UNION 8
200#define FE_MM_W_CHANNEL_CONTEXT 9
201#define FE_MM_R_CHANNEL_UNION 10
202#define FE_MM_R_CHANNEL_CONTEXT 11
203#define FE_MM_R_CHANNEL_TUNE_STATE 12
204
205#define FE_MM_R_GENERIC_MONITORING_SIZE 13
206#define FE_MM_W_GENERIC_MONITORING 14
207#define FE_MM_R_GENERIC_MONITORING 15
208
209#define FE_MM_W_COMPONENT_ACCESS 16
210#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300211static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len);
Olivier Greniedd316c62011-01-04 04:28:59 -0300212static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len);
213
214static u16 to_fw_output_mode(u16 mode)
215{
216 switch (mode) {
217 case OUTMODE_HIGH_Z:
218 return 0;
219 case OUTMODE_MPEG2_PAR_GATED_CLK:
220 return 4;
221 case OUTMODE_MPEG2_PAR_CONT_CLK:
222 return 8;
223 case OUTMODE_MPEG2_SERIAL:
224 return 16;
225 case OUTMODE_DIVERSITY:
226 return 128;
227 case OUTMODE_MPEG2_FIFO:
228 return 2;
229 case OUTMODE_ANALOG_ADC:
230 return 1;
231 default:
232 return 0;
233 }
234}
235
Mauro Carvalho Chehab88d05182016-02-22 13:43:57 -0300236static int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 len, u16 attribute)
Olivier Greniedd316c62011-01-04 04:28:59 -0300237{
238 u32 chunk_size = 126;
239 u32 l;
240 int ret;
Olivier Greniedd316c62011-01-04 04:28:59 -0300241
242 if (state->platform.risc.fw_is_running && (reg < 1024))
243 return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
244
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300245 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
246 state->msg[0].addr = state->i2c.i2c_addr >> 1;
247 state->msg[0].flags = 0;
248 state->msg[0].buf = state->i2c_write_buffer;
249 state->msg[0].len = 2;
250 state->msg[1].addr = state->i2c.i2c_addr >> 1;
251 state->msg[1].flags = I2C_M_RD;
252 state->msg[1].buf = b;
253 state->msg[1].len = len;
254
255 state->i2c_write_buffer[0] = reg >> 8;
256 state->i2c_write_buffer[1] = reg & 0xff;
257
Olivier Greniedd316c62011-01-04 04:28:59 -0300258 if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300259 state->i2c_write_buffer[0] |= (1 << 5);
Olivier Greniedd316c62011-01-04 04:28:59 -0300260 if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300261 state->i2c_write_buffer[0] |= (1 << 4);
Olivier Greniedd316c62011-01-04 04:28:59 -0300262
263 do {
264 l = len < chunk_size ? len : chunk_size;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300265 state->msg[1].len = l;
266 state->msg[1].buf = b;
267 ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300268 if (ret != 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300269 dprintk("i2c read error on %d\n", reg);
Olivier Greniedd316c62011-01-04 04:28:59 -0300270 return -EREMOTEIO;
271 }
272
273 b += l;
274 len -= l;
275
276 if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
277 reg += l / 2;
278 } while ((ret == 0) && len);
279
280 return 0;
281}
282
283static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
284{
Olivier Greniedd316c62011-01-04 04:28:59 -0300285 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300286 {.addr = i2c->i2c_addr >> 1, .flags = 0,
287 .buf = i2c->i2c_write_buffer, .len = 2},
288 {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
289 .buf = i2c->i2c_read_buffer, .len = 2},
Olivier Greniedd316c62011-01-04 04:28:59 -0300290 };
291
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300292 i2c->i2c_write_buffer[0] = reg >> 8;
293 i2c->i2c_write_buffer[1] = reg & 0xff;
294
Olivier Greniedd316c62011-01-04 04:28:59 -0300295 if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300296 dprintk("read register %x error\n", reg);
Olivier Greniedd316c62011-01-04 04:28:59 -0300297 return 0;
298 }
299
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300300 return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
Olivier Greniedd316c62011-01-04 04:28:59 -0300301}
302
303static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
304{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300305 if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
Olivier Greniedd316c62011-01-04 04:28:59 -0300306 return 0;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300307 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Olivier Greniedd316c62011-01-04 04:28:59 -0300308}
309
310static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
311{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300312 if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
313 attribute) != 0)
Olivier Greniedd316c62011-01-04 04:28:59 -0300314 return 0;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300315 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Olivier Greniedd316c62011-01-04 04:28:59 -0300316}
317
318#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
319
Mauro Carvalho Chehab88d05182016-02-22 13:43:57 -0300320static int dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *buf, u32 len, u16 attribute)
Olivier Greniedd316c62011-01-04 04:28:59 -0300321{
Olivier Greniedd316c62011-01-04 04:28:59 -0300322 u32 chunk_size = 126;
323 u32 l;
324 int ret;
325
Olivier Greniedd316c62011-01-04 04:28:59 -0300326 if (state->platform.risc.fw_is_running && (reg < 1024)) {
327 if (dib9000_risc_apb_access_write
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300328 (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
Olivier Greniedd316c62011-01-04 04:28:59 -0300329 return -EINVAL;
330 return 0;
331 }
332
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300333 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
334 state->msg[0].addr = state->i2c.i2c_addr >> 1;
335 state->msg[0].flags = 0;
336 state->msg[0].buf = state->i2c_write_buffer;
337 state->msg[0].len = len + 2;
338
339 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
340 state->i2c_write_buffer[1] = (reg) & 0xff;
Olivier Greniedd316c62011-01-04 04:28:59 -0300341
342 if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300343 state->i2c_write_buffer[0] |= (1 << 5);
Olivier Greniedd316c62011-01-04 04:28:59 -0300344 if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300345 state->i2c_write_buffer[0] |= (1 << 4);
Olivier Greniedd316c62011-01-04 04:28:59 -0300346
347 do {
348 l = len < chunk_size ? len : chunk_size;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300349 state->msg[0].len = l + 2;
350 memcpy(&state->i2c_write_buffer[2], buf, l);
Olivier Greniedd316c62011-01-04 04:28:59 -0300351
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300352 ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300353
354 buf += l;
355 len -= l;
356
357 if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
358 reg += l / 2;
359 } while ((ret == 0) && len);
360
361 return ret;
362}
363
364static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
365{
Olivier Greniedd316c62011-01-04 04:28:59 -0300366 struct i2c_msg msg = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300367 .addr = i2c->i2c_addr >> 1, .flags = 0,
368 .buf = i2c->i2c_write_buffer, .len = 4
Olivier Greniedd316c62011-01-04 04:28:59 -0300369 };
370
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300371 i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
372 i2c->i2c_write_buffer[1] = reg & 0xff;
373 i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
374 i2c->i2c_write_buffer[3] = val & 0xff;
375
Olivier Greniedd316c62011-01-04 04:28:59 -0300376 return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
377}
378
379static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val)
380{
381 u8 b[2] = { val >> 8, val & 0xff };
382 return dib9000_write16_attr(state, reg, b, 2, 0);
383}
384
385static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute)
386{
387 u8 b[2] = { val >> 8, val & 0xff };
388 return dib9000_write16_attr(state, reg, b, 2, attribute);
389}
390
391#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0)
392#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
393#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute))
394
395#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0)
396#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0)
397
398#define MAC_IRQ (1 << 1)
399#define IRQ_POL_MSK (1 << 4)
400
401#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
402#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
403
404static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading)
405{
406 u8 b[14] = { 0 };
407
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300408/* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */
409/* b[0] = 0 << 7; */
Olivier Greniedd316c62011-01-04 04:28:59 -0300410 b[1] = 1;
411
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300412/* b[2] = 0; */
413/* b[3] = 0; */
414 b[4] = (u8) (addr >> 8);
Olivier Greniedd316c62011-01-04 04:28:59 -0300415 b[5] = (u8) (addr & 0xff);
416
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300417/* b[10] = 0; */
418/* b[11] = 0; */
419 b[12] = (u8) (addr >> 8);
Olivier Greniedd316c62011-01-04 04:28:59 -0300420 b[13] = (u8) (addr & 0xff);
421
422 addr += len;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300423/* b[6] = 0; */
424/* b[7] = 0; */
425 b[8] = (u8) (addr >> 8);
Olivier Greniedd316c62011-01-04 04:28:59 -0300426 b[9] = (u8) (addr & 0xff);
427
428 dib9000_write(state, 1056, b, 14);
429 if (reading)
430 dib9000_write_word(state, 1056, (1 << 15) | 1);
431 state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */
432}
433
434static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd)
435{
436 struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f];
437 /* decide whether we need to "refresh" the memory controller */
438 if (state->platform.risc.memcmd == cmd && /* same command */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300439 !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */
Olivier Greniedd316c62011-01-04 04:28:59 -0300440 return;
441 dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80);
442 state->platform.risc.memcmd = cmd;
443}
444
445static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len)
446{
447 if (!state->platform.risc.fw_is_running)
448 return -EIO;
449
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300450 if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300451 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300452 return -EINTR;
453 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300454 dib9000_risc_mem_setup(state, cmd | 0x80);
455 dib9000_risc_mem_read_chunks(state, b, len);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300456 mutex_unlock(&state->platform.risc.mem_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300457 return 0;
458}
459
460static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b)
461{
462 struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd];
463 if (!state->platform.risc.fw_is_running)
464 return -EIO;
465
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300466 if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300467 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300468 return -EINTR;
469 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300470 dib9000_risc_mem_setup(state, cmd);
471 dib9000_risc_mem_write_chunks(state, b, m->size);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300472 mutex_unlock(&state->platform.risc.mem_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300473 return 0;
474}
475
476static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len)
477{
478 u16 offs;
479
480 if (risc_id == 1)
481 offs = 16;
482 else
483 offs = 0;
484
485 /* config crtl reg */
486 dib9000_write_word(state, 1024 + offs, 0x000f);
487 dib9000_write_word(state, 1025 + offs, 0);
488 dib9000_write_word(state, 1031 + offs, key);
489
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300490 dprintk("going to download %dB of microcode\n", len);
Olivier Greniedd316c62011-01-04 04:28:59 -0300491 if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300492 dprintk("error while downloading microcode for RISC %c\n", 'A' + risc_id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300493 return -EIO;
494 }
495
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300496 dprintk("Microcode for RISC %c loaded\n", 'A' + risc_id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300497
498 return 0;
499}
500
501static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id)
502{
503 u16 mbox_offs;
504 u16 reset_reg;
505 u16 tries = 1000;
506
507 if (risc_id == 1)
508 mbox_offs = 16;
509 else
510 mbox_offs = 0;
511
512 /* Reset mailbox */
513 dib9000_write_word(state, 1027 + mbox_offs, 0x8000);
514
515 /* Read reset status */
516 do {
517 reset_reg = dib9000_read_word(state, 1027 + mbox_offs);
518 msleep(100);
519 } while ((reset_reg & 0x8000) && --tries);
520
521 if (reset_reg & 0x8000) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300522 dprintk("MBX: init ERROR, no response from RISC %c\n", 'A' + risc_id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300523 return -EIO;
524 }
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300525 dprintk("MBX: initialized\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300526 return 0;
527}
528
529#define MAX_MAILBOX_TRY 100
530static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr)
531{
Dan Carpenterb00aff62011-01-19 11:28:27 -0300532 u8 *d, b[2];
Olivier Greniedd316c62011-01-04 04:28:59 -0300533 u16 tmp;
534 u16 size;
535 u32 i;
Dan Carpenterb00aff62011-01-19 11:28:27 -0300536 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300537
538 if (!state->platform.risc.fw_is_running)
539 return -EINVAL;
540
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300541 if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300542 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300543 return -EINTR;
544 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300545 tmp = MAX_MAILBOX_TRY;
546 do {
547 size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
548 if ((size + len + 1) > MBX_MAX_WORDS && --tmp) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300549 dprintk("MBX: RISC mbx full, retrying\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300550 msleep(100);
551 } else
552 break;
553 } while (1);
554
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300555 /*dprintk( "MBX: size: %d\n", size); */
Olivier Greniedd316c62011-01-04 04:28:59 -0300556
557 if (tmp == 0) {
558 ret = -EINVAL;
559 goto out;
560 }
561#ifdef DUMP_MSG
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300562 dprintk("--> %02x %d %*ph\n", id, len + 1, len, data);
Olivier Greniedd316c62011-01-04 04:28:59 -0300563#endif
564
565 /* byte-order conversion - works on big (where it is not necessary) or little endian */
566 d = (u8 *) data;
567 for (i = 0; i < len; i++) {
568 tmp = data[i];
569 *d++ = tmp >> 8;
570 *d++ = tmp & 0xff;
571 }
572
573 /* write msg */
574 b[0] = id;
575 b[1] = len + 1;
576 if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) {
577 ret = -EIO;
578 goto out;
579 }
580
581 /* update register nb_mes_in_RX */
582 ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
583
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300584out:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300585 mutex_unlock(&state->platform.risc.mbx_if_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300586
587 return ret;
588}
589
590static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr)
591{
592#ifdef DUMP_MSG
593 u16 *d = data;
594#endif
595
596 u16 tmp, i;
597 u8 size;
598 u8 mc_base;
599
600 if (!state->platform.risc.fw_is_running)
601 return 0;
602
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300603 if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300604 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300605 return 0;
606 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300607 if (risc_id == 1)
608 mc_base = 16;
609 else
610 mc_base = 0;
611
612 /* Length and type in the first word */
613 *data = dib9000_read_word_attr(state, 1029 + mc_base, attr);
614
615 size = *data & 0xff;
616 if (size <= MBX_MAX_WORDS) {
617 data++;
618 size--; /* Initial word already read */
619
620 dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr);
621
622 /* to word conversion */
623 for (i = 0; i < size; i++) {
624 tmp = *data;
625 *data = (tmp >> 8) | (tmp << 8);
626 data++;
627 }
628
629#ifdef DUMP_MSG
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300630 dprintk("<--\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300631 for (i = 0; i < size + 1; i++)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300632 dprintk("%04x\n", d[i]);
Olivier Greniedd316c62011-01-04 04:28:59 -0300633 dprintk("\n");
634#endif
635 } else {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300636 dprintk("MBX: message is too big for message cache (%d), flushing message\n", size);
Olivier Greniedd316c62011-01-04 04:28:59 -0300637 size--; /* Initial word already read */
638 while (size--)
639 dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr);
640 }
641 /* Update register nb_mes_in_TX */
642 dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
643
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300644 mutex_unlock(&state->platform.risc.mbx_if_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300645
646 return size + 1;
647}
648
649static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size)
650{
651 u32 ts = data[1] << 16 | data[0];
652 char *b = (char *)&data[2];
653
654 b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */
655 if (*b == '~') {
656 b++;
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300657 dprintk("%s\n", b);
Olivier Greniedd316c62011-01-04 04:28:59 -0300658 } else
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300659 dprintk("RISC%d: %d.%04d %s\n",
660 state->fe_id,
661 ts / 10000, ts % 10000, *b ? b : "<empty>");
Olivier Greniedd316c62011-01-04 04:28:59 -0300662 return 1;
663}
664
665static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr)
666{
667 int i;
668 u8 size;
669 u16 *block;
670 /* find a free slot */
671 for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
672 block = state->platform.risc.message_cache[i];
673 if (*block == 0) {
674 size = dib9000_mbx_read(state, block, 1, attr);
675
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300676/* dprintk( "MBX: fetched %04x message to cache\n", *block); */
Olivier Greniedd316c62011-01-04 04:28:59 -0300677
678 switch (*block >> 8) {
679 case IN_MSG_DEBUG_BUF:
680 dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */
681 *block = 0; /* free the block */
682 break;
683#if 0
684 case IN_MSG_DATA: /* FE-TRACE */
685 dib9000_risc_data_process(state, block + 1, size);
686 *block = 0;
687 break;
688#endif
689 default:
690 break;
691 }
692
693 return 1;
694 }
695 }
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300696 dprintk("MBX: no free cache-slot found for new message...\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300697 return -1;
698}
699
700static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr)
701{
702 if (risc_id == 0)
703 return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */
704 else
705 return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */
706}
707
708static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
709{
710 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300711
712 if (!state->platform.risc.fw_is_running)
713 return -1;
714
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300715 if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300716 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300717 return -1;
718 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300719
720 if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */
721 ret = dib9000_mbx_fetch_to_cache(state, attr);
722
Hans Verkuilfdf07b02012-04-20 08:04:48 -0300723 dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300724/* if (tmp) */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300725/* dprintk( "cleared IRQ: %x\n", tmp); */
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300726 mutex_unlock(&state->platform.risc.mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300727
728 return ret;
729}
730
731static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr)
732{
733 u8 i;
734 u16 *block;
735 u16 timeout = 30;
736
737 *msg = 0;
738 do {
739 /* dib9000_mbx_get_from_cache(); */
740 for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
741 block = state->platform.risc.message_cache[i];
742 if ((*block >> 8) == id) {
743 *size = (*block & 0xff) - 1;
744 memcpy(msg, block + 1, (*size) * 2);
745 *block = 0; /* free the block */
746 i = 0; /* signal that we found a message */
747 break;
748 }
749 }
750
751 if (i == 0)
752 break;
753
754 if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */
755 return -1;
756
757 } while (--timeout);
758
759 if (timeout == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300760 dprintk("waiting for message %d timed out\n", id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300761 return -1;
762 }
763
764 return i == 0;
765}
766
767static int dib9000_risc_check_version(struct dib9000_state *state)
768{
769 u8 r[4];
770 u8 size;
771 u16 fw_version = 0;
772
773 if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0)
774 return -EIO;
775
776 if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0)
777 return -EIO;
778
779 fw_version = (r[0] << 8) | r[1];
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300780 dprintk("RISC: ver: %d.%02d (IC: %d)\n", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]);
Olivier Greniedd316c62011-01-04 04:28:59 -0300781
782 if ((fw_version >> 10) != 7)
783 return -EINVAL;
784
785 switch (fw_version & 0x3ff) {
786 case 11:
787 case 12:
788 case 14:
789 case 15:
790 case 16:
791 case 17:
792 break;
793 default:
794 dprintk("RISC: invalid firmware version");
795 return -EINVAL;
796 }
797
798 dprintk("RISC: valid firmware version");
799 return 0;
800}
801
802static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB)
803{
804 /* Reconfig pool mac ram */
805 dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */
806 dib9000_write_word(state, 1226, 0x05);
807
808 /* Toggles IP crypto to Host APB interface. */
809 dib9000_write_word(state, 1542, 1);
810
811 /* Set jump and no jump in the dma box */
812 dib9000_write_word(state, 1074, 0);
813 dib9000_write_word(state, 1075, 0);
814
815 /* Set MAC as APB Master. */
816 dib9000_write_word(state, 1237, 0);
817
818 /* Reset the RISCs */
819 if (codeA != NULL)
820 dib9000_write_word(state, 1024, 2);
821 else
822 dib9000_write_word(state, 1024, 15);
823 if (codeB != NULL)
824 dib9000_write_word(state, 1040, 2);
825
826 if (codeA != NULL)
827 dib9000_firmware_download(state, 0, 0x1234, codeA, lenA);
828 if (codeB != NULL)
829 dib9000_firmware_download(state, 1, 0x1234, codeB, lenB);
830
831 /* Run the RISCs */
832 if (codeA != NULL)
833 dib9000_write_word(state, 1024, 0);
834 if (codeB != NULL)
835 dib9000_write_word(state, 1040, 0);
836
837 if (codeA != NULL)
838 if (dib9000_mbx_host_init(state, 0) != 0)
839 return -EIO;
840 if (codeB != NULL)
841 if (dib9000_mbx_host_init(state, 1) != 0)
842 return -EIO;
843
844 msleep(100);
845 state->platform.risc.fw_is_running = 1;
846
847 if (dib9000_risc_check_version(state) != 0)
848 return -EINVAL;
849
850 state->platform.risc.memcmd = 0xff;
851 return 0;
852}
853
854static u16 dib9000_identify(struct i2c_device *client)
855{
856 u16 value;
857
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300858 value = dib9000_i2c_read16(client, 896);
859 if (value != 0x01b3) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300860 dprintk("wrong Vendor ID (0x%x)\n", value);
Olivier Greniedd316c62011-01-04 04:28:59 -0300861 return 0;
862 }
863
864 value = dib9000_i2c_read16(client, 897);
865 if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300866 dprintk("wrong Device ID (0x%x)\n", value);
Olivier Greniedd316c62011-01-04 04:28:59 -0300867 return 0;
868 }
869
870 /* protect this driver to be used with 7000PC */
871 if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300872 dprintk("this driver does not work with DiB7000PC\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300873 return 0;
874 }
875
876 switch (value) {
877 case 0x4000:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300878 dprintk("found DiB7000MA/PA/MB/PB\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300879 break;
880 case 0x4001:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300881 dprintk("found DiB7000HC\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300882 break;
883 case 0x4002:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300884 dprintk("found DiB7000MC\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300885 break;
886 case 0x4003:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300887 dprintk("found DiB9000A\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300888 break;
889 case 0x4004:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300890 dprintk("found DiB9000H\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300891 break;
892 case 0x4005:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300893 dprintk("found DiB9000M\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300894 break;
895 }
896
897 return value;
898}
899
900static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode)
901{
902 /* by default everything is going to be powered off */
903 u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906;
904 u8 offset;
905
906 if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005)
907 offset = 1;
908 else
909 offset = 0;
910
911 reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */
912
913 /* now, depending on the requested mode, we power on */
914 switch (mode) {
915 /* power up everything in the demod */
916 case DIB9000_POWER_ALL:
917 reg_903 = 0x0000;
918 reg_904 = 0x0000;
919 reg_905 = 0x0000;
920 reg_906 = 0x0000;
921 break;
922
923 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
924 case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
925 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
926 break;
927
928 case DIB9000_POWER_INTERF_ANALOG_AGC:
929 reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
930 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
931 reg_906 &= ~((1 << 0));
932 break;
933
934 case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
935 reg_903 = 0x0000;
936 reg_904 = 0x801f;
937 reg_905 = 0x0000;
938 reg_906 &= ~((1 << 0));
939 break;
940
941 case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD:
942 reg_903 = 0x0000;
943 reg_904 = 0x8000;
944 reg_905 = 0x010b;
945 reg_906 &= ~((1 << 0));
946 break;
947 default:
948 case DIB9000_POWER_NO:
949 break;
950 }
951
952 /* always power down unused parts */
953 if (!state->platform.host.mobile_mode)
954 reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
955
956 /* P_sdio_select_clk = 0 on MC and after */
957 if (state->revision != 0x4000)
958 reg_906 <<= 1;
959
960 dib9000_write_word(state, 903 + offset, reg_903);
961 dib9000_write_word(state, 904 + offset, reg_904);
962 dib9000_write_word(state, 905 + offset, reg_905);
963 dib9000_write_word(state, 906 + offset, reg_906);
964}
965
966static int dib9000_fw_reset(struct dvb_frontend *fe)
967{
968 struct dib9000_state *state = fe->demodulator_priv;
969
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300970 dib9000_write_word(state, 1817, 0x0003);
Olivier Greniedd316c62011-01-04 04:28:59 -0300971
972 dib9000_write_word(state, 1227, 1);
973 dib9000_write_word(state, 1227, 0);
974
975 switch ((state->revision = dib9000_identify(&state->i2c))) {
976 case 0x4003:
977 case 0x4004:
978 case 0x4005:
979 state->reg_offs = 1;
980 break;
981 default:
982 return -EINVAL;
983 }
984
985 /* reset the i2c-master to use the host interface */
986 dibx000_reset_i2c_master(&state->i2c_master);
987
988 dib9000_set_power_mode(state, DIB9000_POWER_ALL);
989
990 /* unforce divstr regardless whether i2c enumeration was done or not */
991 dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1));
992 dib9000_write_word(state, 1796, 0);
993 dib9000_write_word(state, 1805, 0x805);
994
995 /* restart all parts */
996 dib9000_write_word(state, 898, 0xffff);
997 dib9000_write_word(state, 899, 0xffff);
998 dib9000_write_word(state, 900, 0x0001);
999 dib9000_write_word(state, 901, 0xff19);
1000 dib9000_write_word(state, 902, 0x003c);
1001
1002 dib9000_write_word(state, 898, 0);
1003 dib9000_write_word(state, 899, 0);
1004 dib9000_write_word(state, 900, 0);
1005 dib9000_write_word(state, 901, 0);
1006 dib9000_write_word(state, 902, 0);
1007
1008 dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives);
1009
1010 dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY);
1011
1012 return 0;
1013}
1014
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001015static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len)
Olivier Greniedd316c62011-01-04 04:28:59 -03001016{
1017 u16 mb[10];
1018 u8 i, s;
1019
1020 if (address >= 1024 || !state->platform.risc.fw_is_running)
1021 return -EINVAL;
1022
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05001023 /* dprintk( "APB access through rd fw %d %x\n", address, attribute); */
Olivier Greniedd316c62011-01-04 04:28:59 -03001024
1025 mb[0] = (u16) address;
1026 mb[1] = len / 2;
1027 dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute);
1028 switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) {
1029 case 1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001030 s--;
Olivier Greniedd316c62011-01-04 04:28:59 -03001031 for (i = 0; i < s; i++) {
1032 b[i * 2] = (mb[i + 1] >> 8) & 0xff;
1033 b[i * 2 + 1] = (mb[i + 1]) & 0xff;
1034 }
1035 return 0;
1036 default:
1037 return -EIO;
1038 }
1039 return -EIO;
1040}
1041
1042static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len)
1043{
1044 u16 mb[10];
1045 u8 s, i;
1046
1047 if (address >= 1024 || !state->platform.risc.fw_is_running)
1048 return -EINVAL;
1049
Heinrich Schuchardt18d75a02014-06-19 11:49:40 -03001050 if (len > 18)
1051 return -EINVAL;
1052
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05001053 /* dprintk( "APB access through wr fw %d %x\n", address, attribute); */
Olivier Greniedd316c62011-01-04 04:28:59 -03001054
Heinrich Schuchardt18d75a02014-06-19 11:49:40 -03001055 mb[0] = (u16)address;
1056 for (i = 0; i + 1 < len; i += 2)
1057 mb[1 + i / 2] = b[i] << 8 | b[i + 1];
1058 if (len & 1)
1059 mb[1 + len / 2] = b[len - 1] << 8;
Olivier Greniedd316c62011-01-04 04:28:59 -03001060
Heinrich Schuchardt18d75a02014-06-19 11:49:40 -03001061 dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, (3 + len) / 2, attribute);
Olivier Greniedd316c62011-01-04 04:28:59 -03001062 return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
1063}
1064
1065static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
1066{
1067 u8 index_loop = 10;
1068
1069 if (!state->platform.risc.fw_is_running)
1070 return 0;
1071 dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
1072 do {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001073 dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
1074 } while (state->i2c_read_buffer[0] && index_loop--);
Olivier Greniedd316c62011-01-04 04:28:59 -03001075
1076 if (index_loop > 0)
1077 return 0;
1078 return -EIO;
1079}
1080
1081static int dib9000_fw_init(struct dib9000_state *state)
1082{
1083 struct dibGPIOFunction *f;
1084 u16 b[40] = { 0 };
1085 u8 i;
1086 u8 size;
1087
1088 if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0)
Olivier Greniedd316c62011-01-04 04:28:59 -03001089 return -EIO;
1090
1091 /* initialize the firmware */
1092 for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) {
1093 f = &state->chip.d9.cfg.gpio_function[i];
1094 if (f->mask) {
1095 switch (f->function) {
1096 case BOARD_GPIO_FUNCTION_COMPONENT_ON:
1097 b[0] = (u16) f->mask;
1098 b[1] = (u16) f->direction;
1099 b[2] = (u16) f->value;
1100 break;
1101 case BOARD_GPIO_FUNCTION_COMPONENT_OFF:
1102 b[3] = (u16) f->mask;
1103 b[4] = (u16) f->direction;
1104 b[5] = (u16) f->value;
1105 break;
1106 }
1107 }
1108 }
1109 if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0)
1110 return -EIO;
1111
1112 /* subband */
1113 b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */
1114 for (i = 0; i < state->chip.d9.cfg.subband.size; i++) {
1115 b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz;
1116 b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask;
1117 b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction;
1118 b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value;
Olivier Greniedd316c62011-01-04 04:28:59 -03001119 }
1120 b[1 + i * 4] = 0; /* fe_id */
1121 if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0)
1122 return -EIO;
1123
1124 /* 0 - id, 1 - no_of_frontends */
1125 b[0] = (0 << 8) | 1;
1126 /* 0 = i2c-address demod, 0 = tuner */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001127 b[1] = (0 << 8) | (0);
Olivier Greniedd316c62011-01-04 04:28:59 -03001128 b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff);
1129 b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff);
1130 b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff);
1131 b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff);
1132 b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff);
1133 b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff);
1134 b[29] = state->chip.d9.cfg.if_drives;
1135 if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0)
1136 return -EIO;
1137
1138 if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0)
1139 return -EIO;
1140
1141 if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0)
1142 return -EIO;
1143
1144 if (size > ARRAY_SIZE(b)) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001145 dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size,
1146 (int)ARRAY_SIZE(b));
Olivier Greniedd316c62011-01-04 04:28:59 -03001147 return -EINVAL;
1148 }
1149
1150 for (i = 0; i < size; i += 2) {
1151 state->platform.risc.fe_mm[i / 2].addr = b[i + 0];
1152 state->platform.risc.fe_mm[i / 2].size = b[i + 1];
Olivier Greniedd316c62011-01-04 04:28:59 -03001153 }
1154
1155 return 0;
1156}
1157
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001158static void dib9000_fw_set_channel_head(struct dib9000_state *state)
Olivier Greniedd316c62011-01-04 04:28:59 -03001159{
1160 u8 b[9];
1161 u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
1162 if (state->fe_id % 2)
1163 freq += 101;
1164
1165 b[0] = (u8) ((freq >> 0) & 0xff);
1166 b[1] = (u8) ((freq >> 8) & 0xff);
1167 b[2] = (u8) ((freq >> 16) & 0xff);
1168 b[3] = (u8) ((freq >> 24) & 0xff);
1169 b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff);
1170 b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff);
1171 b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff);
1172 b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff);
1173 b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */
1174 if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT)
1175 b[8] |= 1;
1176 dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
1177}
1178
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001179static int dib9000_fw_get_channel(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001180{
1181 struct dib9000_state *state = fe->demodulator_priv;
1182 struct dibDVBTChannel {
1183 s8 spectrum_inversion;
1184
1185 s8 nfft;
1186 s8 guard;
1187 s8 constellation;
1188
1189 s8 hrch;
1190 s8 alpha;
1191 s8 code_rate_hp;
1192 s8 code_rate_lp;
1193 s8 select_hp;
1194
1195 s8 intlv_native;
1196 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001197 struct dibDVBTChannel *ch;
Olivier Greniedd316c62011-01-04 04:28:59 -03001198 int ret = 0;
1199
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001200 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001201 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001202 return -EINTR;
1203 }
Olivier Greniedd316c62011-01-04 04:28:59 -03001204 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001205 ret = -EIO;
Dan Carpenter2f098cb2011-08-06 05:01:51 -03001206 goto error;
Olivier Greniedd316c62011-01-04 04:28:59 -03001207 }
1208
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001209 dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
1210 state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
1211 ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03001212
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001213
1214 switch (ch->spectrum_inversion & 0x7) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001215 case 1:
1216 state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
1217 break;
1218 case 0:
1219 state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF;
1220 break;
1221 default:
1222 case -1:
1223 state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
1224 break;
1225 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001226 switch (ch->nfft) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001227 case 0:
1228 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
1229 break;
1230 case 2:
1231 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
1232 break;
1233 case 1:
1234 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1235 break;
1236 default:
1237 case -1:
1238 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
1239 break;
1240 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001241 switch (ch->guard) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001242 case 0:
1243 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
1244 break;
1245 case 1:
1246 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
1247 break;
1248 case 2:
1249 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
1250 break;
1251 case 3:
1252 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
1253 break;
1254 default:
1255 case -1:
1256 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
1257 break;
1258 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001259 switch (ch->constellation) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001260 case 2:
1261 state->fe[0]->dtv_property_cache.modulation = QAM_64;
1262 break;
1263 case 1:
1264 state->fe[0]->dtv_property_cache.modulation = QAM_16;
1265 break;
1266 case 0:
1267 state->fe[0]->dtv_property_cache.modulation = QPSK;
1268 break;
1269 default:
1270 case -1:
1271 state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
1272 break;
1273 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001274 switch (ch->hrch) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001275 case 0:
1276 state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
1277 break;
1278 case 1:
1279 state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1;
1280 break;
1281 default:
1282 case -1:
1283 state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
1284 break;
1285 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001286 switch (ch->code_rate_hp) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001287 case 1:
1288 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
1289 break;
1290 case 2:
1291 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3;
1292 break;
1293 case 3:
1294 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4;
1295 break;
1296 case 5:
1297 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6;
1298 break;
1299 case 7:
1300 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8;
1301 break;
1302 default:
1303 case -1:
1304 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
1305 break;
1306 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001307 switch (ch->code_rate_lp) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001308 case 1:
1309 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
1310 break;
1311 case 2:
1312 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3;
1313 break;
1314 case 3:
1315 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4;
1316 break;
1317 case 5:
1318 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6;
1319 break;
1320 case 7:
1321 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8;
1322 break;
1323 default:
1324 case -1:
1325 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO;
1326 break;
1327 }
1328
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001329error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001330 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03001331 return ret;
1332}
1333
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03001334static int dib9000_fw_set_channel_union(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001335{
1336 struct dib9000_state *state = fe->demodulator_priv;
1337 struct dibDVBTChannel {
1338 s8 spectrum_inversion;
1339
1340 s8 nfft;
1341 s8 guard;
1342 s8 constellation;
1343
1344 s8 hrch;
1345 s8 alpha;
1346 s8 code_rate_hp;
1347 s8 code_rate_lp;
1348 s8 select_hp;
1349
1350 s8 intlv_native;
1351 };
1352 struct dibDVBTChannel ch;
1353
1354 switch (state->fe[0]->dtv_property_cache.inversion) {
1355 case INVERSION_ON:
1356 ch.spectrum_inversion = 1;
1357 break;
1358 case INVERSION_OFF:
1359 ch.spectrum_inversion = 0;
1360 break;
1361 default:
1362 case INVERSION_AUTO:
1363 ch.spectrum_inversion = -1;
1364 break;
1365 }
1366 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
1367 case TRANSMISSION_MODE_2K:
1368 ch.nfft = 0;
1369 break;
1370 case TRANSMISSION_MODE_4K:
1371 ch.nfft = 2;
1372 break;
1373 case TRANSMISSION_MODE_8K:
1374 ch.nfft = 1;
1375 break;
1376 default:
1377 case TRANSMISSION_MODE_AUTO:
1378 ch.nfft = 1;
1379 break;
1380 }
1381 switch (state->fe[0]->dtv_property_cache.guard_interval) {
1382 case GUARD_INTERVAL_1_32:
1383 ch.guard = 0;
1384 break;
1385 case GUARD_INTERVAL_1_16:
1386 ch.guard = 1;
1387 break;
1388 case GUARD_INTERVAL_1_8:
1389 ch.guard = 2;
1390 break;
1391 case GUARD_INTERVAL_1_4:
1392 ch.guard = 3;
1393 break;
1394 default:
1395 case GUARD_INTERVAL_AUTO:
1396 ch.guard = -1;
1397 break;
1398 }
1399 switch (state->fe[0]->dtv_property_cache.modulation) {
1400 case QAM_64:
1401 ch.constellation = 2;
1402 break;
1403 case QAM_16:
1404 ch.constellation = 1;
1405 break;
1406 case QPSK:
1407 ch.constellation = 0;
1408 break;
1409 default:
1410 case QAM_AUTO:
1411 ch.constellation = -1;
1412 break;
1413 }
1414 switch (state->fe[0]->dtv_property_cache.hierarchy) {
1415 case HIERARCHY_NONE:
1416 ch.hrch = 0;
1417 break;
1418 case HIERARCHY_1:
1419 case HIERARCHY_2:
1420 case HIERARCHY_4:
1421 ch.hrch = 1;
1422 break;
1423 default:
1424 case HIERARCHY_AUTO:
1425 ch.hrch = -1;
1426 break;
1427 }
1428 ch.alpha = 1;
1429 switch (state->fe[0]->dtv_property_cache.code_rate_HP) {
1430 case FEC_1_2:
1431 ch.code_rate_hp = 1;
1432 break;
1433 case FEC_2_3:
1434 ch.code_rate_hp = 2;
1435 break;
1436 case FEC_3_4:
1437 ch.code_rate_hp = 3;
1438 break;
1439 case FEC_5_6:
1440 ch.code_rate_hp = 5;
1441 break;
1442 case FEC_7_8:
1443 ch.code_rate_hp = 7;
1444 break;
1445 default:
1446 case FEC_AUTO:
1447 ch.code_rate_hp = -1;
1448 break;
1449 }
1450 switch (state->fe[0]->dtv_property_cache.code_rate_LP) {
1451 case FEC_1_2:
1452 ch.code_rate_lp = 1;
1453 break;
1454 case FEC_2_3:
1455 ch.code_rate_lp = 2;
1456 break;
1457 case FEC_3_4:
1458 ch.code_rate_lp = 3;
1459 break;
1460 case FEC_5_6:
1461 ch.code_rate_lp = 5;
1462 break;
1463 case FEC_7_8:
1464 ch.code_rate_lp = 7;
1465 break;
1466 default:
1467 case FEC_AUTO:
1468 ch.code_rate_lp = -1;
1469 break;
1470 }
1471 ch.select_hp = 1;
1472 ch.intlv_native = 1;
1473
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001474 dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch);
Olivier Greniedd316c62011-01-04 04:28:59 -03001475
1476 return 0;
1477}
1478
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03001479static int dib9000_fw_tune(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001480{
1481 struct dib9000_state *state = fe->demodulator_priv;
1482 int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
1483 s8 i;
1484
1485 switch (state->tune_state) {
1486 case CT_DEMOD_START:
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001487 dib9000_fw_set_channel_head(state);
Olivier Greniedd316c62011-01-04 04:28:59 -03001488
1489 /* write the channel context - a channel is initialized to 0, so it is OK */
1490 dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
1491 dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info);
1492
1493 if (search)
1494 dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
1495 else {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03001496 dib9000_fw_set_channel_union(fe);
Olivier Greniedd316c62011-01-04 04:28:59 -03001497 dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
1498 }
1499 state->tune_state = CT_DEMOD_STEP_1;
1500 break;
1501 case CT_DEMOD_STEP_1:
1502 if (search)
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001503 dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
Olivier Greniedd316c62011-01-04 04:28:59 -03001504 else
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001505 dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
1506 i = (s8)state->i2c_read_buffer[0];
Olivier Greniedd316c62011-01-04 04:28:59 -03001507 switch (i) { /* something happened */
1508 case 0:
1509 break;
1510 case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */
1511 if (search)
1512 state->status = FE_STATUS_DEMOD_SUCCESS;
1513 else {
1514 state->tune_state = CT_DEMOD_STOP;
1515 state->status = FE_STATUS_LOCKED;
1516 }
1517 break;
1518 default:
1519 state->status = FE_STATUS_TUNE_FAILED;
1520 state->tune_state = CT_DEMOD_STOP;
1521 break;
1522 }
1523 break;
1524 default:
1525 ret = FE_CALLBACK_TIME_NEVER;
1526 break;
1527 }
1528
1529 return ret;
1530}
1531
1532static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff)
1533{
1534 struct dib9000_state *state = fe->demodulator_priv;
1535 u16 mode = (u16) onoff;
1536 return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1);
1537}
1538
1539static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode)
1540{
1541 struct dib9000_state *state = fe->demodulator_priv;
1542 u16 outreg, smo_mode;
1543
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001544 dprintk("setting output mode for demod %p to %d\n", fe, mode);
Olivier Greniedd316c62011-01-04 04:28:59 -03001545
1546 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001547 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Greniedd316c62011-01-04 04:28:59 -03001548 outreg = (1 << 10); /* 0x0400 */
1549 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001550 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Greniedd316c62011-01-04 04:28:59 -03001551 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
1552 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001553 case OUTMODE_MPEG2_SERIAL:
Olivier Greniedd316c62011-01-04 04:28:59 -03001554 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
1555 break;
1556 case OUTMODE_DIVERSITY:
1557 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
1558 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001559 case OUTMODE_MPEG2_FIFO:
Olivier Greniedd316c62011-01-04 04:28:59 -03001560 outreg = (1 << 10) | (5 << 6);
1561 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001562 case OUTMODE_HIGH_Z:
Olivier Greniedd316c62011-01-04 04:28:59 -03001563 outreg = 0;
1564 break;
1565 default:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001566 dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->fe[0]);
Olivier Greniedd316c62011-01-04 04:28:59 -03001567 return -EINVAL;
1568 }
1569
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001570 dib9000_write_word(state, 1795, outreg);
Olivier Greniedd316c62011-01-04 04:28:59 -03001571
1572 switch (mode) {
1573 case OUTMODE_MPEG2_PAR_GATED_CLK:
1574 case OUTMODE_MPEG2_PAR_CONT_CLK:
1575 case OUTMODE_MPEG2_SERIAL:
1576 case OUTMODE_MPEG2_FIFO:
1577 smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1);
1578 if (state->chip.d9.cfg.output_mpeg2_in_188_bytes)
1579 smo_mode |= (1 << 5);
1580 dib9000_write_word(state, 295, smo_mode);
1581 break;
1582 }
1583
1584 outreg = to_fw_output_mode(mode);
1585 return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1);
1586}
1587
1588static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1589{
1590 struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
1591 u16 i, len, t, index_msg;
1592
1593 for (index_msg = 0; index_msg < num; index_msg++) {
1594 if (msg[index_msg].flags & I2C_M_RD) { /* read */
1595 len = msg[index_msg].len;
1596 if (len > 16)
1597 len = 16;
1598
1599 if (dib9000_read_word(state, 790) != 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001600 dprintk("TunerITF: read busy\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001601
1602 dib9000_write_word(state, 784, (u16) (msg[index_msg].addr));
1603 dib9000_write_word(state, 787, (len / 2) - 1);
1604 dib9000_write_word(state, 786, 1); /* start read */
1605
1606 i = 1000;
1607 while (dib9000_read_word(state, 790) != (len / 2) && i)
1608 i--;
1609
1610 if (i == 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001611 dprintk("TunerITF: read failed\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001612
1613 for (i = 0; i < len; i += 2) {
1614 t = dib9000_read_word(state, 785);
1615 msg[index_msg].buf[i] = (t >> 8) & 0xff;
1616 msg[index_msg].buf[i + 1] = (t) & 0xff;
1617 }
1618 if (dib9000_read_word(state, 790) != 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001619 dprintk("TunerITF: read more data than expected\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001620 } else {
1621 i = 1000;
1622 while (dib9000_read_word(state, 789) && i)
1623 i--;
1624 if (i == 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001625 dprintk("TunerITF: write busy\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001626
1627 len = msg[index_msg].len;
1628 if (len > 16)
1629 len = 16;
1630
1631 for (i = 0; i < len; i += 2)
1632 dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]);
1633 dib9000_write_word(state, 784, (u16) msg[index_msg].addr);
1634 dib9000_write_word(state, 787, (len / 2) - 1);
1635 dib9000_write_word(state, 786, 0); /* start write */
1636
1637 i = 1000;
1638 while (dib9000_read_word(state, 791) > 0 && i)
1639 i--;
1640 if (i == 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001641 dprintk("TunerITF: write failed\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001642 }
1643 }
1644 return num;
1645}
1646
1647int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
1648{
1649 struct dib9000_state *state = fe->demodulator_priv;
1650
1651 state->component_bus_speed = speed;
1652 return 0;
1653}
1654EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed);
1655
1656static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1657{
1658 struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001659 u8 type = 0; /* I2C */
Olivier Greniedd316c62011-01-04 04:28:59 -03001660 u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001661 u16 scl = state->component_bus_speed; /* SCL frequency */
Olivier Greniedd316c62011-01-04 04:28:59 -03001662 struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER];
1663 u8 p[13] = { 0 };
1664
1665 p[0] = type;
1666 p[1] = port;
1667 p[2] = msg[0].addr << 1;
1668
1669 p[3] = (u8) scl & 0xff; /* scl */
1670 p[4] = (u8) (scl >> 8);
1671
Olivier Greniedd316c62011-01-04 04:28:59 -03001672 p[7] = 0;
1673 p[8] = 0;
1674
1675 p[9] = (u8) (msg[0].len);
1676 p[10] = (u8) (msg[0].len >> 8);
1677 if ((num > 1) && (msg[1].flags & I2C_M_RD)) {
1678 p[11] = (u8) (msg[1].len);
1679 p[12] = (u8) (msg[1].len >> 8);
1680 } else {
1681 p[11] = 0;
1682 p[12] = 0;
1683 }
1684
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001685 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001686 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001687 return 0;
1688 }
Olivier Greniedd316c62011-01-04 04:28:59 -03001689
1690 dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
1691
1692 { /* write-part */
1693 dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0);
1694 dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len);
1695 }
1696
1697 /* do the transaction */
1698 if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001699 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03001700 return 0;
1701 }
1702
1703 /* read back any possible result */
1704 if ((num > 1) && (msg[1].flags & I2C_M_RD))
1705 dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
1706
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001707 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03001708
1709 return num;
1710}
1711
1712static u32 dib9000_i2c_func(struct i2c_adapter *adapter)
1713{
1714 return I2C_FUNC_I2C;
1715}
1716
Gustavo A. R. Silva19779f42017-07-09 18:24:19 -04001717static const struct i2c_algorithm dib9000_tuner_algo = {
Olivier Greniedd316c62011-01-04 04:28:59 -03001718 .master_xfer = dib9000_tuner_xfer,
1719 .functionality = dib9000_i2c_func,
1720};
1721
Gustavo A. R. Silva19779f42017-07-09 18:24:19 -04001722static const struct i2c_algorithm dib9000_component_bus_algo = {
Olivier Greniedd316c62011-01-04 04:28:59 -03001723 .master_xfer = dib9000_fw_component_bus_xfer,
1724 .functionality = dib9000_i2c_func,
1725};
1726
1727struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
1728{
1729 struct dib9000_state *st = fe->demodulator_priv;
1730 return &st->tuner_adap;
1731}
Olivier Greniedd316c62011-01-04 04:28:59 -03001732EXPORT_SYMBOL(dib9000_get_tuner_interface);
1733
1734struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
1735{
1736 struct dib9000_state *st = fe->demodulator_priv;
1737 return &st->component_bus;
1738}
Olivier Greniedd316c62011-01-04 04:28:59 -03001739EXPORT_SYMBOL(dib9000_get_component_bus_interface);
1740
1741struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
1742{
1743 struct dib9000_state *st = fe->demodulator_priv;
1744 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1745}
Olivier Greniedd316c62011-01-04 04:28:59 -03001746EXPORT_SYMBOL(dib9000_get_i2c_master);
1747
1748int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
1749{
1750 struct dib9000_state *st = fe->demodulator_priv;
1751
1752 st->i2c.i2c_adap = i2c;
1753 return 0;
1754}
Olivier Greniedd316c62011-01-04 04:28:59 -03001755EXPORT_SYMBOL(dib9000_set_i2c_adapter);
1756
1757static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val)
1758{
1759 st->gpio_dir = dib9000_read_word(st, 773);
1760 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
1761 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
1762 dib9000_write_word(st, 773, st->gpio_dir);
1763
1764 st->gpio_val = dib9000_read_word(st, 774);
1765 st->gpio_val &= ~(1 << num); /* reset the direction bit */
1766 st->gpio_val |= (val & 0x01) << num; /* set the new value */
1767 dib9000_write_word(st, 774, st->gpio_val);
1768
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001769 dprintk("gpio dir: %04x: gpio val: %04x\n", st->gpio_dir, st->gpio_val);
Olivier Greniedd316c62011-01-04 04:28:59 -03001770
1771 return 0;
1772}
1773
1774int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
1775{
1776 struct dib9000_state *state = fe->demodulator_priv;
1777 return dib9000_cfg_gpio(state, num, dir, val);
1778}
Olivier Greniedd316c62011-01-04 04:28:59 -03001779EXPORT_SYMBOL(dib9000_set_gpio);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001780
Olivier Greniedd316c62011-01-04 04:28:59 -03001781int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1782{
1783 struct dib9000_state *state = fe->demodulator_priv;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001784 u16 val;
1785 int ret;
1786
1787 if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
1788 /* postpone the pid filtering cmd */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001789 dprintk("pid filter cmd postpone\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001790 state->pid_ctrl_index++;
1791 state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
1792 state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
1793 return 0;
1794 }
1795
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001796 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001797 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001798 return -EINTR;
1799 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001800
1801 val = dib9000_read_word(state, 294 + 1) & 0xffef;
Olivier Greniedd316c62011-01-04 04:28:59 -03001802 val |= (onoff & 0x1) << 4;
1803
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001804 dprintk("PID filter enabled %d\n", onoff);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001805 ret = dib9000_write_word(state, 294 + 1, val);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001806 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001807 return ret;
1808
Olivier Greniedd316c62011-01-04 04:28:59 -03001809}
Olivier Greniedd316c62011-01-04 04:28:59 -03001810EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001811
Olivier Greniedd316c62011-01-04 04:28:59 -03001812int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1813{
1814 struct dib9000_state *state = fe->demodulator_priv;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001815 int ret;
1816
1817 if (state->pid_ctrl_index != -2) {
1818 /* postpone the pid filtering cmd */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001819 dprintk("pid filter postpone\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001820 if (state->pid_ctrl_index < 9) {
1821 state->pid_ctrl_index++;
1822 state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
1823 state->pid_ctrl[state->pid_ctrl_index].id = id;
1824 state->pid_ctrl[state->pid_ctrl_index].pid = pid;
1825 state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
1826 } else
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001827 dprintk("can not add any more pid ctrl cmd\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001828 return 0;
1829 }
1830
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001831 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001832 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001833 return -EINTR;
1834 }
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001835 dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001836 ret = dib9000_write_word(state, 300 + 1 + id,
1837 onoff ? (1 << 13) | pid : 0);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001838 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001839 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03001840}
Olivier Greniedd316c62011-01-04 04:28:59 -03001841EXPORT_SYMBOL(dib9000_fw_pid_filter);
1842
1843int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
1844{
1845 struct dib9000_state *state = fe->demodulator_priv;
1846 return dib9000_fw_init(state);
1847}
Olivier Greniedd316c62011-01-04 04:28:59 -03001848EXPORT_SYMBOL(dib9000_firmware_post_pll_init);
1849
1850static void dib9000_release(struct dvb_frontend *demod)
1851{
1852 struct dib9000_state *st = demod->demodulator_priv;
1853 u8 index_frontend;
1854
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001855 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03001856 dvb_frontend_detach(st->fe[index_frontend]);
1857
Olivier Greniedd316c62011-01-04 04:28:59 -03001858 dibx000_exit_i2c_master(&st->i2c_master);
1859
1860 i2c_del_adapter(&st->tuner_adap);
1861 i2c_del_adapter(&st->component_bus);
1862 kfree(st->fe[0]);
1863 kfree(st);
1864}
1865
1866static int dib9000_wakeup(struct dvb_frontend *fe)
1867{
1868 return 0;
1869}
1870
1871static int dib9000_sleep(struct dvb_frontend *fe)
1872{
1873 struct dib9000_state *state = fe->demodulator_priv;
1874 u8 index_frontend;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001875 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03001876
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001877 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001878 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001879 return -EINTR;
1880 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001881 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001882 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
1883 if (ret < 0)
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001884 goto error;
Olivier Greniedd316c62011-01-04 04:28:59 -03001885 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001886 ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
1887
1888error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001889 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001890 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03001891}
1892
1893static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
1894{
1895 tune->min_delay_ms = 1000;
1896 return 0;
1897}
1898
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001899static int dib9000_get_frontend(struct dvb_frontend *fe,
1900 struct dtv_frontend_properties *c)
Olivier Greniedd316c62011-01-04 04:28:59 -03001901{
1902 struct dib9000_state *state = fe->demodulator_priv;
1903 u8 index_frontend, sub_index_frontend;
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001904 enum fe_status stat;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001905 int ret = 0;
1906
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001907 if (state->get_frontend_internal == 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001908 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001909 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001910 return -EINTR;
1911 }
1912 }
Olivier Greniedd316c62011-01-04 04:28:59 -03001913
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001914 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001915 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
1916 if (stat & FE_HAS_SYNC) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001917 dprintk("TPS lock on the slave%i\n", index_frontend);
Olivier Greniedd316c62011-01-04 04:28:59 -03001918
1919 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001920 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001921 for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
1922 sub_index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001923 if (sub_index_frontend != index_frontend) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001924 state->fe[sub_index_frontend]->dtv_property_cache.modulation =
1925 state->fe[index_frontend]->dtv_property_cache.modulation;
1926 state->fe[sub_index_frontend]->dtv_property_cache.inversion =
1927 state->fe[index_frontend]->dtv_property_cache.inversion;
1928 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode =
1929 state->fe[index_frontend]->dtv_property_cache.transmission_mode;
1930 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval =
1931 state->fe[index_frontend]->dtv_property_cache.guard_interval;
1932 state->fe[sub_index_frontend]->dtv_property_cache.hierarchy =
1933 state->fe[index_frontend]->dtv_property_cache.hierarchy;
1934 state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP =
1935 state->fe[index_frontend]->dtv_property_cache.code_rate_HP;
1936 state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP =
1937 state->fe[index_frontend]->dtv_property_cache.code_rate_LP;
1938 state->fe[sub_index_frontend]->dtv_property_cache.rolloff =
1939 state->fe[index_frontend]->dtv_property_cache.rolloff;
Olivier Greniedd316c62011-01-04 04:28:59 -03001940 }
1941 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001942 ret = 0;
1943 goto return_value;
Olivier Greniedd316c62011-01-04 04:28:59 -03001944 }
1945 }
1946
1947 /* get the channel from master chip */
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001948 ret = dib9000_fw_get_channel(fe);
Olivier Greniedd316c62011-01-04 04:28:59 -03001949 if (ret != 0)
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001950 goto return_value;
Olivier Greniedd316c62011-01-04 04:28:59 -03001951
1952 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001953 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001954 state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
1955 state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
1956 state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
1957 state->fe[index_frontend]->dtv_property_cache.modulation = c->modulation;
1958 state->fe[index_frontend]->dtv_property_cache.hierarchy = c->hierarchy;
1959 state->fe[index_frontend]->dtv_property_cache.code_rate_HP = c->code_rate_HP;
1960 state->fe[index_frontend]->dtv_property_cache.code_rate_LP = c->code_rate_LP;
1961 state->fe[index_frontend]->dtv_property_cache.rolloff = c->rolloff;
Olivier Greniedd316c62011-01-04 04:28:59 -03001962 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001963 ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03001964
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001965return_value:
1966 if (state->get_frontend_internal == 0)
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001967 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001968 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03001969}
1970
1971static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
1972{
1973 struct dib9000_state *state = fe->demodulator_priv;
1974 state->tune_state = tune_state;
1975 if (tune_state == CT_DEMOD_START)
1976 state->status = FE_STATUS_TUNE_PENDING;
1977
1978 return 0;
1979}
1980
1981static u32 dib9000_get_status(struct dvb_frontend *fe)
1982{
1983 struct dib9000_state *state = fe->demodulator_priv;
1984 return state->status;
1985}
1986
1987static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status)
1988{
1989 struct dib9000_state *state = fe->demodulator_priv;
1990
1991 memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext));
1992 return 0;
1993}
1994
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03001995static int dib9000_set_frontend(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001996{
1997 struct dib9000_state *state = fe->demodulator_priv;
1998 int sleep_time, sleep_time_slave;
1999 u32 frontend_status;
2000 u8 nbr_pending, exit_condition, index_frontend, index_frontend_success;
2001 struct dvb_frontend_parametersContext channel_status;
2002
2003 /* check that the correct parameters are set */
2004 if (state->fe[0]->dtv_property_cache.frequency == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002005 dprintk("dib9000: must specify frequency\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03002006 return 0;
2007 }
2008
2009 if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002010 dprintk("dib9000: must specify bandwidth\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03002011 return 0;
2012 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002013
2014 state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002015 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002016 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002017 return 0;
2018 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002019
Olivier Greniedd316c62011-01-04 04:28:59 -03002020 fe->dtv_property_cache.delivery_system = SYS_DVBT;
2021
2022 /* set the master status */
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002023 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO ||
2024 state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO ||
2025 state->fe[0]->dtv_property_cache.modulation == QAM_AUTO ||
2026 state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002027 /* no channel specified, autosearch the channel */
2028 state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
2029 } else
2030 state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
2031
2032 /* set mode and status for the different frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002033 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002034 dib9000_fw_set_diversity_in(state->fe[index_frontend], 1);
2035
2036 /* synchronization of the cache */
2037 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
2038
2039 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT;
2040 dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
2041
2042 dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status);
2043 dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2044 }
2045
2046 /* actual tune */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002047 exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
Olivier Greniedd316c62011-01-04 04:28:59 -03002048 index_frontend_success = 0;
2049 do {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03002050 sleep_time = dib9000_fw_tune(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002051 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03002052 sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
Olivier Greniedd316c62011-01-04 04:28:59 -03002053 if (sleep_time == FE_CALLBACK_TIME_NEVER)
2054 sleep_time = sleep_time_slave;
2055 else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
2056 sleep_time = sleep_time_slave;
2057 }
2058 if (sleep_time != FE_CALLBACK_TIME_NEVER)
2059 msleep(sleep_time / 10);
2060 else
2061 break;
2062
2063 nbr_pending = 0;
2064 exit_condition = 0;
2065 index_frontend_success = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002066 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002067 frontend_status = -dib9000_get_status(state->fe[index_frontend]);
2068 if (frontend_status > -FE_STATUS_TUNE_PENDING) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002069 exit_condition = 2; /* tune success */
Olivier Greniedd316c62011-01-04 04:28:59 -03002070 index_frontend_success = index_frontend;
2071 break;
2072 }
2073 if (frontend_status == -FE_STATUS_TUNE_PENDING)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002074 nbr_pending++; /* some frontends are still tuning */
Olivier Greniedd316c62011-01-04 04:28:59 -03002075 }
2076 if ((exit_condition != 2) && (nbr_pending == 0))
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002077 exit_condition = 1; /* if all tune are done and no success, exit: tune failed */
Olivier Greniedd316c62011-01-04 04:28:59 -03002078
2079 } while (exit_condition == 0);
2080
2081 /* check the tune result */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002082 if (exit_condition == 1) { /* tune failed */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002083 dprintk("tune failed\n");
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002084 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002085 /* tune failed; put all the pid filtering cmd to junk */
2086 state->pid_ctrl_index = -1;
Olivier Greniedd316c62011-01-04 04:28:59 -03002087 return 0;
2088 }
2089
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002090 dprintk("tune success on frontend%i\n", index_frontend_success);
Olivier Greniedd316c62011-01-04 04:28:59 -03002091
2092 /* synchronize all the channel cache */
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002093 state->get_frontend_internal = 1;
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02002094 dib9000_get_frontend(state->fe[0], &state->fe[0]->dtv_property_cache);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002095 state->get_frontend_internal = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002096
2097 /* retune the other frontends with the found channel */
2098 channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002099 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002100 /* only retune the frontends which was not tuned success */
2101 if (index_frontend != index_frontend_success) {
2102 dib9000_set_channel_status(state->fe[index_frontend], &channel_status);
2103 dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2104 }
2105 }
2106 do {
2107 sleep_time = FE_CALLBACK_TIME_NEVER;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002108 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002109 if (index_frontend != index_frontend_success) {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03002110 sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
Olivier Greniedd316c62011-01-04 04:28:59 -03002111 if (sleep_time == FE_CALLBACK_TIME_NEVER)
2112 sleep_time = sleep_time_slave;
2113 else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
2114 sleep_time = sleep_time_slave;
2115 }
2116 }
2117 if (sleep_time != FE_CALLBACK_TIME_NEVER)
2118 msleep(sleep_time / 10);
2119 else
2120 break;
2121
2122 nbr_pending = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002123 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002124 if (index_frontend != index_frontend_success) {
2125 frontend_status = -dib9000_get_status(state->fe[index_frontend]);
2126 if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING))
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002127 nbr_pending++; /* some frontends are still tuning */
Olivier Greniedd316c62011-01-04 04:28:59 -03002128 }
2129 }
2130 } while (nbr_pending != 0);
2131
2132 /* set the output mode */
2133 dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002134 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03002135 dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
2136
2137 /* turn off the diversity for the last frontend */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002138 dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
Olivier Greniedd316c62011-01-04 04:28:59 -03002139
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002140 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002141 if (state->pid_ctrl_index >= 0) {
2142 u8 index_pid_filter_cmd;
2143 u8 pid_ctrl_index = state->pid_ctrl_index;
2144
2145 state->pid_ctrl_index = -2;
2146 for (index_pid_filter_cmd = 0;
2147 index_pid_filter_cmd <= pid_ctrl_index;
2148 index_pid_filter_cmd++) {
2149 if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
2150 dib9000_fw_pid_filter_ctrl(state->fe[0],
2151 state->pid_ctrl[index_pid_filter_cmd].onoff);
2152 else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
2153 dib9000_fw_pid_filter(state->fe[0],
2154 state->pid_ctrl[index_pid_filter_cmd].id,
2155 state->pid_ctrl[index_pid_filter_cmd].pid,
2156 state->pid_ctrl[index_pid_filter_cmd].onoff);
2157 }
2158 }
2159 /* do not postpone any more the pid filtering */
2160 state->pid_ctrl_index = -2;
2161
Olivier Greniedd316c62011-01-04 04:28:59 -03002162 return 0;
2163}
2164
2165static u16 dib9000_read_lock(struct dvb_frontend *fe)
2166{
2167 struct dib9000_state *state = fe->demodulator_priv;
2168
2169 return dib9000_read_word(state, 535);
2170}
2171
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03002172static int dib9000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Olivier Greniedd316c62011-01-04 04:28:59 -03002173{
2174 struct dib9000_state *state = fe->demodulator_priv;
2175 u8 index_frontend;
2176 u16 lock = 0, lock_slave = 0;
2177
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002178 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002179 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002180 return -EINTR;
2181 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002182 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03002183 lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
2184
2185 lock = dib9000_read_word(state, 535);
2186
2187 *stat = 0;
2188
2189 if ((lock & 0x8000) || (lock_slave & 0x8000))
2190 *stat |= FE_HAS_SIGNAL;
2191 if ((lock & 0x3000) || (lock_slave & 0x3000))
2192 *stat |= FE_HAS_CARRIER;
2193 if ((lock & 0x0100) || (lock_slave & 0x0100))
2194 *stat |= FE_HAS_VITERBI;
2195 if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38))
2196 *stat |= FE_HAS_SYNC;
2197 if ((lock & 0x0008) || (lock_slave & 0x0008))
2198 *stat |= FE_HAS_LOCK;
2199
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002200 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002201
Olivier Greniedd316c62011-01-04 04:28:59 -03002202 return 0;
2203}
2204
2205static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
2206{
2207 struct dib9000_state *state = fe->demodulator_priv;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002208 u16 *c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002209 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002210
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002211 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002212 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002213 return -EINTR;
2214 }
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002215 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002216 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002217 ret = -EINTR;
2218 goto error;
2219 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002220 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002221 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002222 ret = -EIO;
2223 goto error;
2224 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002225 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
2226 state->i2c_read_buffer, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002227 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002228
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002229 c = (u16 *)state->i2c_read_buffer;
2230
Olivier Greniedd316c62011-01-04 04:28:59 -03002231 *ber = c[10] << 16 | c[11];
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002232
2233error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002234 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002235 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002236}
2237
2238static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
2239{
2240 struct dib9000_state *state = fe->demodulator_priv;
2241 u8 index_frontend;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002242 u16 *c = (u16 *)state->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03002243 u16 val;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002244 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002245
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002246 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002247 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002248 return -EINTR;
2249 }
Olivier Greniedd316c62011-01-04 04:28:59 -03002250 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002251 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002252 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
2253 if (val > 65535 - *strength)
2254 *strength = 65535;
2255 else
2256 *strength += val;
2257 }
2258
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002259 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002260 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002261 ret = -EINTR;
2262 goto error;
2263 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002264 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002265 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002266 ret = -EIO;
2267 goto error;
2268 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002269 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002270 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002271
2272 val = 65535 - c[4];
2273 if (val > 65535 - *strength)
2274 *strength = 65535;
2275 else
2276 *strength += val;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002277
2278error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002279 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002280 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002281}
2282
2283static u32 dib9000_get_snr(struct dvb_frontend *fe)
2284{
2285 struct dib9000_state *state = fe->demodulator_priv;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002286 u16 *c = (u16 *)state->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03002287 u32 n, s, exp;
2288 u16 val;
2289
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002290 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002291 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002292 return 0;
2293 }
Alexey Khoroshilov9bb24a72012-03-06 17:08:16 -03002294 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002295 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002296 return 0;
Alexey Khoroshilov9bb24a72012-03-06 17:08:16 -03002297 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002298 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002299 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002300
2301 val = c[7];
2302 n = (val >> 4) & 0xff;
2303 exp = ((val & 0xf) << 2);
2304 val = c[8];
2305 exp += ((val >> 14) & 0x3);
2306 if ((exp & 0x20) != 0)
2307 exp -= 0x40;
2308 n <<= exp + 16;
2309
2310 s = (val >> 6) & 0xFF;
2311 exp = (val & 0x3F);
2312 if ((exp & 0x20) != 0)
2313 exp -= 0x40;
2314 s <<= exp + 16;
2315
2316 if (n > 0) {
2317 u32 t = (s / n) << 16;
2318 return t + ((s << 16) - n * t) / n;
2319 }
2320 return 0xffffffff;
2321}
2322
2323static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
2324{
2325 struct dib9000_state *state = fe->demodulator_priv;
2326 u8 index_frontend;
2327 u32 snr_master;
2328
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002329 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002330 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002331 return -EINTR;
2332 }
Olivier Greniedd316c62011-01-04 04:28:59 -03002333 snr_master = dib9000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002334 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03002335 snr_master += dib9000_get_snr(state->fe[index_frontend]);
2336
2337 if ((snr_master >> 16) != 0) {
2338 snr_master = 10 * intlog10(snr_master >> 16);
2339 *snr = snr_master / ((1 << 24) / 10);
2340 } else
2341 *snr = 0;
2342
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002343 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002344
Olivier Greniedd316c62011-01-04 04:28:59 -03002345 return 0;
2346}
2347
2348static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
2349{
2350 struct dib9000_state *state = fe->demodulator_priv;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002351 u16 *c = (u16 *)state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002352 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002353
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002354 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002355 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002356 return -EINTR;
2357 }
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002358 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002359 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002360 ret = -EINTR;
2361 goto error;
2362 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002363 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002364 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002365 ret = -EIO;
2366 goto error;
2367 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002368 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002369 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002370
2371 *unc = c[12];
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002372
2373error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002374 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002375 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002376}
2377
2378int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
2379{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002380 int k = 0, ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002381 u8 new_addr = 0;
2382 struct i2c_device client = {.i2c_adap = i2c };
2383
Kees Cook6396bb22018-06-12 14:03:40 -07002384 client.i2c_write_buffer = kzalloc(4, GFP_KERNEL);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002385 if (!client.i2c_write_buffer) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002386 dprintk("%s: not enough memory\n", __func__);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002387 return -ENOMEM;
2388 }
Kees Cook6396bb22018-06-12 14:03:40 -07002389 client.i2c_read_buffer = kzalloc(4, GFP_KERNEL);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002390 if (!client.i2c_read_buffer) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002391 dprintk("%s: not enough memory\n", __func__);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002392 ret = -ENOMEM;
2393 goto error_memory;
2394 }
2395
Olivier Greniedd316c62011-01-04 04:28:59 -03002396 client.i2c_addr = default_addr + 16;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002397 dib9000_i2c_write16(&client, 1796, 0x0);
Olivier Greniedd316c62011-01-04 04:28:59 -03002398
2399 for (k = no_of_demods - 1; k >= 0; k--) {
2400 /* designated i2c address */
2401 new_addr = first_addr + (k << 1);
2402 client.i2c_addr = default_addr;
2403
2404 dib9000_i2c_write16(&client, 1817, 3);
2405 dib9000_i2c_write16(&client, 1796, 0);
2406 dib9000_i2c_write16(&client, 1227, 1);
2407 dib9000_i2c_write16(&client, 1227, 0);
2408
2409 client.i2c_addr = new_addr;
2410 dib9000_i2c_write16(&client, 1817, 3);
2411 dib9000_i2c_write16(&client, 1796, 0);
2412 dib9000_i2c_write16(&client, 1227, 1);
2413 dib9000_i2c_write16(&client, 1227, 0);
2414
2415 if (dib9000_identify(&client) == 0) {
2416 client.i2c_addr = default_addr;
2417 if (dib9000_identify(&client) == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002418 dprintk("DiB9000 #%d: not identified\n", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002419 ret = -EIO;
2420 goto error;
Olivier Greniedd316c62011-01-04 04:28:59 -03002421 }
2422 }
2423
2424 dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6));
2425 dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2);
2426
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002427 dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
Olivier Greniedd316c62011-01-04 04:28:59 -03002428 }
2429
2430 for (k = 0; k < no_of_demods; k++) {
2431 new_addr = first_addr | (k << 1);
2432 client.i2c_addr = new_addr;
2433
2434 dib9000_i2c_write16(&client, 1794, (new_addr << 2));
2435 dib9000_i2c_write16(&client, 1795, 0);
2436 }
2437
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002438error:
2439 kfree(client.i2c_read_buffer);
2440error_memory:
2441 kfree(client.i2c_write_buffer);
2442
2443 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002444}
Olivier Greniedd316c62011-01-04 04:28:59 -03002445EXPORT_SYMBOL(dib9000_i2c_enumeration);
2446
2447int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
2448{
2449 struct dib9000_state *state = fe->demodulator_priv;
2450 u8 index_frontend = 1;
2451
2452 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2453 index_frontend++;
2454 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002455 dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
Olivier Greniedd316c62011-01-04 04:28:59 -03002456 state->fe[index_frontend] = fe_slave;
2457 return 0;
2458 }
2459
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002460 dprintk("too many slave frontend\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03002461 return -ENOMEM;
2462}
2463EXPORT_SYMBOL(dib9000_set_slave_frontend);
2464
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002465struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Greniedd316c62011-01-04 04:28:59 -03002466{
2467 struct dib9000_state *state = fe->demodulator_priv;
2468
2469 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
2470 return NULL;
2471 return state->fe[slave_index];
2472}
2473EXPORT_SYMBOL(dib9000_get_slave_frontend);
2474
Max Kellermannbd336e62016-08-09 18:32:21 -03002475static const struct dvb_frontend_ops dib9000_ops;
Olivier Greniedd316c62011-01-04 04:28:59 -03002476struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg)
2477{
2478 struct dvb_frontend *fe;
2479 struct dib9000_state *st;
2480 st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL);
2481 if (st == NULL)
2482 return NULL;
2483 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
Jesper Juhl451a51b2011-04-07 16:34:30 -03002484 if (fe == NULL) {
2485 kfree(st);
Olivier Greniedd316c62011-01-04 04:28:59 -03002486 return NULL;
Jesper Juhl451a51b2011-04-07 16:34:30 -03002487 }
Olivier Greniedd316c62011-01-04 04:28:59 -03002488
2489 memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
2490 st->i2c.i2c_adap = i2c_adap;
2491 st->i2c.i2c_addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002492 st->i2c.i2c_write_buffer = st->i2c_write_buffer;
2493 st->i2c.i2c_read_buffer = st->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03002494
2495 st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
2496 st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
2497 st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
2498
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002499 mutex_init(&st->platform.risc.mbx_if_lock);
2500 mutex_init(&st->platform.risc.mbx_lock);
2501 mutex_init(&st->platform.risc.mem_lock);
2502 mutex_init(&st->platform.risc.mem_mbx_lock);
2503 mutex_init(&st->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002504 st->get_frontend_internal = 0;
2505
2506 st->pid_ctrl_index = -2;
Olivier Greniedd316c62011-01-04 04:28:59 -03002507
2508 st->fe[0] = fe;
2509 fe->demodulator_priv = st;
2510 memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops));
2511
2512 /* Ensure the output mode remains at the previous default if it's
2513 * not specifically set by the caller.
2514 */
2515 if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
2516 st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO;
2517
2518 if (dib9000_identify(&st->i2c) == 0)
2519 goto error;
2520
2521 dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr);
2522
2523 st->tuner_adap.dev.parent = i2c_adap->dev.parent;
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -04002524 strscpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS",
2525 sizeof(st->tuner_adap.name));
Olivier Greniedd316c62011-01-04 04:28:59 -03002526 st->tuner_adap.algo = &dib9000_tuner_algo;
2527 st->tuner_adap.algo_data = NULL;
2528 i2c_set_adapdata(&st->tuner_adap, st);
2529 if (i2c_add_adapter(&st->tuner_adap) < 0)
2530 goto error;
2531
2532 st->component_bus.dev.parent = i2c_adap->dev.parent;
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -04002533 strscpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS",
2534 sizeof(st->component_bus.name));
Olivier Greniedd316c62011-01-04 04:28:59 -03002535 st->component_bus.algo = &dib9000_component_bus_algo;
2536 st->component_bus.algo_data = NULL;
2537 st->component_bus_speed = 340;
2538 i2c_set_adapdata(&st->component_bus, st);
2539 if (i2c_add_adapter(&st->component_bus) < 0)
2540 goto component_bus_add_error;
2541
2542 dib9000_fw_reset(fe);
2543
2544 return fe;
2545
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002546component_bus_add_error:
Olivier Greniedd316c62011-01-04 04:28:59 -03002547 i2c_del_adapter(&st->tuner_adap);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002548error:
Olivier Greniedd316c62011-01-04 04:28:59 -03002549 kfree(st);
2550 return NULL;
2551}
Olivier Greniedd316c62011-01-04 04:28:59 -03002552EXPORT_SYMBOL(dib9000_attach);
2553
Max Kellermannbd336e62016-08-09 18:32:21 -03002554static const struct dvb_frontend_ops dib9000_ops = {
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002555 .delsys = { SYS_DVBT },
Olivier Greniedd316c62011-01-04 04:28:59 -03002556 .info = {
2557 .name = "DiBcom 9000",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -04002558 .frequency_min_hz = 44250 * kHz,
2559 .frequency_max_hz = 867250 * kHz,
2560 .frequency_stepsize_hz = 62500,
Olivier Greniedd316c62011-01-04 04:28:59 -03002561 .caps = FE_CAN_INVERSION_AUTO |
2562 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2563 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2564 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2565 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2566 },
2567
2568 .release = dib9000_release,
2569
2570 .init = dib9000_wakeup,
2571 .sleep = dib9000_sleep,
2572
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002573 .set_frontend = dib9000_set_frontend,
Olivier Greniedd316c62011-01-04 04:28:59 -03002574 .get_tune_settings = dib9000_fe_get_tune_settings,
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002575 .get_frontend = dib9000_get_frontend,
Olivier Greniedd316c62011-01-04 04:28:59 -03002576
2577 .read_status = dib9000_read_status,
2578 .read_ber = dib9000_read_ber,
2579 .read_signal_strength = dib9000_read_signal_strength,
2580 .read_snr = dib9000_read_snr,
2581 .read_ucblocks = dib9000_read_unc_blocks,
2582};
2583
Patrick Boettcher99e44da2016-01-24 12:56:58 -02002584MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
2585MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
Olivier Greniedd316c62011-01-04 04:28:59 -03002586MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator");
2587MODULE_LICENSE("GPL");