blob: 46427fd3b220dc211f8a29bcd04a747ead171089 [file] [log] [blame]
Sri Deevie0d3baf2009-03-03 14:37:50 -03001/*
2 DVB device driver for cx231xx
3
4 Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
Sri Deevib9255172009-03-04 17:49:01 -03005 Based on em28xx driver
Sri Deevie0d3baf2009-03-03 14:37:50 -03006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
Mauro Carvalho Chehab589dadf2014-11-01 08:09:44 -030022#include "cx231xx.h"
Sri Deevie0d3baf2009-03-03 14:37:50 -030023#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Sri Deevie0d3baf2009-03-03 14:37:50 -030025
Sri Deevie0d3baf2009-03-03 14:37:50 -030026#include <media/v4l2-common.h>
27#include <media/videobuf-vmalloc.h>
Mauro Carvalho Chehab61683092016-02-11 22:39:52 -020028#include <media/tuner.h>
Sri Deevie0d3baf2009-03-03 14:37:50 -030029
30#include "xc5000.h"
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -030031#include "s5h1432.h"
32#include "tda18271.h"
33#include "s5h1411.h"
Michael Krufky1a50fdd2010-07-06 18:23:53 -030034#include "lgdt3305.h"
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -030035#include "si2165.h"
Oleh Kravchenkoa096fd62017-01-29 16:03:51 -020036#include "si2168.h"
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -030037#include "mb86a20s.h"
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -030038#include "si2157.h"
Olli Salonen809abdb2015-02-28 12:25:24 -030039#include "lgdt3306a.h"
Sri Deevie0d3baf2009-03-03 14:37:50 -030040
Sri Deevie0d3baf2009-03-03 14:37:50 -030041MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
42MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
43MODULE_LICENSE("GPL");
44
45static unsigned int debug;
46module_param(debug, int, 0644);
47MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
48
49DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
50
Sri Deevie0d3baf2009-03-03 14:37:50 -030051#define CX231XX_DVB_NUM_BUFS 5
52#define CX231XX_DVB_MAX_PACKETSIZE 564
53#define CX231XX_DVB_MAX_PACKETS 64
54
55struct cx231xx_dvb {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030056 struct dvb_frontend *frontend;
Sri Deevie0d3baf2009-03-03 14:37:50 -030057
58 /* feed count management */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030059 struct mutex lock;
60 int nfeeds;
Sri Deevie0d3baf2009-03-03 14:37:50 -030061
62 /* general boilerplate stuff */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030063 struct dvb_adapter adapter;
64 struct dvb_demux demux;
65 struct dmxdev dmxdev;
66 struct dmx_frontend fe_hw;
67 struct dmx_frontend fe_mem;
68 struct dvb_net net;
Matthias Schwarzottd28d7f82016-07-26 04:09:04 -030069 struct i2c_client *i2c_client_demod;
Matthias Schwarzott6d3deba2014-07-22 17:12:14 -030070 struct i2c_client *i2c_client_tuner;
Sri Deevie0d3baf2009-03-03 14:37:50 -030071};
72
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -030073static struct s5h1432_config dvico_s5h1432_config = {
74 .output_mode = S5H1432_SERIAL_OUTPUT,
75 .gpio = S5H1432_GPIO_ON,
76 .qam_if = S5H1432_IF_4000,
77 .vsb_if = S5H1432_IF_4000,
78 .inversion = S5H1432_INVERSION_OFF,
79 .status_mode = S5H1432_DEMODLOCKING,
80 .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
81};
82
83static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
84 .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
85 .if_lvl = 1, .rfagc_top = 0x37, },
86 .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
87 .if_lvl = 1, .rfagc_top = 0x37, },
88 .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6,
89 .if_lvl = 1, .rfagc_top = 0x37, },
90};
91
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -030092static struct tda18271_std_map mb86a20s_tda18271_config = {
Mauro Carvalho Chehab84c09d72013-03-03 07:49:50 -030093 .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
94 .if_lvl = 0, .rfagc_top = 0x37, },
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -030095};
96
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -030097static struct tda18271_config cnxt_rde253s_tunerconfig = {
98 .std_map = &cnxt_rde253s_tda18271_std_map,
99 .gate = TDA18271_GATE_ANALOG,
100};
101
102static struct s5h1411_config tda18271_s5h1411_config = {
103 .output_mode = S5H1411_SERIAL_OUTPUT,
104 .gpio = S5H1411_GPIO_OFF,
105 .vsb_if = S5H1411_IF_3250,
106 .qam_if = S5H1411_IF_4000,
107 .inversion = S5H1411_INVERSION_ON,
108 .status_mode = S5H1411_DEMODLOCKING,
109 .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
110};
111static struct s5h1411_config xc5000_s5h1411_config = {
112 .output_mode = S5H1411_SERIAL_OUTPUT,
113 .gpio = S5H1411_GPIO_OFF,
114 .vsb_if = S5H1411_IF_3250,
115 .qam_if = S5H1411_IF_3250,
116 .inversion = S5H1411_INVERSION_OFF,
117 .status_mode = S5H1411_DEMODLOCKING,
118 .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
119};
Michael Krufky1a50fdd2010-07-06 18:23:53 -0300120
121static struct lgdt3305_config hcw_lgdt3305_config = {
122 .i2c_addr = 0x0e,
123 .mpeg_mode = LGDT3305_MPEG_SERIAL,
124 .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
125 .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
126 .deny_i2c_rptr = 1,
127 .spectral_inversion = 1,
128 .qam_if_khz = 4000,
129 .vsb_if_khz = 3250,
130};
131
132static struct tda18271_std_map hauppauge_tda18271_std_map = {
133 .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
134 .if_lvl = 1, .rfagc_top = 0x58, },
135 .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
136 .if_lvl = 1, .rfagc_top = 0x58, },
137};
138
139static struct tda18271_config hcw_tda18271_config = {
140 .std_map = &hauppauge_tda18271_std_map,
141 .gate = TDA18271_GATE_DIGITAL,
142};
143
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300144static const struct mb86a20s_config pv_mb86a20s_config = {
145 .demod_address = 0x10,
Mauro Carvalho Chehab7572f9c2010-10-03 16:48:49 -0300146 .is_serial = true,
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300147};
148
149static struct tda18271_config pv_tda18271_config = {
150 .std_map = &mb86a20s_tda18271_config,
151 .gate = TDA18271_GATE_DIGITAL,
152 .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
153};
154
Olli Salonen809abdb2015-02-28 12:25:24 -0300155static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = {
156 .i2c_addr = 0x59,
157 .qam_if_khz = 4000,
158 .vsb_if_khz = 3250,
159 .deny_i2c_rptr = 1,
160 .spectral_inversion = 1,
161 .mpeg_mode = LGDT3306A_MPEG_SERIAL,
162 .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE,
163 .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH,
164 .xtalMHz = 25,
165};
166
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300167static inline void print_err_status(struct cx231xx *dev, int packet, int status)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300168{
169 char *errmsg = "Unknown";
170
171 switch (status) {
172 case -ENOENT:
173 errmsg = "unlinked synchronuously";
174 break;
175 case -ECONNRESET:
176 errmsg = "unlinked asynchronuously";
177 break;
178 case -ENOSR:
179 errmsg = "Buffer error (overrun)";
180 break;
181 case -EPIPE:
182 errmsg = "Stalled (device not responding)";
183 break;
184 case -EOVERFLOW:
185 errmsg = "Babble (bad cable?)";
186 break;
187 case -EPROTO:
188 errmsg = "Bit-stuff error (bad cable?)";
189 break;
190 case -EILSEQ:
191 errmsg = "CRC/Timeout (could be anything)";
192 break;
193 case -ETIME:
194 errmsg = "Device does not respond";
195 break;
196 }
197 if (packet < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300198 dev_dbg(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300199 "URB status %d [%s].\n", status, errmsg);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300200 } else {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300201 dev_dbg(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300202 "URB packet %d, status %d [%s].\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300203 packet, status, errmsg);
204 }
205}
206
207static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
208{
209 int i;
210
211 if (!dev)
212 return 0;
213
Mauro Carvalho Chehab990862a2012-01-10 09:48:50 -0200214 if (dev->state & DEV_DISCONNECTED)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300215 return 0;
216
217 if (urb->status < 0) {
218 print_err_status(dev, -1, urb->status);
219 if (urb->status == -ENOENT)
220 return 0;
221 }
222
223 for (i = 0; i < urb->number_of_packets; i++) {
224 int status = urb->iso_frame_desc[i].status;
225
226 if (status < 0) {
227 print_err_status(dev, i, status);
228 if (urb->iso_frame_desc[i].status != -EPROTO)
229 continue;
230 }
231
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300232 dvb_dmx_swfilter(&dev->dvb->demux,
233 urb->transfer_buffer +
234 urb->iso_frame_desc[i].offset,
235 urb->iso_frame_desc[i].actual_length);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300236 }
237
238 return 0;
239}
240
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300241static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
242{
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300243 if (!dev)
244 return 0;
245
Mauro Carvalho Chehab990862a2012-01-10 09:48:50 -0200246 if (dev->state & DEV_DISCONNECTED)
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300247 return 0;
248
249 if (urb->status < 0) {
250 print_err_status(dev, -1, urb->status);
251 if (urb->status == -ENOENT)
252 return 0;
253 }
254
255 /* Feed the transport payload into the kernel demux */
256 dvb_dmx_swfilter(&dev->dvb->demux,
257 urb->transfer_buffer, urb->actual_length);
258
259 return 0;
260}
261
Sri Deevie0d3baf2009-03-03 14:37:50 -0300262static int start_streaming(struct cx231xx_dvb *dvb)
263{
264 int rc;
265 struct cx231xx *dev = dvb->adapter.priv;
266
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300267 if (dev->USE_ISO) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300268 dev_dbg(dev->dev, "DVB transfer mode is ISO.\n");
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300269 cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300270 rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
271 if (rc < 0)
272 return rc;
273 dev->mode_tv = 1;
274 return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
275 CX231XX_DVB_NUM_BUFS,
276 dev->ts1_mode.max_pkt_size,
277 dvb_isoc_copy);
278 } else {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300279 dev_dbg(dev->dev, "DVB transfer mode is BULK.\n");
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300280 cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
281 rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
282 if (rc < 0)
283 return rc;
284 dev->mode_tv = 1;
285 return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS,
286 CX231XX_DVB_NUM_BUFS,
287 dev->ts1_mode.max_pkt_size,
288 dvb_bulk_copy);
289 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300290
Sri Deevie0d3baf2009-03-03 14:37:50 -0300291}
292
293static int stop_streaming(struct cx231xx_dvb *dvb)
294{
295 struct cx231xx *dev = dvb->adapter.priv;
296
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300297 if (dev->USE_ISO)
298 cx231xx_uninit_isoc(dev);
299 else
300 cx231xx_uninit_bulk(dev);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300301
302 cx231xx_set_mode(dev, CX231XX_SUSPEND);
303
304 return 0;
305}
306
307static int start_feed(struct dvb_demux_feed *feed)
308{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300309 struct dvb_demux *demux = feed->demux;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300310 struct cx231xx_dvb *dvb = demux->priv;
311 int rc, ret;
312
313 if (!demux->dmx.frontend)
314 return -EINVAL;
315
316 mutex_lock(&dvb->lock);
317 dvb->nfeeds++;
318 rc = dvb->nfeeds;
319
320 if (dvb->nfeeds == 1) {
321 ret = start_streaming(dvb);
322 if (ret < 0)
323 rc = ret;
324 }
325
326 mutex_unlock(&dvb->lock);
327 return rc;
328}
329
330static int stop_feed(struct dvb_demux_feed *feed)
331{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300332 struct dvb_demux *demux = feed->demux;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300333 struct cx231xx_dvb *dvb = demux->priv;
334 int err = 0;
335
336 mutex_lock(&dvb->lock);
337 dvb->nfeeds--;
338
339 if (0 == dvb->nfeeds)
340 err = stop_streaming(dvb);
341
342 mutex_unlock(&dvb->lock);
343 return err;
344}
345
Sri Deevie0d3baf2009-03-03 14:37:50 -0300346/* ------------------------------------------------------------------ */
347static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
348{
349 struct cx231xx *dev = fe->dvb->priv;
350
351 if (acquire)
352 return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
353 else
354 return cx231xx_set_mode(dev, CX231XX_SUSPEND);
355}
356
357/* ------------------------------------------------------------------ */
358
Sri Deevie0d3baf2009-03-03 14:37:50 -0300359static struct xc5000_config cnxt_rde250_tunerconfig = {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300360 .i2c_address = 0x61,
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300361 .if_khz = 4000,
362};
363static struct xc5000_config cnxt_rdu250_tunerconfig = {
364 .i2c_address = 0x61,
365 .if_khz = 3250,
Sri Deevie0d3baf2009-03-03 14:37:50 -0300366};
367
Sri Deevie0d3baf2009-03-03 14:37:50 -0300368/* ------------------------------------------------------------------ */
369#if 0
370static int attach_xc5000(u8 addr, struct cx231xx *dev)
371{
372
373 struct dvb_frontend *fe;
374 struct xc5000_config cfg;
375
376 memset(&cfg, 0, sizeof(cfg));
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300377 cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300378 cfg.i2c_addr = addr;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300379
380 if (!dev->dvb->frontend) {
Mauro Carvalho Chehabba1da972016-10-18 17:44:14 -0200381 dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
382 dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300383 return -EINVAL;
384 }
385
386 fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
387 if (!fe) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300388 dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300389 dvb_frontend_detach(dev->dvb->frontend);
390 dev->dvb->frontend = NULL;
391 return -EINVAL;
392 }
393
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300394 dev_info(dev->dev, "%s/2: xc5000 attached\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300395
396 return 0;
397}
398#endif
399
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300400int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300401{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300402 if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300403
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300404 struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300405
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300406 if (dops->set_analog_params != NULL) {
407 struct analog_parameters params;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300408
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300409 params.frequency = freq;
410 params.std = dev->norm;
411 params.mode = 0; /* 0- Air; 1 - cable */
412 /*params.audmode = ; */
Sri Deevie0d3baf2009-03-03 14:37:50 -0300413
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300414 /* Set the analog parameters to set the frequency */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300415 dops->set_analog_params(dev->dvb->frontend, &params);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300416 }
417
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300418 }
419
Mauro Carvalho Chehabea21f702014-09-03 16:16:53 -0300420 return 0;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300421}
422
423int cx231xx_reset_analog_tuner(struct cx231xx *dev)
424{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300425 int status = 0;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300426
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300427 if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300428
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300429 struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300430
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300431 if (dops->init != NULL && !dev->xc_fw_load_done) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300432
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300433 dev_dbg(dev->dev,
Mauro Carvalho Chehabb7085c02014-11-02 07:21:44 -0300434 "Reloading firmware for XC5000\n");
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300435 status = dops->init(dev->dvb->frontend);
436 if (status == 0) {
437 dev->xc_fw_load_done = 1;
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300438 dev_dbg(dev->dev,
Mauro Carvalho Chehabb7085c02014-11-02 07:21:44 -0300439 "XC5000 firmware download completed\n");
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300440 } else {
441 dev->xc_fw_load_done = 0;
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300442 dev_dbg(dev->dev,
Mauro Carvalho Chehabb7085c02014-11-02 07:21:44 -0300443 "XC5000 firmware download failed !!!\n");
Sri Deevie0d3baf2009-03-03 14:37:50 -0300444 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300445 }
446
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300447 }
448
Sri Deevie0d3baf2009-03-03 14:37:50 -0300449 return status;
450}
451
Sri Deevie0d3baf2009-03-03 14:37:50 -0300452/* ------------------------------------------------------------------ */
453
454static int register_dvb(struct cx231xx_dvb *dvb,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300455 struct module *module,
456 struct cx231xx *dev, struct device *device)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300457{
458 int result;
459
460 mutex_init(&dvb->lock);
461
Mauro Carvalho Chehab1d058bd2015-01-01 11:37:17 -0300462
Sri Deevie0d3baf2009-03-03 14:37:50 -0300463 /* register adapter */
464 result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
465 adapter_nr);
466 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300467 dev_warn(dev->dev,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300468 "%s: dvb_register_adapter failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300469 dev->name, result);
470 goto fail_adapter;
471 }
Mauro Carvalho Chehab89a2c1d2015-03-02 11:26:14 -0300472 dvb_register_media_controller(&dvb->adapter, dev->media_dev);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300473
474 /* Ensure all frontends negotiate bus access */
475 dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
476
477 dvb->adapter.priv = dev;
478
479 /* register frontend */
480 result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
481 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300482 dev_warn(dev->dev,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300483 "%s: dvb_register_frontend failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300484 dev->name, result);
485 goto fail_frontend;
486 }
487
488 /* register demux stuff */
489 dvb->demux.dmx.capabilities =
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300490 DMX_TS_FILTERING | DMX_SECTION_FILTERING |
491 DMX_MEMORY_BASED_FILTERING;
492 dvb->demux.priv = dvb;
493 dvb->demux.filternum = 256;
494 dvb->demux.feednum = 256;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300495 dvb->demux.start_feed = start_feed;
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300496 dvb->demux.stop_feed = stop_feed;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300497
498 result = dvb_dmx_init(&dvb->demux);
499 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300500 dev_warn(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300501 "%s: dvb_dmx_init failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300502 dev->name, result);
503 goto fail_dmx;
504 }
505
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300506 dvb->dmxdev.filternum = 256;
507 dvb->dmxdev.demux = &dvb->demux.dmx;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300508 dvb->dmxdev.capabilities = 0;
509 result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
510 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300511 dev_warn(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300512 "%s: dvb_dmxdev_init failed (errno = %d)\n",
513 dev->name, result);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300514 goto fail_dmxdev;
515 }
516
517 dvb->fe_hw.source = DMX_FRONTEND_0;
518 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
519 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300520 dev_warn(dev->dev,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300521 "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300522 dev->name, result);
523 goto fail_fe_hw;
524 }
525
526 dvb->fe_mem.source = DMX_MEMORY_FE;
527 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
528 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300529 dev_warn(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300530 "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
531 dev->name, result);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300532 goto fail_fe_mem;
533 }
534
535 result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
536 if (result < 0) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300537 dev_warn(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300538 "%s: connect_frontend failed (errno = %d)\n",
539 dev->name, result);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300540 goto fail_fe_conn;
541 }
542
543 /* register network adapter */
544 dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
Mauro Carvalho Chehab61683092016-02-11 22:39:52 -0200545 result = dvb_create_media_graph(&dvb->adapter,
546 dev->tuner_type == TUNER_ABSENT);
Mauro Carvalho Chehab0d3ab842015-09-04 15:33:46 -0300547 if (result < 0)
548 goto fail_create_graph;
Mauro Carvalho Chehab480884b2015-03-02 10:49:04 -0300549
Sri Deevie0d3baf2009-03-03 14:37:50 -0300550 return 0;
551
Mauro Carvalho Chehab0d3ab842015-09-04 15:33:46 -0300552fail_create_graph:
553 dvb_net_release(&dvb->net);
Sri Deevib9255172009-03-04 17:49:01 -0300554fail_fe_conn:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300555 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
Sri Deevib9255172009-03-04 17:49:01 -0300556fail_fe_mem:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300557 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
Sri Deevib9255172009-03-04 17:49:01 -0300558fail_fe_hw:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300559 dvb_dmxdev_release(&dvb->dmxdev);
Sri Deevib9255172009-03-04 17:49:01 -0300560fail_dmxdev:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300561 dvb_dmx_release(&dvb->demux);
Sri Deevib9255172009-03-04 17:49:01 -0300562fail_dmx:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300563 dvb_unregister_frontend(dvb->frontend);
Sri Deevib9255172009-03-04 17:49:01 -0300564fail_frontend:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300565 dvb_frontend_detach(dvb->frontend);
566 dvb_unregister_adapter(&dvb->adapter);
Sri Deevib9255172009-03-04 17:49:01 -0300567fail_adapter:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300568 return result;
569}
570
571static void unregister_dvb(struct cx231xx_dvb *dvb)
572{
Matthias Schwarzott6d3deba2014-07-22 17:12:14 -0300573 struct i2c_client *client;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300574 dvb_net_release(&dvb->net);
575 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
576 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
577 dvb_dmxdev_release(&dvb->dmxdev);
578 dvb_dmx_release(&dvb->demux);
Matthias Schwarzott6d3deba2014-07-22 17:12:14 -0300579 /* remove I2C tuner */
Matthias Schwarzottd28d7f82016-07-26 04:09:04 -0300580 client = dvb->i2c_client_tuner;
581 if (client) {
582 module_put(client->dev.driver->owner);
583 i2c_unregister_device(client);
584 }
585 /* remove I2C demod */
586 client = dvb->i2c_client_demod;
Matthias Schwarzott6d3deba2014-07-22 17:12:14 -0300587 if (client) {
588 module_put(client->dev.driver->owner);
589 i2c_unregister_device(client);
590 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300591 dvb_unregister_frontend(dvb->frontend);
592 dvb_frontend_detach(dvb->frontend);
593 dvb_unregister_adapter(&dvb->adapter);
594}
595
Sri Deevie0d3baf2009-03-03 14:37:50 -0300596static int dvb_init(struct cx231xx *dev)
597{
598 int result = 0;
599 struct cx231xx_dvb *dvb;
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300600 struct i2c_adapter *tuner_i2c;
601 struct i2c_adapter *demod_i2c;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300602
603 if (!dev->board.has_dvb) {
604 /* This device does not support the extension */
605 return 0;
606 }
607
608 dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
609
610 if (dvb == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300611 dev_info(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300612 "cx231xx_dvb: memory allocation failed\n");
Sri Deevie0d3baf2009-03-03 14:37:50 -0300613 return -ENOMEM;
614 }
615 dev->dvb = dvb;
616 dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300617 dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300618
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300619 tuner_i2c = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
620 demod_i2c = cx231xx_get_i2c_adap(dev, dev->board.demod_i2c_master);
Devin Heitmueller761f6cf2010-07-06 19:24:19 -0300621 mutex_lock(&dev->lock);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300622 cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300623 cx231xx_demod_reset(dev);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300624 /* init frontend */
625 switch (dev->model) {
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300626 case CX231XX_BOARD_CNXT_CARRAERA:
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300627 case CX231XX_BOARD_CNXT_RDE_250:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300628
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300629 dev->dvb->frontend = dvb_attach(s5h1432_attach,
630 &dvico_s5h1432_config,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300631 demod_i2c);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300632
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300633 if (dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300634 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300635 "Failed to attach s5h1432 front end\n");
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300636 result = -EINVAL;
637 goto out_free;
638 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300639
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300640 /* define general-purpose callback pointer */
641 dvb->frontend->callback = cx231xx_tuner_callback;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300642
Márton Némethd5abcc72010-01-16 13:21:59 -0300643 if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300644 tuner_i2c,
Márton Némethd5abcc72010-01-16 13:21:59 -0300645 &cnxt_rde250_tunerconfig)) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300646 result = -EINVAL;
647 goto out_free;
648 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300649
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300650 break;
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300651 case CX231XX_BOARD_CNXT_SHELBY:
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300652 case CX231XX_BOARD_CNXT_RDU_250:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300653
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300654 dev->dvb->frontend = dvb_attach(s5h1411_attach,
655 &xc5000_s5h1411_config,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300656 demod_i2c);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300657
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300658 if (dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300659 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300660 "Failed to attach s5h1411 front end\n");
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300661 result = -EINVAL;
662 goto out_free;
663 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300664
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300665 /* define general-purpose callback pointer */
666 dvb->frontend->callback = cx231xx_tuner_callback;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300667
Márton Némethd5abcc72010-01-16 13:21:59 -0300668 if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300669 tuner_i2c,
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300670 &cnxt_rdu250_tunerconfig)) {
671 result = -EINVAL;
672 goto out_free;
673 }
674 break;
675 case CX231XX_BOARD_CNXT_RDE_253S:
676
677 dev->dvb->frontend = dvb_attach(s5h1432_attach,
678 &dvico_s5h1432_config,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300679 demod_i2c);
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300680
681 if (dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300682 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300683 "Failed to attach s5h1432 front end\n");
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300684 result = -EINVAL;
685 goto out_free;
686 }
687
688 /* define general-purpose callback pointer */
689 dvb->frontend->callback = cx231xx_tuner_callback;
690
691 if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300692 0x60, tuner_i2c,
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300693 &cnxt_rde253s_tunerconfig)) {
694 result = -EINVAL;
695 goto out_free;
696 }
697 break;
698 case CX231XX_BOARD_CNXT_RDU_253S:
Johannes Erdfelt8b1255a2013-08-16 21:29:02 -0300699 case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300700
701 dev->dvb->frontend = dvb_attach(s5h1411_attach,
702 &tda18271_s5h1411_config,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300703 demod_i2c);
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300704
705 if (dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300706 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300707 "Failed to attach s5h1411 front end\n");
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300708 result = -EINVAL;
709 goto out_free;
710 }
711
712 /* define general-purpose callback pointer */
713 dvb->frontend->callback = cx231xx_tuner_callback;
714
715 if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300716 0x60, tuner_i2c,
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300717 &cnxt_rde253s_tunerconfig)) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300718 result = -EINVAL;
719 goto out_free;
720 }
721 break;
Michael Krufky1a50fdd2010-07-06 18:23:53 -0300722 case CX231XX_BOARD_HAUPPAUGE_EXETER:
723
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300724 dev_info(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300725 "%s: looking for tuner / demod on i2c bus: %d\n",
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300726 __func__, i2c_adapter_id(tuner_i2c));
Michael Krufky1a50fdd2010-07-06 18:23:53 -0300727
728 dev->dvb->frontend = dvb_attach(lgdt3305_attach,
729 &hcw_lgdt3305_config,
Matthias Schwarzott599bedb2015-11-13 20:54:55 -0200730 demod_i2c);
Michael Krufky1a50fdd2010-07-06 18:23:53 -0300731
732 if (dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300733 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300734 "Failed to attach LG3305 front end\n");
Michael Krufky1a50fdd2010-07-06 18:23:53 -0300735 result = -EINVAL;
736 goto out_free;
737 }
738
739 /* define general-purpose callback pointer */
740 dvb->frontend->callback = cx231xx_tuner_callback;
741
742 dvb_attach(tda18271_attach, dev->dvb->frontend,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300743 0x60, tuner_i2c,
Michael Krufky1a50fdd2010-07-06 18:23:53 -0300744 &hcw_tda18271_config);
745 break;
746
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -0300747 case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300748 {
749 struct i2c_client *client;
750 struct i2c_board_info info;
751 struct si2165_platform_data si2165_pdata;
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -0300752
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300753 /* attach demod */
754 memset(&si2165_pdata, 0, sizeof(si2165_pdata));
755 si2165_pdata.fe = &dev->dvb->frontend;
756 si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL,
757 si2165_pdata.ref_freq_Hz = 16000000,
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -0300758
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300759 memset(&info, 0, sizeof(struct i2c_board_info));
760 strlcpy(info.type, "si2165", I2C_NAME_SIZE);
761 info.addr = 0x64;
762 info.platform_data = &si2165_pdata;
763 request_module(info.type);
764 client = i2c_new_device(demod_i2c, &info);
765 if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300766 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300767 "Failed to attach SI2165 front end\n");
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -0300768 result = -EINVAL;
769 goto out_free;
770 }
771
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300772 if (!try_module_get(client->dev.driver->owner)) {
773 i2c_unregister_device(client);
774 result = -ENODEV;
775 goto out_free;
776 }
777
778 dvb->i2c_client_demod = client;
779
Hans Verkuil3f9280a2014-08-21 11:34:02 -0300780 dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -0300781
782 /* define general-purpose callback pointer */
783 dvb->frontend->callback = cx231xx_tuner_callback;
784
785 dvb_attach(tda18271_attach, dev->dvb->frontend,
786 0x60,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300787 tuner_i2c,
Matthias Schwarzottdd2e7dd2014-07-22 17:12:15 -0300788 &hcw_tda18271_config);
789
790 dev->cx231xx_reset_analog_tuner = NULL;
791 break;
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300792 }
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300793 case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
794 {
795 struct i2c_client *client;
796 struct i2c_board_info info;
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300797 struct si2165_platform_data si2165_pdata;
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300798 struct si2157_config si2157_config;
799
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300800 /* attach demod */
801 memset(&si2165_pdata, 0, sizeof(si2165_pdata));
802 si2165_pdata.fe = &dev->dvb->frontend;
803 si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT,
804 si2165_pdata.ref_freq_Hz = 24000000,
805
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300806 memset(&info, 0, sizeof(struct i2c_board_info));
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300807 strlcpy(info.type, "si2165", I2C_NAME_SIZE);
808 info.addr = 0x64;
809 info.platform_data = &si2165_pdata;
810 request_module(info.type);
811 client = i2c_new_device(demod_i2c, &info);
812 if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300813 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300814 "Failed to attach SI2165 front end\n");
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300815 result = -EINVAL;
816 goto out_free;
817 }
818
Matthias Schwarzott773028f2016-07-26 04:09:05 -0300819 if (!try_module_get(client->dev.driver->owner)) {
820 i2c_unregister_device(client);
821 result = -ENODEV;
822 goto out_free;
823 }
824
825 dvb->i2c_client_demod = client;
826
827 memset(&info, 0, sizeof(struct i2c_board_info));
828
Hans Verkuil3f9280a2014-08-21 11:34:02 -0300829 dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300830
831 /* define general-purpose callback pointer */
832 dvb->frontend->callback = cx231xx_tuner_callback;
833
834 /* attach tuner */
835 memset(&si2157_config, 0, sizeof(si2157_config));
836 si2157_config.fe = dev->dvb->frontend;
Mauro Carvalho Chehab133bc4e2016-02-11 22:18:36 -0200837#ifdef CONFIG_MEDIA_CONTROLLER_DVB
838 si2157_config.mdev = dev->media_dev;
839#endif
Olli Salonenee3c3e42015-05-05 13:54:17 -0300840 si2157_config.if_port = 1;
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300841 si2157_config.inversion = true;
842 strlcpy(info.type, "si2157", I2C_NAME_SIZE);
843 info.addr = 0x60;
844 info.platform_data = &si2157_config;
845 request_module("si2157");
846
847 client = i2c_new_device(
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300848 tuner_i2c,
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300849 &info);
850 if (client == NULL || client->dev.driver == NULL) {
851 dvb_frontend_detach(dev->dvb->frontend);
852 result = -ENODEV;
853 goto out_free;
854 }
855
856 if (!try_module_get(client->dev.driver->owner)) {
857 i2c_unregister_device(client);
858 dvb_frontend_detach(dev->dvb->frontend);
859 result = -ENODEV;
860 goto out_free;
861 }
862
863 dev->cx231xx_reset_analog_tuner = NULL;
864
865 dev->dvb->i2c_client_tuner = client;
866 break;
867 }
Olli Salonen809abdb2015-02-28 12:25:24 -0300868 case CX231XX_BOARD_HAUPPAUGE_955Q:
869 {
870 struct i2c_client *client;
871 struct i2c_board_info info;
872 struct si2157_config si2157_config;
Matthias Schwarzott9e49f7c2014-07-22 17:12:16 -0300873
Olli Salonen809abdb2015-02-28 12:25:24 -0300874 memset(&info, 0, sizeof(struct i2c_board_info));
875
876 dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
877 &hauppauge_955q_lgdt3306a_config,
Matthias Schwarzott599bedb2015-11-13 20:54:55 -0200878 demod_i2c
Olli Salonen809abdb2015-02-28 12:25:24 -0300879 );
880
881 if (dev->dvb->frontend == NULL) {
882 dev_err(dev->dev,
883 "Failed to attach LGDT3306A frontend.\n");
884 result = -EINVAL;
885 goto out_free;
886 }
887
888 dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
889
890 /* define general-purpose callback pointer */
891 dvb->frontend->callback = cx231xx_tuner_callback;
892
893 /* attach tuner */
894 memset(&si2157_config, 0, sizeof(si2157_config));
895 si2157_config.fe = dev->dvb->frontend;
Mauro Carvalho Chehab133bc4e2016-02-11 22:18:36 -0200896#ifdef CONFIG_MEDIA_CONTROLLER_DVB
897 si2157_config.mdev = dev->media_dev;
898#endif
Olli Salonenee3c3e42015-05-05 13:54:17 -0300899 si2157_config.if_port = 1;
Olli Salonen809abdb2015-02-28 12:25:24 -0300900 si2157_config.inversion = true;
901 strlcpy(info.type, "si2157", I2C_NAME_SIZE);
902 info.addr = 0x60;
903 info.platform_data = &si2157_config;
904 request_module("si2157");
905
906 client = i2c_new_device(
907 tuner_i2c,
908 &info);
909 if (client == NULL || client->dev.driver == NULL) {
910 dvb_frontend_detach(dev->dvb->frontend);
911 result = -ENODEV;
912 goto out_free;
913 }
914
915 if (!try_module_get(client->dev.driver->owner)) {
916 i2c_unregister_device(client);
917 dvb_frontend_detach(dev->dvb->frontend);
918 result = -ENODEV;
919 goto out_free;
920 }
921
922 dev->cx231xx_reset_analog_tuner = NULL;
923
924 dev->dvb->i2c_client_tuner = client;
925 break;
926 }
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300927 case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
Márcio Alveseeaaf812011-04-11 19:57:15 -0300928 case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300929
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300930 dev_info(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300931 "%s: looking for demod on i2c bus: %d\n",
932 __func__, i2c_adapter_id(tuner_i2c));
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300933
934 dev->dvb->frontend = dvb_attach(mb86a20s_attach,
935 &pv_mb86a20s_config,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300936 demod_i2c);
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300937
938 if (dev->dvb->frontend == NULL) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -0300939 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -0300940 "Failed to attach mb86a20s demod\n");
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300941 result = -EINVAL;
942 goto out_free;
943 }
944
945 /* define general-purpose callback pointer */
946 dvb->frontend->callback = cx231xx_tuner_callback;
947
948 dvb_attach(tda18271_attach, dev->dvb->frontend,
Matthias Schwarzottc3c3f1a2014-10-02 02:20:59 -0300949 0x60, tuner_i2c,
Mauro Carvalho Chehabede676c2010-09-27 23:44:27 -0300950 &pv_tda18271_config);
951 break;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300952
Oleh Kravchenkoa096fd62017-01-29 16:03:51 -0200953 case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
954 {
955 struct si2157_config si2157_config = {};
956 struct si2168_config si2168_config = {};
957 struct i2c_board_info info = {};
958 struct i2c_client *client;
959 struct i2c_adapter *adapter;
960
961 /* attach demodulator chip */
962 si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
963 si2168_config.fe = &dev->dvb->frontend;
964 si2168_config.i2c_adapter = &adapter;
965 si2168_config.ts_clock_inv = true;
966
967 strlcpy(info.type, "si2168", sizeof(info.type));
968 info.addr = dev->board.demod_addr;
969 info.platform_data = &si2168_config;
970
971 request_module(info.type);
972 client = i2c_new_device(demod_i2c, &info);
973
974 if (client == NULL || client->dev.driver == NULL) {
975 result = -ENODEV;
976 goto out_free;
977 }
978
979 if (!try_module_get(client->dev.driver->owner)) {
980 i2c_unregister_device(client);
981 result = -ENODEV;
982 goto out_free;
983 }
984
985 dvb->i2c_client_demod = client;
986
987 /* attach tuner chip */
988 si2157_config.fe = dev->dvb->frontend;
989#ifdef CONFIG_MEDIA_CONTROLLER_DVB
990 si2157_config.mdev = dev->media_dev;
991#endif
992 si2157_config.if_port = 1;
993 si2157_config.inversion = false;
994
995 memset(&info, 0, sizeof(info));
996 strlcpy(info.type, "si2157", sizeof(info.type));
997 info.addr = dev->board.tuner_addr;
998 info.platform_data = &si2157_config;
999
1000 request_module(info.type);
1001 client = i2c_new_device(tuner_i2c, &info);
1002
1003 if (client == NULL || client->dev.driver == NULL) {
1004 module_put(dvb->i2c_client_demod->dev.driver->owner);
1005 i2c_unregister_device(dvb->i2c_client_demod);
1006 result = -ENODEV;
1007 goto out_free;
1008 }
1009
1010 if (!try_module_get(client->dev.driver->owner)) {
1011 i2c_unregister_device(client);
1012 module_put(dvb->i2c_client_demod->dev.driver->owner);
1013 i2c_unregister_device(dvb->i2c_client_demod);
1014 result = -ENODEV;
1015 goto out_free;
1016 }
1017
1018 dev->cx231xx_reset_analog_tuner = NULL;
1019 dev->dvb->i2c_client_tuner = client;
1020 break;
1021 }
Sri Deevie0d3baf2009-03-03 14:37:50 -03001022 default:
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -03001023 dev_err(dev->dev,
Mauro Carvalho Chehab3b795d02014-11-02 07:45:56 -03001024 "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
1025 dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -03001026 break;
1027 }
1028 if (NULL == dvb->frontend) {
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -03001029 dev_err(dev->dev,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -03001030 "%s/2: frontend initialization failed\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -03001031 result = -EINVAL;
1032 goto out_free;
1033 }
1034
Sri Deevie0d3baf2009-03-03 14:37:50 -03001035 /* register everything */
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -03001036 result = register_dvb(dvb, THIS_MODULE, dev, dev->dev);
Sri Deevie0d3baf2009-03-03 14:37:50 -03001037
1038 if (result < 0)
1039 goto out_free;
1040
Devin Heitmueller761f6cf2010-07-06 19:24:19 -03001041
Mauro Carvalho Chehab336fea92014-11-03 06:07:38 -03001042 dev_info(dev->dev, "Successfully loaded cx231xx-dvb\n");
Devin Heitmueller761f6cf2010-07-06 19:24:19 -03001043
1044ret:
1045 cx231xx_set_mode(dev, CX231XX_SUSPEND);
1046 mutex_unlock(&dev->lock);
1047 return result;
Sri Deevie0d3baf2009-03-03 14:37:50 -03001048
Sri Deevib9255172009-03-04 17:49:01 -03001049out_free:
Sri Deevie0d3baf2009-03-03 14:37:50 -03001050 kfree(dvb);
1051 dev->dvb = NULL;
Devin Heitmueller761f6cf2010-07-06 19:24:19 -03001052 goto ret;
Sri Deevie0d3baf2009-03-03 14:37:50 -03001053}
1054
1055static int dvb_fini(struct cx231xx *dev)
1056{
1057 if (!dev->board.has_dvb) {
1058 /* This device does not support the extension */
1059 return 0;
1060 }
1061
1062 if (dev->dvb) {
1063 unregister_dvb(dev->dvb);
1064 dev->dvb = NULL;
1065 }
1066
1067 return 0;
1068}
1069
1070static struct cx231xx_ops dvb_ops = {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -03001071 .id = CX231XX_DVB,
Sri Deevie0d3baf2009-03-03 14:37:50 -03001072 .name = "Cx231xx dvb Extension",
1073 .init = dvb_init,
1074 .fini = dvb_fini,
1075};
1076
1077static int __init cx231xx_dvb_register(void)
1078{
1079 return cx231xx_register_extension(&dvb_ops);
1080}
1081
1082static void __exit cx231xx_dvb_unregister(void)
1083{
1084 cx231xx_unregister_extension(&dvb_ops);
1085}
1086
1087module_init(cx231xx_dvb_register);
1088module_exit(cx231xx_dvb_unregister);