blob: eecfe2284c91c8c418face49de0696c7d7f8fd6b [file] [log] [blame]
Jemma Denson5afc9a22015-04-14 09:04:50 -03001/*
2 Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner driver
3
4 Copyright (C) 2008 Patrick Boettcher <pb@linuxtv.org>
5 Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
6 Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
7 Copyright (C) 2015 Jemma Denson <jdenson@gmail.com>
8 April 2015
9 Refactored & simplified driver
10 Updated to work with delivery system supplied by DVBv5
11 Add frequency, fec & pilot to get_frontend
12
13 Cards supported: Technisat Skystar S2
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24*/
25
26#include <linux/slab.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/init.h>
31#include <linux/firmware.h>
32#include "dvb_frontend.h"
33#include "cx24120.h"
34
35#define CX24120_SEARCH_RANGE_KHZ 5000
36#define CX24120_FIRMWARE "dvb-fe-cx24120-1.20.58.2.fw"
37
38/* cx24120 i2c registers */
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030039#define CX24120_REG_CMD_START 0x00 /* write cmd_id */
40#define CX24120_REG_CMD_ARGS 0x01 /* write command arguments */
41#define CX24120_REG_CMD_END 0x1f /* write 0x01 for end */
Jemma Denson5afc9a22015-04-14 09:04:50 -030042
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030043#define CX24120_REG_MAILBOX 0x33
44#define CX24120_REG_FREQ3 0x34 /* frequency */
45#define CX24120_REG_FREQ2 0x35
46#define CX24120_REG_FREQ1 0x36
Jemma Denson5afc9a22015-04-14 09:04:50 -030047
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030048#define CX24120_REG_FECMODE 0x39 /* FEC status */
49#define CX24120_REG_STATUS 0x3a /* Tuner status */
50#define CX24120_REG_SIGSTR_H 0x3a /* Signal strength high */
51#define CX24120_REG_SIGSTR_L 0x3b /* Signal strength low byte */
52#define CX24120_REG_QUALITY_H 0x40 /* SNR high byte */
53#define CX24120_REG_QUALITY_L 0x41 /* SNR low byte */
Jemma Denson5afc9a22015-04-14 09:04:50 -030054
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030055#define CX24120_REG_BER_HH 0x47 /* BER high byte of high word */
56#define CX24120_REG_BER_HL 0x48 /* BER low byte of high word */
57#define CX24120_REG_BER_LH 0x49 /* BER high byte of low word */
58#define CX24120_REG_BER_LL 0x4a /* BER low byte of low word */
Jemma Denson5afc9a22015-04-14 09:04:50 -030059
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030060#define CX24120_REG_UCB_H 0x50 /* UCB high byte */
61#define CX24120_REG_UCB_L 0x51 /* UCB low byte */
Jemma Denson5afc9a22015-04-14 09:04:50 -030062
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030063#define CX24120_REG_CLKDIV 0xe6
64#define CX24120_REG_RATEDIV 0xf0
Jemma Denson5afc9a22015-04-14 09:04:50 -030065
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030066#define CX24120_REG_REVISION 0xff /* Chip revision (ro) */
Jemma Denson5afc9a22015-04-14 09:04:50 -030067
Jemma Denson5afc9a22015-04-14 09:04:50 -030068/* Command messages */
69enum command_message_id {
70 CMD_VCO_SET = 0x10, /* cmd.len = 12; */
71 CMD_TUNEREQUEST = 0x11, /* cmd.len = 15; */
72
73 CMD_MPEG_ONOFF = 0x13, /* cmd.len = 4; */
74 CMD_MPEG_INIT = 0x14, /* cmd.len = 7; */
75 CMD_BANDWIDTH = 0x15, /* cmd.len = 12; */
76 CMD_CLOCK_READ = 0x16, /* read clock */
77 CMD_CLOCK_SET = 0x17, /* cmd.len = 10; */
78
79 CMD_DISEQC_MSG1 = 0x20, /* cmd.len = 11; */
80 CMD_DISEQC_MSG2 = 0x21, /* cmd.len = d->msg_len + 6; */
81 CMD_SETVOLTAGE = 0x22, /* cmd.len = 2; */
82 CMD_SETTONE = 0x23, /* cmd.len = 4; */
83 CMD_DISEQC_BURST = 0x24, /* cmd.len not used !!! */
84
85 CMD_READ_SNR = 0x1a, /* Read signal strength */
86 CMD_START_TUNER = 0x1b, /* ??? */
87
88 CMD_FWVERSION = 0x35,
89
90 CMD_TUNER_INIT = 0x3c, /* cmd.len = 0x03; */
91};
92
93#define CX24120_MAX_CMD_LEN 30
94
95/* pilot mask */
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -030096#define CX24120_PILOT_OFF 0x00
97#define CX24120_PILOT_ON 0x40
98#define CX24120_PILOT_AUTO 0x80
Jemma Denson5afc9a22015-04-14 09:04:50 -030099
100/* signal status */
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300101#define CX24120_HAS_SIGNAL 0x01
102#define CX24120_HAS_CARRIER 0x02
103#define CX24120_HAS_VITERBI 0x04
104#define CX24120_HAS_LOCK 0x08
105#define CX24120_HAS_UNK1 0x10
106#define CX24120_HAS_UNK2 0x20
107#define CX24120_STATUS_MASK 0x0f
108#define CX24120_SIGNAL_MASK 0xc0
Jemma Denson5afc9a22015-04-14 09:04:50 -0300109
Patrick Boettcherc5fb0f52015-04-17 06:04:53 -0300110#define info(args...) pr_info("cx24120: " args)
111#define err(args...) pr_err("cx24120: ### ERROR: " args)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300112
113/* The Demod/Tuner can't easily provide these, we cache them */
114struct cx24120_tuning {
115 u32 frequency;
116 u32 symbol_rate;
117 fe_spectral_inversion_t inversion;
118 fe_code_rate_t fec;
119
120 fe_delivery_system_t delsys;
121 fe_modulation_t modulation;
122 fe_pilot_t pilot;
123
124 /* Demod values */
125 u8 fec_val;
126 u8 fec_mask;
127 u8 clkdiv;
128 u8 ratediv;
129 u8 inversion_val;
130 u8 pilot_val;
131};
132
Jemma Denson5afc9a22015-04-14 09:04:50 -0300133/* Private state */
134struct cx24120_state {
135 struct i2c_adapter *i2c;
136 const struct cx24120_config *config;
137 struct dvb_frontend frontend;
138
139 u8 cold_init;
140 u8 mpeg_enabled;
Jemma Denson6138dc22015-04-30 16:37:42 -0300141 u8 need_clock_set;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300142
143 /* current and next tuning parameters */
144 struct cx24120_tuning dcur;
145 struct cx24120_tuning dnxt;
Jemma Denson14626122015-05-05 17:18:11 -0300146
147 fe_status_t fe_status;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300148};
149
Jemma Denson5afc9a22015-04-14 09:04:50 -0300150/* Command message to firmware */
151struct cx24120_cmd {
152 u8 id;
153 u8 len;
154 u8 arg[CX24120_MAX_CMD_LEN];
155};
156
Jemma Denson5afc9a22015-04-14 09:04:50 -0300157/* Read single register */
158static int cx24120_readreg(struct cx24120_state *state, u8 reg)
159{
160 int ret;
161 u8 buf = 0;
162 struct i2c_msg msg[] = {
163 { .addr = state->config->i2c_addr,
164 .flags = 0,
165 .len = 1,
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300166 .buf = &reg
167 }, {
168 .addr = state->config->i2c_addr,
Jemma Denson5afc9a22015-04-14 09:04:50 -0300169 .flags = I2C_M_RD,
170 .len = 1,
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300171 .buf = &buf
172 }
Jemma Denson5afc9a22015-04-14 09:04:50 -0300173 };
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300174
Jemma Denson5afc9a22015-04-14 09:04:50 -0300175 ret = i2c_transfer(state->i2c, msg, 2);
176 if (ret != 2) {
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300177 err("Read error: reg=0x%02x, ret=%i)\n", reg, ret);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300178 return ret;
179 }
180
181 dev_dbg(&state->i2c->dev, "%s: reg=0x%02x; data=0x%02x\n",
182 __func__, reg, buf);
183
184 return buf;
185}
186
Jemma Denson5afc9a22015-04-14 09:04:50 -0300187/* Write single register */
188static int cx24120_writereg(struct cx24120_state *state, u8 reg, u8 data)
189{
190 u8 buf[] = { reg, data };
191 struct i2c_msg msg = {
192 .addr = state->config->i2c_addr,
193 .flags = 0,
194 .buf = buf,
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300195 .len = 2
196 };
Jemma Denson5afc9a22015-04-14 09:04:50 -0300197 int ret;
198
199 ret = i2c_transfer(state->i2c, &msg, 1);
200 if (ret != 1) {
201 err("Write error: i2c_write error(err == %i, 0x%02x: 0x%02x)\n",
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300202 ret, reg, data);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300203 return ret;
204 }
205
206 dev_dbg(&state->i2c->dev, "%s: reg=0x%02x; data=0x%02x\n",
207 __func__, reg, data);
208
209 return 0;
210}
211
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300212/* Write multiple registers in chunks of i2c_wr_max-sized buffers */
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300213static int cx24120_writeregs(struct cx24120_state *state,
214 u8 reg, const u8 *values, u16 len, u8 incr)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300215{
216 int ret;
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300217 u16 max = state->config->i2c_wr_max > 0 ?
218 state->config->i2c_wr_max :
219 len;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300220
221 struct i2c_msg msg = {
222 .addr = state->config->i2c_addr,
223 .flags = 0,
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300224 };
225
226 msg.buf = kmalloc(max + 1, GFP_KERNEL);
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300227 if (!msg.buf)
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300228 return -ENOMEM;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300229
230 while (len) {
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300231 msg.buf[0] = reg;
232 msg.len = len > max ? max : len;
233 memcpy(&msg.buf[1], values, msg.len);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300234
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300235 len -= msg.len; /* data length revers counter */
236 values += msg.len; /* incr data pointer */
Jemma Denson5afc9a22015-04-14 09:04:50 -0300237
238 if (incr)
239 reg += msg.len;
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300240 msg.len++; /* don't forget the addr byte */
Jemma Denson5afc9a22015-04-14 09:04:50 -0300241
242 ret = i2c_transfer(state->i2c, &msg, 1);
243 if (ret != 1) {
244 err("i2c_write error(err == %i, 0x%02x)\n", ret, reg);
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300245 goto out;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300246 }
247
248 dev_dbg(&state->i2c->dev,
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300249 "%s: reg=0x%02x; data=%*ph\n",
Jemma Denson6ce41222015-05-01 16:20:16 -0300250 __func__, reg, msg.len - 1, msg.buf + 1);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300251 }
252
Patrick Boettcherf7a77eb2015-04-28 02:47:42 -0300253 ret = 0;
254
255out:
256 kfree(msg.buf);
257 return ret;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300258}
259
Jemma Denson5afc9a22015-04-14 09:04:50 -0300260static struct dvb_frontend_ops cx24120_ops;
261
262struct dvb_frontend *cx24120_attach(const struct cx24120_config *config,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300263 struct i2c_adapter *i2c)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300264{
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300265 struct cx24120_state *state;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300266 int demod_rev;
267
268 info("Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner\n");
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300269 state = kzalloc(sizeof(*state), GFP_KERNEL);
270 if (!state) {
Jemma Denson5afc9a22015-04-14 09:04:50 -0300271 err("Unable to allocate memory for cx24120_state\n");
272 goto error;
273 }
274
275 /* setup the state */
276 state->config = config;
277 state->i2c = i2c;
278
279 /* check if the demod is present and has proper type */
280 demod_rev = cx24120_readreg(state, CX24120_REG_REVISION);
281 switch (demod_rev) {
282 case 0x07:
283 info("Demod cx24120 rev. 0x07 detected.\n");
284 break;
285 case 0x05:
286 info("Demod cx24120 rev. 0x05 detected.\n");
287 break;
288 default:
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300289 err("Unsupported demod revision: 0x%x detected.\n", demod_rev);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300290 goto error;
291 }
292
293 /* create dvb_frontend */
294 state->cold_init = 0;
295 memcpy(&state->frontend.ops, &cx24120_ops,
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300296 sizeof(struct dvb_frontend_ops));
Jemma Denson5afc9a22015-04-14 09:04:50 -0300297 state->frontend.demodulator_priv = state;
298
299 info("Conexant cx24120/cx24118 attached.\n");
300 return &state->frontend;
301
302error:
303 kfree(state);
304 return NULL;
305}
306EXPORT_SYMBOL(cx24120_attach);
307
308static int cx24120_test_rom(struct cx24120_state *state)
309{
310 int err, ret;
311
312 err = cx24120_readreg(state, 0xfd);
313 if (err & 4) {
314 ret = cx24120_readreg(state, 0xdf) & 0xfe;
315 err = cx24120_writereg(state, 0xdf, ret);
316 }
317 return err;
318}
319
Jemma Denson5afc9a22015-04-14 09:04:50 -0300320static int cx24120_read_snr(struct dvb_frontend *fe, u16 *snr)
321{
322 struct cx24120_state *state = fe->demodulator_priv;
323
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300324 *snr = (cx24120_readreg(state, CX24120_REG_QUALITY_H) << 8) |
Jemma Denson5afc9a22015-04-14 09:04:50 -0300325 (cx24120_readreg(state, CX24120_REG_QUALITY_L));
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300326 dev_dbg(&state->i2c->dev, "%s: read SNR index = %d\n", __func__, *snr);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300327
328 return 0;
329}
330
Jemma Denson5afc9a22015-04-14 09:04:50 -0300331static int cx24120_read_ber(struct dvb_frontend *fe, u32 *ber)
332{
333 struct cx24120_state *state = fe->demodulator_priv;
334
335 *ber = (cx24120_readreg(state, CX24120_REG_BER_HH) << 24) |
336 (cx24120_readreg(state, CX24120_REG_BER_HL) << 16) |
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300337 (cx24120_readreg(state, CX24120_REG_BER_LH) << 8) |
Jemma Denson5afc9a22015-04-14 09:04:50 -0300338 cx24120_readreg(state, CX24120_REG_BER_LL);
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300339 dev_dbg(&state->i2c->dev, "%s: read BER index = %d\n", __func__, *ber);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300340
341 return 0;
342}
343
344static int cx24120_msg_mpeg_output_global_config(struct cx24120_state *state,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300345 u8 flag);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300346
347/* Check if we're running a command that needs to disable mpeg out */
348static void cx24120_check_cmd(struct cx24120_state *state, u8 id)
349{
350 switch (id) {
351 case CMD_TUNEREQUEST:
352 case CMD_CLOCK_READ:
353 case CMD_DISEQC_MSG1:
354 case CMD_DISEQC_MSG2:
355 case CMD_SETVOLTAGE:
356 case CMD_SETTONE:
Jemma Denson270e707132015-04-30 17:05:14 -0300357 case CMD_DISEQC_BURST:
Jemma Denson5afc9a22015-04-14 09:04:50 -0300358 cx24120_msg_mpeg_output_global_config(state, 0);
359 /* Old driver would do a msleep(100) here */
360 default:
361 return;
362 }
363}
364
Jemma Denson5afc9a22015-04-14 09:04:50 -0300365/* Send a message to the firmware */
366static int cx24120_message_send(struct cx24120_state *state,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300367 struct cx24120_cmd *cmd)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300368{
369 int ret, ficus;
370
371 if (state->mpeg_enabled) {
372 /* Disable mpeg out on certain commands */
373 cx24120_check_cmd(state, cmd->id);
374 }
375
376 ret = cx24120_writereg(state, CX24120_REG_CMD_START, cmd->id);
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300377 ret = cx24120_writeregs(state, CX24120_REG_CMD_ARGS, &cmd->arg[0],
Jemma Denson5afc9a22015-04-14 09:04:50 -0300378 cmd->len, 1);
379 ret = cx24120_writereg(state, CX24120_REG_CMD_END, 0x01);
380
381 ficus = 1000;
382 while (cx24120_readreg(state, CX24120_REG_CMD_END)) {
383 msleep(20);
384 ficus -= 20;
385 if (ficus == 0) {
386 err("Error sending message to firmware\n");
387 return -EREMOTEIO;
388 }
389 }
390 dev_dbg(&state->i2c->dev, "%s: Successfully send message 0x%02x\n",
391 __func__, cmd->id);
392
393 return 0;
394}
395
396/* Send a message and fill arg[] with the results */
397static int cx24120_message_sendrcv(struct cx24120_state *state,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300398 struct cx24120_cmd *cmd, u8 numreg)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300399{
400 int ret, i;
401
402 if (numreg > CX24120_MAX_CMD_LEN) {
403 err("Too many registers to read. cmd->reg = %d", numreg);
404 return -EREMOTEIO;
405 }
406
407 ret = cx24120_message_send(state, cmd);
408 if (ret != 0)
409 return ret;
410
411 if (!numreg)
412 return 0;
413
414 /* Read numreg registers starting from register cmd->len */
415 for (i = 0; i < numreg; i++)
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300416 cmd->arg[i] = cx24120_readreg(state, (cmd->len + i + 1));
Jemma Denson5afc9a22015-04-14 09:04:50 -0300417
418 return 0;
419}
420
Jemma Denson5afc9a22015-04-14 09:04:50 -0300421static int cx24120_read_signal_strength(struct dvb_frontend *fe,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300422 u16 *signal_strength)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300423{
424 struct cx24120_state *state = fe->demodulator_priv;
Jemma Denson34ce4752015-05-05 17:47:55 -0300425 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300426
Jemma Denson34ce4752015-05-05 17:47:55 -0300427 if (c->strength.stat[0].scale != FE_SCALE_RELATIVE)
428 *signal_strength = 0;
429 else
430 *signal_strength = c->strength.stat[0].uvalue;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300431
Jemma Denson34ce4752015-05-05 17:47:55 -0300432 dev_dbg(&state->i2c->dev, "%s: Signal strength from cache: 0x%x\n",
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300433 __func__, *signal_strength);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300434
435 return 0;
436}
437
Jemma Denson5afc9a22015-04-14 09:04:50 -0300438static int cx24120_msg_mpeg_output_global_config(struct cx24120_state *state,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300439 u8 enable)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300440{
441 struct cx24120_cmd cmd;
442 int ret;
443
444 cmd.id = CMD_MPEG_ONOFF;
445 cmd.len = 4;
446 cmd.arg[0] = 0x01;
447 cmd.arg[1] = 0x00;
448 cmd.arg[2] = enable ? 0 : (u8)(-1);
449 cmd.arg[3] = 0x01;
450
451 ret = cx24120_message_send(state, &cmd);
452 if (ret != 0) {
453 dev_dbg(&state->i2c->dev,
454 "%s: Failed to set MPEG output to %s\n",
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300455 __func__, enable ? "enabled" : "disabled");
Jemma Denson5afc9a22015-04-14 09:04:50 -0300456 return ret;
457 }
458
459 state->mpeg_enabled = enable;
460 dev_dbg(&state->i2c->dev, "%s: MPEG output %s\n",
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300461 __func__, enable ? "enabled" : "disabled");
Jemma Denson5afc9a22015-04-14 09:04:50 -0300462
463 return 0;
464}
465
Jemma Denson5afc9a22015-04-14 09:04:50 -0300466static int cx24120_msg_mpeg_output_config(struct cx24120_state *state, u8 seq)
467{
468 struct cx24120_cmd cmd;
469 struct cx24120_initial_mpeg_config i =
470 state->config->initial_mpeg_config;
471
472 cmd.id = CMD_MPEG_INIT;
473 cmd.len = 7;
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300474 cmd.arg[0] = seq; /* sequental number - can be 0,1,2 */
Jemma Denson5afc9a22015-04-14 09:04:50 -0300475 cmd.arg[1] = ((i.x1 & 0x01) << 1) | ((i.x1 >> 1) & 0x01);
476 cmd.arg[2] = 0x05;
477 cmd.arg[3] = 0x02;
478 cmd.arg[4] = ((i.x2 >> 1) & 0x01);
479 cmd.arg[5] = (i.x2 & 0xf0) | (i.x3 & 0x0f);
480 cmd.arg[6] = 0x10;
481
482 return cx24120_message_send(state, &cmd);
483}
484
Jemma Denson5afc9a22015-04-14 09:04:50 -0300485static int cx24120_diseqc_send_burst(struct dvb_frontend *fe,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300486 fe_sec_mini_cmd_t burst)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300487{
488 struct cx24120_state *state = fe->demodulator_priv;
489 struct cx24120_cmd cmd;
490
491 /* Yes, cmd.len is set to zero. The old driver
492 * didn't specify any len, but also had a
493 * memset 0 before every use of the cmd struct
494 * which would have set it to zero.
495 * This quite probably needs looking into.
496 */
497 cmd.id = CMD_DISEQC_BURST;
498 cmd.len = 0;
499 cmd.arg[0] = 0x00;
500 if (burst)
501 cmd.arg[1] = 0x01;
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300502
Jemma Denson5afc9a22015-04-14 09:04:50 -0300503 dev_dbg(&state->i2c->dev, "%s: burst sent.\n", __func__);
504
505 return cx24120_message_send(state, &cmd);
506}
507
Jemma Denson5afc9a22015-04-14 09:04:50 -0300508static int cx24120_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
509{
510 struct cx24120_state *state = fe->demodulator_priv;
511 struct cx24120_cmd cmd;
512
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300513 dev_dbg(&state->i2c->dev, "%s(%d)\n", __func__, tone);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300514
515 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
516 err("Invalid tone=%d\n", tone);
517 return -EINVAL;
518 }
519
520 cmd.id = CMD_SETTONE;
521 cmd.len = 4;
522 cmd.arg[0] = 0x00;
523 cmd.arg[1] = 0x00;
524 cmd.arg[2] = 0x00;
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300525 cmd.arg[3] = (tone == SEC_TONE_ON) ? 0x01 : 0x00;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300526
527 return cx24120_message_send(state, &cmd);
528}
529
Jemma Denson5afc9a22015-04-14 09:04:50 -0300530static int cx24120_set_voltage(struct dvb_frontend *fe,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300531 fe_sec_voltage_t voltage)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300532{
533 struct cx24120_state *state = fe->demodulator_priv;
534 struct cx24120_cmd cmd;
535
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300536 dev_dbg(&state->i2c->dev, "%s(%d)\n", __func__, voltage);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300537
538 cmd.id = CMD_SETVOLTAGE;
539 cmd.len = 2;
540 cmd.arg[0] = 0x00;
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300541 cmd.arg[1] = (voltage == SEC_VOLTAGE_18) ? 0x01 : 0x00;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300542
543 return cx24120_message_send(state, &cmd);
544}
545
Jemma Denson5afc9a22015-04-14 09:04:50 -0300546static int cx24120_send_diseqc_msg(struct dvb_frontend *fe,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300547 struct dvb_diseqc_master_cmd *d)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300548{
549 struct cx24120_state *state = fe->demodulator_priv;
550 struct cx24120_cmd cmd;
551 int back_count;
552
553 dev_dbg(&state->i2c->dev, "%s()\n", __func__);
554
555 cmd.id = CMD_DISEQC_MSG1;
556 cmd.len = 11;
557 cmd.arg[0] = 0x00;
558 cmd.arg[1] = 0x00;
559 cmd.arg[2] = 0x03;
560 cmd.arg[3] = 0x16;
561 cmd.arg[4] = 0x28;
562 cmd.arg[5] = 0x01;
563 cmd.arg[6] = 0x01;
564 cmd.arg[7] = 0x14;
565 cmd.arg[8] = 0x19;
566 cmd.arg[9] = 0x14;
567 cmd.arg[10] = 0x1e;
568
569 if (cx24120_message_send(state, &cmd)) {
570 err("send 1st message(0x%x) failed\n", cmd.id);
571 return -EREMOTEIO;
572 }
573
574 cmd.id = CMD_DISEQC_MSG2;
575 cmd.len = d->msg_len + 6;
576 cmd.arg[0] = 0x00;
577 cmd.arg[1] = 0x01;
578 cmd.arg[2] = 0x02;
579 cmd.arg[3] = 0x00;
580 cmd.arg[4] = 0x00;
581 cmd.arg[5] = d->msg_len;
582
583 memcpy(&cmd.arg[6], &d->msg, d->msg_len);
584
585 if (cx24120_message_send(state, &cmd)) {
586 err("send 2nd message(0x%x) failed\n", cmd.id);
587 return -EREMOTEIO;
588 }
589
590 back_count = 500;
591 do {
592 if (!(cx24120_readreg(state, 0x93) & 0x01)) {
593 dev_dbg(&state->i2c->dev,
594 "%s: diseqc sequence sent success\n",
595 __func__);
596 return 0;
597 }
598 msleep(20);
599 back_count -= 20;
600 } while (back_count);
601
602 err("Too long waiting for diseqc.\n");
603 return -ETIMEDOUT;
604}
605
Jemma Denson14626122015-05-05 17:18:11 -0300606static void cx24120_get_stats(struct cx24120_state *state)
Jemma Denson9fc18f12015-05-05 16:59:27 -0300607{
608 struct dvb_frontend *fe = &state->frontend;
609 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Jemma Denson34ce4752015-05-05 17:47:55 -0300610 struct cx24120_cmd cmd;
611 int ret, sigstr_h, sigstr_l;
Jemma Denson9fc18f12015-05-05 16:59:27 -0300612 u16 u16tmp;
613
614 dev_dbg(&state->i2c->dev, "%s()\n", __func__);
615
616 /* signal strength */
Jemma Denson14626122015-05-05 17:18:11 -0300617 if (state->fe_status & FE_HAS_SIGNAL) {
Jemma Denson34ce4752015-05-05 17:47:55 -0300618 cmd.id = CMD_READ_SNR;
619 cmd.len = 1;
620 cmd.arg[0] = 0x00;
621
622 ret = cx24120_message_send(state, &cmd);
623 if (ret != 0) {
624 err("error reading signal strength\n");
Jemma Denson9fc18f12015-05-05 16:59:27 -0300625 return;
Jemma Denson34ce4752015-05-05 17:47:55 -0300626 }
627
628 /* raw */
629 sigstr_h = (cx24120_readreg(state, CX24120_REG_SIGSTR_H) >> 6) << 8;
630 sigstr_l = cx24120_readreg(state, CX24120_REG_SIGSTR_L);
631 dev_dbg(&state->i2c->dev, "%s: Signal strength from firmware= 0x%x\n",
632 __func__, (sigstr_h | sigstr_l));
633
634 /* cooked */
635 u16tmp = ((sigstr_h | sigstr_l) << 5) & 0x0000ffff;
636 dev_dbg(&state->i2c->dev, "%s: Signal strength= 0x%x\n",
637 __func__, u16tmp);
Jemma Denson9fc18f12015-05-05 16:59:27 -0300638
639 c->strength.stat[0].scale = FE_SCALE_RELATIVE;
640 c->strength.stat[0].uvalue = u16tmp;
641 } else {
642 c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
643 }
644
645 /* FIXME: add CNR */
646
647 /* FIXME: add UCB/BER */
648}
649
Jemma Denson6138dc22015-04-30 16:37:42 -0300650static void cx24120_set_clock_ratios(struct dvb_frontend *fe);
651
Jemma Denson5afc9a22015-04-14 09:04:50 -0300652/* Read current tuning status */
653static int cx24120_read_status(struct dvb_frontend *fe, fe_status_t *status)
654{
655 struct cx24120_state *state = fe->demodulator_priv;
656 int lock;
657
658 lock = cx24120_readreg(state, CX24120_REG_STATUS);
659
660 dev_dbg(&state->i2c->dev, "%s() status = 0x%02x\n",
661 __func__, lock);
662
663 *status = 0;
664
665 if (lock & CX24120_HAS_SIGNAL)
666 *status = FE_HAS_SIGNAL;
667 if (lock & CX24120_HAS_CARRIER)
668 *status |= FE_HAS_CARRIER;
669 if (lock & CX24120_HAS_VITERBI)
670 *status |= FE_HAS_VITERBI | FE_HAS_SYNC;
671 if (lock & CX24120_HAS_LOCK)
672 *status |= FE_HAS_LOCK;
673
674 /* TODO: is FE_HAS_SYNC in the right place?
675 * Other cx241xx drivers have this slightly
676 * different */
677
Jemma Denson14626122015-05-05 17:18:11 -0300678 state->fe_status = *status;
679 cx24120_get_stats(state);
Jemma Denson9fc18f12015-05-05 16:59:27 -0300680
Jemma Denson6138dc22015-04-30 16:37:42 -0300681 /* Set the clock once tuned in */
682 if (state->need_clock_set && *status & FE_HAS_LOCK) {
683 /* Set clock ratios */
684 cx24120_set_clock_ratios(fe);
685
686 /* Old driver would do a msleep(200) here */
687
688 /* Renable mpeg output */
689 if (!state->mpeg_enabled)
690 cx24120_msg_mpeg_output_global_config(state, 1);
691
692 state->need_clock_set = 0;
693 }
694
Jemma Denson5afc9a22015-04-14 09:04:50 -0300695 return 0;
696}
697
Jemma Denson5afc9a22015-04-14 09:04:50 -0300698/* FEC & modulation lookup table
699 * Used for decoding the REG_FECMODE register
700 * once tuned in.
701 */
702static struct cx24120_modfec {
703 fe_delivery_system_t delsys;
704 fe_modulation_t mod;
705 fe_code_rate_t fec;
706 u8 val;
707} modfec_lookup_table[] = {
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300708 /*delsys mod fec val */
709 { SYS_DVBS, QPSK, FEC_1_2, 0x01 },
710 { SYS_DVBS, QPSK, FEC_2_3, 0x02 },
711 { SYS_DVBS, QPSK, FEC_3_4, 0x03 },
712 { SYS_DVBS, QPSK, FEC_4_5, 0x04 },
713 { SYS_DVBS, QPSK, FEC_5_6, 0x05 },
714 { SYS_DVBS, QPSK, FEC_6_7, 0x06 },
715 { SYS_DVBS, QPSK, FEC_7_8, 0x07 },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300716
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300717 { SYS_DVBS2, QPSK, FEC_1_2, 0x04 },
718 { SYS_DVBS2, QPSK, FEC_3_5, 0x05 },
719 { SYS_DVBS2, QPSK, FEC_2_3, 0x06 },
720 { SYS_DVBS2, QPSK, FEC_3_4, 0x07 },
721 { SYS_DVBS2, QPSK, FEC_4_5, 0x08 },
722 { SYS_DVBS2, QPSK, FEC_5_6, 0x09 },
723 { SYS_DVBS2, QPSK, FEC_8_9, 0x0a },
724 { SYS_DVBS2, QPSK, FEC_9_10, 0x0b },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300725
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300726 { SYS_DVBS2, PSK_8, FEC_3_5, 0x0c },
727 { SYS_DVBS2, PSK_8, FEC_2_3, 0x0d },
728 { SYS_DVBS2, PSK_8, FEC_3_4, 0x0e },
729 { SYS_DVBS2, PSK_8, FEC_5_6, 0x0f },
730 { SYS_DVBS2, PSK_8, FEC_8_9, 0x10 },
731 { SYS_DVBS2, PSK_8, FEC_9_10, 0x11 },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300732};
733
Jemma Denson5afc9a22015-04-14 09:04:50 -0300734/* Retrieve current fec, modulation & pilot values */
735static int cx24120_get_fec(struct dvb_frontend *fe)
736{
737 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
738 struct cx24120_state *state = fe->demodulator_priv;
739 int idx;
740 int ret;
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300741 int fec;
Jemma Denson5afc9a22015-04-14 09:04:50 -0300742
743 dev_dbg(&state->i2c->dev, "%s()\n", __func__);
744
745 ret = cx24120_readreg(state, CX24120_REG_FECMODE);
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300746 fec = ret & 0x3f; /* Lower 6 bits */
Jemma Denson5afc9a22015-04-14 09:04:50 -0300747
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300748 dev_dbg(&state->i2c->dev, "%s: Get FEC: %d\n", __func__, fec);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300749
750 for (idx = 0; idx < ARRAY_SIZE(modfec_lookup_table); idx++) {
751 if (modfec_lookup_table[idx].delsys != state->dcur.delsys)
752 continue;
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300753 if (modfec_lookup_table[idx].val != fec)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300754 continue;
755
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300756 break; /* found */
Jemma Denson5afc9a22015-04-14 09:04:50 -0300757 }
758
759 if (idx >= ARRAY_SIZE(modfec_lookup_table)) {
760 dev_dbg(&state->i2c->dev, "%s: Couldn't find fec!\n",
761 __func__);
762 return -EINVAL;
763 }
764
765 /* save values back to cache */
766 c->modulation = modfec_lookup_table[idx].mod;
767 c->fec_inner = modfec_lookup_table[idx].fec;
768 c->pilot = (ret & 0x80) ? PILOT_ON : PILOT_OFF;
769
770 dev_dbg(&state->i2c->dev,
771 "%s: mod(%d), fec(%d), pilot(%d)\n",
772 __func__,
773 c->modulation, c->fec_inner, c->pilot);
774
775 return 0;
776}
777
Jemma Denson5afc9a22015-04-14 09:04:50 -0300778/* Clock ratios lookup table
779 *
780 * Values obtained from much larger table in old driver
781 * which had numerous entries which would never match.
782 *
783 * There's probably some way of calculating these but I
784 * can't determine the pattern
785*/
786static struct cx24120_clock_ratios_table {
787 fe_delivery_system_t delsys;
788 fe_pilot_t pilot;
789 fe_modulation_t mod;
790 fe_code_rate_t fec;
791 u32 m_rat;
792 u32 n_rat;
793 u32 rate;
794} clock_ratios_table[] = {
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300795 /*delsys pilot mod fec m_rat n_rat rate */
796 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_1_2, 273088, 254505, 274 },
797 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_3_5, 17272, 13395, 330 },
798 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_2_3, 24344, 16967, 367 },
799 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_3_4, 410788, 254505, 413 },
800 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_4_5, 438328, 254505, 440 },
801 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_5_6, 30464, 16967, 459 },
802 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_8_9, 487832, 254505, 490 },
803 { SYS_DVBS2, PILOT_OFF, QPSK, FEC_9_10, 493952, 254505, 496 },
804 { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_3_5, 328168, 169905, 494 },
805 { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_2_3, 24344, 11327, 550 },
806 { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_3_4, 410788, 169905, 618 },
807 { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_5_6, 30464, 11327, 688 },
808 { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_8_9, 487832, 169905, 735 },
809 { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_9_10, 493952, 169905, 744 },
810 { SYS_DVBS2, PILOT_ON, QPSK, FEC_1_2, 273088, 260709, 268 },
811 { SYS_DVBS2, PILOT_ON, QPSK, FEC_3_5, 328168, 260709, 322 },
812 { SYS_DVBS2, PILOT_ON, QPSK, FEC_2_3, 121720, 86903, 358 },
813 { SYS_DVBS2, PILOT_ON, QPSK, FEC_3_4, 410788, 260709, 403 },
814 { SYS_DVBS2, PILOT_ON, QPSK, FEC_4_5, 438328, 260709, 430 },
815 { SYS_DVBS2, PILOT_ON, QPSK, FEC_5_6, 152320, 86903, 448 },
816 { SYS_DVBS2, PILOT_ON, QPSK, FEC_8_9, 487832, 260709, 479 },
817 { SYS_DVBS2, PILOT_ON, QPSK, FEC_9_10, 493952, 260709, 485 },
818 { SYS_DVBS2, PILOT_ON, PSK_8, FEC_3_5, 328168, 173853, 483 },
819 { SYS_DVBS2, PILOT_ON, PSK_8, FEC_2_3, 121720, 57951, 537 },
820 { SYS_DVBS2, PILOT_ON, PSK_8, FEC_3_4, 410788, 173853, 604 },
821 { SYS_DVBS2, PILOT_ON, PSK_8, FEC_5_6, 152320, 57951, 672 },
822 { SYS_DVBS2, PILOT_ON, PSK_8, FEC_8_9, 487832, 173853, 718 },
823 { SYS_DVBS2, PILOT_ON, PSK_8, FEC_9_10, 493952, 173853, 727 },
824 { SYS_DVBS, PILOT_OFF, QPSK, FEC_1_2, 152592, 152592, 256 },
825 { SYS_DVBS, PILOT_OFF, QPSK, FEC_2_3, 305184, 228888, 341 },
826 { SYS_DVBS, PILOT_OFF, QPSK, FEC_3_4, 457776, 305184, 384 },
827 { SYS_DVBS, PILOT_OFF, QPSK, FEC_5_6, 762960, 457776, 427 },
828 { SYS_DVBS, PILOT_OFF, QPSK, FEC_7_8, 1068144, 610368, 448 },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300829};
830
Jemma Denson5afc9a22015-04-14 09:04:50 -0300831/* Set clock ratio from lookup table */
832static void cx24120_set_clock_ratios(struct dvb_frontend *fe)
833{
834 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
835 struct cx24120_state *state = fe->demodulator_priv;
836 struct cx24120_cmd cmd;
837 int ret, idx;
838
839 /* Find fec, modulation, pilot */
840 ret = cx24120_get_fec(fe);
841 if (ret != 0)
842 return;
843
844 /* Find the clock ratios in the lookup table */
845 for (idx = 0; idx < ARRAY_SIZE(clock_ratios_table); idx++) {
846 if (clock_ratios_table[idx].delsys != state->dcur.delsys)
847 continue;
848 if (clock_ratios_table[idx].mod != c->modulation)
849 continue;
850 if (clock_ratios_table[idx].fec != c->fec_inner)
851 continue;
852 if (clock_ratios_table[idx].pilot != c->pilot)
853 continue;
854
855 break; /* found */
856 }
857
858 if (idx >= ARRAY_SIZE(clock_ratios_table)) {
859 info("Clock ratio not found - data reception in danger\n");
860 return;
861 }
862
Jemma Denson5afc9a22015-04-14 09:04:50 -0300863 /* Read current values? */
864 cmd.id = CMD_CLOCK_READ;
865 cmd.len = 1;
866 cmd.arg[0] = 0x00;
867 ret = cx24120_message_sendrcv(state, &cmd, 6);
868 if (ret != 0)
869 return;
870 /* in cmd[0]-[5] - result */
871
872 dev_dbg(&state->i2c->dev,
873 "%s: m=%d, n=%d; idx: %d m=%d, n=%d, rate=%d\n",
874 __func__,
875 cmd.arg[2] | (cmd.arg[1] << 8) | (cmd.arg[0] << 16),
876 cmd.arg[5] | (cmd.arg[4] << 8) | (cmd.arg[3] << 16),
877 idx,
878 clock_ratios_table[idx].m_rat,
879 clock_ratios_table[idx].n_rat,
880 clock_ratios_table[idx].rate);
881
Jemma Denson5afc9a22015-04-14 09:04:50 -0300882 /* Set the clock */
883 cmd.id = CMD_CLOCK_SET;
884 cmd.len = 10;
885 cmd.arg[0] = 0;
886 cmd.arg[1] = 0x10;
887 cmd.arg[2] = (clock_ratios_table[idx].m_rat >> 16) & 0xff;
888 cmd.arg[3] = (clock_ratios_table[idx].m_rat >> 8) & 0xff;
889 cmd.arg[4] = (clock_ratios_table[idx].m_rat >> 0) & 0xff;
890 cmd.arg[5] = (clock_ratios_table[idx].n_rat >> 16) & 0xff;
891 cmd.arg[6] = (clock_ratios_table[idx].n_rat >> 8) & 0xff;
892 cmd.arg[7] = (clock_ratios_table[idx].n_rat >> 0) & 0xff;
893 cmd.arg[8] = (clock_ratios_table[idx].rate >> 8) & 0xff;
894 cmd.arg[9] = (clock_ratios_table[idx].rate >> 0) & 0xff;
895
896 cx24120_message_send(state, &cmd);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300897}
898
Jemma Denson5afc9a22015-04-14 09:04:50 -0300899/* Set inversion value */
900static int cx24120_set_inversion(struct cx24120_state *state,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300901 fe_spectral_inversion_t inversion)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300902{
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300903 dev_dbg(&state->i2c->dev, "%s(%d)\n", __func__, inversion);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300904
905 switch (inversion) {
906 case INVERSION_OFF:
907 state->dnxt.inversion_val = 0x00;
908 break;
909 case INVERSION_ON:
910 state->dnxt.inversion_val = 0x04;
911 break;
912 case INVERSION_AUTO:
913 state->dnxt.inversion_val = 0x0c;
914 break;
915 default:
916 return -EINVAL;
917 }
918
919 state->dnxt.inversion = inversion;
920
921 return 0;
922}
923
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300924/*
925 * FEC lookup table for tuning Some DVB-S2 val's have been found by
926 * trial and error. Sofar it seems to match up with the contents of
927 * the REG_FECMODE after tuning The rest will probably be the same but
928 * would need testing. Anything not in the table will run with
929 * FEC_AUTO and take a while longer to tune in ( c.500ms instead of
930 * 30ms )
Jemma Denson5afc9a22015-04-14 09:04:50 -0300931 */
932static struct cx24120_modfec_table {
933 fe_delivery_system_t delsys;
934 fe_modulation_t mod;
935 fe_code_rate_t fec;
936 u8 val;
937} modfec_table[] = {
938/*delsys mod fec val */
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300939 { SYS_DVBS, QPSK, FEC_1_2, 0x2e },
940 { SYS_DVBS, QPSK, FEC_2_3, 0x2f },
941 { SYS_DVBS, QPSK, FEC_3_4, 0x30 },
942 { SYS_DVBS, QPSK, FEC_5_6, 0x31 },
943 { SYS_DVBS, QPSK, FEC_6_7, 0x32 },
944 { SYS_DVBS, QPSK, FEC_7_8, 0x33 },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300945
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300946 { SYS_DVBS2, QPSK, FEC_3_4, 0x07 },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300947
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300948 { SYS_DVBS2, PSK_8, FEC_2_3, 0x0d },
949 { SYS_DVBS2, PSK_8, FEC_3_4, 0x0e },
Jemma Denson5afc9a22015-04-14 09:04:50 -0300950};
951
952/* Set fec_val & fec_mask values from delsys, modulation & fec */
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300953static int cx24120_set_fec(struct cx24120_state *state, fe_modulation_t mod,
954 fe_code_rate_t fec)
Jemma Denson5afc9a22015-04-14 09:04:50 -0300955{
956 int idx;
957
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300958 dev_dbg(&state->i2c->dev, "%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300959
960 state->dnxt.fec = fec;
961
962 /* Lookup fec_val from modfec table */
963 for (idx = 0; idx < ARRAY_SIZE(modfec_table); idx++) {
964 if (modfec_table[idx].delsys != state->dnxt.delsys)
965 continue;
966 if (modfec_table[idx].mod != mod)
967 continue;
968 if (modfec_table[idx].fec != fec)
969 continue;
970
971 /* found */
972 state->dnxt.fec_mask = 0x00;
973 state->dnxt.fec_val = modfec_table[idx].val;
974 return 0;
975 }
976
Jemma Denson5afc9a22015-04-14 09:04:50 -0300977 if (state->dnxt.delsys == SYS_DVBS2) {
978 /* DVBS2 auto is 0x00/0x00 */
979 state->dnxt.fec_mask = 0x00;
980 state->dnxt.fec_val = 0x00;
981 } else {
982 /* Set DVB-S to auto */
983 state->dnxt.fec_val = 0x2e;
984 state->dnxt.fec_mask = 0xac;
985 }
986
987 return 0;
988}
989
Jemma Denson5afc9a22015-04-14 09:04:50 -0300990/* Set pilot */
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -0300991static int cx24120_set_pilot(struct cx24120_state *state, fe_pilot_t pilot)
992{
Patrick Boettcher2e89a5e2015-04-28 13:18:05 -0300993 dev_dbg(&state->i2c->dev, "%s(%d)\n", __func__, pilot);
Jemma Denson5afc9a22015-04-14 09:04:50 -0300994
995 /* Pilot only valid in DVBS2 */
996 if (state->dnxt.delsys != SYS_DVBS2) {
997 state->dnxt.pilot_val = CX24120_PILOT_OFF;
998 return 0;
999 }
1000
Jemma Denson5afc9a22015-04-14 09:04:50 -03001001 switch (pilot) {
1002 case PILOT_OFF:
1003 state->dnxt.pilot_val = CX24120_PILOT_OFF;
1004 break;
1005 case PILOT_ON:
1006 state->dnxt.pilot_val = CX24120_PILOT_ON;
1007 break;
1008 case PILOT_AUTO:
1009 default:
1010 state->dnxt.pilot_val = CX24120_PILOT_AUTO;
1011 }
1012
1013 return 0;
1014}
1015
1016/* Set symbol rate */
1017static int cx24120_set_symbolrate(struct cx24120_state *state, u32 rate)
1018{
1019 dev_dbg(&state->i2c->dev, "%s(%d)\n",
1020 __func__, rate);
1021
1022 state->dnxt.symbol_rate = rate;
1023
1024 /* Check symbol rate */
1025 if (rate > 31000000) {
1026 state->dnxt.clkdiv = (-(rate < 31000001) & 3) + 2;
1027 state->dnxt.ratediv = (-(rate < 31000001) & 6) + 4;
1028 } else {
1029 state->dnxt.clkdiv = 3;
1030 state->dnxt.ratediv = 6;
1031 }
1032
1033 return 0;
1034}
1035
Jemma Denson5afc9a22015-04-14 09:04:50 -03001036/* Overwrite the current tuning params, we are about to tune */
1037static void cx24120_clone_params(struct dvb_frontend *fe)
1038{
1039 struct cx24120_state *state = fe->demodulator_priv;
1040
1041 state->dcur = state->dnxt;
1042}
1043
Jemma Denson5afc9a22015-04-14 09:04:50 -03001044static int cx24120_set_frontend(struct dvb_frontend *fe)
1045{
1046 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1047 struct cx24120_state *state = fe->demodulator_priv;
1048 struct cx24120_cmd cmd;
1049 int ret;
Jemma Denson5afc9a22015-04-14 09:04:50 -03001050
1051 switch (c->delivery_system) {
1052 case SYS_DVBS2:
1053 dev_dbg(&state->i2c->dev, "%s() DVB-S2\n",
1054 __func__);
1055 break;
1056 case SYS_DVBS:
1057 dev_dbg(&state->i2c->dev, "%s() DVB-S\n",
1058 __func__);
1059 break;
1060 default:
1061 dev_dbg(&state->i2c->dev,
1062 "%s() Delivery system(%d) not supported\n",
1063 __func__, c->delivery_system);
1064 ret = -EINVAL;
1065 break;
1066 }
1067
Jemma Denson5afc9a22015-04-14 09:04:50 -03001068 state->dnxt.delsys = c->delivery_system;
1069 state->dnxt.modulation = c->modulation;
1070 state->dnxt.frequency = c->frequency;
1071 state->dnxt.pilot = c->pilot;
1072
1073 ret = cx24120_set_inversion(state, c->inversion);
1074 if (ret != 0)
1075 return ret;
1076
1077 ret = cx24120_set_fec(state, c->modulation, c->fec_inner);
1078 if (ret != 0)
1079 return ret;
1080
1081 ret = cx24120_set_pilot(state, c->pilot);
1082 if (ret != 0)
1083 return ret;
1084
1085 ret = cx24120_set_symbolrate(state, c->symbol_rate);
1086 if (ret != 0)
1087 return ret;
1088
Jemma Denson5afc9a22015-04-14 09:04:50 -03001089 /* discard the 'current' tuning parameters and prepare to tune */
1090 cx24120_clone_params(fe);
1091
1092 dev_dbg(&state->i2c->dev,
1093 "%s: delsys = %d\n", __func__, state->dcur.delsys);
1094 dev_dbg(&state->i2c->dev,
1095 "%s: modulation = %d\n", __func__, state->dcur.modulation);
1096 dev_dbg(&state->i2c->dev,
1097 "%s: frequency = %d\n", __func__, state->dcur.frequency);
1098 dev_dbg(&state->i2c->dev,
1099 "%s: pilot = %d (val = 0x%02x)\n", __func__,
1100 state->dcur.pilot, state->dcur.pilot_val);
1101 dev_dbg(&state->i2c->dev,
1102 "%s: symbol_rate = %d (clkdiv/ratediv = 0x%02x/0x%02x)\n",
1103 __func__, state->dcur.symbol_rate,
1104 state->dcur.clkdiv, state->dcur.ratediv);
1105 dev_dbg(&state->i2c->dev,
1106 "%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1107 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1108 dev_dbg(&state->i2c->dev,
1109 "%s: Inversion = %d (val = 0x%02x)\n", __func__,
1110 state->dcur.inversion, state->dcur.inversion_val);
1111
Jemma Denson6138dc22015-04-30 16:37:42 -03001112 /* Flag that clock needs to be set after tune */
1113 state->need_clock_set = 1;
1114
Jemma Denson5afc9a22015-04-14 09:04:50 -03001115 /* Tune in */
1116 cmd.id = CMD_TUNEREQUEST;
1117 cmd.len = 15;
1118 cmd.arg[0] = 0;
1119 cmd.arg[1] = (state->dcur.frequency & 0xff0000) >> 16;
1120 cmd.arg[2] = (state->dcur.frequency & 0x00ff00) >> 8;
1121 cmd.arg[3] = (state->dcur.frequency & 0x0000ff);
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -03001122 cmd.arg[4] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1123 cmd.arg[5] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001124 cmd.arg[6] = state->dcur.inversion;
1125 cmd.arg[7] = state->dcur.fec_val | state->dcur.pilot_val;
1126 cmd.arg[8] = CX24120_SEARCH_RANGE_KHZ >> 8;
1127 cmd.arg[9] = CX24120_SEARCH_RANGE_KHZ & 0xff;
1128 cmd.arg[10] = 0; /* maybe rolloff? */
1129 cmd.arg[11] = state->dcur.fec_mask;
1130 cmd.arg[12] = state->dcur.ratediv;
1131 cmd.arg[13] = state->dcur.clkdiv;
1132 cmd.arg[14] = 0;
1133
Jemma Denson5afc9a22015-04-14 09:04:50 -03001134 /* Send tune command */
1135 ret = cx24120_message_send(state, &cmd);
1136 if (ret != 0)
1137 return ret;
1138
1139 /* Write symbol rate values */
1140 ret = cx24120_writereg(state, CX24120_REG_CLKDIV, state->dcur.clkdiv);
1141 ret = cx24120_readreg(state, CX24120_REG_RATEDIV);
1142 ret &= 0xfffffff0;
1143 ret |= state->dcur.ratediv;
1144 ret = cx24120_writereg(state, CX24120_REG_RATEDIV, ret);
1145
Jemma Denson5afc9a22015-04-14 09:04:50 -03001146 return 0;
1147}
1148
Jemma Densonc84251b2015-05-03 08:55:15 -03001149/* Set vco from config */
1150static int cx24120_set_vco(struct cx24120_state *state)
Jemma Denson5afc9a22015-04-14 09:04:50 -03001151{
Jemma Densonc84251b2015-05-03 08:55:15 -03001152 struct cx24120_cmd cmd;
1153 u32 nxtal_khz, vco;
1154 u64 inv_vco;
Jemma Denson5afc9a22015-04-14 09:04:50 -03001155 u32 xtal_khz = state->config->xtal_khz;
1156
Jemma Densonc84251b2015-05-03 08:55:15 -03001157 nxtal_khz = xtal_khz * 4;
1158 vco = nxtal_khz * 10;
1159 inv_vco = DIV_ROUND_CLOSEST_ULL(0x400000000ULL, vco);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001160
1161 dev_dbg(&state->i2c->dev,
Jemma Densonc84251b2015-05-03 08:55:15 -03001162 "%s: xtal=%d, vco=%d, inv_vco=%lld\n",
1163 __func__, xtal_khz, vco, inv_vco);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001164
Jemma Densonc84251b2015-05-03 08:55:15 -03001165 cmd.id = CMD_VCO_SET;
1166 cmd.len = 12;
1167 cmd.arg[0] = (vco >> 16) & 0xff;
1168 cmd.arg[1] = (vco >> 8) & 0xff;
1169 cmd.arg[2] = vco & 0xff;
1170 cmd.arg[3] = (inv_vco >> 8) & 0xff;
1171 cmd.arg[4] = (inv_vco) & 0xff;
1172 cmd.arg[5] = 0x03;
1173 cmd.arg[6] = (nxtal_khz >> 8) & 0xff;
1174 cmd.arg[7] = nxtal_khz & 0xff;
1175 cmd.arg[8] = 0x06;
1176 cmd.arg[9] = 0x03;
1177 cmd.arg[10] = (xtal_khz >> 16) & 0xff;
1178 cmd.arg[11] = xtal_khz & 0xff;
1179
1180 return cx24120_message_send(state, &cmd);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001181}
1182
Jemma Denson5afc9a22015-04-14 09:04:50 -03001183int cx24120_init(struct dvb_frontend *fe)
1184{
1185 const struct firmware *fw;
Jemma Densond3cf06b2015-05-05 17:10:13 -03001186 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Jemma Denson5afc9a22015-04-14 09:04:50 -03001187 struct cx24120_state *state = fe->demodulator_priv;
1188 struct cx24120_cmd cmd;
1189 u8 ret, ret_EA, reg1;
Jemma Denson5afc9a22015-04-14 09:04:50 -03001190 int reset_result;
1191
1192 int i;
1193 unsigned char vers[4];
1194
1195 if (state->cold_init)
1196 return 0;
1197
1198 /* ???? */
1199 ret = cx24120_writereg(state, 0xea, 0x00);
1200 ret = cx24120_test_rom(state);
1201 ret = cx24120_readreg(state, 0xfb) & 0xfe;
1202 ret = cx24120_writereg(state, 0xfb, ret);
1203 ret = cx24120_readreg(state, 0xfc) & 0xfe;
1204 ret = cx24120_writereg(state, 0xfc, ret);
1205 ret = cx24120_writereg(state, 0xc3, 0x04);
1206 ret = cx24120_writereg(state, 0xc4, 0x04);
1207 ret = cx24120_writereg(state, 0xce, 0x00);
1208 ret = cx24120_writereg(state, 0xcf, 0x00);
1209 ret_EA = cx24120_readreg(state, 0xea) & 0xfe;
1210 ret = cx24120_writereg(state, 0xea, ret_EA);
1211 ret = cx24120_writereg(state, 0xeb, 0x0c);
1212 ret = cx24120_writereg(state, 0xec, 0x06);
1213 ret = cx24120_writereg(state, 0xed, 0x05);
1214 ret = cx24120_writereg(state, 0xee, 0x03);
1215 ret = cx24120_writereg(state, 0xef, 0x05);
1216 ret = cx24120_writereg(state, 0xf3, 0x03);
1217 ret = cx24120_writereg(state, 0xf4, 0x44);
1218
1219 for (reg1 = 0xf0; reg1 < 0xf3; reg1++) {
1220 cx24120_writereg(state, reg1, 0x04);
1221 cx24120_writereg(state, reg1 - 10, 0x02);
1222 }
1223
1224 ret = cx24120_writereg(state, 0xea, (ret_EA | 0x01));
1225 for (reg1 = 0xc5; reg1 < 0xcb; reg1 += 2) {
1226 ret = cx24120_writereg(state, reg1, 0x00);
1227 ret = cx24120_writereg(state, reg1 + 1, 0x00);
1228 }
1229
1230 ret = cx24120_writereg(state, 0xe4, 0x03);
1231 ret = cx24120_writereg(state, 0xeb, 0x0a);
1232
1233 dev_dbg(&state->i2c->dev,
1234 "%s: Requesting firmware (%s) to download...\n",
1235 __func__, CX24120_FIRMWARE);
1236
1237 ret = state->config->request_firmware(fe, &fw, CX24120_FIRMWARE);
1238 if (ret) {
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -03001239 err("Could not load firmware (%s): %d\n", CX24120_FIRMWARE,
1240 ret);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001241 return ret;
1242 }
1243
1244 dev_dbg(&state->i2c->dev,
1245 "%s: Firmware found, size %d bytes (%02x %02x .. %02x %02x)\n",
1246 __func__,
1247 (int)fw->size, /* firmware_size in bytes */
1248 fw->data[0], /* fw 1st byte */
1249 fw->data[1], /* fw 2d byte */
1250 fw->data[fw->size - 2], /* fw before last byte */
1251 fw->data[fw->size - 1]); /* fw last byte */
1252
1253 ret = cx24120_test_rom(state);
1254 ret = cx24120_readreg(state, 0xfb) & 0xfe;
1255 ret = cx24120_writereg(state, 0xfb, ret);
1256 ret = cx24120_writereg(state, 0xe0, 0x76);
1257 ret = cx24120_writereg(state, 0xf7, 0x81);
1258 ret = cx24120_writereg(state, 0xf8, 0x00);
1259 ret = cx24120_writereg(state, 0xf9, 0x00);
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -03001260 ret = cx24120_writeregs(state, 0xfa, fw->data, (fw->size - 1), 0x00);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001261 ret = cx24120_writereg(state, 0xf7, 0xc0);
1262 ret = cx24120_writereg(state, 0xe0, 0x00);
1263 ret = (fw->size - 2) & 0x00ff;
1264 ret = cx24120_writereg(state, 0xf8, ret);
1265 ret = ((fw->size - 2) >> 8) & 0x00ff;
1266 ret = cx24120_writereg(state, 0xf9, ret);
1267 ret = cx24120_writereg(state, 0xf7, 0x00);
1268 ret = cx24120_writereg(state, 0xdc, 0x00);
1269 ret = cx24120_writereg(state, 0xdc, 0x07);
1270 msleep(500);
1271
1272 /* Check final byte matches final byte of firmware */
1273 ret = cx24120_readreg(state, 0xe1);
1274 if (ret == fw->data[fw->size - 1]) {
1275 dev_dbg(&state->i2c->dev,
1276 "%s: Firmware uploaded successfully\n",
1277 __func__);
1278 reset_result = 0;
1279 } else {
1280 err("Firmware upload failed. Last byte returned=0x%x\n", ret);
1281 reset_result = -EREMOTEIO;
1282 }
1283 ret = cx24120_writereg(state, 0xdc, 0x00);
1284 release_firmware(fw);
1285 if (reset_result != 0)
1286 return reset_result;
1287
Jemma Denson5afc9a22015-04-14 09:04:50 -03001288 /* Start tuner */
1289 cmd.id = CMD_START_TUNER;
1290 cmd.len = 3;
1291 cmd.arg[0] = 0x00;
1292 cmd.arg[1] = 0x00;
1293 cmd.arg[2] = 0x00;
1294
1295 if (cx24120_message_send(state, &cmd) != 0) {
1296 err("Error tuner start! :(\n");
1297 return -EREMOTEIO;
1298 }
1299
1300 /* Set VCO */
Jemma Densonc84251b2015-05-03 08:55:15 -03001301 ret = cx24120_set_vco(state);
1302 if (ret != 0) {
Jemma Denson5afc9a22015-04-14 09:04:50 -03001303 err("Error set VCO! :(\n");
Jemma Densonc84251b2015-05-03 08:55:15 -03001304 return ret;
Jemma Denson5afc9a22015-04-14 09:04:50 -03001305 }
1306
Jemma Denson5afc9a22015-04-14 09:04:50 -03001307 /* set bandwidth */
1308 cmd.id = CMD_BANDWIDTH;
1309 cmd.len = 12;
1310 cmd.arg[0] = 0x00;
1311 cmd.arg[1] = 0x00;
1312 cmd.arg[2] = 0x00;
1313 cmd.arg[3] = 0x00;
1314 cmd.arg[4] = 0x05;
1315 cmd.arg[5] = 0x02;
1316 cmd.arg[6] = 0x02;
1317 cmd.arg[7] = 0x00;
1318 cmd.arg[8] = 0x05;
1319 cmd.arg[9] = 0x02;
1320 cmd.arg[10] = 0x02;
1321 cmd.arg[11] = 0x00;
1322
1323 if (cx24120_message_send(state, &cmd)) {
1324 err("Error set bandwidth!\n");
1325 return -EREMOTEIO;
1326 }
1327
1328 ret = cx24120_readreg(state, 0xba);
1329 if (ret > 3) {
1330 dev_dbg(&state->i2c->dev, "%s: Reset-readreg 0xba: %x\n",
1331 __func__, ret);
1332 err("Error initialising tuner!\n");
1333 return -EREMOTEIO;
1334 }
1335
1336 dev_dbg(&state->i2c->dev, "%s: Tuner initialised correctly.\n",
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -03001337 __func__);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001338
1339 /* Initialise mpeg outputs */
1340 ret = cx24120_writereg(state, 0xeb, 0x0a);
1341 if (cx24120_msg_mpeg_output_global_config(state, 0) ||
1342 cx24120_msg_mpeg_output_config(state, 0) ||
1343 cx24120_msg_mpeg_output_config(state, 1) ||
1344 cx24120_msg_mpeg_output_config(state, 2)) {
1345 err("Error initialising mpeg output. :(\n");
1346 return -EREMOTEIO;
1347 }
1348
Jemma Denson5afc9a22015-04-14 09:04:50 -03001349 /* ???? */
1350 cmd.id = CMD_TUNER_INIT;
1351 cmd.len = 3;
1352 cmd.arg[0] = 0x00;
1353 cmd.arg[1] = 0x10;
1354 cmd.arg[2] = 0x10;
1355 if (cx24120_message_send(state, &cmd)) {
1356 err("Error sending final init message. :(\n");
1357 return -EREMOTEIO;
1358 }
1359
Jemma Denson5afc9a22015-04-14 09:04:50 -03001360 /* Firmware CMD 35: Get firmware version */
1361 cmd.id = CMD_FWVERSION;
1362 cmd.len = 1;
1363 for (i = 0; i < 4; i++) {
1364 cmd.arg[0] = i;
1365 ret = cx24120_message_send(state, &cmd);
1366 if (ret != 0)
1367 return ret;
1368 vers[i] = cx24120_readreg(state, CX24120_REG_MAILBOX);
1369 }
1370 info("FW version %i.%i.%i.%i\n", vers[0], vers[1], vers[2], vers[3]);
1371
Jemma Densond3cf06b2015-05-05 17:10:13 -03001372 /* init stats here in order signal app which stats are supported */
1373 c->strength.len = 1;
1374 c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1375
Jemma Denson5afc9a22015-04-14 09:04:50 -03001376 state->cold_init = 1;
1377 return 0;
1378}
1379
Jemma Denson5afc9a22015-04-14 09:04:50 -03001380static int cx24120_tune(struct dvb_frontend *fe, bool re_tune,
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -03001381 unsigned int mode_flags, unsigned int *delay,
1382 fe_status_t *status)
Jemma Denson5afc9a22015-04-14 09:04:50 -03001383{
1384 struct cx24120_state *state = fe->demodulator_priv;
1385 int ret;
1386
1387 dev_dbg(&state->i2c->dev, "%s(%d)\n", __func__, re_tune);
1388
1389 /* TODO: Do we need to set delay? */
1390
1391 if (re_tune) {
1392 ret = cx24120_set_frontend(fe);
1393 if (ret)
1394 return ret;
1395 }
1396
1397 return cx24120_read_status(fe, status);
1398}
1399
Jemma Denson5afc9a22015-04-14 09:04:50 -03001400static int cx24120_get_algo(struct dvb_frontend *fe)
1401{
1402 return DVBFE_ALGO_HW;
1403}
1404
Jemma Denson5afc9a22015-04-14 09:04:50 -03001405static int cx24120_sleep(struct dvb_frontend *fe)
1406{
1407 return 0;
1408}
1409
Jemma Denson5afc9a22015-04-14 09:04:50 -03001410static int cx24120_get_frontend(struct dvb_frontend *fe)
1411{
1412 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1413 struct cx24120_state *state = fe->demodulator_priv;
1414 u8 freq1, freq2, freq3;
1415
1416 dev_dbg(&state->i2c->dev, "%s()", __func__);
1417
1418 /* don't return empty data if we're not tuned in */
Jemma Denson14626122015-05-05 17:18:11 -03001419 if ((state->fe_status & FE_HAS_LOCK) == 0)
Jemma Denson5afc9a22015-04-14 09:04:50 -03001420 return 0;
1421
1422 /* Get frequency */
1423 freq1 = cx24120_readreg(state, CX24120_REG_FREQ1);
1424 freq2 = cx24120_readreg(state, CX24120_REG_FREQ2);
1425 freq3 = cx24120_readreg(state, CX24120_REG_FREQ3);
1426 c->frequency = (freq3 << 16) | (freq2 << 8) | freq1;
1427 dev_dbg(&state->i2c->dev, "%s frequency = %d\n", __func__,
1428 c->frequency);
1429
1430 /* Get modulation, fec, pilot */
1431 cx24120_get_fec(fe);
1432
1433 return 0;
1434}
1435
Jemma Denson5afc9a22015-04-14 09:04:50 -03001436static void cx24120_release(struct dvb_frontend *fe)
1437{
1438 struct cx24120_state *state = fe->demodulator_priv;
1439
1440 dev_dbg(&state->i2c->dev, "%s: Clear state structure\n", __func__);
1441 kfree(state);
1442}
1443
Jemma Denson5afc9a22015-04-14 09:04:50 -03001444static int cx24120_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
1445{
1446 struct cx24120_state *state = fe->demodulator_priv;
1447
1448 *ucblocks = (cx24120_readreg(state, CX24120_REG_UCB_H) << 8) |
1449 cx24120_readreg(state, CX24120_REG_UCB_L);
1450
Patrick Boettcher1ff2e8e2015-04-28 13:39:20 -03001451 dev_dbg(&state->i2c->dev, "%s: Blocks = %d\n", __func__, *ucblocks);
Jemma Denson5afc9a22015-04-14 09:04:50 -03001452 return 0;
1453}
1454
Jemma Denson5afc9a22015-04-14 09:04:50 -03001455static struct dvb_frontend_ops cx24120_ops = {
1456 .delsys = { SYS_DVBS, SYS_DVBS2 },
1457 .info = {
1458 .name = "Conexant CX24120/CX24118",
1459 .frequency_min = 950000,
1460 .frequency_max = 2150000,
1461 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1462 .frequency_tolerance = 5000,
1463 .symbol_rate_min = 1000000,
1464 .symbol_rate_max = 45000000,
1465 .caps = FE_CAN_INVERSION_AUTO |
1466 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1467 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1468 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1469 FE_CAN_2G_MODULATION |
1470 FE_CAN_QPSK | FE_CAN_RECOVER
1471 },
1472 .release = cx24120_release,
1473
1474 .init = cx24120_init,
1475 .sleep = cx24120_sleep,
1476
1477 .tune = cx24120_tune,
1478 .get_frontend_algo = cx24120_get_algo,
1479 .set_frontend = cx24120_set_frontend,
1480
1481 .get_frontend = cx24120_get_frontend,
1482 .read_status = cx24120_read_status,
1483 .read_ber = cx24120_read_ber,
1484 .read_signal_strength = cx24120_read_signal_strength,
1485 .read_snr = cx24120_read_snr,
1486 .read_ucblocks = cx24120_read_ucblocks,
1487
1488 .diseqc_send_master_cmd = cx24120_send_diseqc_msg,
1489
1490 .diseqc_send_burst = cx24120_diseqc_send_burst,
1491 .set_tone = cx24120_set_tone,
1492 .set_voltage = cx24120_set_voltage,
1493};
1494
1495MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24120/CX24118 hardware");
1496MODULE_AUTHOR("Jemma Denson");
1497MODULE_LICENSE("GPL");