blob: 04d92d6142797e658ca0747f330f5c935af2a2c3 [file] [log] [blame]
Thomas Gleixnera10e7632019-05-31 01:09:32 -07001// SPDX-License-Identifier: GPL-2.0-only
Olivier Greniedd316c62011-01-04 04:28:59 -03002/*
3 * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family.
4 *
5 * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/)
Olivier Greniedd316c62011-01-04 04:28:59 -03006 */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03007
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
Olivier Greniedd316c62011-01-04 04:28:59 -030010#include <linux/kernel.h>
11#include <linux/i2c.h>
12#include <linux/mutex.h>
13
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050014#include <media/dvb_math.h>
15#include <media/dvb_frontend.h>
Olivier Greniedd316c62011-01-04 04:28:59 -030016
17#include "dib9000.h"
18#include "dibx000_common.h"
19
20static int debug;
21module_param(debug, int, 0644);
22MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
23
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -030024#define dprintk(fmt, arg...) do { \
25 if (debug) \
26 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
27 __func__, ##arg); \
28} while (0)
29
Olivier Greniedd316c62011-01-04 04:28:59 -030030#define MAX_NUMBER_OF_FRONTENDS 6
31
32struct i2c_device {
33 struct i2c_adapter *i2c_adap;
34 u8 i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030035 u8 *i2c_read_buffer;
36 u8 *i2c_write_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -030037};
38
Patrick Boettcher79fcce32011-08-03 12:08:21 -030039struct dib9000_pid_ctrl {
40#define DIB9000_PID_FILTER_CTRL 0
41#define DIB9000_PID_FILTER 1
42 u8 cmd;
43 u8 id;
44 u16 pid;
45 u8 onoff;
46};
47
Olivier Greniedd316c62011-01-04 04:28:59 -030048struct dib9000_state {
49 struct i2c_device i2c;
50
51 struct dibx000_i2c_master i2c_master;
52 struct i2c_adapter tuner_adap;
53 struct i2c_adapter component_bus;
54
55 u16 revision;
56 u8 reg_offs;
57
58 enum frontend_tune_state tune_state;
59 u32 status;
60 struct dvb_frontend_parametersContext channel_status;
61
62 u8 fe_id;
63
64#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff
65 u16 gpio_dir;
66#define DIB9000_GPIO_DEFAULT_VALUES 0x0000
67 u16 gpio_val;
68#define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff
69 u16 gpio_pwm_pos;
70
71 union { /* common for all chips */
72 struct {
73 u8 mobile_mode:1;
74 } host;
75
76 struct {
77 struct dib9000_fe_memory_map {
78 u16 addr;
79 u16 size;
80 } fe_mm[18];
81 u8 memcmd;
82
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -030083 struct mutex mbx_if_lock; /* to protect read/write operations */
84 struct mutex mbx_lock; /* to protect the whole mailbox handling */
Olivier Greniedd316c62011-01-04 04:28:59 -030085
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -030086 struct mutex mem_lock; /* to protect the memory accesses */
87 struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */
Olivier Greniedd316c62011-01-04 04:28:59 -030088
89#define MBX_MAX_WORDS (256 - 200 - 2)
90#define DIB9000_MSG_CACHE_SIZE 2
91 u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS];
92 u8 fw_is_running;
93 } risc;
94 } platform;
95
96 union { /* common for all platforms */
97 struct {
98 struct dib9000_config cfg;
99 } d9;
100 } chip;
101
102 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
103 u16 component_bus_speed;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300104
105 /* for the I2C transfer */
106 struct i2c_msg msg[2];
107 u8 i2c_write_buffer[255];
108 u8 i2c_read_buffer[255];
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300109 struct mutex demod_lock;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300110 u8 get_frontend_internal;
111 struct dib9000_pid_ctrl pid_ctrl[10];
112 s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
Olivier Greniedd316c62011-01-04 04:28:59 -0300113};
114
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300115static 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 -0300116 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 -0300117 0, 0, 0, 0, 0, 0, 0, 0
Olivier Greniedd316c62011-01-04 04:28:59 -0300118};
119
120enum dib9000_power_mode {
121 DIB9000_POWER_ALL = 0,
122
123 DIB9000_POWER_NO,
124 DIB9000_POWER_INTERF_ANALOG_AGC,
125 DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
126 DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD,
127 DIB9000_POWER_INTERFACE_ONLY,
128};
129
130enum dib9000_out_messages {
131 OUT_MSG_HBM_ACK,
132 OUT_MSG_HOST_BUF_FAIL,
133 OUT_MSG_REQ_VERSION,
134 OUT_MSG_BRIDGE_I2C_W,
135 OUT_MSG_BRIDGE_I2C_R,
136 OUT_MSG_BRIDGE_APB_W,
137 OUT_MSG_BRIDGE_APB_R,
138 OUT_MSG_SCAN_CHANNEL,
139 OUT_MSG_MONIT_DEMOD,
140 OUT_MSG_CONF_GPIO,
141 OUT_MSG_DEBUG_HELP,
142 OUT_MSG_SUBBAND_SEL,
143 OUT_MSG_ENABLE_TIME_SLICE,
144 OUT_MSG_FE_FW_DL,
145 OUT_MSG_FE_CHANNEL_SEARCH,
146 OUT_MSG_FE_CHANNEL_TUNE,
147 OUT_MSG_FE_SLEEP,
148 OUT_MSG_FE_SYNC,
149 OUT_MSG_CTL_MONIT,
150
151 OUT_MSG_CONF_SVC,
152 OUT_MSG_SET_HBM,
153 OUT_MSG_INIT_DEMOD,
154 OUT_MSG_ENABLE_DIVERSITY,
155 OUT_MSG_SET_OUTPUT_MODE,
156 OUT_MSG_SET_PRIORITARY_CHANNEL,
157 OUT_MSG_ACK_FRG,
158 OUT_MSG_INIT_PMU,
159};
160
161enum dib9000_in_messages {
162 IN_MSG_DATA,
163 IN_MSG_FRAME_INFO,
164 IN_MSG_CTL_MONIT,
165 IN_MSG_ACK_FREE_ITEM,
166 IN_MSG_DEBUG_BUF,
167 IN_MSG_MPE_MONITOR,
168 IN_MSG_RAWTS_MONITOR,
169 IN_MSG_END_BRIDGE_I2C_RW,
170 IN_MSG_END_BRIDGE_APB_RW,
171 IN_MSG_VERSION,
172 IN_MSG_END_OF_SCAN,
173 IN_MSG_MONIT_DEMOD,
174 IN_MSG_ERROR,
175 IN_MSG_FE_FW_DL_DONE,
176 IN_MSG_EVENT,
177 IN_MSG_ACK_CHANGE_SVC,
178 IN_MSG_HBM_PROF,
179};
180
181/* memory_access requests */
182#define FE_MM_W_CHANNEL 0
183#define FE_MM_W_FE_INFO 1
184#define FE_MM_RW_SYNC 2
185
186#define FE_SYNC_CHANNEL 1
187#define FE_SYNC_W_GENERIC_MONIT 2
188#define FE_SYNC_COMPONENT_ACCESS 3
189
190#define FE_MM_R_CHANNEL_SEARCH_STATE 3
191#define FE_MM_R_CHANNEL_UNION_CONTEXT 4
192#define FE_MM_R_FE_INFO 5
193#define FE_MM_R_FE_MONITOR 6
194
195#define FE_MM_W_CHANNEL_HEAD 7
196#define FE_MM_W_CHANNEL_UNION 8
197#define FE_MM_W_CHANNEL_CONTEXT 9
198#define FE_MM_R_CHANNEL_UNION 10
199#define FE_MM_R_CHANNEL_CONTEXT 11
200#define FE_MM_R_CHANNEL_TUNE_STATE 12
201
202#define FE_MM_R_GENERIC_MONITORING_SIZE 13
203#define FE_MM_W_GENERIC_MONITORING 14
204#define FE_MM_R_GENERIC_MONITORING 15
205
206#define FE_MM_W_COMPONENT_ACCESS 16
207#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300208static 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 -0300209static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len);
210
211static u16 to_fw_output_mode(u16 mode)
212{
213 switch (mode) {
214 case OUTMODE_HIGH_Z:
215 return 0;
216 case OUTMODE_MPEG2_PAR_GATED_CLK:
217 return 4;
218 case OUTMODE_MPEG2_PAR_CONT_CLK:
219 return 8;
220 case OUTMODE_MPEG2_SERIAL:
221 return 16;
222 case OUTMODE_DIVERSITY:
223 return 128;
224 case OUTMODE_MPEG2_FIFO:
225 return 2;
226 case OUTMODE_ANALOG_ADC:
227 return 1;
228 default:
229 return 0;
230 }
231}
232
Mauro Carvalho Chehab88d05182016-02-22 13:43:57 -0300233static int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 len, u16 attribute)
Olivier Greniedd316c62011-01-04 04:28:59 -0300234{
235 u32 chunk_size = 126;
236 u32 l;
237 int ret;
Olivier Greniedd316c62011-01-04 04:28:59 -0300238
239 if (state->platform.risc.fw_is_running && (reg < 1024))
240 return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
241
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300242 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
243 state->msg[0].addr = state->i2c.i2c_addr >> 1;
244 state->msg[0].flags = 0;
245 state->msg[0].buf = state->i2c_write_buffer;
246 state->msg[0].len = 2;
247 state->msg[1].addr = state->i2c.i2c_addr >> 1;
248 state->msg[1].flags = I2C_M_RD;
249 state->msg[1].buf = b;
250 state->msg[1].len = len;
251
252 state->i2c_write_buffer[0] = reg >> 8;
253 state->i2c_write_buffer[1] = reg & 0xff;
254
Olivier Greniedd316c62011-01-04 04:28:59 -0300255 if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300256 state->i2c_write_buffer[0] |= (1 << 5);
Olivier Greniedd316c62011-01-04 04:28:59 -0300257 if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300258 state->i2c_write_buffer[0] |= (1 << 4);
Olivier Greniedd316c62011-01-04 04:28:59 -0300259
260 do {
261 l = len < chunk_size ? len : chunk_size;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300262 state->msg[1].len = l;
263 state->msg[1].buf = b;
264 ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300265 if (ret != 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300266 dprintk("i2c read error on %d\n", reg);
Olivier Greniedd316c62011-01-04 04:28:59 -0300267 return -EREMOTEIO;
268 }
269
270 b += l;
271 len -= l;
272
273 if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
274 reg += l / 2;
275 } while ((ret == 0) && len);
276
277 return 0;
278}
279
280static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
281{
Olivier Greniedd316c62011-01-04 04:28:59 -0300282 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300283 {.addr = i2c->i2c_addr >> 1, .flags = 0,
284 .buf = i2c->i2c_write_buffer, .len = 2},
285 {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
286 .buf = i2c->i2c_read_buffer, .len = 2},
Olivier Greniedd316c62011-01-04 04:28:59 -0300287 };
288
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300289 i2c->i2c_write_buffer[0] = reg >> 8;
290 i2c->i2c_write_buffer[1] = reg & 0xff;
291
Olivier Greniedd316c62011-01-04 04:28:59 -0300292 if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300293 dprintk("read register %x error\n", reg);
Olivier Greniedd316c62011-01-04 04:28:59 -0300294 return 0;
295 }
296
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300297 return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
Olivier Greniedd316c62011-01-04 04:28:59 -0300298}
299
300static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
301{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300302 if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
Olivier Greniedd316c62011-01-04 04:28:59 -0300303 return 0;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300304 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Olivier Greniedd316c62011-01-04 04:28:59 -0300305}
306
307static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
308{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300309 if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
310 attribute) != 0)
Olivier Greniedd316c62011-01-04 04:28:59 -0300311 return 0;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300312 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Olivier Greniedd316c62011-01-04 04:28:59 -0300313}
314
315#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)
316
Mauro Carvalho Chehab88d05182016-02-22 13:43:57 -0300317static int dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *buf, u32 len, u16 attribute)
Olivier Greniedd316c62011-01-04 04:28:59 -0300318{
Olivier Greniedd316c62011-01-04 04:28:59 -0300319 u32 chunk_size = 126;
320 u32 l;
321 int ret;
322
Olivier Greniedd316c62011-01-04 04:28:59 -0300323 if (state->platform.risc.fw_is_running && (reg < 1024)) {
324 if (dib9000_risc_apb_access_write
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300325 (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 -0300326 return -EINVAL;
327 return 0;
328 }
329
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300330 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
331 state->msg[0].addr = state->i2c.i2c_addr >> 1;
332 state->msg[0].flags = 0;
333 state->msg[0].buf = state->i2c_write_buffer;
334 state->msg[0].len = len + 2;
335
336 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
337 state->i2c_write_buffer[1] = (reg) & 0xff;
Olivier Greniedd316c62011-01-04 04:28:59 -0300338
339 if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300340 state->i2c_write_buffer[0] |= (1 << 5);
Olivier Greniedd316c62011-01-04 04:28:59 -0300341 if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300342 state->i2c_write_buffer[0] |= (1 << 4);
Olivier Greniedd316c62011-01-04 04:28:59 -0300343
344 do {
345 l = len < chunk_size ? len : chunk_size;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300346 state->msg[0].len = l + 2;
347 memcpy(&state->i2c_write_buffer[2], buf, l);
Olivier Greniedd316c62011-01-04 04:28:59 -0300348
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300349 ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300350
351 buf += l;
352 len -= l;
353
354 if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
355 reg += l / 2;
356 } while ((ret == 0) && len);
357
358 return ret;
359}
360
361static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
362{
Olivier Greniedd316c62011-01-04 04:28:59 -0300363 struct i2c_msg msg = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300364 .addr = i2c->i2c_addr >> 1, .flags = 0,
365 .buf = i2c->i2c_write_buffer, .len = 4
Olivier Greniedd316c62011-01-04 04:28:59 -0300366 };
367
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300368 i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
369 i2c->i2c_write_buffer[1] = reg & 0xff;
370 i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
371 i2c->i2c_write_buffer[3] = val & 0xff;
372
Olivier Greniedd316c62011-01-04 04:28:59 -0300373 return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
374}
375
376static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val)
377{
378 u8 b[2] = { val >> 8, val & 0xff };
379 return dib9000_write16_attr(state, reg, b, 2, 0);
380}
381
382static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute)
383{
384 u8 b[2] = { val >> 8, val & 0xff };
385 return dib9000_write16_attr(state, reg, b, 2, attribute);
386}
387
388#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0)
389#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
390#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))
391
392#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0)
393#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0)
394
395#define MAC_IRQ (1 << 1)
396#define IRQ_POL_MSK (1 << 4)
397
398#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)
399#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)
400
401static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading)
402{
403 u8 b[14] = { 0 };
404
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300405/* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */
406/* b[0] = 0 << 7; */
Olivier Greniedd316c62011-01-04 04:28:59 -0300407 b[1] = 1;
408
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300409/* b[2] = 0; */
410/* b[3] = 0; */
411 b[4] = (u8) (addr >> 8);
Olivier Greniedd316c62011-01-04 04:28:59 -0300412 b[5] = (u8) (addr & 0xff);
413
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300414/* b[10] = 0; */
415/* b[11] = 0; */
416 b[12] = (u8) (addr >> 8);
Olivier Greniedd316c62011-01-04 04:28:59 -0300417 b[13] = (u8) (addr & 0xff);
418
419 addr += len;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300420/* b[6] = 0; */
421/* b[7] = 0; */
422 b[8] = (u8) (addr >> 8);
Olivier Greniedd316c62011-01-04 04:28:59 -0300423 b[9] = (u8) (addr & 0xff);
424
425 dib9000_write(state, 1056, b, 14);
426 if (reading)
427 dib9000_write_word(state, 1056, (1 << 15) | 1);
428 state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */
429}
430
431static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd)
432{
433 struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f];
434 /* decide whether we need to "refresh" the memory controller */
435 if (state->platform.risc.memcmd == cmd && /* same command */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300436 !(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 -0300437 return;
438 dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80);
439 state->platform.risc.memcmd = cmd;
440}
441
442static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len)
443{
444 if (!state->platform.risc.fw_is_running)
445 return -EIO;
446
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300447 if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300448 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300449 return -EINTR;
450 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300451 dib9000_risc_mem_setup(state, cmd | 0x80);
452 dib9000_risc_mem_read_chunks(state, b, len);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300453 mutex_unlock(&state->platform.risc.mem_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300454 return 0;
455}
456
457static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b)
458{
459 struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd];
460 if (!state->platform.risc.fw_is_running)
461 return -EIO;
462
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300463 if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300464 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300465 return -EINTR;
466 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300467 dib9000_risc_mem_setup(state, cmd);
468 dib9000_risc_mem_write_chunks(state, b, m->size);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300469 mutex_unlock(&state->platform.risc.mem_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300470 return 0;
471}
472
473static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len)
474{
475 u16 offs;
476
477 if (risc_id == 1)
478 offs = 16;
479 else
480 offs = 0;
481
482 /* config crtl reg */
483 dib9000_write_word(state, 1024 + offs, 0x000f);
484 dib9000_write_word(state, 1025 + offs, 0);
485 dib9000_write_word(state, 1031 + offs, key);
486
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300487 dprintk("going to download %dB of microcode\n", len);
Olivier Greniedd316c62011-01-04 04:28:59 -0300488 if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300489 dprintk("error while downloading microcode for RISC %c\n", 'A' + risc_id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300490 return -EIO;
491 }
492
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300493 dprintk("Microcode for RISC %c loaded\n", 'A' + risc_id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300494
495 return 0;
496}
497
498static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id)
499{
500 u16 mbox_offs;
501 u16 reset_reg;
502 u16 tries = 1000;
503
504 if (risc_id == 1)
505 mbox_offs = 16;
506 else
507 mbox_offs = 0;
508
509 /* Reset mailbox */
510 dib9000_write_word(state, 1027 + mbox_offs, 0x8000);
511
512 /* Read reset status */
513 do {
514 reset_reg = dib9000_read_word(state, 1027 + mbox_offs);
515 msleep(100);
516 } while ((reset_reg & 0x8000) && --tries);
517
518 if (reset_reg & 0x8000) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300519 dprintk("MBX: init ERROR, no response from RISC %c\n", 'A' + risc_id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300520 return -EIO;
521 }
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300522 dprintk("MBX: initialized\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300523 return 0;
524}
525
526#define MAX_MAILBOX_TRY 100
527static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr)
528{
Dan Carpenterb00aff62011-01-19 11:28:27 -0300529 u8 *d, b[2];
Olivier Greniedd316c62011-01-04 04:28:59 -0300530 u16 tmp;
531 u16 size;
532 u32 i;
Dan Carpenterb00aff62011-01-19 11:28:27 -0300533 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300534
535 if (!state->platform.risc.fw_is_running)
536 return -EINVAL;
537
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300538 if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300539 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300540 return -EINTR;
541 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300542 tmp = MAX_MAILBOX_TRY;
543 do {
544 size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
545 if ((size + len + 1) > MBX_MAX_WORDS && --tmp) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300546 dprintk("MBX: RISC mbx full, retrying\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300547 msleep(100);
548 } else
549 break;
550 } while (1);
551
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300552 /*dprintk( "MBX: size: %d\n", size); */
Olivier Greniedd316c62011-01-04 04:28:59 -0300553
554 if (tmp == 0) {
555 ret = -EINVAL;
556 goto out;
557 }
558#ifdef DUMP_MSG
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300559 dprintk("--> %02x %d %*ph\n", id, len + 1, len, data);
Olivier Greniedd316c62011-01-04 04:28:59 -0300560#endif
561
562 /* byte-order conversion - works on big (where it is not necessary) or little endian */
563 d = (u8 *) data;
564 for (i = 0; i < len; i++) {
565 tmp = data[i];
566 *d++ = tmp >> 8;
567 *d++ = tmp & 0xff;
568 }
569
570 /* write msg */
571 b[0] = id;
572 b[1] = len + 1;
573 if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) {
574 ret = -EIO;
575 goto out;
576 }
577
578 /* update register nb_mes_in_RX */
579 ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
580
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300581out:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300582 mutex_unlock(&state->platform.risc.mbx_if_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300583
584 return ret;
585}
586
587static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr)
588{
589#ifdef DUMP_MSG
590 u16 *d = data;
591#endif
592
593 u16 tmp, i;
594 u8 size;
595 u8 mc_base;
596
597 if (!state->platform.risc.fw_is_running)
598 return 0;
599
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300600 if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300601 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300602 return 0;
603 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300604 if (risc_id == 1)
605 mc_base = 16;
606 else
607 mc_base = 0;
608
609 /* Length and type in the first word */
610 *data = dib9000_read_word_attr(state, 1029 + mc_base, attr);
611
612 size = *data & 0xff;
613 if (size <= MBX_MAX_WORDS) {
614 data++;
615 size--; /* Initial word already read */
616
617 dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr);
618
619 /* to word conversion */
620 for (i = 0; i < size; i++) {
621 tmp = *data;
622 *data = (tmp >> 8) | (tmp << 8);
623 data++;
624 }
625
626#ifdef DUMP_MSG
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300627 dprintk("<--\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300628 for (i = 0; i < size + 1; i++)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300629 dprintk("%04x\n", d[i]);
Olivier Greniedd316c62011-01-04 04:28:59 -0300630 dprintk("\n");
631#endif
632 } else {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300633 dprintk("MBX: message is too big for message cache (%d), flushing message\n", size);
Olivier Greniedd316c62011-01-04 04:28:59 -0300634 size--; /* Initial word already read */
635 while (size--)
636 dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr);
637 }
638 /* Update register nb_mes_in_TX */
639 dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
640
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300641 mutex_unlock(&state->platform.risc.mbx_if_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300642
643 return size + 1;
644}
645
646static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size)
647{
648 u32 ts = data[1] << 16 | data[0];
649 char *b = (char *)&data[2];
650
651 b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */
652 if (*b == '~') {
653 b++;
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300654 dprintk("%s\n", b);
Olivier Greniedd316c62011-01-04 04:28:59 -0300655 } else
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300656 dprintk("RISC%d: %d.%04d %s\n",
657 state->fe_id,
658 ts / 10000, ts % 10000, *b ? b : "<empty>");
Olivier Greniedd316c62011-01-04 04:28:59 -0300659 return 1;
660}
661
662static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr)
663{
664 int i;
665 u8 size;
666 u16 *block;
667 /* find a free slot */
668 for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
669 block = state->platform.risc.message_cache[i];
670 if (*block == 0) {
671 size = dib9000_mbx_read(state, block, 1, attr);
672
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300673/* dprintk( "MBX: fetched %04x message to cache\n", *block); */
Olivier Greniedd316c62011-01-04 04:28:59 -0300674
675 switch (*block >> 8) {
676 case IN_MSG_DEBUG_BUF:
677 dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */
678 *block = 0; /* free the block */
679 break;
680#if 0
681 case IN_MSG_DATA: /* FE-TRACE */
682 dib9000_risc_data_process(state, block + 1, size);
683 *block = 0;
684 break;
685#endif
686 default:
687 break;
688 }
689
690 return 1;
691 }
692 }
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300693 dprintk("MBX: no free cache-slot found for new message...\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300694 return -1;
695}
696
697static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr)
698{
699 if (risc_id == 0)
700 return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */
701 else
702 return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */
703}
704
705static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
706{
707 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -0300708
709 if (!state->platform.risc.fw_is_running)
710 return -1;
711
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300712 if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300713 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -0300714 return -1;
715 }
Olivier Greniedd316c62011-01-04 04:28:59 -0300716
717 if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */
718 ret = dib9000_mbx_fetch_to_cache(state, attr);
719
Hans Verkuilfdf07b02012-04-20 08:04:48 -0300720 dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300721/* if (tmp) */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300722/* dprintk( "cleared IRQ: %x\n", tmp); */
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -0300723 mutex_unlock(&state->platform.risc.mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -0300724
725 return ret;
726}
727
728static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr)
729{
730 u8 i;
731 u16 *block;
732 u16 timeout = 30;
733
734 *msg = 0;
735 do {
736 /* dib9000_mbx_get_from_cache(); */
737 for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
738 block = state->platform.risc.message_cache[i];
739 if ((*block >> 8) == id) {
740 *size = (*block & 0xff) - 1;
741 memcpy(msg, block + 1, (*size) * 2);
742 *block = 0; /* free the block */
743 i = 0; /* signal that we found a message */
744 break;
745 }
746 }
747
748 if (i == 0)
749 break;
750
751 if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */
752 return -1;
753
754 } while (--timeout);
755
756 if (timeout == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300757 dprintk("waiting for message %d timed out\n", id);
Olivier Greniedd316c62011-01-04 04:28:59 -0300758 return -1;
759 }
760
761 return i == 0;
762}
763
764static int dib9000_risc_check_version(struct dib9000_state *state)
765{
766 u8 r[4];
767 u8 size;
768 u16 fw_version = 0;
769
770 if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0)
771 return -EIO;
772
773 if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0)
774 return -EIO;
775
776 fw_version = (r[0] << 8) | r[1];
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300777 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 -0300778
779 if ((fw_version >> 10) != 7)
780 return -EINVAL;
781
782 switch (fw_version & 0x3ff) {
783 case 11:
784 case 12:
785 case 14:
786 case 15:
787 case 16:
788 case 17:
789 break;
790 default:
791 dprintk("RISC: invalid firmware version");
792 return -EINVAL;
793 }
794
795 dprintk("RISC: valid firmware version");
796 return 0;
797}
798
799static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB)
800{
801 /* Reconfig pool mac ram */
802 dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */
803 dib9000_write_word(state, 1226, 0x05);
804
805 /* Toggles IP crypto to Host APB interface. */
806 dib9000_write_word(state, 1542, 1);
807
808 /* Set jump and no jump in the dma box */
809 dib9000_write_word(state, 1074, 0);
810 dib9000_write_word(state, 1075, 0);
811
812 /* Set MAC as APB Master. */
813 dib9000_write_word(state, 1237, 0);
814
815 /* Reset the RISCs */
816 if (codeA != NULL)
817 dib9000_write_word(state, 1024, 2);
818 else
819 dib9000_write_word(state, 1024, 15);
820 if (codeB != NULL)
821 dib9000_write_word(state, 1040, 2);
822
823 if (codeA != NULL)
824 dib9000_firmware_download(state, 0, 0x1234, codeA, lenA);
825 if (codeB != NULL)
826 dib9000_firmware_download(state, 1, 0x1234, codeB, lenB);
827
828 /* Run the RISCs */
829 if (codeA != NULL)
830 dib9000_write_word(state, 1024, 0);
831 if (codeB != NULL)
832 dib9000_write_word(state, 1040, 0);
833
834 if (codeA != NULL)
835 if (dib9000_mbx_host_init(state, 0) != 0)
836 return -EIO;
837 if (codeB != NULL)
838 if (dib9000_mbx_host_init(state, 1) != 0)
839 return -EIO;
840
841 msleep(100);
842 state->platform.risc.fw_is_running = 1;
843
844 if (dib9000_risc_check_version(state) != 0)
845 return -EINVAL;
846
847 state->platform.risc.memcmd = 0xff;
848 return 0;
849}
850
851static u16 dib9000_identify(struct i2c_device *client)
852{
853 u16 value;
854
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300855 value = dib9000_i2c_read16(client, 896);
856 if (value != 0x01b3) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300857 dprintk("wrong Vendor ID (0x%x)\n", value);
Olivier Greniedd316c62011-01-04 04:28:59 -0300858 return 0;
859 }
860
861 value = dib9000_i2c_read16(client, 897);
862 if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300863 dprintk("wrong Device ID (0x%x)\n", value);
Olivier Greniedd316c62011-01-04 04:28:59 -0300864 return 0;
865 }
866
867 /* protect this driver to be used with 7000PC */
868 if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300869 dprintk("this driver does not work with DiB7000PC\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300870 return 0;
871 }
872
873 switch (value) {
874 case 0x4000:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300875 dprintk("found DiB7000MA/PA/MB/PB\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300876 break;
877 case 0x4001:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300878 dprintk("found DiB7000HC\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300879 break;
880 case 0x4002:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300881 dprintk("found DiB7000MC\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300882 break;
883 case 0x4003:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300884 dprintk("found DiB9000A\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300885 break;
886 case 0x4004:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300887 dprintk("found DiB9000H\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300888 break;
889 case 0x4005:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -0300890 dprintk("found DiB9000M\n");
Olivier Greniedd316c62011-01-04 04:28:59 -0300891 break;
892 }
893
894 return value;
895}
896
897static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode)
898{
899 /* by default everything is going to be powered off */
900 u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906;
901 u8 offset;
902
903 if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005)
904 offset = 1;
905 else
906 offset = 0;
907
908 reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */
909
910 /* now, depending on the requested mode, we power on */
911 switch (mode) {
912 /* power up everything in the demod */
913 case DIB9000_POWER_ALL:
914 reg_903 = 0x0000;
915 reg_904 = 0x0000;
916 reg_905 = 0x0000;
917 reg_906 = 0x0000;
918 break;
919
920 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
921 case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
922 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
923 break;
924
925 case DIB9000_POWER_INTERF_ANALOG_AGC:
926 reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
927 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
928 reg_906 &= ~((1 << 0));
929 break;
930
931 case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
932 reg_903 = 0x0000;
933 reg_904 = 0x801f;
934 reg_905 = 0x0000;
935 reg_906 &= ~((1 << 0));
936 break;
937
938 case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD:
939 reg_903 = 0x0000;
940 reg_904 = 0x8000;
941 reg_905 = 0x010b;
942 reg_906 &= ~((1 << 0));
943 break;
944 default:
945 case DIB9000_POWER_NO:
946 break;
947 }
948
949 /* always power down unused parts */
950 if (!state->platform.host.mobile_mode)
951 reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
952
953 /* P_sdio_select_clk = 0 on MC and after */
954 if (state->revision != 0x4000)
955 reg_906 <<= 1;
956
957 dib9000_write_word(state, 903 + offset, reg_903);
958 dib9000_write_word(state, 904 + offset, reg_904);
959 dib9000_write_word(state, 905 + offset, reg_905);
960 dib9000_write_word(state, 906 + offset, reg_906);
961}
962
963static int dib9000_fw_reset(struct dvb_frontend *fe)
964{
965 struct dib9000_state *state = fe->demodulator_priv;
966
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300967 dib9000_write_word(state, 1817, 0x0003);
Olivier Greniedd316c62011-01-04 04:28:59 -0300968
969 dib9000_write_word(state, 1227, 1);
970 dib9000_write_word(state, 1227, 0);
971
972 switch ((state->revision = dib9000_identify(&state->i2c))) {
973 case 0x4003:
974 case 0x4004:
975 case 0x4005:
976 state->reg_offs = 1;
977 break;
978 default:
979 return -EINVAL;
980 }
981
982 /* reset the i2c-master to use the host interface */
983 dibx000_reset_i2c_master(&state->i2c_master);
984
985 dib9000_set_power_mode(state, DIB9000_POWER_ALL);
986
987 /* unforce divstr regardless whether i2c enumeration was done or not */
988 dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1));
989 dib9000_write_word(state, 1796, 0);
990 dib9000_write_word(state, 1805, 0x805);
991
992 /* restart all parts */
993 dib9000_write_word(state, 898, 0xffff);
994 dib9000_write_word(state, 899, 0xffff);
995 dib9000_write_word(state, 900, 0x0001);
996 dib9000_write_word(state, 901, 0xff19);
997 dib9000_write_word(state, 902, 0x003c);
998
999 dib9000_write_word(state, 898, 0);
1000 dib9000_write_word(state, 899, 0);
1001 dib9000_write_word(state, 900, 0);
1002 dib9000_write_word(state, 901, 0);
1003 dib9000_write_word(state, 902, 0);
1004
1005 dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives);
1006
1007 dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY);
1008
1009 return 0;
1010}
1011
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001012static 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 -03001013{
1014 u16 mb[10];
1015 u8 i, s;
1016
1017 if (address >= 1024 || !state->platform.risc.fw_is_running)
1018 return -EINVAL;
1019
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05001020 /* dprintk( "APB access through rd fw %d %x\n", address, attribute); */
Olivier Greniedd316c62011-01-04 04:28:59 -03001021
1022 mb[0] = (u16) address;
1023 mb[1] = len / 2;
1024 dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute);
1025 switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) {
1026 case 1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001027 s--;
Olivier Greniedd316c62011-01-04 04:28:59 -03001028 for (i = 0; i < s; i++) {
1029 b[i * 2] = (mb[i + 1] >> 8) & 0xff;
1030 b[i * 2 + 1] = (mb[i + 1]) & 0xff;
1031 }
1032 return 0;
1033 default:
1034 return -EIO;
1035 }
1036 return -EIO;
1037}
1038
1039static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len)
1040{
1041 u16 mb[10];
1042 u8 s, i;
1043
1044 if (address >= 1024 || !state->platform.risc.fw_is_running)
1045 return -EINVAL;
1046
Heinrich Schuchardt18d75a02014-06-19 11:49:40 -03001047 if (len > 18)
1048 return -EINVAL;
1049
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05001050 /* dprintk( "APB access through wr fw %d %x\n", address, attribute); */
Olivier Greniedd316c62011-01-04 04:28:59 -03001051
Heinrich Schuchardt18d75a02014-06-19 11:49:40 -03001052 mb[0] = (u16)address;
1053 for (i = 0; i + 1 < len; i += 2)
1054 mb[1 + i / 2] = b[i] << 8 | b[i + 1];
1055 if (len & 1)
1056 mb[1 + len / 2] = b[len - 1] << 8;
Olivier Greniedd316c62011-01-04 04:28:59 -03001057
Heinrich Schuchardt18d75a02014-06-19 11:49:40 -03001058 dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, (3 + len) / 2, attribute);
Olivier Greniedd316c62011-01-04 04:28:59 -03001059 return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
1060}
1061
1062static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
1063{
1064 u8 index_loop = 10;
1065
1066 if (!state->platform.risc.fw_is_running)
1067 return 0;
1068 dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
1069 do {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001070 dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
1071 } while (state->i2c_read_buffer[0] && index_loop--);
Olivier Greniedd316c62011-01-04 04:28:59 -03001072
1073 if (index_loop > 0)
1074 return 0;
1075 return -EIO;
1076}
1077
1078static int dib9000_fw_init(struct dib9000_state *state)
1079{
1080 struct dibGPIOFunction *f;
1081 u16 b[40] = { 0 };
1082 u8 i;
1083 u8 size;
1084
1085 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 -03001086 return -EIO;
1087
1088 /* initialize the firmware */
1089 for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) {
1090 f = &state->chip.d9.cfg.gpio_function[i];
1091 if (f->mask) {
1092 switch (f->function) {
1093 case BOARD_GPIO_FUNCTION_COMPONENT_ON:
1094 b[0] = (u16) f->mask;
1095 b[1] = (u16) f->direction;
1096 b[2] = (u16) f->value;
1097 break;
1098 case BOARD_GPIO_FUNCTION_COMPONENT_OFF:
1099 b[3] = (u16) f->mask;
1100 b[4] = (u16) f->direction;
1101 b[5] = (u16) f->value;
1102 break;
1103 }
1104 }
1105 }
1106 if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0)
1107 return -EIO;
1108
1109 /* subband */
1110 b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */
1111 for (i = 0; i < state->chip.d9.cfg.subband.size; i++) {
1112 b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz;
1113 b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask;
1114 b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction;
1115 b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value;
Olivier Greniedd316c62011-01-04 04:28:59 -03001116 }
1117 b[1 + i * 4] = 0; /* fe_id */
1118 if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0)
1119 return -EIO;
1120
1121 /* 0 - id, 1 - no_of_frontends */
1122 b[0] = (0 << 8) | 1;
1123 /* 0 = i2c-address demod, 0 = tuner */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001124 b[1] = (0 << 8) | (0);
Olivier Greniedd316c62011-01-04 04:28:59 -03001125 b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff);
1126 b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff);
1127 b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff);
1128 b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff);
1129 b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff);
1130 b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff);
1131 b[29] = state->chip.d9.cfg.if_drives;
1132 if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0)
1133 return -EIO;
1134
1135 if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0)
1136 return -EIO;
1137
1138 if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0)
1139 return -EIO;
1140
1141 if (size > ARRAY_SIZE(b)) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001142 dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size,
1143 (int)ARRAY_SIZE(b));
Olivier Greniedd316c62011-01-04 04:28:59 -03001144 return -EINVAL;
1145 }
1146
1147 for (i = 0; i < size; i += 2) {
1148 state->platform.risc.fe_mm[i / 2].addr = b[i + 0];
1149 state->platform.risc.fe_mm[i / 2].size = b[i + 1];
Olivier Greniedd316c62011-01-04 04:28:59 -03001150 }
1151
1152 return 0;
1153}
1154
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001155static void dib9000_fw_set_channel_head(struct dib9000_state *state)
Olivier Greniedd316c62011-01-04 04:28:59 -03001156{
1157 u8 b[9];
1158 u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
1159 if (state->fe_id % 2)
1160 freq += 101;
1161
1162 b[0] = (u8) ((freq >> 0) & 0xff);
1163 b[1] = (u8) ((freq >> 8) & 0xff);
1164 b[2] = (u8) ((freq >> 16) & 0xff);
1165 b[3] = (u8) ((freq >> 24) & 0xff);
1166 b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff);
1167 b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff);
1168 b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff);
1169 b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff);
1170 b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */
1171 if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT)
1172 b[8] |= 1;
1173 dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
1174}
1175
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001176static int dib9000_fw_get_channel(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001177{
1178 struct dib9000_state *state = fe->demodulator_priv;
1179 struct dibDVBTChannel {
1180 s8 spectrum_inversion;
1181
1182 s8 nfft;
1183 s8 guard;
1184 s8 constellation;
1185
1186 s8 hrch;
1187 s8 alpha;
1188 s8 code_rate_hp;
1189 s8 code_rate_lp;
1190 s8 select_hp;
1191
1192 s8 intlv_native;
1193 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001194 struct dibDVBTChannel *ch;
Olivier Greniedd316c62011-01-04 04:28:59 -03001195 int ret = 0;
1196
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001197 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001198 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001199 return -EINTR;
1200 }
Olivier Greniedd316c62011-01-04 04:28:59 -03001201 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001202 ret = -EIO;
Dan Carpenter2f098cb2011-08-06 05:01:51 -03001203 goto error;
Olivier Greniedd316c62011-01-04 04:28:59 -03001204 }
1205
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001206 dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
1207 state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
1208 ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03001209
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001210
1211 switch (ch->spectrum_inversion & 0x7) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001212 case 1:
1213 state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
1214 break;
1215 case 0:
1216 state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF;
1217 break;
1218 default:
1219 case -1:
1220 state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
1221 break;
1222 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001223 switch (ch->nfft) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001224 case 0:
1225 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
1226 break;
1227 case 2:
1228 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
1229 break;
1230 case 1:
1231 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1232 break;
1233 default:
1234 case -1:
1235 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
1236 break;
1237 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001238 switch (ch->guard) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001239 case 0:
1240 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
1241 break;
1242 case 1:
1243 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
1244 break;
1245 case 2:
1246 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
1247 break;
1248 case 3:
1249 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
1250 break;
1251 default:
1252 case -1:
1253 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
1254 break;
1255 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001256 switch (ch->constellation) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001257 case 2:
1258 state->fe[0]->dtv_property_cache.modulation = QAM_64;
1259 break;
1260 case 1:
1261 state->fe[0]->dtv_property_cache.modulation = QAM_16;
1262 break;
1263 case 0:
1264 state->fe[0]->dtv_property_cache.modulation = QPSK;
1265 break;
1266 default:
1267 case -1:
1268 state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
1269 break;
1270 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001271 switch (ch->hrch) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001272 case 0:
1273 state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
1274 break;
1275 case 1:
1276 state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1;
1277 break;
1278 default:
1279 case -1:
1280 state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
1281 break;
1282 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001283 switch (ch->code_rate_hp) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001284 case 1:
1285 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
1286 break;
1287 case 2:
1288 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3;
1289 break;
1290 case 3:
1291 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4;
1292 break;
1293 case 5:
1294 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6;
1295 break;
1296 case 7:
1297 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8;
1298 break;
1299 default:
1300 case -1:
1301 state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
1302 break;
1303 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001304 switch (ch->code_rate_lp) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001305 case 1:
1306 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
1307 break;
1308 case 2:
1309 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3;
1310 break;
1311 case 3:
1312 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4;
1313 break;
1314 case 5:
1315 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6;
1316 break;
1317 case 7:
1318 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8;
1319 break;
1320 default:
1321 case -1:
1322 state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO;
1323 break;
1324 }
1325
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001326error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001327 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03001328 return ret;
1329}
1330
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03001331static int dib9000_fw_set_channel_union(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001332{
1333 struct dib9000_state *state = fe->demodulator_priv;
1334 struct dibDVBTChannel {
1335 s8 spectrum_inversion;
1336
1337 s8 nfft;
1338 s8 guard;
1339 s8 constellation;
1340
1341 s8 hrch;
1342 s8 alpha;
1343 s8 code_rate_hp;
1344 s8 code_rate_lp;
1345 s8 select_hp;
1346
1347 s8 intlv_native;
1348 };
1349 struct dibDVBTChannel ch;
1350
1351 switch (state->fe[0]->dtv_property_cache.inversion) {
1352 case INVERSION_ON:
1353 ch.spectrum_inversion = 1;
1354 break;
1355 case INVERSION_OFF:
1356 ch.spectrum_inversion = 0;
1357 break;
1358 default:
1359 case INVERSION_AUTO:
1360 ch.spectrum_inversion = -1;
1361 break;
1362 }
1363 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
1364 case TRANSMISSION_MODE_2K:
1365 ch.nfft = 0;
1366 break;
1367 case TRANSMISSION_MODE_4K:
1368 ch.nfft = 2;
1369 break;
1370 case TRANSMISSION_MODE_8K:
1371 ch.nfft = 1;
1372 break;
1373 default:
1374 case TRANSMISSION_MODE_AUTO:
1375 ch.nfft = 1;
1376 break;
1377 }
1378 switch (state->fe[0]->dtv_property_cache.guard_interval) {
1379 case GUARD_INTERVAL_1_32:
1380 ch.guard = 0;
1381 break;
1382 case GUARD_INTERVAL_1_16:
1383 ch.guard = 1;
1384 break;
1385 case GUARD_INTERVAL_1_8:
1386 ch.guard = 2;
1387 break;
1388 case GUARD_INTERVAL_1_4:
1389 ch.guard = 3;
1390 break;
1391 default:
1392 case GUARD_INTERVAL_AUTO:
1393 ch.guard = -1;
1394 break;
1395 }
1396 switch (state->fe[0]->dtv_property_cache.modulation) {
1397 case QAM_64:
1398 ch.constellation = 2;
1399 break;
1400 case QAM_16:
1401 ch.constellation = 1;
1402 break;
1403 case QPSK:
1404 ch.constellation = 0;
1405 break;
1406 default:
1407 case QAM_AUTO:
1408 ch.constellation = -1;
1409 break;
1410 }
1411 switch (state->fe[0]->dtv_property_cache.hierarchy) {
1412 case HIERARCHY_NONE:
1413 ch.hrch = 0;
1414 break;
1415 case HIERARCHY_1:
1416 case HIERARCHY_2:
1417 case HIERARCHY_4:
1418 ch.hrch = 1;
1419 break;
1420 default:
1421 case HIERARCHY_AUTO:
1422 ch.hrch = -1;
1423 break;
1424 }
1425 ch.alpha = 1;
1426 switch (state->fe[0]->dtv_property_cache.code_rate_HP) {
1427 case FEC_1_2:
1428 ch.code_rate_hp = 1;
1429 break;
1430 case FEC_2_3:
1431 ch.code_rate_hp = 2;
1432 break;
1433 case FEC_3_4:
1434 ch.code_rate_hp = 3;
1435 break;
1436 case FEC_5_6:
1437 ch.code_rate_hp = 5;
1438 break;
1439 case FEC_7_8:
1440 ch.code_rate_hp = 7;
1441 break;
1442 default:
1443 case FEC_AUTO:
1444 ch.code_rate_hp = -1;
1445 break;
1446 }
1447 switch (state->fe[0]->dtv_property_cache.code_rate_LP) {
1448 case FEC_1_2:
1449 ch.code_rate_lp = 1;
1450 break;
1451 case FEC_2_3:
1452 ch.code_rate_lp = 2;
1453 break;
1454 case FEC_3_4:
1455 ch.code_rate_lp = 3;
1456 break;
1457 case FEC_5_6:
1458 ch.code_rate_lp = 5;
1459 break;
1460 case FEC_7_8:
1461 ch.code_rate_lp = 7;
1462 break;
1463 default:
1464 case FEC_AUTO:
1465 ch.code_rate_lp = -1;
1466 break;
1467 }
1468 ch.select_hp = 1;
1469 ch.intlv_native = 1;
1470
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001471 dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch);
Olivier Greniedd316c62011-01-04 04:28:59 -03001472
1473 return 0;
1474}
1475
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03001476static int dib9000_fw_tune(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001477{
1478 struct dib9000_state *state = fe->demodulator_priv;
1479 int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
1480 s8 i;
1481
1482 switch (state->tune_state) {
1483 case CT_DEMOD_START:
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001484 dib9000_fw_set_channel_head(state);
Olivier Greniedd316c62011-01-04 04:28:59 -03001485
1486 /* write the channel context - a channel is initialized to 0, so it is OK */
1487 dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
1488 dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info);
1489
1490 if (search)
1491 dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
1492 else {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03001493 dib9000_fw_set_channel_union(fe);
Olivier Greniedd316c62011-01-04 04:28:59 -03001494 dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
1495 }
1496 state->tune_state = CT_DEMOD_STEP_1;
1497 break;
1498 case CT_DEMOD_STEP_1:
1499 if (search)
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001500 dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
Olivier Greniedd316c62011-01-04 04:28:59 -03001501 else
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001502 dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
1503 i = (s8)state->i2c_read_buffer[0];
Olivier Greniedd316c62011-01-04 04:28:59 -03001504 switch (i) { /* something happened */
1505 case 0:
1506 break;
1507 case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */
1508 if (search)
1509 state->status = FE_STATUS_DEMOD_SUCCESS;
1510 else {
1511 state->tune_state = CT_DEMOD_STOP;
1512 state->status = FE_STATUS_LOCKED;
1513 }
1514 break;
1515 default:
1516 state->status = FE_STATUS_TUNE_FAILED;
1517 state->tune_state = CT_DEMOD_STOP;
1518 break;
1519 }
1520 break;
1521 default:
1522 ret = FE_CALLBACK_TIME_NEVER;
1523 break;
1524 }
1525
1526 return ret;
1527}
1528
1529static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff)
1530{
1531 struct dib9000_state *state = fe->demodulator_priv;
1532 u16 mode = (u16) onoff;
1533 return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1);
1534}
1535
1536static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode)
1537{
1538 struct dib9000_state *state = fe->demodulator_priv;
1539 u16 outreg, smo_mode;
1540
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001541 dprintk("setting output mode for demod %p to %d\n", fe, mode);
Olivier Greniedd316c62011-01-04 04:28:59 -03001542
1543 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001544 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Greniedd316c62011-01-04 04:28:59 -03001545 outreg = (1 << 10); /* 0x0400 */
1546 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001547 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Greniedd316c62011-01-04 04:28:59 -03001548 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
1549 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001550 case OUTMODE_MPEG2_SERIAL:
Olivier Greniedd316c62011-01-04 04:28:59 -03001551 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
1552 break;
1553 case OUTMODE_DIVERSITY:
1554 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
1555 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001556 case OUTMODE_MPEG2_FIFO:
Olivier Greniedd316c62011-01-04 04:28:59 -03001557 outreg = (1 << 10) | (5 << 6);
1558 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001559 case OUTMODE_HIGH_Z:
Olivier Greniedd316c62011-01-04 04:28:59 -03001560 outreg = 0;
1561 break;
1562 default:
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001563 dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->fe[0]);
Olivier Greniedd316c62011-01-04 04:28:59 -03001564 return -EINVAL;
1565 }
1566
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001567 dib9000_write_word(state, 1795, outreg);
Olivier Greniedd316c62011-01-04 04:28:59 -03001568
1569 switch (mode) {
1570 case OUTMODE_MPEG2_PAR_GATED_CLK:
1571 case OUTMODE_MPEG2_PAR_CONT_CLK:
1572 case OUTMODE_MPEG2_SERIAL:
1573 case OUTMODE_MPEG2_FIFO:
1574 smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1);
1575 if (state->chip.d9.cfg.output_mpeg2_in_188_bytes)
1576 smo_mode |= (1 << 5);
1577 dib9000_write_word(state, 295, smo_mode);
1578 break;
1579 }
1580
1581 outreg = to_fw_output_mode(mode);
1582 return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1);
1583}
1584
1585static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1586{
1587 struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
1588 u16 i, len, t, index_msg;
1589
1590 for (index_msg = 0; index_msg < num; index_msg++) {
1591 if (msg[index_msg].flags & I2C_M_RD) { /* read */
1592 len = msg[index_msg].len;
1593 if (len > 16)
1594 len = 16;
1595
1596 if (dib9000_read_word(state, 790) != 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001597 dprintk("TunerITF: read busy\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001598
1599 dib9000_write_word(state, 784, (u16) (msg[index_msg].addr));
1600 dib9000_write_word(state, 787, (len / 2) - 1);
1601 dib9000_write_word(state, 786, 1); /* start read */
1602
1603 i = 1000;
1604 while (dib9000_read_word(state, 790) != (len / 2) && i)
1605 i--;
1606
1607 if (i == 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001608 dprintk("TunerITF: read failed\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001609
1610 for (i = 0; i < len; i += 2) {
1611 t = dib9000_read_word(state, 785);
1612 msg[index_msg].buf[i] = (t >> 8) & 0xff;
1613 msg[index_msg].buf[i + 1] = (t) & 0xff;
1614 }
1615 if (dib9000_read_word(state, 790) != 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001616 dprintk("TunerITF: read more data than expected\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001617 } else {
1618 i = 1000;
1619 while (dib9000_read_word(state, 789) && i)
1620 i--;
1621 if (i == 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001622 dprintk("TunerITF: write busy\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001623
1624 len = msg[index_msg].len;
1625 if (len > 16)
1626 len = 16;
1627
1628 for (i = 0; i < len; i += 2)
1629 dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]);
1630 dib9000_write_word(state, 784, (u16) msg[index_msg].addr);
1631 dib9000_write_word(state, 787, (len / 2) - 1);
1632 dib9000_write_word(state, 786, 0); /* start write */
1633
1634 i = 1000;
1635 while (dib9000_read_word(state, 791) > 0 && i)
1636 i--;
1637 if (i == 0)
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001638 dprintk("TunerITF: write failed\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03001639 }
1640 }
1641 return num;
1642}
1643
1644int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
1645{
1646 struct dib9000_state *state = fe->demodulator_priv;
1647
1648 state->component_bus_speed = speed;
1649 return 0;
1650}
1651EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed);
1652
1653static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1654{
1655 struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001656 u8 type = 0; /* I2C */
Olivier Greniedd316c62011-01-04 04:28:59 -03001657 u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001658 u16 scl = state->component_bus_speed; /* SCL frequency */
Olivier Greniedd316c62011-01-04 04:28:59 -03001659 struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER];
1660 u8 p[13] = { 0 };
1661
1662 p[0] = type;
1663 p[1] = port;
1664 p[2] = msg[0].addr << 1;
1665
1666 p[3] = (u8) scl & 0xff; /* scl */
1667 p[4] = (u8) (scl >> 8);
1668
Olivier Greniedd316c62011-01-04 04:28:59 -03001669 p[7] = 0;
1670 p[8] = 0;
1671
1672 p[9] = (u8) (msg[0].len);
1673 p[10] = (u8) (msg[0].len >> 8);
1674 if ((num > 1) && (msg[1].flags & I2C_M_RD)) {
1675 p[11] = (u8) (msg[1].len);
1676 p[12] = (u8) (msg[1].len >> 8);
1677 } else {
1678 p[11] = 0;
1679 p[12] = 0;
1680 }
1681
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001682 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001683 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001684 return 0;
1685 }
Olivier Greniedd316c62011-01-04 04:28:59 -03001686
1687 dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
1688
1689 { /* write-part */
1690 dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0);
1691 dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len);
1692 }
1693
1694 /* do the transaction */
1695 if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001696 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03001697 return 0;
1698 }
1699
1700 /* read back any possible result */
1701 if ((num > 1) && (msg[1].flags & I2C_M_RD))
1702 dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
1703
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001704 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03001705
1706 return num;
1707}
1708
1709static u32 dib9000_i2c_func(struct i2c_adapter *adapter)
1710{
1711 return I2C_FUNC_I2C;
1712}
1713
Gustavo A. R. Silva19779f42017-07-09 18:24:19 -04001714static const struct i2c_algorithm dib9000_tuner_algo = {
Olivier Greniedd316c62011-01-04 04:28:59 -03001715 .master_xfer = dib9000_tuner_xfer,
1716 .functionality = dib9000_i2c_func,
1717};
1718
Gustavo A. R. Silva19779f42017-07-09 18:24:19 -04001719static const struct i2c_algorithm dib9000_component_bus_algo = {
Olivier Greniedd316c62011-01-04 04:28:59 -03001720 .master_xfer = dib9000_fw_component_bus_xfer,
1721 .functionality = dib9000_i2c_func,
1722};
1723
1724struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
1725{
1726 struct dib9000_state *st = fe->demodulator_priv;
1727 return &st->tuner_adap;
1728}
Olivier Greniedd316c62011-01-04 04:28:59 -03001729EXPORT_SYMBOL(dib9000_get_tuner_interface);
1730
1731struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
1732{
1733 struct dib9000_state *st = fe->demodulator_priv;
1734 return &st->component_bus;
1735}
Olivier Greniedd316c62011-01-04 04:28:59 -03001736EXPORT_SYMBOL(dib9000_get_component_bus_interface);
1737
1738struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
1739{
1740 struct dib9000_state *st = fe->demodulator_priv;
1741 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1742}
Olivier Greniedd316c62011-01-04 04:28:59 -03001743EXPORT_SYMBOL(dib9000_get_i2c_master);
1744
1745int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
1746{
1747 struct dib9000_state *st = fe->demodulator_priv;
1748
1749 st->i2c.i2c_adap = i2c;
1750 return 0;
1751}
Olivier Greniedd316c62011-01-04 04:28:59 -03001752EXPORT_SYMBOL(dib9000_set_i2c_adapter);
1753
1754static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val)
1755{
1756 st->gpio_dir = dib9000_read_word(st, 773);
1757 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
1758 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
1759 dib9000_write_word(st, 773, st->gpio_dir);
1760
1761 st->gpio_val = dib9000_read_word(st, 774);
1762 st->gpio_val &= ~(1 << num); /* reset the direction bit */
1763 st->gpio_val |= (val & 0x01) << num; /* set the new value */
1764 dib9000_write_word(st, 774, st->gpio_val);
1765
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001766 dprintk("gpio dir: %04x: gpio val: %04x\n", st->gpio_dir, st->gpio_val);
Olivier Greniedd316c62011-01-04 04:28:59 -03001767
1768 return 0;
1769}
1770
1771int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
1772{
1773 struct dib9000_state *state = fe->demodulator_priv;
1774 return dib9000_cfg_gpio(state, num, dir, val);
1775}
Olivier Greniedd316c62011-01-04 04:28:59 -03001776EXPORT_SYMBOL(dib9000_set_gpio);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001777
Olivier Greniedd316c62011-01-04 04:28:59 -03001778int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1779{
1780 struct dib9000_state *state = fe->demodulator_priv;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001781 u16 val;
1782 int ret;
1783
1784 if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
1785 /* postpone the pid filtering cmd */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001786 dprintk("pid filter cmd postpone\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001787 state->pid_ctrl_index++;
1788 state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
1789 state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
1790 return 0;
1791 }
1792
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001793 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001794 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001795 return -EINTR;
1796 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001797
1798 val = dib9000_read_word(state, 294 + 1) & 0xffef;
Olivier Greniedd316c62011-01-04 04:28:59 -03001799 val |= (onoff & 0x1) << 4;
1800
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001801 dprintk("PID filter enabled %d\n", onoff);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001802 ret = dib9000_write_word(state, 294 + 1, val);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001803 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001804 return ret;
1805
Olivier Greniedd316c62011-01-04 04:28:59 -03001806}
Olivier Greniedd316c62011-01-04 04:28:59 -03001807EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001808
Olivier Greniedd316c62011-01-04 04:28:59 -03001809int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1810{
1811 struct dib9000_state *state = fe->demodulator_priv;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001812 int ret;
1813
1814 if (state->pid_ctrl_index != -2) {
1815 /* postpone the pid filtering cmd */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001816 dprintk("pid filter postpone\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001817 if (state->pid_ctrl_index < 9) {
1818 state->pid_ctrl_index++;
1819 state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
1820 state->pid_ctrl[state->pid_ctrl_index].id = id;
1821 state->pid_ctrl[state->pid_ctrl_index].pid = pid;
1822 state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
1823 } else
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001824 dprintk("can not add any more pid ctrl cmd\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001825 return 0;
1826 }
1827
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001828 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001829 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001830 return -EINTR;
1831 }
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001832 dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001833 ret = dib9000_write_word(state, 300 + 1 + id,
1834 onoff ? (1 << 13) | pid : 0);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001835 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001836 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03001837}
Olivier Greniedd316c62011-01-04 04:28:59 -03001838EXPORT_SYMBOL(dib9000_fw_pid_filter);
1839
1840int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
1841{
1842 struct dib9000_state *state = fe->demodulator_priv;
1843 return dib9000_fw_init(state);
1844}
Olivier Greniedd316c62011-01-04 04:28:59 -03001845EXPORT_SYMBOL(dib9000_firmware_post_pll_init);
1846
1847static void dib9000_release(struct dvb_frontend *demod)
1848{
1849 struct dib9000_state *st = demod->demodulator_priv;
1850 u8 index_frontend;
1851
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001852 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03001853 dvb_frontend_detach(st->fe[index_frontend]);
1854
Olivier Greniedd316c62011-01-04 04:28:59 -03001855 dibx000_exit_i2c_master(&st->i2c_master);
1856
1857 i2c_del_adapter(&st->tuner_adap);
1858 i2c_del_adapter(&st->component_bus);
1859 kfree(st->fe[0]);
1860 kfree(st);
1861}
1862
1863static int dib9000_wakeup(struct dvb_frontend *fe)
1864{
1865 return 0;
1866}
1867
1868static int dib9000_sleep(struct dvb_frontend *fe)
1869{
1870 struct dib9000_state *state = fe->demodulator_priv;
1871 u8 index_frontend;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001872 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03001873
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001874 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001875 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001876 return -EINTR;
1877 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001878 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001879 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
1880 if (ret < 0)
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001881 goto error;
Olivier Greniedd316c62011-01-04 04:28:59 -03001882 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001883 ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
1884
1885error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001886 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001887 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03001888}
1889
1890static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
1891{
1892 tune->min_delay_ms = 1000;
1893 return 0;
1894}
1895
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001896static int dib9000_get_frontend(struct dvb_frontend *fe,
1897 struct dtv_frontend_properties *c)
Olivier Greniedd316c62011-01-04 04:28:59 -03001898{
1899 struct dib9000_state *state = fe->demodulator_priv;
1900 u8 index_frontend, sub_index_frontend;
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001901 enum fe_status stat;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001902 int ret = 0;
1903
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001904 if (state->get_frontend_internal == 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001905 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001906 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03001907 return -EINTR;
1908 }
1909 }
Olivier Greniedd316c62011-01-04 04:28:59 -03001910
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001911 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001912 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
1913 if (stat & FE_HAS_SYNC) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03001914 dprintk("TPS lock on the slave%i\n", index_frontend);
Olivier Greniedd316c62011-01-04 04:28:59 -03001915
1916 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001917 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001918 for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
1919 sub_index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03001920 if (sub_index_frontend != index_frontend) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001921 state->fe[sub_index_frontend]->dtv_property_cache.modulation =
1922 state->fe[index_frontend]->dtv_property_cache.modulation;
1923 state->fe[sub_index_frontend]->dtv_property_cache.inversion =
1924 state->fe[index_frontend]->dtv_property_cache.inversion;
1925 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode =
1926 state->fe[index_frontend]->dtv_property_cache.transmission_mode;
1927 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval =
1928 state->fe[index_frontend]->dtv_property_cache.guard_interval;
1929 state->fe[sub_index_frontend]->dtv_property_cache.hierarchy =
1930 state->fe[index_frontend]->dtv_property_cache.hierarchy;
1931 state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP =
1932 state->fe[index_frontend]->dtv_property_cache.code_rate_HP;
1933 state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP =
1934 state->fe[index_frontend]->dtv_property_cache.code_rate_LP;
1935 state->fe[sub_index_frontend]->dtv_property_cache.rolloff =
1936 state->fe[index_frontend]->dtv_property_cache.rolloff;
Olivier Greniedd316c62011-01-04 04:28:59 -03001937 }
1938 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001939 ret = 0;
1940 goto return_value;
Olivier Greniedd316c62011-01-04 04:28:59 -03001941 }
1942 }
1943
1944 /* get the channel from master chip */
Mauro Carvalho Chehab759e2362011-12-22 19:54:08 -03001945 ret = dib9000_fw_get_channel(fe);
Olivier Greniedd316c62011-01-04 04:28:59 -03001946 if (ret != 0)
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001947 goto return_value;
Olivier Greniedd316c62011-01-04 04:28:59 -03001948
1949 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001950 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 -02001951 state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
1952 state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
1953 state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
1954 state->fe[index_frontend]->dtv_property_cache.modulation = c->modulation;
1955 state->fe[index_frontend]->dtv_property_cache.hierarchy = c->hierarchy;
1956 state->fe[index_frontend]->dtv_property_cache.code_rate_HP = c->code_rate_HP;
1957 state->fe[index_frontend]->dtv_property_cache.code_rate_LP = c->code_rate_LP;
1958 state->fe[index_frontend]->dtv_property_cache.rolloff = c->rolloff;
Olivier Greniedd316c62011-01-04 04:28:59 -03001959 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001960 ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03001961
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001962return_value:
1963 if (state->get_frontend_internal == 0)
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03001964 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001965 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03001966}
1967
1968static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
1969{
1970 struct dib9000_state *state = fe->demodulator_priv;
1971 state->tune_state = tune_state;
1972 if (tune_state == CT_DEMOD_START)
1973 state->status = FE_STATUS_TUNE_PENDING;
1974
1975 return 0;
1976}
1977
1978static u32 dib9000_get_status(struct dvb_frontend *fe)
1979{
1980 struct dib9000_state *state = fe->demodulator_priv;
1981 return state->status;
1982}
1983
1984static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status)
1985{
1986 struct dib9000_state *state = fe->demodulator_priv;
1987
1988 memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext));
1989 return 0;
1990}
1991
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03001992static int dib9000_set_frontend(struct dvb_frontend *fe)
Olivier Greniedd316c62011-01-04 04:28:59 -03001993{
1994 struct dib9000_state *state = fe->demodulator_priv;
1995 int sleep_time, sleep_time_slave;
1996 u32 frontend_status;
1997 u8 nbr_pending, exit_condition, index_frontend, index_frontend_success;
1998 struct dvb_frontend_parametersContext channel_status;
1999
2000 /* check that the correct parameters are set */
2001 if (state->fe[0]->dtv_property_cache.frequency == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002002 dprintk("dib9000: must specify frequency\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03002003 return 0;
2004 }
2005
2006 if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002007 dprintk("dib9000: must specify bandwidth\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03002008 return 0;
2009 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002010
2011 state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002012 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002013 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002014 return 0;
2015 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002016
Olivier Greniedd316c62011-01-04 04:28:59 -03002017 fe->dtv_property_cache.delivery_system = SYS_DVBT;
2018
2019 /* set the master status */
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002020 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO ||
2021 state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO ||
2022 state->fe[0]->dtv_property_cache.modulation == QAM_AUTO ||
2023 state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002024 /* no channel specified, autosearch the channel */
2025 state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
2026 } else
2027 state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
2028
2029 /* set mode and status for the different frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002030 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002031 dib9000_fw_set_diversity_in(state->fe[index_frontend], 1);
2032
2033 /* synchronization of the cache */
2034 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
2035
2036 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT;
2037 dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
2038
2039 dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status);
2040 dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2041 }
2042
2043 /* actual tune */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002044 exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
Olivier Greniedd316c62011-01-04 04:28:59 -03002045 index_frontend_success = 0;
2046 do {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03002047 sleep_time = dib9000_fw_tune(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002048 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 -03002049 sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
Olivier Greniedd316c62011-01-04 04:28:59 -03002050 if (sleep_time == FE_CALLBACK_TIME_NEVER)
2051 sleep_time = sleep_time_slave;
2052 else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
2053 sleep_time = sleep_time_slave;
2054 }
2055 if (sleep_time != FE_CALLBACK_TIME_NEVER)
2056 msleep(sleep_time / 10);
2057 else
2058 break;
2059
2060 nbr_pending = 0;
2061 exit_condition = 0;
2062 index_frontend_success = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002063 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002064 frontend_status = -dib9000_get_status(state->fe[index_frontend]);
2065 if (frontend_status > -FE_STATUS_TUNE_PENDING) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002066 exit_condition = 2; /* tune success */
Olivier Greniedd316c62011-01-04 04:28:59 -03002067 index_frontend_success = index_frontend;
2068 break;
2069 }
2070 if (frontend_status == -FE_STATUS_TUNE_PENDING)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002071 nbr_pending++; /* some frontends are still tuning */
Olivier Greniedd316c62011-01-04 04:28:59 -03002072 }
2073 if ((exit_condition != 2) && (nbr_pending == 0))
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002074 exit_condition = 1; /* if all tune are done and no success, exit: tune failed */
Olivier Greniedd316c62011-01-04 04:28:59 -03002075
2076 } while (exit_condition == 0);
2077
2078 /* check the tune result */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002079 if (exit_condition == 1) { /* tune failed */
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002080 dprintk("tune failed\n");
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002081 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002082 /* tune failed; put all the pid filtering cmd to junk */
2083 state->pid_ctrl_index = -1;
Olivier Greniedd316c62011-01-04 04:28:59 -03002084 return 0;
2085 }
2086
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002087 dprintk("tune success on frontend%i\n", index_frontend_success);
Olivier Greniedd316c62011-01-04 04:28:59 -03002088
2089 /* synchronize all the channel cache */
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002090 state->get_frontend_internal = 1;
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02002091 dib9000_get_frontend(state->fe[0], &state->fe[0]->dtv_property_cache);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002092 state->get_frontend_internal = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002093
2094 /* retune the other frontends with the found channel */
2095 channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002096 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002097 /* only retune the frontends which was not tuned success */
2098 if (index_frontend != index_frontend_success) {
2099 dib9000_set_channel_status(state->fe[index_frontend], &channel_status);
2100 dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2101 }
2102 }
2103 do {
2104 sleep_time = FE_CALLBACK_TIME_NEVER;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002105 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002106 if (index_frontend != index_frontend_success) {
Mauro Carvalho Chehabf20b12e2011-12-22 20:42:12 -03002107 sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
Olivier Greniedd316c62011-01-04 04:28:59 -03002108 if (sleep_time == FE_CALLBACK_TIME_NEVER)
2109 sleep_time = sleep_time_slave;
2110 else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
2111 sleep_time = sleep_time_slave;
2112 }
2113 }
2114 if (sleep_time != FE_CALLBACK_TIME_NEVER)
2115 msleep(sleep_time / 10);
2116 else
2117 break;
2118
2119 nbr_pending = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002120 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002121 if (index_frontend != index_frontend_success) {
2122 frontend_status = -dib9000_get_status(state->fe[index_frontend]);
2123 if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING))
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002124 nbr_pending++; /* some frontends are still tuning */
Olivier Greniedd316c62011-01-04 04:28:59 -03002125 }
2126 }
2127 } while (nbr_pending != 0);
2128
2129 /* set the output mode */
2130 dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002131 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03002132 dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
2133
2134 /* turn off the diversity for the last frontend */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002135 dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
Olivier Greniedd316c62011-01-04 04:28:59 -03002136
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002137 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002138 if (state->pid_ctrl_index >= 0) {
2139 u8 index_pid_filter_cmd;
2140 u8 pid_ctrl_index = state->pid_ctrl_index;
2141
2142 state->pid_ctrl_index = -2;
2143 for (index_pid_filter_cmd = 0;
2144 index_pid_filter_cmd <= pid_ctrl_index;
2145 index_pid_filter_cmd++) {
2146 if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
2147 dib9000_fw_pid_filter_ctrl(state->fe[0],
2148 state->pid_ctrl[index_pid_filter_cmd].onoff);
2149 else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
2150 dib9000_fw_pid_filter(state->fe[0],
2151 state->pid_ctrl[index_pid_filter_cmd].id,
2152 state->pid_ctrl[index_pid_filter_cmd].pid,
2153 state->pid_ctrl[index_pid_filter_cmd].onoff);
2154 }
2155 }
2156 /* do not postpone any more the pid filtering */
2157 state->pid_ctrl_index = -2;
2158
Olivier Greniedd316c62011-01-04 04:28:59 -03002159 return 0;
2160}
2161
2162static u16 dib9000_read_lock(struct dvb_frontend *fe)
2163{
2164 struct dib9000_state *state = fe->demodulator_priv;
2165
2166 return dib9000_read_word(state, 535);
2167}
2168
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03002169static int dib9000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Olivier Greniedd316c62011-01-04 04:28:59 -03002170{
2171 struct dib9000_state *state = fe->demodulator_priv;
2172 u8 index_frontend;
2173 u16 lock = 0, lock_slave = 0;
2174
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002175 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002176 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002177 return -EINTR;
2178 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002179 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03002180 lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
2181
2182 lock = dib9000_read_word(state, 535);
2183
2184 *stat = 0;
2185
2186 if ((lock & 0x8000) || (lock_slave & 0x8000))
2187 *stat |= FE_HAS_SIGNAL;
2188 if ((lock & 0x3000) || (lock_slave & 0x3000))
2189 *stat |= FE_HAS_CARRIER;
2190 if ((lock & 0x0100) || (lock_slave & 0x0100))
2191 *stat |= FE_HAS_VITERBI;
2192 if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38))
2193 *stat |= FE_HAS_SYNC;
2194 if ((lock & 0x0008) || (lock_slave & 0x0008))
2195 *stat |= FE_HAS_LOCK;
2196
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002197 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002198
Olivier Greniedd316c62011-01-04 04:28:59 -03002199 return 0;
2200}
2201
2202static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
2203{
2204 struct dib9000_state *state = fe->demodulator_priv;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002205 u16 *c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002206 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002207
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002208 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002209 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002210 return -EINTR;
2211 }
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002212 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002213 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002214 ret = -EINTR;
2215 goto error;
2216 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002217 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002218 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002219 ret = -EIO;
2220 goto error;
2221 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002222 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
2223 state->i2c_read_buffer, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002224 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002225
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002226 c = (u16 *)state->i2c_read_buffer;
2227
Olivier Greniedd316c62011-01-04 04:28:59 -03002228 *ber = c[10] << 16 | c[11];
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002229
2230error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002231 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002232 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002233}
2234
2235static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
2236{
2237 struct dib9000_state *state = fe->demodulator_priv;
2238 u8 index_frontend;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002239 u16 *c = (u16 *)state->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03002240 u16 val;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002241 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002242
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002243 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002244 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002245 return -EINTR;
2246 }
Olivier Greniedd316c62011-01-04 04:28:59 -03002247 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002248 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Greniedd316c62011-01-04 04:28:59 -03002249 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
2250 if (val > 65535 - *strength)
2251 *strength = 65535;
2252 else
2253 *strength += val;
2254 }
2255
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002256 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002257 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002258 ret = -EINTR;
2259 goto error;
2260 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002261 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002262 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002263 ret = -EIO;
2264 goto error;
2265 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002266 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002267 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002268
2269 val = 65535 - c[4];
2270 if (val > 65535 - *strength)
2271 *strength = 65535;
2272 else
2273 *strength += val;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002274
2275error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002276 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002277 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002278}
2279
2280static u32 dib9000_get_snr(struct dvb_frontend *fe)
2281{
2282 struct dib9000_state *state = fe->demodulator_priv;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002283 u16 *c = (u16 *)state->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03002284 u32 n, s, exp;
2285 u16 val;
2286
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002287 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002288 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002289 return 0;
2290 }
Alexey Khoroshilov9bb24a72012-03-06 17:08:16 -03002291 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002292 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002293 return 0;
Alexey Khoroshilov9bb24a72012-03-06 17:08:16 -03002294 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002295 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002296 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002297
2298 val = c[7];
2299 n = (val >> 4) & 0xff;
2300 exp = ((val & 0xf) << 2);
2301 val = c[8];
2302 exp += ((val >> 14) & 0x3);
2303 if ((exp & 0x20) != 0)
2304 exp -= 0x40;
2305 n <<= exp + 16;
2306
2307 s = (val >> 6) & 0xFF;
2308 exp = (val & 0x3F);
2309 if ((exp & 0x20) != 0)
2310 exp -= 0x40;
2311 s <<= exp + 16;
2312
2313 if (n > 0) {
2314 u32 t = (s / n) << 16;
2315 return t + ((s << 16) - n * t) / n;
2316 }
2317 return 0xffffffff;
2318}
2319
2320static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
2321{
2322 struct dib9000_state *state = fe->demodulator_priv;
2323 u8 index_frontend;
2324 u32 snr_master;
2325
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002326 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002327 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002328 return -EINTR;
2329 }
Olivier Greniedd316c62011-01-04 04:28:59 -03002330 snr_master = dib9000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002331 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Greniedd316c62011-01-04 04:28:59 -03002332 snr_master += dib9000_get_snr(state->fe[index_frontend]);
2333
2334 if ((snr_master >> 16) != 0) {
2335 snr_master = 10 * intlog10(snr_master >> 16);
2336 *snr = snr_master / ((1 << 24) / 10);
2337 } else
2338 *snr = 0;
2339
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002340 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002341
Olivier Greniedd316c62011-01-04 04:28:59 -03002342 return 0;
2343}
2344
2345static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
2346{
2347 struct dib9000_state *state = fe->demodulator_priv;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002348 u16 *c = (u16 *)state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002349 int ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002350
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002351 if (mutex_lock_interruptible(&state->demod_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002352 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002353 return -EINTR;
2354 }
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002355 if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002356 dprintk("could not get the lock\n");
Alexey Khoroshilovf3033ae2012-03-06 17:08:29 -03002357 ret = -EINTR;
2358 goto error;
2359 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002360 if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002361 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002362 ret = -EIO;
2363 goto error;
2364 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002365 dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002366 mutex_unlock(&state->platform.risc.mem_mbx_lock);
Olivier Greniedd316c62011-01-04 04:28:59 -03002367
2368 *unc = c[12];
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002369
2370error:
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002371 mutex_unlock(&state->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002372 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002373}
2374
2375int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
2376{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002377 int k = 0, ret = 0;
Olivier Greniedd316c62011-01-04 04:28:59 -03002378 u8 new_addr = 0;
2379 struct i2c_device client = {.i2c_adap = i2c };
2380
Kees Cook6396bb22018-06-12 14:03:40 -07002381 client.i2c_write_buffer = kzalloc(4, GFP_KERNEL);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002382 if (!client.i2c_write_buffer) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002383 dprintk("%s: not enough memory\n", __func__);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002384 return -ENOMEM;
2385 }
Kees Cook6396bb22018-06-12 14:03:40 -07002386 client.i2c_read_buffer = kzalloc(4, GFP_KERNEL);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002387 if (!client.i2c_read_buffer) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002388 dprintk("%s: not enough memory\n", __func__);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002389 ret = -ENOMEM;
2390 goto error_memory;
2391 }
2392
Olivier Greniedd316c62011-01-04 04:28:59 -03002393 client.i2c_addr = default_addr + 16;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002394 dib9000_i2c_write16(&client, 1796, 0x0);
Olivier Greniedd316c62011-01-04 04:28:59 -03002395
2396 for (k = no_of_demods - 1; k >= 0; k--) {
2397 /* designated i2c address */
2398 new_addr = first_addr + (k << 1);
2399 client.i2c_addr = default_addr;
2400
2401 dib9000_i2c_write16(&client, 1817, 3);
2402 dib9000_i2c_write16(&client, 1796, 0);
2403 dib9000_i2c_write16(&client, 1227, 1);
2404 dib9000_i2c_write16(&client, 1227, 0);
2405
2406 client.i2c_addr = new_addr;
2407 dib9000_i2c_write16(&client, 1817, 3);
2408 dib9000_i2c_write16(&client, 1796, 0);
2409 dib9000_i2c_write16(&client, 1227, 1);
2410 dib9000_i2c_write16(&client, 1227, 0);
2411
2412 if (dib9000_identify(&client) == 0) {
2413 client.i2c_addr = default_addr;
2414 if (dib9000_identify(&client) == 0) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002415 dprintk("DiB9000 #%d: not identified\n", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002416 ret = -EIO;
2417 goto error;
Olivier Greniedd316c62011-01-04 04:28:59 -03002418 }
2419 }
2420
2421 dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6));
2422 dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2);
2423
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002424 dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
Olivier Greniedd316c62011-01-04 04:28:59 -03002425 }
2426
2427 for (k = 0; k < no_of_demods; k++) {
2428 new_addr = first_addr | (k << 1);
2429 client.i2c_addr = new_addr;
2430
2431 dib9000_i2c_write16(&client, 1794, (new_addr << 2));
2432 dib9000_i2c_write16(&client, 1795, 0);
2433 }
2434
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002435error:
2436 kfree(client.i2c_read_buffer);
2437error_memory:
2438 kfree(client.i2c_write_buffer);
2439
2440 return ret;
Olivier Greniedd316c62011-01-04 04:28:59 -03002441}
Olivier Greniedd316c62011-01-04 04:28:59 -03002442EXPORT_SYMBOL(dib9000_i2c_enumeration);
2443
2444int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
2445{
2446 struct dib9000_state *state = fe->demodulator_priv;
2447 u8 index_frontend = 1;
2448
2449 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2450 index_frontend++;
2451 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002452 dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
Olivier Greniedd316c62011-01-04 04:28:59 -03002453 state->fe[index_frontend] = fe_slave;
2454 return 0;
2455 }
2456
Mauro Carvalho Chehab3dd72262016-10-14 10:08:40 -03002457 dprintk("too many slave frontend\n");
Olivier Greniedd316c62011-01-04 04:28:59 -03002458 return -ENOMEM;
2459}
2460EXPORT_SYMBOL(dib9000_set_slave_frontend);
2461
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002462struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Greniedd316c62011-01-04 04:28:59 -03002463{
2464 struct dib9000_state *state = fe->demodulator_priv;
2465
2466 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
2467 return NULL;
2468 return state->fe[slave_index];
2469}
2470EXPORT_SYMBOL(dib9000_get_slave_frontend);
2471
Max Kellermannbd336e62016-08-09 18:32:21 -03002472static const struct dvb_frontend_ops dib9000_ops;
Olivier Greniedd316c62011-01-04 04:28:59 -03002473struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg)
2474{
2475 struct dvb_frontend *fe;
2476 struct dib9000_state *st;
2477 st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL);
2478 if (st == NULL)
2479 return NULL;
2480 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
Jesper Juhl451a51b2011-04-07 16:34:30 -03002481 if (fe == NULL) {
2482 kfree(st);
Olivier Greniedd316c62011-01-04 04:28:59 -03002483 return NULL;
Jesper Juhl451a51b2011-04-07 16:34:30 -03002484 }
Olivier Greniedd316c62011-01-04 04:28:59 -03002485
2486 memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
2487 st->i2c.i2c_adap = i2c_adap;
2488 st->i2c.i2c_addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002489 st->i2c.i2c_write_buffer = st->i2c_write_buffer;
2490 st->i2c.i2c_read_buffer = st->i2c_read_buffer;
Olivier Greniedd316c62011-01-04 04:28:59 -03002491
2492 st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
2493 st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
2494 st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
2495
Alexey Khoroshilov1eaef482012-03-19 16:48:34 -03002496 mutex_init(&st->platform.risc.mbx_if_lock);
2497 mutex_init(&st->platform.risc.mbx_lock);
2498 mutex_init(&st->platform.risc.mem_lock);
2499 mutex_init(&st->platform.risc.mem_mbx_lock);
2500 mutex_init(&st->demod_lock);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002501 st->get_frontend_internal = 0;
2502
2503 st->pid_ctrl_index = -2;
Olivier Greniedd316c62011-01-04 04:28:59 -03002504
2505 st->fe[0] = fe;
2506 fe->demodulator_priv = st;
2507 memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops));
2508
2509 /* Ensure the output mode remains at the previous default if it's
2510 * not specifically set by the caller.
2511 */
2512 if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
2513 st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO;
2514
2515 if (dib9000_identify(&st->i2c) == 0)
2516 goto error;
2517
2518 dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr);
2519
2520 st->tuner_adap.dev.parent = i2c_adap->dev.parent;
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -04002521 strscpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS",
2522 sizeof(st->tuner_adap.name));
Olivier Greniedd316c62011-01-04 04:28:59 -03002523 st->tuner_adap.algo = &dib9000_tuner_algo;
2524 st->tuner_adap.algo_data = NULL;
2525 i2c_set_adapdata(&st->tuner_adap, st);
2526 if (i2c_add_adapter(&st->tuner_adap) < 0)
2527 goto error;
2528
2529 st->component_bus.dev.parent = i2c_adap->dev.parent;
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -04002530 strscpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS",
2531 sizeof(st->component_bus.name));
Olivier Greniedd316c62011-01-04 04:28:59 -03002532 st->component_bus.algo = &dib9000_component_bus_algo;
2533 st->component_bus.algo_data = NULL;
2534 st->component_bus_speed = 340;
2535 i2c_set_adapdata(&st->component_bus, st);
2536 if (i2c_add_adapter(&st->component_bus) < 0)
2537 goto component_bus_add_error;
2538
2539 dib9000_fw_reset(fe);
2540
2541 return fe;
2542
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002543component_bus_add_error:
Olivier Greniedd316c62011-01-04 04:28:59 -03002544 i2c_del_adapter(&st->tuner_adap);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002545error:
Olivier Greniedd316c62011-01-04 04:28:59 -03002546 kfree(st);
2547 return NULL;
2548}
Olivier Greniedd316c62011-01-04 04:28:59 -03002549EXPORT_SYMBOL(dib9000_attach);
2550
Max Kellermannbd336e62016-08-09 18:32:21 -03002551static const struct dvb_frontend_ops dib9000_ops = {
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002552 .delsys = { SYS_DVBT },
Olivier Greniedd316c62011-01-04 04:28:59 -03002553 .info = {
2554 .name = "DiBcom 9000",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -04002555 .frequency_min_hz = 44250 * kHz,
2556 .frequency_max_hz = 867250 * kHz,
2557 .frequency_stepsize_hz = 62500,
Olivier Greniedd316c62011-01-04 04:28:59 -03002558 .caps = FE_CAN_INVERSION_AUTO |
2559 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2560 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2561 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2562 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2563 },
2564
2565 .release = dib9000_release,
2566
2567 .init = dib9000_wakeup,
2568 .sleep = dib9000_sleep,
2569
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002570 .set_frontend = dib9000_set_frontend,
Olivier Greniedd316c62011-01-04 04:28:59 -03002571 .get_tune_settings = dib9000_fe_get_tune_settings,
Mauro Carvalho Chehab9e9c5bf2011-12-22 20:12:18 -03002572 .get_frontend = dib9000_get_frontend,
Olivier Greniedd316c62011-01-04 04:28:59 -03002573
2574 .read_status = dib9000_read_status,
2575 .read_ber = dib9000_read_ber,
2576 .read_signal_strength = dib9000_read_signal_strength,
2577 .read_snr = dib9000_read_snr,
2578 .read_ucblocks = dib9000_read_unc_blocks,
2579};
2580
Patrick Boettcher99e44da2016-01-24 12:56:58 -02002581MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
2582MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
Olivier Greniedd316c62011-01-04 04:28:59 -03002583MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator");
2584MODULE_LICENSE("GPL");