xref: /linux/drivers/media/pci/ddbridge/ddbridge-core.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
14771d831SDaniel Scheller // SPDX-License-Identifier: GPL-2.0
225aee3deSMauro Carvalho Chehab /*
322e74389SDaniel Scheller  * ddbridge-core.c: Digital Devices bridge core functions
425aee3deSMauro Carvalho Chehab  *
522e74389SDaniel Scheller  * Copyright (C) 2010-2017 Digital Devices GmbH
622e74389SDaniel Scheller  *                         Marcus Metzler <mocm@metzlerbros.de>
722e74389SDaniel Scheller  *                         Ralph Metzler <rjkm@metzlerbros.de>
825aee3deSMauro Carvalho Chehab  */
925aee3deSMauro Carvalho Chehab 
1025aee3deSMauro Carvalho Chehab #include <linux/module.h>
1125aee3deSMauro Carvalho Chehab #include <linux/init.h>
1225aee3deSMauro Carvalho Chehab #include <linux/interrupt.h>
1325aee3deSMauro Carvalho Chehab #include <linux/delay.h>
1425aee3deSMauro Carvalho Chehab #include <linux/slab.h>
1525aee3deSMauro Carvalho Chehab #include <linux/poll.h>
1625aee3deSMauro Carvalho Chehab #include <linux/io.h>
1725aee3deSMauro Carvalho Chehab #include <linux/pci.h>
1825aee3deSMauro Carvalho Chehab #include <linux/pci_ids.h>
1925aee3deSMauro Carvalho Chehab #include <linux/timer.h>
2025aee3deSMauro Carvalho Chehab #include <linux/i2c.h>
2125aee3deSMauro Carvalho Chehab #include <linux/swab.h>
2225aee3deSMauro Carvalho Chehab #include <linux/vmalloc.h>
2325aee3deSMauro Carvalho Chehab 
24a96e5ab8SDaniel Scheller #include "ddbridge.h"
25a96e5ab8SDaniel Scheller #include "ddbridge-i2c.h"
2625aee3deSMauro Carvalho Chehab #include "ddbridge-regs.h"
272d8c98b8SDaniel Scheller #include "ddbridge-max.h"
2870d3ae1bSDaniel Scheller #include "ddbridge-ci.h"
2914e27a10SDaniel Scheller #include "ddbridge-io.h"
3025aee3deSMauro Carvalho Chehab 
3125aee3deSMauro Carvalho Chehab #include "tda18271c2dd.h"
3225aee3deSMauro Carvalho Chehab #include "stv6110x.h"
3325aee3deSMauro Carvalho Chehab #include "stv090x.h"
3425aee3deSMauro Carvalho Chehab #include "lnbh24.h"
3525aee3deSMauro Carvalho Chehab #include "drxk.h"
3605da9437SDaniel Scheller #include "stv0367.h"
3705da9437SDaniel Scheller #include "stv0367_priv.h"
3869e1749cSDaniel Scheller #include "cxd2841er.h"
3905da9437SDaniel Scheller #include "tda18212.h"
40df3082dfSDaniel Scheller #include "stv0910.h"
41df3082dfSDaniel Scheller #include "stv6111.h"
42df3082dfSDaniel Scheller #include "lnbh25.h"
4322e74389SDaniel Scheller #include "cxd2099.h"
449a33a27eSMauro Carvalho Chehab #include "ddbridge-dummy-fe.h"
4522e74389SDaniel Scheller 
4622e74389SDaniel Scheller /****************************************************************************/
4722e74389SDaniel Scheller 
4822e74389SDaniel Scheller #define DDB_MAX_ADAPTER 64
4925aee3deSMauro Carvalho Chehab 
508e4eef22SDaniel Scheller /****************************************************************************/
518e4eef22SDaniel Scheller 
5225aee3deSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
5325aee3deSMauro Carvalho Chehab 
548e4eef22SDaniel Scheller static int adapter_alloc;
558e4eef22SDaniel Scheller module_param(adapter_alloc, int, 0444);
568e4eef22SDaniel Scheller MODULE_PARM_DESC(adapter_alloc,
578e4eef22SDaniel Scheller 		 "0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
588e4eef22SDaniel Scheller 
595589974eSDaniel Scheller static int ci_bitrate = 70000;
605589974eSDaniel Scheller module_param(ci_bitrate, int, 0444);
615589974eSDaniel Scheller MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI.");
625589974eSDaniel Scheller 
635589974eSDaniel Scheller static int ts_loop = -1;
645589974eSDaniel Scheller module_param(ts_loop, int, 0444);
655589974eSDaniel Scheller MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop");
665589974eSDaniel Scheller 
675589974eSDaniel Scheller static int xo2_speed = 2;
685589974eSDaniel Scheller module_param(xo2_speed, int, 0444);
695589974eSDaniel Scheller MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards");
705589974eSDaniel Scheller 
715589974eSDaniel Scheller #ifdef __arm__
725589974eSDaniel Scheller static int alt_dma = 1;
735589974eSDaniel Scheller #else
745589974eSDaniel Scheller static int alt_dma;
755589974eSDaniel Scheller #endif
765589974eSDaniel Scheller module_param(alt_dma, int, 0444);
775589974eSDaniel Scheller MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling");
785589974eSDaniel Scheller 
795589974eSDaniel Scheller static int no_init;
805589974eSDaniel Scheller module_param(no_init, int, 0444);
815589974eSDaniel Scheller MODULE_PARM_DESC(no_init, "do not initialize most devices");
825589974eSDaniel Scheller 
835589974eSDaniel Scheller static int stv0910_single;
845589974eSDaniel Scheller module_param(stv0910_single, int, 0444);
855589974eSDaniel Scheller MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
865589974eSDaniel Scheller 
870a68fc44SDaniel Scheller static int dma_buf_num = 8;
880a68fc44SDaniel Scheller module_param(dma_buf_num, int, 0444);
890a68fc44SDaniel Scheller MODULE_PARM_DESC(dma_buf_num, "Number of DMA buffers, possible values: 8-32");
900a68fc44SDaniel Scheller 
910a68fc44SDaniel Scheller static int dma_buf_size = 21;
920a68fc44SDaniel Scheller module_param(dma_buf_size, int, 0444);
930a68fc44SDaniel Scheller MODULE_PARM_DESC(dma_buf_size,
940a68fc44SDaniel Scheller 		 "DMA buffer size as multiple of 128*47, possible values: 1-43");
950a68fc44SDaniel Scheller 
96ab12397fSDaniel Scheller static int dummy_tuner;
97ab12397fSDaniel Scheller module_param(dummy_tuner, int, 0444);
98ab12397fSDaniel Scheller MODULE_PARM_DESC(dummy_tuner,
99ab12397fSDaniel Scheller 		 "attach dummy tuner to port 0 on Octopus V3 or Octopus Mini cards");
100ab12397fSDaniel Scheller 
1018e4eef22SDaniel Scheller /****************************************************************************/
1028e4eef22SDaniel Scheller 
103b5967860SDaniel Scheller static DEFINE_MUTEX(redirect_lock);
10425aee3deSMauro Carvalho Chehab 
10505ed62daSDaniel Scheller static struct workqueue_struct *ddb_wq;
1068e4eef22SDaniel Scheller 
10722e74389SDaniel Scheller static struct ddb *ddbs[DDB_MAX_ADAPTER];
10822e74389SDaniel Scheller 
10922e74389SDaniel Scheller /****************************************************************************/
11022e74389SDaniel Scheller /****************************************************************************/
11122e74389SDaniel Scheller /****************************************************************************/
11222e74389SDaniel Scheller 
ddb_irq_set(struct ddb * dev,u32 link,u32 nr,void (* handler)(void *),void * data)1131dda87acSDaniel Scheller struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
1141dda87acSDaniel Scheller 			    void (*handler)(void *), void *data)
1151dda87acSDaniel Scheller {
1161dda87acSDaniel Scheller 	struct ddb_irq *irq = &dev->link[link].irq[nr];
1171dda87acSDaniel Scheller 
1181dda87acSDaniel Scheller 	irq->handler = handler;
1191dda87acSDaniel Scheller 	irq->data = data;
1201dda87acSDaniel Scheller 	return irq;
1211dda87acSDaniel Scheller }
1221dda87acSDaniel Scheller 
ddb_set_dma_table(struct ddb_io * io)12322e74389SDaniel Scheller static void ddb_set_dma_table(struct ddb_io *io)
12422e74389SDaniel Scheller {
12522e74389SDaniel Scheller 	struct ddb *dev = io->port->dev;
12622e74389SDaniel Scheller 	struct ddb_dma *dma = io->dma;
12722e74389SDaniel Scheller 	u32 i;
12822e74389SDaniel Scheller 	u64 mem;
12922e74389SDaniel Scheller 
13022e74389SDaniel Scheller 	if (!dma)
13122e74389SDaniel Scheller 		return;
13222e74389SDaniel Scheller 	for (i = 0; i < dma->num; i++) {
13322e74389SDaniel Scheller 		mem = dma->pbuf[i];
13422e74389SDaniel Scheller 		ddbwritel(dev, mem & 0xffffffff, dma->bufregs + i * 8);
13522e74389SDaniel Scheller 		ddbwritel(dev, mem >> 32, dma->bufregs + i * 8 + 4);
13622e74389SDaniel Scheller 	}
13722e74389SDaniel Scheller 	dma->bufval = ((dma->div & 0x0f) << 16) |
13822e74389SDaniel Scheller 		((dma->num & 0x1f) << 11) |
13922e74389SDaniel Scheller 		((dma->size >> 7) & 0x7ff);
14022e74389SDaniel Scheller }
14122e74389SDaniel Scheller 
ddb_set_dma_tables(struct ddb * dev)14222e74389SDaniel Scheller static void ddb_set_dma_tables(struct ddb *dev)
14322e74389SDaniel Scheller {
14422e74389SDaniel Scheller 	u32 i;
14522e74389SDaniel Scheller 
14622e74389SDaniel Scheller 	for (i = 0; i < DDB_MAX_PORT; i++) {
14722e74389SDaniel Scheller 		if (dev->port[i].input[0])
14822e74389SDaniel Scheller 			ddb_set_dma_table(dev->port[i].input[0]);
14922e74389SDaniel Scheller 		if (dev->port[i].input[1])
15022e74389SDaniel Scheller 			ddb_set_dma_table(dev->port[i].input[1]);
15122e74389SDaniel Scheller 		if (dev->port[i].output)
15222e74389SDaniel Scheller 			ddb_set_dma_table(dev->port[i].output);
15322e74389SDaniel Scheller 	}
15422e74389SDaniel Scheller }
15522e74389SDaniel Scheller 
15622e74389SDaniel Scheller /****************************************************************************/
15722e74389SDaniel Scheller /****************************************************************************/
15822e74389SDaniel Scheller /****************************************************************************/
15922e74389SDaniel Scheller 
ddb_redirect_dma(struct ddb * dev,struct ddb_dma * sdma,struct ddb_dma * ddma)16022e74389SDaniel Scheller static void ddb_redirect_dma(struct ddb *dev,
16122e74389SDaniel Scheller 			     struct ddb_dma *sdma,
16222e74389SDaniel Scheller 			     struct ddb_dma *ddma)
16325aee3deSMauro Carvalho Chehab {
16425aee3deSMauro Carvalho Chehab 	u32 i, base;
16525aee3deSMauro Carvalho Chehab 	u64 mem;
16625aee3deSMauro Carvalho Chehab 
16722e74389SDaniel Scheller 	sdma->bufval = ddma->bufval;
16822e74389SDaniel Scheller 	base = sdma->bufregs;
16922e74389SDaniel Scheller 	for (i = 0; i < ddma->num; i++) {
17022e74389SDaniel Scheller 		mem = ddma->pbuf[i];
17122e74389SDaniel Scheller 		ddbwritel(dev, mem & 0xffffffff, base + i * 8);
17222e74389SDaniel Scheller 		ddbwritel(dev, mem >> 32, base + i * 8 + 4);
17325aee3deSMauro Carvalho Chehab 	}
17425aee3deSMauro Carvalho Chehab }
17525aee3deSMauro Carvalho Chehab 
ddb_unredirect(struct ddb_port * port)17622e74389SDaniel Scheller static int ddb_unredirect(struct ddb_port *port)
17725aee3deSMauro Carvalho Chehab {
178b5967860SDaniel Scheller 	struct ddb_input *oredi, *iredi = NULL;
179b5967860SDaniel Scheller 	struct ddb_output *iredo = NULL;
18025aee3deSMauro Carvalho Chehab 
18122e74389SDaniel Scheller 	/* dev_info(port->dev->dev,
18222e74389SDaniel Scheller 	 * "unredirect %d.%d\n", port->dev->nr, port->nr);
18322e74389SDaniel Scheller 	 */
18422e74389SDaniel Scheller 	mutex_lock(&redirect_lock);
18522e74389SDaniel Scheller 	if (port->output->dma->running) {
18622e74389SDaniel Scheller 		mutex_unlock(&redirect_lock);
18722e74389SDaniel Scheller 		return -EBUSY;
18825aee3deSMauro Carvalho Chehab 	}
18922e74389SDaniel Scheller 	oredi = port->output->redi;
19022e74389SDaniel Scheller 	if (!oredi)
19122e74389SDaniel Scheller 		goto done;
19222e74389SDaniel Scheller 	if (port->input[0]) {
19322e74389SDaniel Scheller 		iredi = port->input[0]->redi;
19422e74389SDaniel Scheller 		iredo = port->input[0]->redo;
19522e74389SDaniel Scheller 
19622e74389SDaniel Scheller 		if (iredo) {
19722e74389SDaniel Scheller 			iredo->port->output->redi = oredi;
19822e74389SDaniel Scheller 			if (iredo->port->input[0]) {
19922e74389SDaniel Scheller 				iredo->port->input[0]->redi = iredi;
20022e74389SDaniel Scheller 				ddb_redirect_dma(oredi->port->dev,
20122e74389SDaniel Scheller 						 oredi->dma, iredo->dma);
20225aee3deSMauro Carvalho Chehab 			}
203b5967860SDaniel Scheller 			port->input[0]->redo = NULL;
20422e74389SDaniel Scheller 			ddb_set_dma_table(port->input[0]);
20525aee3deSMauro Carvalho Chehab 		}
20622e74389SDaniel Scheller 		oredi->redi = iredi;
207b5967860SDaniel Scheller 		port->input[0]->redi = NULL;
20825aee3deSMauro Carvalho Chehab 	}
209b5967860SDaniel Scheller 	oredi->redo = NULL;
210b5967860SDaniel Scheller 	port->output->redi = NULL;
21122e74389SDaniel Scheller 
21222e74389SDaniel Scheller 	ddb_set_dma_table(oredi);
21322e74389SDaniel Scheller done:
21422e74389SDaniel Scheller 	mutex_unlock(&redirect_lock);
21522e74389SDaniel Scheller 	return 0;
21625aee3deSMauro Carvalho Chehab }
21725aee3deSMauro Carvalho Chehab 
ddb_redirect(u32 i,u32 p)21822e74389SDaniel Scheller static int ddb_redirect(u32 i, u32 p)
21922e74389SDaniel Scheller {
22022e74389SDaniel Scheller 	struct ddb *idev = ddbs[(i >> 4) & 0x3f];
22122e74389SDaniel Scheller 	struct ddb_input *input, *input2;
22222e74389SDaniel Scheller 	struct ddb *pdev = ddbs[(p >> 4) & 0x3f];
22322e74389SDaniel Scheller 	struct ddb_port *port;
22422e74389SDaniel Scheller 
22522e74389SDaniel Scheller 	if (!idev || !pdev)
22622e74389SDaniel Scheller 		return -EINVAL;
227e89e02a8SDaniel Scheller 	if (!idev->has_dma || !pdev->has_dma)
228e89e02a8SDaniel Scheller 		return -EINVAL;
22922e74389SDaniel Scheller 
23022e74389SDaniel Scheller 	port = &pdev->port[p & 0x0f];
23122e74389SDaniel Scheller 	if (!port->output)
23222e74389SDaniel Scheller 		return -EINVAL;
23322e74389SDaniel Scheller 	if (ddb_unredirect(port))
23422e74389SDaniel Scheller 		return -EBUSY;
23522e74389SDaniel Scheller 
23622e74389SDaniel Scheller 	if (i == 8)
23722e74389SDaniel Scheller 		return 0;
23822e74389SDaniel Scheller 
23922e74389SDaniel Scheller 	input = &idev->input[i & 7];
24022e74389SDaniel Scheller 	if (!input)
24122e74389SDaniel Scheller 		return -EINVAL;
24222e74389SDaniel Scheller 
24322e74389SDaniel Scheller 	mutex_lock(&redirect_lock);
24422e74389SDaniel Scheller 	if (port->output->dma->running || input->dma->running) {
24522e74389SDaniel Scheller 		mutex_unlock(&redirect_lock);
24622e74389SDaniel Scheller 		return -EBUSY;
24722e74389SDaniel Scheller 	}
24822e74389SDaniel Scheller 	input2 = port->input[0];
24922e74389SDaniel Scheller 	if (input2) {
25022e74389SDaniel Scheller 		if (input->redi) {
25122e74389SDaniel Scheller 			input2->redi = input->redi;
252b5967860SDaniel Scheller 			input->redi = NULL;
253757d78d3SDaniel Scheller 		} else {
25422e74389SDaniel Scheller 			input2->redi = input;
25522e74389SDaniel Scheller 		}
256757d78d3SDaniel Scheller 	}
25722e74389SDaniel Scheller 	input->redo = port->output;
25822e74389SDaniel Scheller 	port->output->redi = input;
25922e74389SDaniel Scheller 
26022e74389SDaniel Scheller 	ddb_redirect_dma(input->port->dev, input->dma, port->output->dma);
26122e74389SDaniel Scheller 	mutex_unlock(&redirect_lock);
26222e74389SDaniel Scheller 	return 0;
26322e74389SDaniel Scheller }
26422e74389SDaniel Scheller 
26522e74389SDaniel Scheller /****************************************************************************/
26622e74389SDaniel Scheller /****************************************************************************/
26722e74389SDaniel Scheller /****************************************************************************/
26822e74389SDaniel Scheller 
dma_free(struct pci_dev * pdev,struct ddb_dma * dma,int dir)26922e74389SDaniel Scheller static void dma_free(struct pci_dev *pdev, struct ddb_dma *dma, int dir)
27025aee3deSMauro Carvalho Chehab {
27125aee3deSMauro Carvalho Chehab 	int i;
27225aee3deSMauro Carvalho Chehab 
27322e74389SDaniel Scheller 	if (!dma)
27422e74389SDaniel Scheller 		return;
27522e74389SDaniel Scheller 	for (i = 0; i < dma->num; i++) {
27622e74389SDaniel Scheller 		if (dma->vbuf[i]) {
27722e74389SDaniel Scheller 			if (alt_dma) {
27822e74389SDaniel Scheller 				dma_unmap_single(&pdev->dev, dma->pbuf[i],
27922e74389SDaniel Scheller 						 dma->size,
28022e74389SDaniel Scheller 						 dir ? DMA_TO_DEVICE :
28122e74389SDaniel Scheller 						 DMA_FROM_DEVICE);
28222e74389SDaniel Scheller 				kfree(dma->vbuf[i]);
28322e74389SDaniel Scheller 				dma->vbuf[i] = NULL;
28422e74389SDaniel Scheller 			} else {
28522e74389SDaniel Scheller 				dma_free_coherent(&pdev->dev, dma->size,
28622e74389SDaniel Scheller 						  dma->vbuf[i], dma->pbuf[i]);
28722e74389SDaniel Scheller 			}
28822e74389SDaniel Scheller 
28922e74389SDaniel Scheller 			dma->vbuf[i] = NULL;
29025aee3deSMauro Carvalho Chehab 		}
29125aee3deSMauro Carvalho Chehab 	}
29225aee3deSMauro Carvalho Chehab }
29325aee3deSMauro Carvalho Chehab 
dma_alloc(struct pci_dev * pdev,struct ddb_dma * dma,int dir)29422e74389SDaniel Scheller static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma, int dir)
29525aee3deSMauro Carvalho Chehab {
29625aee3deSMauro Carvalho Chehab 	int i;
29725aee3deSMauro Carvalho Chehab 
29822e74389SDaniel Scheller 	if (!dma)
29922e74389SDaniel Scheller 		return 0;
30022e74389SDaniel Scheller 	for (i = 0; i < dma->num; i++) {
30122e74389SDaniel Scheller 		if (alt_dma) {
30222e74389SDaniel Scheller 			dma->vbuf[i] = kmalloc(dma->size, __GFP_RETRY_MAYFAIL);
30322e74389SDaniel Scheller 			if (!dma->vbuf[i])
30425aee3deSMauro Carvalho Chehab 				return -ENOMEM;
30522e74389SDaniel Scheller 			dma->pbuf[i] = dma_map_single(&pdev->dev,
30622e74389SDaniel Scheller 						      dma->vbuf[i],
30722e74389SDaniel Scheller 						      dma->size,
30822e74389SDaniel Scheller 						      dir ? DMA_TO_DEVICE :
30922e74389SDaniel Scheller 						      DMA_FROM_DEVICE);
31022e74389SDaniel Scheller 			if (dma_mapping_error(&pdev->dev, dma->pbuf[i])) {
31122e74389SDaniel Scheller 				kfree(dma->vbuf[i]);
31222e74389SDaniel Scheller 				dma->vbuf[i] = NULL;
31322e74389SDaniel Scheller 				return -ENOMEM;
31422e74389SDaniel Scheller 			}
31522e74389SDaniel Scheller 		} else {
31622e74389SDaniel Scheller 			dma->vbuf[i] = dma_alloc_coherent(&pdev->dev,
31722e74389SDaniel Scheller 							  dma->size,
31822e74389SDaniel Scheller 							  &dma->pbuf[i],
31922e74389SDaniel Scheller 							  GFP_KERNEL);
32022e74389SDaniel Scheller 			if (!dma->vbuf[i])
32122e74389SDaniel Scheller 				return -ENOMEM;
32222e74389SDaniel Scheller 		}
32325aee3deSMauro Carvalho Chehab 	}
32425aee3deSMauro Carvalho Chehab 	return 0;
32525aee3deSMauro Carvalho Chehab }
32625aee3deSMauro Carvalho Chehab 
ddb_buffers_alloc(struct ddb * dev)327a96e5ab8SDaniel Scheller int ddb_buffers_alloc(struct ddb *dev)
32825aee3deSMauro Carvalho Chehab {
32925aee3deSMauro Carvalho Chehab 	int i;
33025aee3deSMauro Carvalho Chehab 	struct ddb_port *port;
33125aee3deSMauro Carvalho Chehab 
33222e74389SDaniel Scheller 	for (i = 0; i < dev->port_num; i++) {
33325aee3deSMauro Carvalho Chehab 		port = &dev->port[i];
33425aee3deSMauro Carvalho Chehab 		switch (port->class) {
33525aee3deSMauro Carvalho Chehab 		case DDB_PORT_TUNER:
33622e74389SDaniel Scheller 			if (port->input[0]->dma)
33722e74389SDaniel Scheller 				if (dma_alloc(dev->pdev, port->input[0]->dma, 0)
33822e74389SDaniel Scheller 					< 0)
33925aee3deSMauro Carvalho Chehab 					return -1;
34022e74389SDaniel Scheller 			if (port->input[1]->dma)
34122e74389SDaniel Scheller 				if (dma_alloc(dev->pdev, port->input[1]->dma, 0)
34222e74389SDaniel Scheller 					< 0)
34325aee3deSMauro Carvalho Chehab 					return -1;
34425aee3deSMauro Carvalho Chehab 			break;
34525aee3deSMauro Carvalho Chehab 		case DDB_PORT_CI:
34622e74389SDaniel Scheller 		case DDB_PORT_LOOP:
34722e74389SDaniel Scheller 			if (port->input[0]->dma)
34822e74389SDaniel Scheller 				if (dma_alloc(dev->pdev, port->input[0]->dma, 0)
34922e74389SDaniel Scheller 					< 0)
35025aee3deSMauro Carvalho Chehab 					return -1;
35122e74389SDaniel Scheller 			if (port->output->dma)
35222e74389SDaniel Scheller 				if (dma_alloc(dev->pdev, port->output->dma, 1)
35322e74389SDaniel Scheller 					< 0)
35425aee3deSMauro Carvalho Chehab 					return -1;
35525aee3deSMauro Carvalho Chehab 			break;
35625aee3deSMauro Carvalho Chehab 		default:
35725aee3deSMauro Carvalho Chehab 			break;
35825aee3deSMauro Carvalho Chehab 		}
35925aee3deSMauro Carvalho Chehab 	}
36022e74389SDaniel Scheller 	ddb_set_dma_tables(dev);
36125aee3deSMauro Carvalho Chehab 	return 0;
36225aee3deSMauro Carvalho Chehab }
36325aee3deSMauro Carvalho Chehab 
ddb_buffers_free(struct ddb * dev)364a96e5ab8SDaniel Scheller void ddb_buffers_free(struct ddb *dev)
36525aee3deSMauro Carvalho Chehab {
36625aee3deSMauro Carvalho Chehab 	int i;
36725aee3deSMauro Carvalho Chehab 	struct ddb_port *port;
36825aee3deSMauro Carvalho Chehab 
36922e74389SDaniel Scheller 	for (i = 0; i < dev->port_num; i++) {
37025aee3deSMauro Carvalho Chehab 		port = &dev->port[i];
37122e74389SDaniel Scheller 
37222e74389SDaniel Scheller 		if (port->input[0] && port->input[0]->dma)
37322e74389SDaniel Scheller 			dma_free(dev->pdev, port->input[0]->dma, 0);
37422e74389SDaniel Scheller 		if (port->input[1] && port->input[1]->dma)
37522e74389SDaniel Scheller 			dma_free(dev->pdev, port->input[1]->dma, 0);
37622e74389SDaniel Scheller 		if (port->output && port->output->dma)
37722e74389SDaniel Scheller 			dma_free(dev->pdev, port->output->dma, 1);
37825aee3deSMauro Carvalho Chehab 	}
37925aee3deSMauro Carvalho Chehab }
38025aee3deSMauro Carvalho Chehab 
calc_con(struct ddb_output * output,u32 * con,u32 * con2,u32 flags)38122e74389SDaniel Scheller static void calc_con(struct ddb_output *output, u32 *con, u32 *con2, u32 flags)
38222e74389SDaniel Scheller {
38322e74389SDaniel Scheller 	struct ddb *dev = output->port->dev;
38422e74389SDaniel Scheller 	u32 bitrate = output->port->obr, max_bitrate = 72000;
38522e74389SDaniel Scheller 	u32 gap = 4, nco = 0;
38622e74389SDaniel Scheller 
38722e74389SDaniel Scheller 	*con = 0x1c;
38822e74389SDaniel Scheller 	if (output->port->gap != 0xffffffff) {
38922e74389SDaniel Scheller 		flags |= 1;
39022e74389SDaniel Scheller 		gap = output->port->gap;
391bae7c75bSDaniel Scheller 		max_bitrate = 0;
39222e74389SDaniel Scheller 	}
39322e74389SDaniel Scheller 	if (dev->link[0].info->type == DDB_OCTOPUS_CI && output->port->nr > 1) {
39422e74389SDaniel Scheller 		*con = 0x10c;
39522e74389SDaniel Scheller 		if (dev->link[0].ids.regmapid >= 0x10003 && !(flags & 1)) {
39622e74389SDaniel Scheller 			if (!(flags & 2)) {
39722e74389SDaniel Scheller 				/* NCO */
39822e74389SDaniel Scheller 				max_bitrate = 0;
39922e74389SDaniel Scheller 				gap = 0;
40022e74389SDaniel Scheller 				if (bitrate != 72000) {
401757d78d3SDaniel Scheller 					if (bitrate >= 96000) {
40222e74389SDaniel Scheller 						*con |= 0x800;
403757d78d3SDaniel Scheller 					} else {
40422e74389SDaniel Scheller 						*con |= 0x1000;
40522e74389SDaniel Scheller 						nco = (bitrate * 8192 + 71999)
40622e74389SDaniel Scheller 							/ 72000;
40722e74389SDaniel Scheller 					}
40822e74389SDaniel Scheller 				}
40922e74389SDaniel Scheller 			} else {
41022e74389SDaniel Scheller 				/* Divider and gap */
41122e74389SDaniel Scheller 				*con |= 0x1810;
41222e74389SDaniel Scheller 				if (bitrate <= 64000) {
41322e74389SDaniel Scheller 					max_bitrate = 64000;
41422e74389SDaniel Scheller 					nco = 8;
41522e74389SDaniel Scheller 				} else if (bitrate <= 72000) {
41622e74389SDaniel Scheller 					max_bitrate = 72000;
41722e74389SDaniel Scheller 					nco = 7;
41822e74389SDaniel Scheller 				} else {
41922e74389SDaniel Scheller 					max_bitrate = 96000;
42022e74389SDaniel Scheller 					nco = 5;
42122e74389SDaniel Scheller 				}
42222e74389SDaniel Scheller 			}
42322e74389SDaniel Scheller 		} else {
42422e74389SDaniel Scheller 			if (bitrate > 72000) {
42522e74389SDaniel Scheller 				*con |= 0x810; /* 96 MBit/s and gap */
42622e74389SDaniel Scheller 				max_bitrate = 96000;
42722e74389SDaniel Scheller 			}
428bae7c75bSDaniel Scheller 			*con |= 0x10; /* enable gap */
42922e74389SDaniel Scheller 		}
43022e74389SDaniel Scheller 	}
43122e74389SDaniel Scheller 	if (max_bitrate > 0) {
43222e74389SDaniel Scheller 		if (bitrate > max_bitrate)
43322e74389SDaniel Scheller 			bitrate = max_bitrate;
43422e74389SDaniel Scheller 		if (bitrate < 31000)
43522e74389SDaniel Scheller 			bitrate = 31000;
43622e74389SDaniel Scheller 		gap = ((max_bitrate - bitrate) * 94) / bitrate;
43722e74389SDaniel Scheller 		if (gap < 2)
43822e74389SDaniel Scheller 			*con &= ~0x10; /* Disable gap */
43922e74389SDaniel Scheller 		else
44022e74389SDaniel Scheller 			gap -= 2;
44122e74389SDaniel Scheller 		if (gap > 127)
44222e74389SDaniel Scheller 			gap = 127;
44322e74389SDaniel Scheller 	}
44422e74389SDaniel Scheller 
44522e74389SDaniel Scheller 	*con2 = (nco << 16) | gap;
44622e74389SDaniel Scheller }
44722e74389SDaniel Scheller 
ddb_output_start(struct ddb_output * output)44825aee3deSMauro Carvalho Chehab static void ddb_output_start(struct ddb_output *output)
44925aee3deSMauro Carvalho Chehab {
45025aee3deSMauro Carvalho Chehab 	struct ddb *dev = output->port->dev;
45122e74389SDaniel Scheller 	u32 con = 0x11c, con2 = 0;
45225aee3deSMauro Carvalho Chehab 
45322e74389SDaniel Scheller 	spin_lock_irq(&output->dma->lock);
45422e74389SDaniel Scheller 	output->dma->cbuf = 0;
45522e74389SDaniel Scheller 	output->dma->coff = 0;
45622e74389SDaniel Scheller 	output->dma->stat = 0;
45722e74389SDaniel Scheller 	ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma));
45825aee3deSMauro Carvalho Chehab 
45922e74389SDaniel Scheller 	if (output->port->input[0]->port->class == DDB_PORT_LOOP)
46022e74389SDaniel Scheller 		con = (1UL << 13) | 0x14;
46122e74389SDaniel Scheller 	else
46222e74389SDaniel Scheller 		calc_con(output, &con, &con2, 0);
46322e74389SDaniel Scheller 
46422e74389SDaniel Scheller 	ddbwritel(dev, 0, TS_CONTROL(output));
46522e74389SDaniel Scheller 	ddbwritel(dev, 2, TS_CONTROL(output));
46622e74389SDaniel Scheller 	ddbwritel(dev, 0, TS_CONTROL(output));
46722e74389SDaniel Scheller 	ddbwritel(dev, con, TS_CONTROL(output));
46822e74389SDaniel Scheller 	ddbwritel(dev, con2, TS_CONTROL2(output));
46922e74389SDaniel Scheller 
47022e74389SDaniel Scheller 	ddbwritel(dev, output->dma->bufval,
47122e74389SDaniel Scheller 		  DMA_BUFFER_SIZE(output->dma));
47222e74389SDaniel Scheller 	ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma));
47322e74389SDaniel Scheller 	ddbwritel(dev, 1, DMA_BASE_READ);
47422e74389SDaniel Scheller 	ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma));
47522e74389SDaniel Scheller 
47622e74389SDaniel Scheller 	ddbwritel(dev, con | 1, TS_CONTROL(output));
47722e74389SDaniel Scheller 
47822e74389SDaniel Scheller 	output->dma->running = 1;
47922e74389SDaniel Scheller 	spin_unlock_irq(&output->dma->lock);
48022e74389SDaniel Scheller }
48125aee3deSMauro Carvalho Chehab 
ddb_output_stop(struct ddb_output * output)48225aee3deSMauro Carvalho Chehab static void ddb_output_stop(struct ddb_output *output)
48325aee3deSMauro Carvalho Chehab {
48425aee3deSMauro Carvalho Chehab 	struct ddb *dev = output->port->dev;
48525aee3deSMauro Carvalho Chehab 
48622e74389SDaniel Scheller 	spin_lock_irq(&output->dma->lock);
48722e74389SDaniel Scheller 
48822e74389SDaniel Scheller 	ddbwritel(dev, 0, TS_CONTROL(output));
48922e74389SDaniel Scheller 
49022e74389SDaniel Scheller 	ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma));
49122e74389SDaniel Scheller 	output->dma->running = 0;
49222e74389SDaniel Scheller 	spin_unlock_irq(&output->dma->lock);
49322e74389SDaniel Scheller }
49425aee3deSMauro Carvalho Chehab 
ddb_input_stop(struct ddb_input * input)495335bb883SDaniel Scheller static void ddb_input_stop(struct ddb_input *input)
496335bb883SDaniel Scheller {
497335bb883SDaniel Scheller 	struct ddb *dev = input->port->dev;
49822e74389SDaniel Scheller 	u32 tag = DDB_LINK_TAG(input->port->lnr);
499335bb883SDaniel Scheller 
50022e74389SDaniel Scheller 	spin_lock_irq(&input->dma->lock);
5018b8fcf32SDaniel Scheller 
50222e74389SDaniel Scheller 	ddbwritel(dev, 0, tag | TS_CONTROL(input));
5038b8fcf32SDaniel Scheller 
50422e74389SDaniel Scheller 	ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
50522e74389SDaniel Scheller 	input->dma->running = 0;
50622e74389SDaniel Scheller 	spin_unlock_irq(&input->dma->lock);
50722e74389SDaniel Scheller }
508335bb883SDaniel Scheller 
ddb_input_start(struct ddb_input * input)509335bb883SDaniel Scheller static void ddb_input_start(struct ddb_input *input)
510335bb883SDaniel Scheller {
511335bb883SDaniel Scheller 	struct ddb *dev = input->port->dev;
512335bb883SDaniel Scheller 
51322e74389SDaniel Scheller 	spin_lock_irq(&input->dma->lock);
51422e74389SDaniel Scheller 	input->dma->cbuf = 0;
51522e74389SDaniel Scheller 	input->dma->coff = 0;
51622e74389SDaniel Scheller 	input->dma->stat = 0;
51722e74389SDaniel Scheller 	ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
5188b8fcf32SDaniel Scheller 
51922e74389SDaniel Scheller 	ddbwritel(dev, 0, TS_CONTROL(input));
52022e74389SDaniel Scheller 	ddbwritel(dev, 2, TS_CONTROL(input));
52122e74389SDaniel Scheller 	ddbwritel(dev, 0, TS_CONTROL(input));
522335bb883SDaniel Scheller 
52322e74389SDaniel Scheller 	ddbwritel(dev, input->dma->bufval,
52422e74389SDaniel Scheller 		  DMA_BUFFER_SIZE(input->dma));
52522e74389SDaniel Scheller 	ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma));
52622e74389SDaniel Scheller 	ddbwritel(dev, 1, DMA_BASE_WRITE);
52722e74389SDaniel Scheller 	ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma));
528335bb883SDaniel Scheller 
52922e74389SDaniel Scheller 	ddbwritel(dev, 0x09, TS_CONTROL(input));
530335bb883SDaniel Scheller 
531ab12397fSDaniel Scheller 	if (input->port->type == DDB_TUNER_DUMMY)
532ab12397fSDaniel Scheller 		ddbwritel(dev, 0x000fff01, TS_CONTROL2(input));
533ab12397fSDaniel Scheller 
53422e74389SDaniel Scheller 	input->dma->running = 1;
53522e74389SDaniel Scheller 	spin_unlock_irq(&input->dma->lock);
53622e74389SDaniel Scheller }
53722e74389SDaniel Scheller 
ddb_input_start_all(struct ddb_input * input)53822e74389SDaniel Scheller static void ddb_input_start_all(struct ddb_input *input)
53922e74389SDaniel Scheller {
54022e74389SDaniel Scheller 	struct ddb_input *i = input;
54122e74389SDaniel Scheller 	struct ddb_output *o;
54222e74389SDaniel Scheller 
54322e74389SDaniel Scheller 	mutex_lock(&redirect_lock);
54422e74389SDaniel Scheller 	while (i && (o = i->redo)) {
54522e74389SDaniel Scheller 		ddb_output_start(o);
54622e74389SDaniel Scheller 		i = o->port->input[0];
54722e74389SDaniel Scheller 		if (i)
54822e74389SDaniel Scheller 			ddb_input_start(i);
54922e74389SDaniel Scheller 	}
55022e74389SDaniel Scheller 	ddb_input_start(input);
55122e74389SDaniel Scheller 	mutex_unlock(&redirect_lock);
55222e74389SDaniel Scheller }
55322e74389SDaniel Scheller 
ddb_input_stop_all(struct ddb_input * input)55422e74389SDaniel Scheller static void ddb_input_stop_all(struct ddb_input *input)
55522e74389SDaniel Scheller {
55622e74389SDaniel Scheller 	struct ddb_input *i = input;
55722e74389SDaniel Scheller 	struct ddb_output *o;
55822e74389SDaniel Scheller 
55922e74389SDaniel Scheller 	mutex_lock(&redirect_lock);
56022e74389SDaniel Scheller 	ddb_input_stop(input);
56122e74389SDaniel Scheller 	while (i && (o = i->redo)) {
56222e74389SDaniel Scheller 		ddb_output_stop(o);
56322e74389SDaniel Scheller 		i = o->port->input[0];
56422e74389SDaniel Scheller 		if (i)
56522e74389SDaniel Scheller 			ddb_input_stop(i);
56622e74389SDaniel Scheller 	}
56722e74389SDaniel Scheller 	mutex_unlock(&redirect_lock);
568335bb883SDaniel Scheller }
569335bb883SDaniel Scheller 
ddb_output_free(struct ddb_output * output)57025aee3deSMauro Carvalho Chehab static u32 ddb_output_free(struct ddb_output *output)
57125aee3deSMauro Carvalho Chehab {
57222e74389SDaniel Scheller 	u32 idx, off, stat = output->dma->stat;
57325aee3deSMauro Carvalho Chehab 	s32 diff;
57425aee3deSMauro Carvalho Chehab 
57525aee3deSMauro Carvalho Chehab 	idx = (stat >> 11) & 0x1f;
57625aee3deSMauro Carvalho Chehab 	off = (stat & 0x7ff) << 7;
57725aee3deSMauro Carvalho Chehab 
57822e74389SDaniel Scheller 	if (output->dma->cbuf != idx) {
57922e74389SDaniel Scheller 		if ((((output->dma->cbuf + 1) % output->dma->num) == idx) &&
58028473a19SDaniel Scheller 		    (output->dma->size - output->dma->coff <= (2 * 188)))
58125aee3deSMauro Carvalho Chehab 			return 0;
58225aee3deSMauro Carvalho Chehab 		return 188;
58325aee3deSMauro Carvalho Chehab 	}
58422e74389SDaniel Scheller 	diff = off - output->dma->coff;
58528473a19SDaniel Scheller 	if (diff <= 0 || diff > (2 * 188))
58625aee3deSMauro Carvalho Chehab 		return 188;
58725aee3deSMauro Carvalho Chehab 	return 0;
58825aee3deSMauro Carvalho Chehab }
58925aee3deSMauro Carvalho Chehab 
ddb_output_write(struct ddb_output * output,const __user u8 * buf,size_t count)59025aee3deSMauro Carvalho Chehab static ssize_t ddb_output_write(struct ddb_output *output,
591b5c00cc5SHans Verkuil 				const __user u8 *buf, size_t count)
59225aee3deSMauro Carvalho Chehab {
59325aee3deSMauro Carvalho Chehab 	struct ddb *dev = output->port->dev;
59422e74389SDaniel Scheller 	u32 idx, off, stat = output->dma->stat;
59525aee3deSMauro Carvalho Chehab 	u32 left = count, len;
59625aee3deSMauro Carvalho Chehab 
59725aee3deSMauro Carvalho Chehab 	idx = (stat >> 11) & 0x1f;
59825aee3deSMauro Carvalho Chehab 	off = (stat & 0x7ff) << 7;
59925aee3deSMauro Carvalho Chehab 
60025aee3deSMauro Carvalho Chehab 	while (left) {
60122e74389SDaniel Scheller 		len = output->dma->size - output->dma->coff;
60222e74389SDaniel Scheller 		if ((((output->dma->cbuf + 1) % output->dma->num) == idx) &&
603757d78d3SDaniel Scheller 		    off == 0) {
60425aee3deSMauro Carvalho Chehab 			if (len <= 188)
60525aee3deSMauro Carvalho Chehab 				break;
60625aee3deSMauro Carvalho Chehab 			len -= 188;
60725aee3deSMauro Carvalho Chehab 		}
60822e74389SDaniel Scheller 		if (output->dma->cbuf == idx) {
60922e74389SDaniel Scheller 			if (off > output->dma->coff) {
61022e74389SDaniel Scheller 				len = off - output->dma->coff;
61125aee3deSMauro Carvalho Chehab 				len -= (len % 188);
61225aee3deSMauro Carvalho Chehab 				if (len <= 188)
61325aee3deSMauro Carvalho Chehab 					break;
61425aee3deSMauro Carvalho Chehab 				len -= 188;
61525aee3deSMauro Carvalho Chehab 			}
61625aee3deSMauro Carvalho Chehab 		}
61725aee3deSMauro Carvalho Chehab 		if (len > left)
61825aee3deSMauro Carvalho Chehab 			len = left;
61922e74389SDaniel Scheller 		if (copy_from_user(output->dma->vbuf[output->dma->cbuf] +
62022e74389SDaniel Scheller 				   output->dma->coff,
62125aee3deSMauro Carvalho Chehab 				   buf, len))
62225aee3deSMauro Carvalho Chehab 			return -EIO;
62322e74389SDaniel Scheller 		if (alt_dma)
624757d78d3SDaniel Scheller 			dma_sync_single_for_device(
625757d78d3SDaniel Scheller 				dev->dev,
62622e74389SDaniel Scheller 				output->dma->pbuf[output->dma->cbuf],
62722e74389SDaniel Scheller 				output->dma->size, DMA_TO_DEVICE);
62825aee3deSMauro Carvalho Chehab 		left -= len;
62925aee3deSMauro Carvalho Chehab 		buf += len;
63022e74389SDaniel Scheller 		output->dma->coff += len;
63122e74389SDaniel Scheller 		if (output->dma->coff == output->dma->size) {
63222e74389SDaniel Scheller 			output->dma->coff = 0;
63322e74389SDaniel Scheller 			output->dma->cbuf = ((output->dma->cbuf + 1) %
63422e74389SDaniel Scheller 					     output->dma->num);
63525aee3deSMauro Carvalho Chehab 		}
63622e74389SDaniel Scheller 		ddbwritel(dev,
63722e74389SDaniel Scheller 			  (output->dma->cbuf << 11) |
63822e74389SDaniel Scheller 			  (output->dma->coff >> 7),
63922e74389SDaniel Scheller 			  DMA_BUFFER_ACK(output->dma));
64025aee3deSMauro Carvalho Chehab 	}
64125aee3deSMauro Carvalho Chehab 	return count - left;
64225aee3deSMauro Carvalho Chehab }
64325aee3deSMauro Carvalho Chehab 
ddb_input_avail(struct ddb_input * input)64425aee3deSMauro Carvalho Chehab static u32 ddb_input_avail(struct ddb_input *input)
64525aee3deSMauro Carvalho Chehab {
64625aee3deSMauro Carvalho Chehab 	struct ddb *dev = input->port->dev;
64722e74389SDaniel Scheller 	u32 idx, off, stat = input->dma->stat;
64822e74389SDaniel Scheller 	u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma));
64925aee3deSMauro Carvalho Chehab 
65025aee3deSMauro Carvalho Chehab 	idx = (stat >> 11) & 0x1f;
65125aee3deSMauro Carvalho Chehab 	off = (stat & 0x7ff) << 7;
65225aee3deSMauro Carvalho Chehab 
65325aee3deSMauro Carvalho Chehab 	if (ctrl & 4) {
65422e74389SDaniel Scheller 		dev_err(dev->dev, "IA %d %d %08x\n", idx, off, ctrl);
65522e74389SDaniel Scheller 		ddbwritel(dev, stat, DMA_BUFFER_ACK(input->dma));
65625aee3deSMauro Carvalho Chehab 		return 0;
65725aee3deSMauro Carvalho Chehab 	}
65822e74389SDaniel Scheller 	if (input->dma->cbuf != idx)
65925aee3deSMauro Carvalho Chehab 		return 188;
66025aee3deSMauro Carvalho Chehab 	return 0;
66125aee3deSMauro Carvalho Chehab }
66225aee3deSMauro Carvalho Chehab 
ddb_input_read(struct ddb_input * input,__user u8 * buf,size_t count)66322e74389SDaniel Scheller static ssize_t ddb_input_read(struct ddb_input *input,
66422e74389SDaniel Scheller 			      __user u8 *buf, size_t count)
66525aee3deSMauro Carvalho Chehab {
66625aee3deSMauro Carvalho Chehab 	struct ddb *dev = input->port->dev;
66725aee3deSMauro Carvalho Chehab 	u32 left = count;
66822e74389SDaniel Scheller 	u32 idx, free, stat = input->dma->stat;
66925aee3deSMauro Carvalho Chehab 	int ret;
67025aee3deSMauro Carvalho Chehab 
67125aee3deSMauro Carvalho Chehab 	idx = (stat >> 11) & 0x1f;
67225aee3deSMauro Carvalho Chehab 
67325aee3deSMauro Carvalho Chehab 	while (left) {
67422e74389SDaniel Scheller 		if (input->dma->cbuf == idx)
67525aee3deSMauro Carvalho Chehab 			return count - left;
67622e74389SDaniel Scheller 		free = input->dma->size - input->dma->coff;
67725aee3deSMauro Carvalho Chehab 		if (free > left)
67825aee3deSMauro Carvalho Chehab 			free = left;
67922e74389SDaniel Scheller 		if (alt_dma)
680757d78d3SDaniel Scheller 			dma_sync_single_for_cpu(
681757d78d3SDaniel Scheller 				dev->dev,
68222e74389SDaniel Scheller 				input->dma->pbuf[input->dma->cbuf],
68322e74389SDaniel Scheller 				input->dma->size, DMA_FROM_DEVICE);
68422e74389SDaniel Scheller 		ret = copy_to_user(buf, input->dma->vbuf[input->dma->cbuf] +
68522e74389SDaniel Scheller 				   input->dma->coff, free);
68625aee3deSMauro Carvalho Chehab 		if (ret)
68725aee3deSMauro Carvalho Chehab 			return -EFAULT;
68822e74389SDaniel Scheller 		input->dma->coff += free;
68922e74389SDaniel Scheller 		if (input->dma->coff == input->dma->size) {
69022e74389SDaniel Scheller 			input->dma->coff = 0;
69122e74389SDaniel Scheller 			input->dma->cbuf = (input->dma->cbuf + 1) %
69222e74389SDaniel Scheller 				input->dma->num;
69325aee3deSMauro Carvalho Chehab 		}
69425aee3deSMauro Carvalho Chehab 		left -= free;
69522e74389SDaniel Scheller 		buf += free;
69622e74389SDaniel Scheller 		ddbwritel(dev,
69722e74389SDaniel Scheller 			  (input->dma->cbuf << 11) | (input->dma->coff >> 7),
69822e74389SDaniel Scheller 			  DMA_BUFFER_ACK(input->dma));
69925aee3deSMauro Carvalho Chehab 	}
70025aee3deSMauro Carvalho Chehab 	return count;
70125aee3deSMauro Carvalho Chehab }
70225aee3deSMauro Carvalho Chehab 
703335bb883SDaniel Scheller /****************************************************************************/
704335bb883SDaniel Scheller /****************************************************************************/
705335bb883SDaniel Scheller 
ts_write(struct file * file,const __user char * buf,size_t count,loff_t * ppos)706335bb883SDaniel Scheller static ssize_t ts_write(struct file *file, const __user char *buf,
707335bb883SDaniel Scheller 			size_t count, loff_t *ppos)
708335bb883SDaniel Scheller {
709335bb883SDaniel Scheller 	struct dvb_device *dvbdev = file->private_data;
710335bb883SDaniel Scheller 	struct ddb_output *output = dvbdev->priv;
71122e74389SDaniel Scheller 	struct ddb *dev = output->port->dev;
712335bb883SDaniel Scheller 	size_t left = count;
713335bb883SDaniel Scheller 	int stat;
714335bb883SDaniel Scheller 
71522e74389SDaniel Scheller 	if (!dev->has_dma)
71622e74389SDaniel Scheller 		return -EINVAL;
717335bb883SDaniel Scheller 	while (left) {
718335bb883SDaniel Scheller 		if (ddb_output_free(output) < 188) {
719335bb883SDaniel Scheller 			if (file->f_flags & O_NONBLOCK)
720335bb883SDaniel Scheller 				break;
721335bb883SDaniel Scheller 			if (wait_event_interruptible(
72222e74389SDaniel Scheller 				    output->dma->wq,
72322e74389SDaniel Scheller 				    ddb_output_free(output) >= 188) < 0)
724335bb883SDaniel Scheller 				break;
725335bb883SDaniel Scheller 		}
726335bb883SDaniel Scheller 		stat = ddb_output_write(output, buf, left);
727335bb883SDaniel Scheller 		if (stat < 0)
72822e74389SDaniel Scheller 			return stat;
729335bb883SDaniel Scheller 		buf += stat;
730335bb883SDaniel Scheller 		left -= stat;
731335bb883SDaniel Scheller 	}
732335bb883SDaniel Scheller 	return (left == count) ? -EAGAIN : (count - left);
733335bb883SDaniel Scheller }
734335bb883SDaniel Scheller 
ts_read(struct file * file,__user char * buf,size_t count,loff_t * ppos)735335bb883SDaniel Scheller static ssize_t ts_read(struct file *file, __user char *buf,
736335bb883SDaniel Scheller 		       size_t count, loff_t *ppos)
737335bb883SDaniel Scheller {
738335bb883SDaniel Scheller 	struct dvb_device *dvbdev = file->private_data;
739335bb883SDaniel Scheller 	struct ddb_output *output = dvbdev->priv;
740335bb883SDaniel Scheller 	struct ddb_input *input = output->port->input[0];
74122e74389SDaniel Scheller 	struct ddb *dev = output->port->dev;
74222e74389SDaniel Scheller 	size_t left = count;
74322e74389SDaniel Scheller 	int stat;
744335bb883SDaniel Scheller 
74522e74389SDaniel Scheller 	if (!dev->has_dma)
74622e74389SDaniel Scheller 		return -EINVAL;
747335bb883SDaniel Scheller 	while (left) {
748335bb883SDaniel Scheller 		if (ddb_input_avail(input) < 188) {
749335bb883SDaniel Scheller 			if (file->f_flags & O_NONBLOCK)
750335bb883SDaniel Scheller 				break;
751335bb883SDaniel Scheller 			if (wait_event_interruptible(
75222e74389SDaniel Scheller 				    input->dma->wq,
75322e74389SDaniel Scheller 				    ddb_input_avail(input) >= 188) < 0)
754335bb883SDaniel Scheller 				break;
755335bb883SDaniel Scheller 		}
75622e74389SDaniel Scheller 		stat = ddb_input_read(input, buf, left);
75722e74389SDaniel Scheller 		if (stat < 0)
75822e74389SDaniel Scheller 			return stat;
75922e74389SDaniel Scheller 		left -= stat;
76022e74389SDaniel Scheller 		buf += stat;
761335bb883SDaniel Scheller 	}
76222e74389SDaniel Scheller 	return (count && (left == count)) ? -EAGAIN : (count - left);
763335bb883SDaniel Scheller }
764335bb883SDaniel Scheller 
ts_poll(struct file * file,poll_table * wait)765c23e0cb8SAl Viro static __poll_t ts_poll(struct file *file, poll_table *wait)
766335bb883SDaniel Scheller {
767335bb883SDaniel Scheller 	struct dvb_device *dvbdev = file->private_data;
768335bb883SDaniel Scheller 	struct ddb_output *output = dvbdev->priv;
769335bb883SDaniel Scheller 	struct ddb_input *input = output->port->input[0];
77022e74389SDaniel Scheller 
771c23e0cb8SAl Viro 	__poll_t mask = 0;
772335bb883SDaniel Scheller 
77322e74389SDaniel Scheller 	poll_wait(file, &input->dma->wq, wait);
77422e74389SDaniel Scheller 	poll_wait(file, &output->dma->wq, wait);
77522e74389SDaniel Scheller 	if (ddb_input_avail(input) >= 188)
776a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
77722e74389SDaniel Scheller 	if (ddb_output_free(output) >= 188)
778a9a08845SLinus Torvalds 		mask |= EPOLLOUT | EPOLLWRNORM;
779335bb883SDaniel Scheller 	return mask;
780335bb883SDaniel Scheller }
781335bb883SDaniel Scheller 
ts_release(struct inode * inode,struct file * file)78222e74389SDaniel Scheller static int ts_release(struct inode *inode, struct file *file)
78322e74389SDaniel Scheller {
78422e74389SDaniel Scheller 	struct dvb_device *dvbdev = file->private_data;
785fc3fb43eSDaniel Scheller 	struct ddb_output *output = NULL;
786fc3fb43eSDaniel Scheller 	struct ddb_input *input = NULL;
787fc3fb43eSDaniel Scheller 
788fc3fb43eSDaniel Scheller 	if (dvbdev) {
789fc3fb43eSDaniel Scheller 		output = dvbdev->priv;
790fc3fb43eSDaniel Scheller 		input = output->port->input[0];
791fc3fb43eSDaniel Scheller 	}
79222e74389SDaniel Scheller 
79322e74389SDaniel Scheller 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
79422e74389SDaniel Scheller 		if (!input)
79522e74389SDaniel Scheller 			return -EINVAL;
79622e74389SDaniel Scheller 		ddb_input_stop(input);
79722e74389SDaniel Scheller 	} else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
79822e74389SDaniel Scheller 		if (!output)
79922e74389SDaniel Scheller 			return -EINVAL;
80022e74389SDaniel Scheller 		ddb_output_stop(output);
80122e74389SDaniel Scheller 	}
80222e74389SDaniel Scheller 	return dvb_generic_release(inode, file);
80322e74389SDaniel Scheller }
80422e74389SDaniel Scheller 
ts_open(struct inode * inode,struct file * file)80522e74389SDaniel Scheller static int ts_open(struct inode *inode, struct file *file)
80622e74389SDaniel Scheller {
80722e74389SDaniel Scheller 	int err;
80822e74389SDaniel Scheller 	struct dvb_device *dvbdev = file->private_data;
809fc3fb43eSDaniel Scheller 	struct ddb_output *output = NULL;
810fc3fb43eSDaniel Scheller 	struct ddb_input *input = NULL;
811fc3fb43eSDaniel Scheller 
812fc3fb43eSDaniel Scheller 	if (dvbdev) {
813fc3fb43eSDaniel Scheller 		output = dvbdev->priv;
814fc3fb43eSDaniel Scheller 		input = output->port->input[0];
815fc3fb43eSDaniel Scheller 	}
81622e74389SDaniel Scheller 
81722e74389SDaniel Scheller 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
81822e74389SDaniel Scheller 		if (!input)
81922e74389SDaniel Scheller 			return -EINVAL;
82022e74389SDaniel Scheller 		if (input->redo || input->redi)
82122e74389SDaniel Scheller 			return -EBUSY;
82222e74389SDaniel Scheller 	} else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
82322e74389SDaniel Scheller 		if (!output)
82422e74389SDaniel Scheller 			return -EINVAL;
825757d78d3SDaniel Scheller 	} else {
82622e74389SDaniel Scheller 		return -EINVAL;
827757d78d3SDaniel Scheller 	}
828757d78d3SDaniel Scheller 
82922e74389SDaniel Scheller 	err = dvb_generic_open(inode, file);
83022e74389SDaniel Scheller 	if (err < 0)
83122e74389SDaniel Scheller 		return err;
83222e74389SDaniel Scheller 	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
83322e74389SDaniel Scheller 		ddb_input_start(input);
83422e74389SDaniel Scheller 	else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
83522e74389SDaniel Scheller 		ddb_output_start(output);
83622e74389SDaniel Scheller 	return err;
83722e74389SDaniel Scheller }
83822e74389SDaniel Scheller 
839335bb883SDaniel Scheller static const struct file_operations ci_fops = {
840335bb883SDaniel Scheller 	.owner   = THIS_MODULE,
841335bb883SDaniel Scheller 	.read    = ts_read,
842335bb883SDaniel Scheller 	.write   = ts_write,
84322e74389SDaniel Scheller 	.open    = ts_open,
84422e74389SDaniel Scheller 	.release = ts_release,
845335bb883SDaniel Scheller 	.poll    = ts_poll,
846b5967860SDaniel Scheller 	.mmap    = NULL,
847335bb883SDaniel Scheller };
848335bb883SDaniel Scheller 
849335bb883SDaniel Scheller static struct dvb_device dvbdev_ci = {
850b5967860SDaniel Scheller 	.priv    = NULL,
85122e74389SDaniel Scheller 	.readers = 1,
85222e74389SDaniel Scheller 	.writers = 1,
85322e74389SDaniel Scheller 	.users   = 2,
854335bb883SDaniel Scheller 	.fops    = &ci_fops,
855335bb883SDaniel Scheller };
856335bb883SDaniel Scheller 
85722e74389SDaniel Scheller /****************************************************************************/
85822e74389SDaniel Scheller /****************************************************************************/
85925aee3deSMauro Carvalho Chehab 
locked_gate_ctrl(struct dvb_frontend * fe,int enable)86022e74389SDaniel Scheller static int locked_gate_ctrl(struct dvb_frontend *fe, int enable)
86125aee3deSMauro Carvalho Chehab {
86225aee3deSMauro Carvalho Chehab 	struct ddb_input *input = fe->sec_priv;
86325aee3deSMauro Carvalho Chehab 	struct ddb_port *port = input->port;
86422e74389SDaniel Scheller 	struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
86525aee3deSMauro Carvalho Chehab 	int status;
86625aee3deSMauro Carvalho Chehab 
86725aee3deSMauro Carvalho Chehab 	if (enable) {
86825aee3deSMauro Carvalho Chehab 		mutex_lock(&port->i2c_gate_lock);
86922e74389SDaniel Scheller 		status = dvb->i2c_gate_ctrl(fe, 1);
87025aee3deSMauro Carvalho Chehab 	} else {
87122e74389SDaniel Scheller 		status = dvb->i2c_gate_ctrl(fe, 0);
87225aee3deSMauro Carvalho Chehab 		mutex_unlock(&port->i2c_gate_lock);
87325aee3deSMauro Carvalho Chehab 	}
87425aee3deSMauro Carvalho Chehab 	return status;
87525aee3deSMauro Carvalho Chehab }
87625aee3deSMauro Carvalho Chehab 
demod_attach_drxk(struct ddb_input * input)87725aee3deSMauro Carvalho Chehab static int demod_attach_drxk(struct ddb_input *input)
87825aee3deSMauro Carvalho Chehab {
87925aee3deSMauro Carvalho Chehab 	struct i2c_adapter *i2c = &input->port->i2c->adap;
88022e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
88122e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
88225aee3deSMauro Carvalho Chehab 	struct drxk_config config;
88325aee3deSMauro Carvalho Chehab 
88425aee3deSMauro Carvalho Chehab 	memset(&config, 0, sizeof(config));
88525aee3deSMauro Carvalho Chehab 	config.adr = 0x29 + (input->nr & 1);
88622e74389SDaniel Scheller 	config.microcode_name = "drxk_a3.mc";
88725aee3deSMauro Carvalho Chehab 
8881d8343aaSDaniel Scheller 	dvb->fe = dvb_attach(drxk_attach, &config, i2c);
8891d8343aaSDaniel Scheller 	if (!dvb->fe) {
89011e358bfSDaniel Scheller 		dev_err(dev, "No DRXK found!\n");
89125aee3deSMauro Carvalho Chehab 		return -ENODEV;
89225aee3deSMauro Carvalho Chehab 	}
8931d8343aaSDaniel Scheller 	dvb->fe->sec_priv = input;
8941d8343aaSDaniel Scheller 	dvb->i2c_gate_ctrl = dvb->fe->ops.i2c_gate_ctrl;
8951d8343aaSDaniel Scheller 	dvb->fe->ops.i2c_gate_ctrl = locked_gate_ctrl;
89625aee3deSMauro Carvalho Chehab 	return 0;
89725aee3deSMauro Carvalho Chehab }
89825aee3deSMauro Carvalho Chehab 
tuner_attach_tda18271(struct ddb_input * input)89925aee3deSMauro Carvalho Chehab static int tuner_attach_tda18271(struct ddb_input *input)
90025aee3deSMauro Carvalho Chehab {
90125aee3deSMauro Carvalho Chehab 	struct i2c_adapter *i2c = &input->port->i2c->adap;
90222e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
90322e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
90425aee3deSMauro Carvalho Chehab 	struct dvb_frontend *fe;
90525aee3deSMauro Carvalho Chehab 
90622e74389SDaniel Scheller 	if (dvb->fe->ops.i2c_gate_ctrl)
90722e74389SDaniel Scheller 		dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 1);
90822e74389SDaniel Scheller 	fe = dvb_attach(tda18271c2dd_attach, dvb->fe, i2c, 0x60);
90922e74389SDaniel Scheller 	if (dvb->fe->ops.i2c_gate_ctrl)
91022e74389SDaniel Scheller 		dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 0);
91125aee3deSMauro Carvalho Chehab 	if (!fe) {
91211e358bfSDaniel Scheller 		dev_err(dev, "No TDA18271 found!\n");
91325aee3deSMauro Carvalho Chehab 		return -ENODEV;
91425aee3deSMauro Carvalho Chehab 	}
91525aee3deSMauro Carvalho Chehab 	return 0;
91625aee3deSMauro Carvalho Chehab }
91725aee3deSMauro Carvalho Chehab 
91825aee3deSMauro Carvalho Chehab /******************************************************************************/
91925aee3deSMauro Carvalho Chehab /******************************************************************************/
92025aee3deSMauro Carvalho Chehab /******************************************************************************/
92125aee3deSMauro Carvalho Chehab 
92205da9437SDaniel Scheller static struct stv0367_config ddb_stv0367_config[] = {
92305da9437SDaniel Scheller 	{
92405da9437SDaniel Scheller 		.demod_address = 0x1f,
92505da9437SDaniel Scheller 		.xtal = 27000000,
92605da9437SDaniel Scheller 		.if_khz = 0,
92705da9437SDaniel Scheller 		.if_iq_mode = FE_TER_NORMAL_IF_TUNER,
92805da9437SDaniel Scheller 		.ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
92905da9437SDaniel Scheller 		.clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
93005da9437SDaniel Scheller 	}, {
93105da9437SDaniel Scheller 		.demod_address = 0x1e,
93205da9437SDaniel Scheller 		.xtal = 27000000,
93305da9437SDaniel Scheller 		.if_khz = 0,
93405da9437SDaniel Scheller 		.if_iq_mode = FE_TER_NORMAL_IF_TUNER,
93505da9437SDaniel Scheller 		.ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
93605da9437SDaniel Scheller 		.clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
93705da9437SDaniel Scheller 	},
93805da9437SDaniel Scheller };
93905da9437SDaniel Scheller 
demod_attach_stv0367(struct ddb_input * input)94005da9437SDaniel Scheller static int demod_attach_stv0367(struct ddb_input *input)
94105da9437SDaniel Scheller {
94205da9437SDaniel Scheller 	struct i2c_adapter *i2c = &input->port->i2c->adap;
94322e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
94422e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
94505da9437SDaniel Scheller 
94605da9437SDaniel Scheller 	/* attach frontend */
9471d8343aaSDaniel Scheller 	dvb->fe = dvb_attach(stv0367ddb_attach,
94805da9437SDaniel Scheller 			     &ddb_stv0367_config[(input->nr & 1)], i2c);
94905da9437SDaniel Scheller 
95022e74389SDaniel Scheller 	if (!dvb->fe) {
95122e74389SDaniel Scheller 		dev_err(dev, "No stv0367 found!\n");
95205da9437SDaniel Scheller 		return -ENODEV;
95305da9437SDaniel Scheller 	}
9541d8343aaSDaniel Scheller 	dvb->fe->sec_priv = input;
9551d8343aaSDaniel Scheller 	dvb->i2c_gate_ctrl = dvb->fe->ops.i2c_gate_ctrl;
9561d8343aaSDaniel Scheller 	dvb->fe->ops.i2c_gate_ctrl = locked_gate_ctrl;
95705da9437SDaniel Scheller 	return 0;
95805da9437SDaniel Scheller }
95905da9437SDaniel Scheller 
tuner_tda18212_ping(struct ddb_input * input,unsigned short adr)96005da9437SDaniel Scheller static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr)
96105da9437SDaniel Scheller {
96205da9437SDaniel Scheller 	struct i2c_adapter *adapter = &input->port->i2c->adap;
96322e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
96422e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
96505da9437SDaniel Scheller 	u8 tda_id[2];
96605da9437SDaniel Scheller 	u8 subaddr = 0x00;
96705da9437SDaniel Scheller 
96811e358bfSDaniel Scheller 	dev_dbg(dev, "stv0367-tda18212 tuner ping\n");
96922e74389SDaniel Scheller 	if (dvb->fe->ops.i2c_gate_ctrl)
97022e74389SDaniel Scheller 		dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 1);
97105da9437SDaniel Scheller 
97205da9437SDaniel Scheller 	if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
97311e358bfSDaniel Scheller 		dev_dbg(dev, "tda18212 ping 1 fail\n");
97405da9437SDaniel Scheller 	if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
97511e358bfSDaniel Scheller 		dev_warn(dev, "tda18212 ping failed, expect problems\n");
97605da9437SDaniel Scheller 
97722e74389SDaniel Scheller 	if (dvb->fe->ops.i2c_gate_ctrl)
97822e74389SDaniel Scheller 		dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 0);
97905da9437SDaniel Scheller 
98005da9437SDaniel Scheller 	return 0;
98105da9437SDaniel Scheller }
98205da9437SDaniel Scheller 
demod_attach_cxd28xx(struct ddb_input * input,int par,int osc24)98369e1749cSDaniel Scheller static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24)
98469e1749cSDaniel Scheller {
98569e1749cSDaniel Scheller 	struct i2c_adapter *i2c = &input->port->i2c->adap;
98622e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
98722e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
98869e1749cSDaniel Scheller 	struct cxd2841er_config cfg;
98969e1749cSDaniel Scheller 
99069e1749cSDaniel Scheller 	/* the cxd2841er driver expects 8bit/shifted I2C addresses */
99169e1749cSDaniel Scheller 	cfg.i2c_addr = ((input->nr & 1) ? 0x6d : 0x6c) << 1;
99269e1749cSDaniel Scheller 
99369e1749cSDaniel Scheller 	cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500;
99469e1749cSDaniel Scheller 	cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE |
99569e1749cSDaniel Scheller 		CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG |
99669e1749cSDaniel Scheller 		CXD2841ER_TSBITS;
99769e1749cSDaniel Scheller 
99869e1749cSDaniel Scheller 	if (!par)
99969e1749cSDaniel Scheller 		cfg.flags |= CXD2841ER_TS_SERIAL;
100069e1749cSDaniel Scheller 
100169e1749cSDaniel Scheller 	/* attach frontend */
10021d8343aaSDaniel Scheller 	dvb->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c);
100369e1749cSDaniel Scheller 
100422e74389SDaniel Scheller 	if (!dvb->fe) {
100522e74389SDaniel Scheller 		dev_err(dev, "No cxd2837/38/43/54 found!\n");
100669e1749cSDaniel Scheller 		return -ENODEV;
100769e1749cSDaniel Scheller 	}
10081d8343aaSDaniel Scheller 	dvb->fe->sec_priv = input;
10091d8343aaSDaniel Scheller 	dvb->i2c_gate_ctrl = dvb->fe->ops.i2c_gate_ctrl;
10101d8343aaSDaniel Scheller 	dvb->fe->ops.i2c_gate_ctrl = locked_gate_ctrl;
101169e1749cSDaniel Scheller 	return 0;
101269e1749cSDaniel Scheller }
101369e1749cSDaniel Scheller 
tuner_attach_tda18212(struct ddb_input * input,u32 porttype)101405da9437SDaniel Scheller static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype)
101505da9437SDaniel Scheller {
101605da9437SDaniel Scheller 	struct i2c_adapter *adapter = &input->port->i2c->adap;
101722e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
101822e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
101905da9437SDaniel Scheller 	struct i2c_client *client;
102005da9437SDaniel Scheller 	struct tda18212_config config = {
102122e74389SDaniel Scheller 		.fe = dvb->fe,
102205da9437SDaniel Scheller 		.if_dvbt_6 = 3550,
102305da9437SDaniel Scheller 		.if_dvbt_7 = 3700,
102405da9437SDaniel Scheller 		.if_dvbt_8 = 4150,
102505da9437SDaniel Scheller 		.if_dvbt2_6 = 3250,
102605da9437SDaniel Scheller 		.if_dvbt2_7 = 4000,
102705da9437SDaniel Scheller 		.if_dvbt2_8 = 4000,
102805da9437SDaniel Scheller 		.if_dvbc = 5000,
102905da9437SDaniel Scheller 	};
1030c966453bSDaniel Scheller 	u8 addr = (input->nr & 1) ? 0x63 : 0x60;
103105da9437SDaniel Scheller 
103205da9437SDaniel Scheller 	/* due to a hardware quirk with the I2C gate on the stv0367+tda18212
103305da9437SDaniel Scheller 	 * combo, the tda18212 must be probed by reading it's id _twice_ when
103405da9437SDaniel Scheller 	 * cold started, or it very likely will fail.
103505da9437SDaniel Scheller 	 */
103605da9437SDaniel Scheller 	if (porttype == DDB_TUNER_DVBCT_ST)
1037c966453bSDaniel Scheller 		tuner_tda18212_ping(input, addr);
103805da9437SDaniel Scheller 
1039c966453bSDaniel Scheller 	/* perform tuner probe/init/attach */
1040c966453bSDaniel Scheller 	client = dvb_module_probe("tda18212", NULL, adapter, addr, &config);
1041c966453bSDaniel Scheller 	if (!client)
104205da9437SDaniel Scheller 		goto err;
104305da9437SDaniel Scheller 
104422e74389SDaniel Scheller 	dvb->i2c_client[0] = client;
104505da9437SDaniel Scheller 	return 0;
104605da9437SDaniel Scheller err:
104725ac563aSDaniel Scheller 	dev_err(dev, "TDA18212 tuner not found. Device is not fully operational.\n");
104805da9437SDaniel Scheller 	return -ENODEV;
104905da9437SDaniel Scheller }
105005da9437SDaniel Scheller 
105122e74389SDaniel Scheller /****************************************************************************/
105222e74389SDaniel Scheller /****************************************************************************/
105322e74389SDaniel Scheller /****************************************************************************/
105405da9437SDaniel Scheller 
105525aee3deSMauro Carvalho Chehab static struct stv090x_config stv0900 = {
105625aee3deSMauro Carvalho Chehab 	.device         = STV0900,
105725aee3deSMauro Carvalho Chehab 	.demod_mode     = STV090x_DUAL,
105825aee3deSMauro Carvalho Chehab 	.clk_mode       = STV090x_CLK_EXT,
105925aee3deSMauro Carvalho Chehab 
106025aee3deSMauro Carvalho Chehab 	.xtal           = 27000000,
106125aee3deSMauro Carvalho Chehab 	.address        = 0x69,
106225aee3deSMauro Carvalho Chehab 
106325aee3deSMauro Carvalho Chehab 	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
106425aee3deSMauro Carvalho Chehab 	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
106525aee3deSMauro Carvalho Chehab 
106622e74389SDaniel Scheller 	.ts1_tei        = 1,
106722e74389SDaniel Scheller 	.ts2_tei        = 1,
106822e74389SDaniel Scheller 
106925aee3deSMauro Carvalho Chehab 	.repeater_level = STV090x_RPTLEVEL_16,
107025aee3deSMauro Carvalho Chehab 
107125aee3deSMauro Carvalho Chehab 	.adc1_range	= STV090x_ADC_1Vpp,
107225aee3deSMauro Carvalho Chehab 	.adc2_range	= STV090x_ADC_1Vpp,
107325aee3deSMauro Carvalho Chehab 
107425aee3deSMauro Carvalho Chehab 	.diseqc_envelope_mode = true,
107525aee3deSMauro Carvalho Chehab };
107625aee3deSMauro Carvalho Chehab 
107725aee3deSMauro Carvalho Chehab static struct stv090x_config stv0900_aa = {
107825aee3deSMauro Carvalho Chehab 	.device         = STV0900,
107925aee3deSMauro Carvalho Chehab 	.demod_mode     = STV090x_DUAL,
108025aee3deSMauro Carvalho Chehab 	.clk_mode       = STV090x_CLK_EXT,
108125aee3deSMauro Carvalho Chehab 
108225aee3deSMauro Carvalho Chehab 	.xtal           = 27000000,
108325aee3deSMauro Carvalho Chehab 	.address        = 0x68,
108425aee3deSMauro Carvalho Chehab 
108525aee3deSMauro Carvalho Chehab 	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
108625aee3deSMauro Carvalho Chehab 	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
108725aee3deSMauro Carvalho Chehab 
108822e74389SDaniel Scheller 	.ts1_tei        = 1,
108922e74389SDaniel Scheller 	.ts2_tei        = 1,
109022e74389SDaniel Scheller 
109125aee3deSMauro Carvalho Chehab 	.repeater_level = STV090x_RPTLEVEL_16,
109225aee3deSMauro Carvalho Chehab 
109325aee3deSMauro Carvalho Chehab 	.adc1_range	= STV090x_ADC_1Vpp,
109425aee3deSMauro Carvalho Chehab 	.adc2_range	= STV090x_ADC_1Vpp,
109525aee3deSMauro Carvalho Chehab 
109625aee3deSMauro Carvalho Chehab 	.diseqc_envelope_mode = true,
109725aee3deSMauro Carvalho Chehab };
109825aee3deSMauro Carvalho Chehab 
109925aee3deSMauro Carvalho Chehab static struct stv6110x_config stv6110a = {
110025aee3deSMauro Carvalho Chehab 	.addr    = 0x60,
110125aee3deSMauro Carvalho Chehab 	.refclk	 = 27000000,
110225aee3deSMauro Carvalho Chehab 	.clk_div = 1,
110325aee3deSMauro Carvalho Chehab };
110425aee3deSMauro Carvalho Chehab 
110525aee3deSMauro Carvalho Chehab static struct stv6110x_config stv6110b = {
110625aee3deSMauro Carvalho Chehab 	.addr    = 0x63,
110725aee3deSMauro Carvalho Chehab 	.refclk	 = 27000000,
110825aee3deSMauro Carvalho Chehab 	.clk_div = 1,
110925aee3deSMauro Carvalho Chehab };
111025aee3deSMauro Carvalho Chehab 
demod_attach_stv0900(struct ddb_input * input,int type)111125aee3deSMauro Carvalho Chehab static int demod_attach_stv0900(struct ddb_input *input, int type)
111225aee3deSMauro Carvalho Chehab {
111325aee3deSMauro Carvalho Chehab 	struct i2c_adapter *i2c = &input->port->i2c->adap;
111425aee3deSMauro Carvalho Chehab 	struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
111522e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
111622e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
111725aee3deSMauro Carvalho Chehab 
111822e74389SDaniel Scheller 	dvb->fe = dvb_attach(stv090x_attach, feconf, i2c,
111925aee3deSMauro Carvalho Chehab 			     (input->nr & 1) ? STV090x_DEMODULATOR_1
112025aee3deSMauro Carvalho Chehab 			     : STV090x_DEMODULATOR_0);
112122e74389SDaniel Scheller 	if (!dvb->fe) {
112211e358bfSDaniel Scheller 		dev_err(dev, "No STV0900 found!\n");
112325aee3deSMauro Carvalho Chehab 		return -ENODEV;
112425aee3deSMauro Carvalho Chehab 	}
112522e74389SDaniel Scheller 	if (!dvb_attach(lnbh24_attach, dvb->fe, i2c, 0,
112625aee3deSMauro Carvalho Chehab 			0, (input->nr & 1) ?
112725aee3deSMauro Carvalho Chehab 			(0x09 - type) : (0x0b - type))) {
112811e358bfSDaniel Scheller 		dev_err(dev, "No LNBH24 found!\n");
112978e41c16SDaniel Scheller 		dvb_frontend_detach(dvb->fe);
113025aee3deSMauro Carvalho Chehab 		return -ENODEV;
113125aee3deSMauro Carvalho Chehab 	}
113225aee3deSMauro Carvalho Chehab 	return 0;
113325aee3deSMauro Carvalho Chehab }
113425aee3deSMauro Carvalho Chehab 
tuner_attach_stv6110(struct ddb_input * input,int type)113525aee3deSMauro Carvalho Chehab static int tuner_attach_stv6110(struct ddb_input *input, int type)
113625aee3deSMauro Carvalho Chehab {
113725aee3deSMauro Carvalho Chehab 	struct i2c_adapter *i2c = &input->port->i2c->adap;
113822e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
113922e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
114025aee3deSMauro Carvalho Chehab 	struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
114125aee3deSMauro Carvalho Chehab 	struct stv6110x_config *tunerconf = (input->nr & 1) ?
114225aee3deSMauro Carvalho Chehab 		&stv6110b : &stv6110a;
1143242c5033SJulia Lawall 	const struct stv6110x_devctl *ctl;
114425aee3deSMauro Carvalho Chehab 
114522e74389SDaniel Scheller 	ctl = dvb_attach(stv6110x_attach, dvb->fe, tunerconf, i2c);
114625aee3deSMauro Carvalho Chehab 	if (!ctl) {
114711e358bfSDaniel Scheller 		dev_err(dev, "No STV6110X found!\n");
114825aee3deSMauro Carvalho Chehab 		return -ENODEV;
114925aee3deSMauro Carvalho Chehab 	}
115011e358bfSDaniel Scheller 	dev_info(dev, "attach tuner input %d adr %02x\n",
115125aee3deSMauro Carvalho Chehab 		 input->nr, tunerconf->addr);
115225aee3deSMauro Carvalho Chehab 
115325aee3deSMauro Carvalho Chehab 	feconf->tuner_init          = ctl->tuner_init;
115425aee3deSMauro Carvalho Chehab 	feconf->tuner_sleep         = ctl->tuner_sleep;
115525aee3deSMauro Carvalho Chehab 	feconf->tuner_set_mode      = ctl->tuner_set_mode;
115625aee3deSMauro Carvalho Chehab 	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
115725aee3deSMauro Carvalho Chehab 	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
115825aee3deSMauro Carvalho Chehab 	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
115925aee3deSMauro Carvalho Chehab 	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
116025aee3deSMauro Carvalho Chehab 	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
116125aee3deSMauro Carvalho Chehab 	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
116225aee3deSMauro Carvalho Chehab 	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
116325aee3deSMauro Carvalho Chehab 	feconf->tuner_get_status    = ctl->tuner_get_status;
116425aee3deSMauro Carvalho Chehab 
116525aee3deSMauro Carvalho Chehab 	return 0;
116625aee3deSMauro Carvalho Chehab }
116725aee3deSMauro Carvalho Chehab 
1168e6db389dSJulia Lawall static const struct stv0910_cfg stv0910_p = {
1169df3082dfSDaniel Scheller 	.adr      = 0x68,
1170df3082dfSDaniel Scheller 	.parallel = 1,
1171df3082dfSDaniel Scheller 	.rptlvl   = 4,
1172df3082dfSDaniel Scheller 	.clk      = 30000000,
11737069018eSDaniel Scheller 	.tsspeed  = 0x28,
1174df3082dfSDaniel Scheller };
1175df3082dfSDaniel Scheller 
1176e6db389dSJulia Lawall static const struct lnbh25_config lnbh25_cfg = {
1177df3082dfSDaniel Scheller 	.i2c_address = 0x0c << 1,
1178df3082dfSDaniel Scheller 	.data2_config = LNBH25_TEN
1179df3082dfSDaniel Scheller };
1180df3082dfSDaniel Scheller 
has_lnbh25(struct i2c_adapter * i2c,u8 adr)1181d33be432SDaniel Scheller static int has_lnbh25(struct i2c_adapter *i2c, u8 adr)
1182d33be432SDaniel Scheller {
1183d33be432SDaniel Scheller 	u8 val;
1184d33be432SDaniel Scheller 
1185d33be432SDaniel Scheller 	return i2c_read_reg(i2c, adr, 0, &val) ? 0 : 1;
1186d33be432SDaniel Scheller }
1187d33be432SDaniel Scheller 
demod_attach_stv0910(struct ddb_input * input,int type,int tsfast)1188a00031c1SDaniel Scheller static int demod_attach_stv0910(struct ddb_input *input, int type, int tsfast)
1189df3082dfSDaniel Scheller {
1190df3082dfSDaniel Scheller 	struct i2c_adapter *i2c = &input->port->i2c->adap;
119122e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
119222e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
1193df3082dfSDaniel Scheller 	struct stv0910_cfg cfg = stv0910_p;
1194df3082dfSDaniel Scheller 	struct lnbh25_config lnbcfg = lnbh25_cfg;
1195df3082dfSDaniel Scheller 
119679145059SDaniel Scheller 	if (stv0910_single)
119779145059SDaniel Scheller 		cfg.single = 1;
119879145059SDaniel Scheller 
1199df3082dfSDaniel Scheller 	if (type)
1200df3082dfSDaniel Scheller 		cfg.parallel = 2;
1201a00031c1SDaniel Scheller 
1202a00031c1SDaniel Scheller 	if (tsfast) {
1203a00031c1SDaniel Scheller 		dev_info(dev, "Enabling stv0910 higher speed TS\n");
1204a00031c1SDaniel Scheller 		cfg.tsspeed = 0x10;
1205a00031c1SDaniel Scheller 	}
1206a00031c1SDaniel Scheller 
120722e74389SDaniel Scheller 	dvb->fe = dvb_attach(stv0910_attach, i2c, &cfg, (input->nr & 1));
120822e74389SDaniel Scheller 	if (!dvb->fe) {
1209df3082dfSDaniel Scheller 		cfg.adr = 0x6c;
121022e74389SDaniel Scheller 		dvb->fe = dvb_attach(stv0910_attach, i2c,
1211df3082dfSDaniel Scheller 				     &cfg, (input->nr & 1));
1212df3082dfSDaniel Scheller 	}
121322e74389SDaniel Scheller 	if (!dvb->fe) {
1214df3082dfSDaniel Scheller 		dev_err(dev, "No STV0910 found!\n");
1215df3082dfSDaniel Scheller 		return -ENODEV;
1216df3082dfSDaniel Scheller 	}
1217df3082dfSDaniel Scheller 
1218df3082dfSDaniel Scheller 	/* attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit
1219df3082dfSDaniel Scheller 	 * i2c addresses
1220df3082dfSDaniel Scheller 	 */
1221d33be432SDaniel Scheller 	if (has_lnbh25(i2c, 0x0d))
1222df3082dfSDaniel Scheller 		lnbcfg.i2c_address = (((input->nr & 1) ? 0x0d : 0x0c) << 1);
1223d33be432SDaniel Scheller 	else
1224df3082dfSDaniel Scheller 		lnbcfg.i2c_address = (((input->nr & 1) ? 0x09 : 0x08) << 1);
1225d33be432SDaniel Scheller 
122622e74389SDaniel Scheller 	if (!dvb_attach(lnbh25_attach, dvb->fe, &lnbcfg, i2c)) {
1227df3082dfSDaniel Scheller 		dev_err(dev, "No LNBH25 found!\n");
122878e41c16SDaniel Scheller 		dvb_frontend_detach(dvb->fe);
1229df3082dfSDaniel Scheller 		return -ENODEV;
1230df3082dfSDaniel Scheller 	}
1231df3082dfSDaniel Scheller 
1232df3082dfSDaniel Scheller 	return 0;
1233df3082dfSDaniel Scheller }
1234df3082dfSDaniel Scheller 
tuner_attach_stv6111(struct ddb_input * input,int type)1235df3082dfSDaniel Scheller static int tuner_attach_stv6111(struct ddb_input *input, int type)
1236df3082dfSDaniel Scheller {
1237df3082dfSDaniel Scheller 	struct i2c_adapter *i2c = &input->port->i2c->adap;
123822e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
123922e74389SDaniel Scheller 	struct device *dev = input->port->dev->dev;
1240df3082dfSDaniel Scheller 	struct dvb_frontend *fe;
1241df3082dfSDaniel Scheller 	u8 adr = (type ? 0 : 4) + ((input->nr & 1) ? 0x63 : 0x60);
1242df3082dfSDaniel Scheller 
124322e74389SDaniel Scheller 	fe = dvb_attach(stv6111_attach, dvb->fe, i2c, adr);
1244df3082dfSDaniel Scheller 	if (!fe) {
124522e74389SDaniel Scheller 		fe = dvb_attach(stv6111_attach, dvb->fe, i2c, adr & ~4);
1246df3082dfSDaniel Scheller 		if (!fe) {
1247df3082dfSDaniel Scheller 			dev_err(dev, "No STV6111 found at 0x%02x!\n", adr);
1248df3082dfSDaniel Scheller 			return -ENODEV;
1249df3082dfSDaniel Scheller 		}
1250df3082dfSDaniel Scheller 	}
1251df3082dfSDaniel Scheller 	return 0;
1252df3082dfSDaniel Scheller }
1253df3082dfSDaniel Scheller 
demod_attach_dummy(struct ddb_input * input)1254ab12397fSDaniel Scheller static int demod_attach_dummy(struct ddb_input *input)
1255ab12397fSDaniel Scheller {
1256ab12397fSDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
1257ab12397fSDaniel Scheller 	struct device *dev = input->port->dev->dev;
1258ab12397fSDaniel Scheller 
12599a33a27eSMauro Carvalho Chehab 	dvb->fe = dvb_attach(ddbridge_dummy_fe_qam_attach);
1260ab12397fSDaniel Scheller 	if (!dvb->fe) {
1261ab12397fSDaniel Scheller 		dev_err(dev, "QAM dummy attach failed!\n");
1262ab12397fSDaniel Scheller 		return -ENODEV;
1263ab12397fSDaniel Scheller 	}
1264ab12397fSDaniel Scheller 
1265ab12397fSDaniel Scheller 	return 0;
1266ab12397fSDaniel Scheller }
1267ab12397fSDaniel Scheller 
start_feed(struct dvb_demux_feed * dvbdmxfeed)126825aee3deSMauro Carvalho Chehab static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
126925aee3deSMauro Carvalho Chehab {
127025aee3deSMauro Carvalho Chehab 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
127125aee3deSMauro Carvalho Chehab 	struct ddb_input *input = dvbdmx->priv;
127222e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
127325aee3deSMauro Carvalho Chehab 
127422e74389SDaniel Scheller 	if (!dvb->users)
127522e74389SDaniel Scheller 		ddb_input_start_all(input);
127625aee3deSMauro Carvalho Chehab 
127722e74389SDaniel Scheller 	return ++dvb->users;
127825aee3deSMauro Carvalho Chehab }
127925aee3deSMauro Carvalho Chehab 
stop_feed(struct dvb_demux_feed * dvbdmxfeed)128025aee3deSMauro Carvalho Chehab static int stop_feed(struct dvb_demux_feed *dvbdmxfeed)
128125aee3deSMauro Carvalho Chehab {
128225aee3deSMauro Carvalho Chehab 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
128325aee3deSMauro Carvalho Chehab 	struct ddb_input *input = dvbdmx->priv;
128422e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
128525aee3deSMauro Carvalho Chehab 
128622e74389SDaniel Scheller 	if (--dvb->users)
128722e74389SDaniel Scheller 		return dvb->users;
128825aee3deSMauro Carvalho Chehab 
128922e74389SDaniel Scheller 	ddb_input_stop_all(input);
129025aee3deSMauro Carvalho Chehab 	return 0;
129125aee3deSMauro Carvalho Chehab }
129225aee3deSMauro Carvalho Chehab 
dvb_input_detach(struct ddb_input * input)129325aee3deSMauro Carvalho Chehab static void dvb_input_detach(struct ddb_input *input)
129425aee3deSMauro Carvalho Chehab {
129522e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
129622e74389SDaniel Scheller 	struct dvb_demux *dvbdemux = &dvb->demux;
129725aee3deSMauro Carvalho Chehab 
129822e74389SDaniel Scheller 	switch (dvb->attached) {
129922e74389SDaniel Scheller 	case 0x31:
130022e74389SDaniel Scheller 		if (dvb->fe2)
130122e74389SDaniel Scheller 			dvb_unregister_frontend(dvb->fe2);
130222e74389SDaniel Scheller 		if (dvb->fe)
130322e74389SDaniel Scheller 			dvb_unregister_frontend(dvb->fe);
1304df561f66SGustavo A. R. Silva 		fallthrough;
130522e74389SDaniel Scheller 	case 0x30:
1306c966453bSDaniel Scheller 		dvb_module_release(dvb->i2c_client[0]);
1307a1c484b3SDaniel Scheller 		dvb->i2c_client[0] = NULL;
13081502efd2SDaniel Scheller 
130922e74389SDaniel Scheller 		if (dvb->fe2)
131022e74389SDaniel Scheller 			dvb_frontend_detach(dvb->fe2);
131122e74389SDaniel Scheller 		if (dvb->fe)
131222e74389SDaniel Scheller 			dvb_frontend_detach(dvb->fe);
1313757d78d3SDaniel Scheller 		dvb->fe = NULL;
1314757d78d3SDaniel Scheller 		dvb->fe2 = NULL;
1315df561f66SGustavo A. R. Silva 		fallthrough;
131622e74389SDaniel Scheller 	case 0x20:
131722e74389SDaniel Scheller 		dvb_net_release(&dvb->dvbnet);
1318df561f66SGustavo A. R. Silva 		fallthrough;
131922e74389SDaniel Scheller 	case 0x12:
132025aee3deSMauro Carvalho Chehab 		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
132122e74389SDaniel Scheller 					      &dvb->hw_frontend);
132225aee3deSMauro Carvalho Chehab 		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
132322e74389SDaniel Scheller 					      &dvb->mem_frontend);
1324df561f66SGustavo A. R. Silva 		fallthrough;
132522e74389SDaniel Scheller 	case 0x11:
132622e74389SDaniel Scheller 		dvb_dmxdev_release(&dvb->dmxdev);
1327df561f66SGustavo A. R. Silva 		fallthrough;
132822e74389SDaniel Scheller 	case 0x10:
132922e74389SDaniel Scheller 		dvb_dmx_release(&dvb->demux);
1330df561f66SGustavo A. R. Silva 		fallthrough;
133122e74389SDaniel Scheller 	case 0x01:
133222e74389SDaniel Scheller 		break;
133325aee3deSMauro Carvalho Chehab 	}
133422e74389SDaniel Scheller 	dvb->attached = 0x00;
133522e74389SDaniel Scheller }
133622e74389SDaniel Scheller 
dvb_register_adapters(struct ddb * dev)133722e74389SDaniel Scheller static int dvb_register_adapters(struct ddb *dev)
133822e74389SDaniel Scheller {
133922e74389SDaniel Scheller 	int i, ret = 0;
134022e74389SDaniel Scheller 	struct ddb_port *port;
134122e74389SDaniel Scheller 	struct dvb_adapter *adap;
134222e74389SDaniel Scheller 
134322e74389SDaniel Scheller 	if (adapter_alloc == 3) {
134422e74389SDaniel Scheller 		port = &dev->port[0];
134522e74389SDaniel Scheller 		adap = port->dvb[0].adap;
134622e74389SDaniel Scheller 		ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
134722e74389SDaniel Scheller 					   port->dev->dev,
134822e74389SDaniel Scheller 					   adapter_nr);
134922e74389SDaniel Scheller 		if (ret < 0)
135022e74389SDaniel Scheller 			return ret;
135122e74389SDaniel Scheller 		port->dvb[0].adap_registered = 1;
135222e74389SDaniel Scheller 		for (i = 0; i < dev->port_num; i++) {
135322e74389SDaniel Scheller 			port = &dev->port[i];
135422e74389SDaniel Scheller 			port->dvb[0].adap = adap;
135522e74389SDaniel Scheller 			port->dvb[1].adap = adap;
135622e74389SDaniel Scheller 		}
135722e74389SDaniel Scheller 		return 0;
135822e74389SDaniel Scheller 	}
135922e74389SDaniel Scheller 
136022e74389SDaniel Scheller 	for (i = 0; i < dev->port_num; i++) {
136122e74389SDaniel Scheller 		port = &dev->port[i];
136222e74389SDaniel Scheller 		switch (port->class) {
136322e74389SDaniel Scheller 		case DDB_PORT_TUNER:
136422e74389SDaniel Scheller 			adap = port->dvb[0].adap;
136522e74389SDaniel Scheller 			ret = dvb_register_adapter(adap, "DDBridge",
136622e74389SDaniel Scheller 						   THIS_MODULE,
136722e74389SDaniel Scheller 						   port->dev->dev,
136822e74389SDaniel Scheller 						   adapter_nr);
136922e74389SDaniel Scheller 			if (ret < 0)
137022e74389SDaniel Scheller 				return ret;
137122e74389SDaniel Scheller 			port->dvb[0].adap_registered = 1;
137222e74389SDaniel Scheller 
137322e74389SDaniel Scheller 			if (adapter_alloc > 0) {
137422e74389SDaniel Scheller 				port->dvb[1].adap = port->dvb[0].adap;
137522e74389SDaniel Scheller 				break;
137622e74389SDaniel Scheller 			}
137722e74389SDaniel Scheller 			adap = port->dvb[1].adap;
137822e74389SDaniel Scheller 			ret = dvb_register_adapter(adap, "DDBridge",
137922e74389SDaniel Scheller 						   THIS_MODULE,
138022e74389SDaniel Scheller 						   port->dev->dev,
138122e74389SDaniel Scheller 						   adapter_nr);
138222e74389SDaniel Scheller 			if (ret < 0)
138322e74389SDaniel Scheller 				return ret;
138422e74389SDaniel Scheller 			port->dvb[1].adap_registered = 1;
138522e74389SDaniel Scheller 			break;
138622e74389SDaniel Scheller 
138722e74389SDaniel Scheller 		case DDB_PORT_CI:
138822e74389SDaniel Scheller 		case DDB_PORT_LOOP:
138922e74389SDaniel Scheller 			adap = port->dvb[0].adap;
139022e74389SDaniel Scheller 			ret = dvb_register_adapter(adap, "DDBridge",
139122e74389SDaniel Scheller 						   THIS_MODULE,
139222e74389SDaniel Scheller 						   port->dev->dev,
139322e74389SDaniel Scheller 						   adapter_nr);
139422e74389SDaniel Scheller 			if (ret < 0)
139522e74389SDaniel Scheller 				return ret;
139622e74389SDaniel Scheller 			port->dvb[0].adap_registered = 1;
139722e74389SDaniel Scheller 			break;
139822e74389SDaniel Scheller 		default:
139922e74389SDaniel Scheller 			if (adapter_alloc < 2)
140022e74389SDaniel Scheller 				break;
140122e74389SDaniel Scheller 			adap = port->dvb[0].adap;
140222e74389SDaniel Scheller 			ret = dvb_register_adapter(adap, "DDBridge",
140322e74389SDaniel Scheller 						   THIS_MODULE,
140422e74389SDaniel Scheller 						   port->dev->dev,
140522e74389SDaniel Scheller 						   adapter_nr);
140622e74389SDaniel Scheller 			if (ret < 0)
140722e74389SDaniel Scheller 				return ret;
140822e74389SDaniel Scheller 			port->dvb[0].adap_registered = 1;
140922e74389SDaniel Scheller 			break;
141022e74389SDaniel Scheller 		}
141122e74389SDaniel Scheller 	}
141222e74389SDaniel Scheller 	return ret;
141322e74389SDaniel Scheller }
141422e74389SDaniel Scheller 
dvb_unregister_adapters(struct ddb * dev)141522e74389SDaniel Scheller static void dvb_unregister_adapters(struct ddb *dev)
141622e74389SDaniel Scheller {
141722e74389SDaniel Scheller 	int i;
141822e74389SDaniel Scheller 	struct ddb_port *port;
141922e74389SDaniel Scheller 	struct ddb_dvb *dvb;
142022e74389SDaniel Scheller 
142122e74389SDaniel Scheller 	for (i = 0; i < dev->link[0].info->port_num; i++) {
142222e74389SDaniel Scheller 		port = &dev->port[i];
142322e74389SDaniel Scheller 
142422e74389SDaniel Scheller 		dvb = &port->dvb[0];
142522e74389SDaniel Scheller 		if (dvb->adap_registered)
142622e74389SDaniel Scheller 			dvb_unregister_adapter(dvb->adap);
142722e74389SDaniel Scheller 		dvb->adap_registered = 0;
142822e74389SDaniel Scheller 
142922e74389SDaniel Scheller 		dvb = &port->dvb[1];
143022e74389SDaniel Scheller 		if (dvb->adap_registered)
143122e74389SDaniel Scheller 			dvb_unregister_adapter(dvb->adap);
143222e74389SDaniel Scheller 		dvb->adap_registered = 0;
143322e74389SDaniel Scheller 	}
143425aee3deSMauro Carvalho Chehab }
143525aee3deSMauro Carvalho Chehab 
dvb_input_attach(struct ddb_input * input)143625aee3deSMauro Carvalho Chehab static int dvb_input_attach(struct ddb_input *input)
143725aee3deSMauro Carvalho Chehab {
143822e74389SDaniel Scheller 	int ret = 0;
143922e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
144025aee3deSMauro Carvalho Chehab 	struct ddb_port *port = input->port;
144122e74389SDaniel Scheller 	struct dvb_adapter *adap = dvb->adap;
144222e74389SDaniel Scheller 	struct dvb_demux *dvbdemux = &dvb->demux;
1443a00031c1SDaniel Scheller 	struct ddb_ids *devids = &input->port->dev->link[input->port->lnr].ids;
1444a00031c1SDaniel Scheller 	int par = 0, osc24 = 0, tsfast = 0;
1445a00031c1SDaniel Scheller 
1446a00031c1SDaniel Scheller 	/*
1447a00031c1SDaniel Scheller 	 * Determine if bridges with stv0910 demods can run with fast TS and
1448a00031c1SDaniel Scheller 	 * thus support high bandwidth transponders.
1449a00031c1SDaniel Scheller 	 * STV0910_PR and STV0910_P tuner types covers all relevant bridges,
1450a00031c1SDaniel Scheller 	 * namely the CineS2 V7(A) and the Octopus CI S2 Pro/Advanced. All
1451a00031c1SDaniel Scheller 	 * DuoFlex S2 V4(A) have type=DDB_TUNER_DVBS_STV0910 without any suffix
1452a00031c1SDaniel Scheller 	 * and are limited by the serial link to the bridge, thus won't work
1453a00031c1SDaniel Scheller 	 * in fast TS mode.
1454a00031c1SDaniel Scheller 	 */
1455a00031c1SDaniel Scheller 	if (port->nr == 0 &&
1456a00031c1SDaniel Scheller 	    (port->type == DDB_TUNER_DVBS_STV0910_PR ||
1457a00031c1SDaniel Scheller 	     port->type == DDB_TUNER_DVBS_STV0910_P)) {
1458a00031c1SDaniel Scheller 		/* fast TS on port 0 requires FPGA version >= 1.7 */
1459a00031c1SDaniel Scheller 		if ((devids->hwid & 0x00ffffff) >= 0x00010007)
1460a00031c1SDaniel Scheller 			tsfast = 1;
1461a00031c1SDaniel Scheller 	}
146225aee3deSMauro Carvalho Chehab 
146322e74389SDaniel Scheller 	dvb->attached = 0x01;
146425aee3deSMauro Carvalho Chehab 
146522e74389SDaniel Scheller 	dvbdemux->priv = input;
146622e74389SDaniel Scheller 	dvbdemux->dmx.capabilities = DMX_TS_FILTERING |
146722e74389SDaniel Scheller 		DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
146822e74389SDaniel Scheller 	dvbdemux->start_feed = start_feed;
146922e74389SDaniel Scheller 	dvbdemux->stop_feed = stop_feed;
1470757d78d3SDaniel Scheller 	dvbdemux->filternum = 256;
1471757d78d3SDaniel Scheller 	dvbdemux->feednum = 256;
147222e74389SDaniel Scheller 	ret = dvb_dmx_init(dvbdemux);
147325aee3deSMauro Carvalho Chehab 	if (ret < 0)
147425aee3deSMauro Carvalho Chehab 		return ret;
147522e74389SDaniel Scheller 	dvb->attached = 0x10;
147625aee3deSMauro Carvalho Chehab 
147722e74389SDaniel Scheller 	dvb->dmxdev.filternum = 256;
147822e74389SDaniel Scheller 	dvb->dmxdev.demux = &dvbdemux->dmx;
147922e74389SDaniel Scheller 	ret = dvb_dmxdev_init(&dvb->dmxdev, adap);
148025aee3deSMauro Carvalho Chehab 	if (ret < 0)
148125ac563aSDaniel Scheller 		goto err_detach;
148222e74389SDaniel Scheller 	dvb->attached = 0x11;
148325aee3deSMauro Carvalho Chehab 
148422e74389SDaniel Scheller 	dvb->mem_frontend.source = DMX_MEMORY_FE;
148522e74389SDaniel Scheller 	dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->mem_frontend);
148622e74389SDaniel Scheller 	dvb->hw_frontend.source = DMX_FRONTEND_0;
148722e74389SDaniel Scheller 	dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->hw_frontend);
148822e74389SDaniel Scheller 	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &dvb->hw_frontend);
148925aee3deSMauro Carvalho Chehab 	if (ret < 0)
149025ac563aSDaniel Scheller 		goto err_detach;
149122e74389SDaniel Scheller 	dvb->attached = 0x12;
149225aee3deSMauro Carvalho Chehab 
149322e74389SDaniel Scheller 	ret = dvb_net_init(adap, &dvb->dvbnet, dvb->dmxdev.demux);
149422e74389SDaniel Scheller 	if (ret < 0)
149525ac563aSDaniel Scheller 		goto err_detach;
149622e74389SDaniel Scheller 	dvb->attached = 0x20;
149722e74389SDaniel Scheller 
1498757d78d3SDaniel Scheller 	dvb->fe = NULL;
1499757d78d3SDaniel Scheller 	dvb->fe2 = NULL;
150025aee3deSMauro Carvalho Chehab 	switch (port->type) {
150122e74389SDaniel Scheller 	case DDB_TUNER_MXL5XX:
15021c714501SDaniel Scheller 		if (ddb_fe_attach_mxl5xx(input) < 0)
150325ac563aSDaniel Scheller 			goto err_detach;
1504bb4cec96SDaniel Scheller 		break;
150525aee3deSMauro Carvalho Chehab 	case DDB_TUNER_DVBS_ST:
150625aee3deSMauro Carvalho Chehab 		if (demod_attach_stv0900(input, 0) < 0)
150725ac563aSDaniel Scheller 			goto err_detach;
150825aee3deSMauro Carvalho Chehab 		if (tuner_attach_stv6110(input, 0) < 0)
1509b32a2b42SDaniel Scheller 			goto err_tuner;
151025aee3deSMauro Carvalho Chehab 		break;
151125aee3deSMauro Carvalho Chehab 	case DDB_TUNER_DVBS_ST_AA:
151225aee3deSMauro Carvalho Chehab 		if (demod_attach_stv0900(input, 1) < 0)
151325ac563aSDaniel Scheller 			goto err_detach;
151425aee3deSMauro Carvalho Chehab 		if (tuner_attach_stv6110(input, 1) < 0)
1515b32a2b42SDaniel Scheller 			goto err_tuner;
151625aee3deSMauro Carvalho Chehab 		break;
151722e74389SDaniel Scheller 	case DDB_TUNER_DVBS_STV0910:
1518a00031c1SDaniel Scheller 		if (demod_attach_stv0910(input, 0, tsfast) < 0)
151925ac563aSDaniel Scheller 			goto err_detach;
1520df3082dfSDaniel Scheller 		if (tuner_attach_stv6111(input, 0) < 0)
1521b32a2b42SDaniel Scheller 			goto err_tuner;
1522df3082dfSDaniel Scheller 		break;
1523df3082dfSDaniel Scheller 	case DDB_TUNER_DVBS_STV0910_PR:
1524a00031c1SDaniel Scheller 		if (demod_attach_stv0910(input, 1, tsfast) < 0)
152525ac563aSDaniel Scheller 			goto err_detach;
1526df3082dfSDaniel Scheller 		if (tuner_attach_stv6111(input, 1) < 0)
1527b32a2b42SDaniel Scheller 			goto err_tuner;
1528df3082dfSDaniel Scheller 		break;
1529df3082dfSDaniel Scheller 	case DDB_TUNER_DVBS_STV0910_P:
1530a00031c1SDaniel Scheller 		if (demod_attach_stv0910(input, 0, tsfast) < 0)
153125ac563aSDaniel Scheller 			goto err_detach;
1532df3082dfSDaniel Scheller 		if (tuner_attach_stv6111(input, 1) < 0)
1533b32a2b42SDaniel Scheller 			goto err_tuner;
1534df3082dfSDaniel Scheller 		break;
153525aee3deSMauro Carvalho Chehab 	case DDB_TUNER_DVBCT_TR:
153625aee3deSMauro Carvalho Chehab 		if (demod_attach_drxk(input) < 0)
153725ac563aSDaniel Scheller 			goto err_detach;
153825aee3deSMauro Carvalho Chehab 		if (tuner_attach_tda18271(input) < 0)
1539b32a2b42SDaniel Scheller 			goto err_tuner;
154025aee3deSMauro Carvalho Chehab 		break;
154105da9437SDaniel Scheller 	case DDB_TUNER_DVBCT_ST:
154205da9437SDaniel Scheller 		if (demod_attach_stv0367(input) < 0)
154325ac563aSDaniel Scheller 			goto err_detach;
1544b32a2b42SDaniel Scheller 		if (tuner_attach_tda18212(input, port->type) < 0)
1545b32a2b42SDaniel Scheller 			goto err_tuner;
154605da9437SDaniel Scheller 		break;
154769e1749cSDaniel Scheller 	case DDB_TUNER_DVBC2T2I_SONY_P:
154822e74389SDaniel Scheller 		if (input->port->dev->link[input->port->lnr].info->ts_quirks &
154922e74389SDaniel Scheller 		    TS_QUIRK_ALT_OSC)
155022e74389SDaniel Scheller 			osc24 = 0;
155122e74389SDaniel Scheller 		else
155222e74389SDaniel Scheller 			osc24 = 1;
1553df561f66SGustavo A. R. Silva 		fallthrough;
155469e1749cSDaniel Scheller 	case DDB_TUNER_DVBCT2_SONY_P:
155569e1749cSDaniel Scheller 	case DDB_TUNER_DVBC2T2_SONY_P:
155669e1749cSDaniel Scheller 	case DDB_TUNER_ISDBT_SONY_P:
155722e74389SDaniel Scheller 		if (input->port->dev->link[input->port->lnr].info->ts_quirks
155822e74389SDaniel Scheller 			& TS_QUIRK_SERIAL)
155922e74389SDaniel Scheller 			par = 0;
156069e1749cSDaniel Scheller 		else
156122e74389SDaniel Scheller 			par = 1;
156222e74389SDaniel Scheller 		if (demod_attach_cxd28xx(input, par, osc24) < 0)
156325ac563aSDaniel Scheller 			goto err_detach;
1564b32a2b42SDaniel Scheller 		if (tuner_attach_tda18212(input, port->type) < 0)
1565b32a2b42SDaniel Scheller 			goto err_tuner;
156669e1749cSDaniel Scheller 		break;
156722e74389SDaniel Scheller 	case DDB_TUNER_DVBC2T2I_SONY:
156822e74389SDaniel Scheller 		osc24 = 1;
1569df561f66SGustavo A. R. Silva 		fallthrough;
157022e74389SDaniel Scheller 	case DDB_TUNER_DVBCT2_SONY:
157122e74389SDaniel Scheller 	case DDB_TUNER_DVBC2T2_SONY:
157222e74389SDaniel Scheller 	case DDB_TUNER_ISDBT_SONY:
157322e74389SDaniel Scheller 		if (demod_attach_cxd28xx(input, 0, osc24) < 0)
157425ac563aSDaniel Scheller 			goto err_detach;
1575b32a2b42SDaniel Scheller 		if (tuner_attach_tda18212(input, port->type) < 0)
1576b32a2b42SDaniel Scheller 			goto err_tuner;
157769e1749cSDaniel Scheller 		break;
1578ab12397fSDaniel Scheller 	case DDB_TUNER_DUMMY:
1579ab12397fSDaniel Scheller 		if (demod_attach_dummy(input) < 0)
1580ab12397fSDaniel Scheller 			goto err_detach;
1581ab12397fSDaniel Scheller 		break;
15829f269f1fSDaniel Scheller 	case DDB_TUNER_MCI_SX8:
1583e5526848SDaniel Scheller 		if (ddb_fe_attach_mci(input, port->type) < 0)
1584879973e5SDaniel Scheller 			goto err_detach;
1585879973e5SDaniel Scheller 		break;
158622e74389SDaniel Scheller 	default:
158722e74389SDaniel Scheller 		return 0;
158805da9437SDaniel Scheller 	}
158922e74389SDaniel Scheller 	dvb->attached = 0x30;
1590f597f2a8SDaniel Scheller 
159122e74389SDaniel Scheller 	if (dvb->fe) {
159222e74389SDaniel Scheller 		if (dvb_register_frontend(adap, dvb->fe) < 0)
159325ac563aSDaniel Scheller 			goto err_detach;
1594f597f2a8SDaniel Scheller 
159522e74389SDaniel Scheller 		if (dvb->fe2) {
159625ac563aSDaniel Scheller 			if (dvb_register_frontend(adap, dvb->fe2) < 0) {
159725ac563aSDaniel Scheller 				dvb_unregister_frontend(dvb->fe);
159825ac563aSDaniel Scheller 				goto err_detach;
159925ac563aSDaniel Scheller 			}
160022e74389SDaniel Scheller 			dvb->fe2->tuner_priv = dvb->fe->tuner_priv;
160122e74389SDaniel Scheller 			memcpy(&dvb->fe2->ops.tuner_ops,
160222e74389SDaniel Scheller 			       &dvb->fe->ops.tuner_ops,
160322e74389SDaniel Scheller 			       sizeof(struct dvb_tuner_ops));
160422e74389SDaniel Scheller 		}
1605f597f2a8SDaniel Scheller 	}
1606f597f2a8SDaniel Scheller 
160722e74389SDaniel Scheller 	dvb->attached = 0x31;
160825aee3deSMauro Carvalho Chehab 	return 0;
1609b32a2b42SDaniel Scheller 
1610b32a2b42SDaniel Scheller err_tuner:
161125ac563aSDaniel Scheller 	dev_err(port->dev->dev, "tuner attach failed!\n");
1612b32a2b42SDaniel Scheller 
1613b32a2b42SDaniel Scheller 	if (dvb->fe2)
1614b32a2b42SDaniel Scheller 		dvb_frontend_detach(dvb->fe2);
1615b32a2b42SDaniel Scheller 	if (dvb->fe)
1616b32a2b42SDaniel Scheller 		dvb_frontend_detach(dvb->fe);
161725ac563aSDaniel Scheller err_detach:
161825ac563aSDaniel Scheller 	dvb_input_detach(input);
161925ac563aSDaniel Scheller 
162025ac563aSDaniel Scheller 	/* return error from ret if set */
162125ac563aSDaniel Scheller 	if (ret < 0)
162225ac563aSDaniel Scheller 		return ret;
1623b32a2b42SDaniel Scheller 
1624b32a2b42SDaniel Scheller 	return -ENODEV;
162525aee3deSMauro Carvalho Chehab }
162625aee3deSMauro Carvalho Chehab 
port_has_encti(struct ddb_port * port)162722e74389SDaniel Scheller static int port_has_encti(struct ddb_port *port)
162822e74389SDaniel Scheller {
162922e74389SDaniel Scheller 	struct device *dev = port->dev->dev;
163022e74389SDaniel Scheller 	u8 val;
163122e74389SDaniel Scheller 	int ret = i2c_read_reg(&port->i2c->adap, 0x20, 0, &val);
163222e74389SDaniel Scheller 
163322e74389SDaniel Scheller 	if (!ret)
163422e74389SDaniel Scheller 		dev_info(dev, "[0x20]=0x%02x\n", val);
163522e74389SDaniel Scheller 	return ret ? 0 : 1;
163622e74389SDaniel Scheller }
163722e74389SDaniel Scheller 
port_has_cxd(struct ddb_port * port,u8 * type)163822e74389SDaniel Scheller static int port_has_cxd(struct ddb_port *port, u8 *type)
163925aee3deSMauro Carvalho Chehab {
1640335bb883SDaniel Scheller 	u8 val;
164122e74389SDaniel Scheller 	u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4];
164222e74389SDaniel Scheller 	struct i2c_msg msgs[2] = {{ .addr = 0x40,  .flags = 0,
164322e74389SDaniel Scheller 				    .buf  = probe, .len   = 4 },
164422e74389SDaniel Scheller 				  { .addr = 0x40,  .flags = I2C_M_RD,
164522e74389SDaniel Scheller 				    .buf  = data,  .len   = 4 } };
164622e74389SDaniel Scheller 	val = i2c_transfer(&port->i2c->adap, msgs, 2);
164722e74389SDaniel Scheller 	if (val != 2)
164822e74389SDaniel Scheller 		return 0;
164922e74389SDaniel Scheller 
165022e74389SDaniel Scheller 	if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43)
165122e74389SDaniel Scheller 		*type = 2;
165222e74389SDaniel Scheller 	else
165322e74389SDaniel Scheller 		*type = 1;
165422e74389SDaniel Scheller 	return 1;
165525aee3deSMauro Carvalho Chehab }
165625aee3deSMauro Carvalho Chehab 
port_has_xo2(struct ddb_port * port,u8 * type,u8 * id)1657335bb883SDaniel Scheller static int port_has_xo2(struct ddb_port *port, u8 *type, u8 *id)
165825aee3deSMauro Carvalho Chehab {
1659335bb883SDaniel Scheller 	u8 probe[1] = { 0x00 }, data[4];
166025aee3deSMauro Carvalho Chehab 
1661335bb883SDaniel Scheller 	if (i2c_io(&port->i2c->adap, 0x10, probe, 1, data, 4))
1662335bb883SDaniel Scheller 		return 0;
1663335bb883SDaniel Scheller 	if (data[0] == 'D' && data[1] == 'F') {
1664335bb883SDaniel Scheller 		*id = data[2];
166522e74389SDaniel Scheller 		*type = 1;
1666335bb883SDaniel Scheller 		return 1;
166725aee3deSMauro Carvalho Chehab 	}
1668335bb883SDaniel Scheller 	if (data[0] == 'C' && data[1] == 'I') {
1669335bb883SDaniel Scheller 		*id = data[2];
167022e74389SDaniel Scheller 		*type = 2;
1671335bb883SDaniel Scheller 		return 1;
167225aee3deSMauro Carvalho Chehab 	}
1673335bb883SDaniel Scheller 	return 0;
167425aee3deSMauro Carvalho Chehab }
167525aee3deSMauro Carvalho Chehab 
port_has_stv0900(struct ddb_port * port)1676335bb883SDaniel Scheller static int port_has_stv0900(struct ddb_port *port)
167725aee3deSMauro Carvalho Chehab {
1678335bb883SDaniel Scheller 	u8 val;
167922e74389SDaniel Scheller 
1680335bb883SDaniel Scheller 	if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0)
1681335bb883SDaniel Scheller 		return 0;
1682335bb883SDaniel Scheller 	return 1;
168325aee3deSMauro Carvalho Chehab }
168425aee3deSMauro Carvalho Chehab 
port_has_stv0900_aa(struct ddb_port * port,u8 * id)1685335bb883SDaniel Scheller static int port_has_stv0900_aa(struct ddb_port *port, u8 *id)
168625aee3deSMauro Carvalho Chehab {
1687335bb883SDaniel Scheller 	if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, id) < 0)
1688335bb883SDaniel Scheller 		return 0;
1689335bb883SDaniel Scheller 	return 1;
169025aee3deSMauro Carvalho Chehab }
169125aee3deSMauro Carvalho Chehab 
port_has_drxks(struct ddb_port * port)1692335bb883SDaniel Scheller static int port_has_drxks(struct ddb_port *port)
169325aee3deSMauro Carvalho Chehab {
1694335bb883SDaniel Scheller 	u8 val;
169522e74389SDaniel Scheller 
1696335bb883SDaniel Scheller 	if (i2c_read(&port->i2c->adap, 0x29, &val) < 0)
1697335bb883SDaniel Scheller 		return 0;
1698335bb883SDaniel Scheller 	if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0)
1699335bb883SDaniel Scheller 		return 0;
1700335bb883SDaniel Scheller 	return 1;
170125aee3deSMauro Carvalho Chehab }
170225aee3deSMauro Carvalho Chehab 
port_has_stv0367(struct ddb_port * port)1703335bb883SDaniel Scheller static int port_has_stv0367(struct ddb_port *port)
170425aee3deSMauro Carvalho Chehab {
1705335bb883SDaniel Scheller 	u8 val;
170622e74389SDaniel Scheller 
1707335bb883SDaniel Scheller 	if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0)
1708335bb883SDaniel Scheller 		return 0;
1709335bb883SDaniel Scheller 	if (val != 0x60)
1710335bb883SDaniel Scheller 		return 0;
1711335bb883SDaniel Scheller 	if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0)
1712335bb883SDaniel Scheller 		return 0;
1713335bb883SDaniel Scheller 	if (val != 0x60)
1714335bb883SDaniel Scheller 		return 0;
1715335bb883SDaniel Scheller 	return 1;
171625aee3deSMauro Carvalho Chehab }
171725aee3deSMauro Carvalho Chehab 
init_xo2(struct ddb_port * port)1718e933a6f1SDaniel Scheller static int init_xo2(struct ddb_port *port)
1719e933a6f1SDaniel Scheller {
1720e933a6f1SDaniel Scheller 	struct i2c_adapter *i2c = &port->i2c->adap;
172122e74389SDaniel Scheller 	struct ddb *dev = port->dev;
1722e933a6f1SDaniel Scheller 	u8 val, data[2];
1723e933a6f1SDaniel Scheller 	int res;
1724e933a6f1SDaniel Scheller 
1725e933a6f1SDaniel Scheller 	res = i2c_read_regs(i2c, 0x10, 0x04, data, 2);
1726e933a6f1SDaniel Scheller 	if (res < 0)
1727e933a6f1SDaniel Scheller 		return res;
1728e933a6f1SDaniel Scheller 
1729e933a6f1SDaniel Scheller 	if (data[0] != 0x01)  {
173022e74389SDaniel Scheller 		dev_info(dev->dev, "Port %d: invalid XO2\n", port->nr);
1731e933a6f1SDaniel Scheller 		return -1;
1732e933a6f1SDaniel Scheller 	}
1733e933a6f1SDaniel Scheller 
1734e933a6f1SDaniel Scheller 	i2c_read_reg(i2c, 0x10, 0x08, &val);
1735e933a6f1SDaniel Scheller 	if (val != 0) {
1736e933a6f1SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x08, 0x00);
1737e933a6f1SDaniel Scheller 		msleep(100);
1738e933a6f1SDaniel Scheller 	}
1739e933a6f1SDaniel Scheller 	/* Enable tuner power, disable pll, reset demods */
1740e933a6f1SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x08, 0x04);
1741e933a6f1SDaniel Scheller 	usleep_range(2000, 3000);
1742e933a6f1SDaniel Scheller 	/* Release demod resets */
1743e933a6f1SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x08, 0x07);
1744e933a6f1SDaniel Scheller 
1745e933a6f1SDaniel Scheller 	/* speed: 0=55,1=75,2=90,3=104 MBit/s */
174622e74389SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x09, xo2_speed);
1747e933a6f1SDaniel Scheller 
174822e74389SDaniel Scheller 	if (dev->link[port->lnr].info->con_clock) {
174922e74389SDaniel Scheller 		dev_info(dev->dev, "Setting continuous clock for XO2\n");
175022e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0a, 0x03);
175122e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0b, 0x03);
175222e74389SDaniel Scheller 	} else {
1753e933a6f1SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0a, 0x01);
1754e933a6f1SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0b, 0x01);
175522e74389SDaniel Scheller 	}
1756e933a6f1SDaniel Scheller 
1757e933a6f1SDaniel Scheller 	usleep_range(2000, 3000);
1758e933a6f1SDaniel Scheller 	/* Start XO2 PLL */
1759e933a6f1SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x08, 0x87);
1760e933a6f1SDaniel Scheller 
1761e933a6f1SDaniel Scheller 	return 0;
1762e933a6f1SDaniel Scheller }
1763e933a6f1SDaniel Scheller 
init_xo2_ci(struct ddb_port * port)176422e74389SDaniel Scheller static int init_xo2_ci(struct ddb_port *port)
176522e74389SDaniel Scheller {
176622e74389SDaniel Scheller 	struct i2c_adapter *i2c = &port->i2c->adap;
176722e74389SDaniel Scheller 	struct ddb *dev = port->dev;
176822e74389SDaniel Scheller 	u8 val, data[2];
176922e74389SDaniel Scheller 	int res;
177022e74389SDaniel Scheller 
177122e74389SDaniel Scheller 	res = i2c_read_regs(i2c, 0x10, 0x04, data, 2);
177222e74389SDaniel Scheller 	if (res < 0)
177322e74389SDaniel Scheller 		return res;
177422e74389SDaniel Scheller 
177522e74389SDaniel Scheller 	if (data[0] > 1)  {
177622e74389SDaniel Scheller 		dev_info(dev->dev, "Port %d: invalid XO2 CI %02x\n",
177722e74389SDaniel Scheller 			 port->nr, data[0]);
177822e74389SDaniel Scheller 		return -1;
177922e74389SDaniel Scheller 	}
178022e74389SDaniel Scheller 	dev_info(dev->dev, "Port %d: DuoFlex CI %u.%u\n",
178122e74389SDaniel Scheller 		 port->nr, data[0], data[1]);
178222e74389SDaniel Scheller 
178322e74389SDaniel Scheller 	i2c_read_reg(i2c, 0x10, 0x08, &val);
178422e74389SDaniel Scheller 	if (val != 0) {
178522e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x08, 0x00);
178622e74389SDaniel Scheller 		msleep(100);
178722e74389SDaniel Scheller 	}
178822e74389SDaniel Scheller 	/* Enable both CI */
178922e74389SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x08, 3);
179022e74389SDaniel Scheller 	usleep_range(2000, 3000);
179122e74389SDaniel Scheller 
179222e74389SDaniel Scheller 	/* speed: 0=55,1=75,2=90,3=104 MBit/s */
179322e74389SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x09, 1);
179422e74389SDaniel Scheller 
179522e74389SDaniel Scheller 	i2c_write_reg(i2c, 0x10, 0x08, 0x83);
179622e74389SDaniel Scheller 	usleep_range(2000, 3000);
179722e74389SDaniel Scheller 
179822e74389SDaniel Scheller 	if (dev->link[port->lnr].info->con_clock) {
179922e74389SDaniel Scheller 		dev_info(dev->dev, "Setting continuous clock for DuoFlex CI\n");
180022e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0a, 0x03);
180122e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0b, 0x03);
180222e74389SDaniel Scheller 	} else {
180322e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0a, 0x01);
180422e74389SDaniel Scheller 		i2c_write_reg(i2c, 0x10, 0x0b, 0x01);
180522e74389SDaniel Scheller 	}
180622e74389SDaniel Scheller 	return 0;
180722e74389SDaniel Scheller }
180822e74389SDaniel Scheller 
port_has_cxd28xx(struct ddb_port * port,u8 * id)180969e1749cSDaniel Scheller static int port_has_cxd28xx(struct ddb_port *port, u8 *id)
181069e1749cSDaniel Scheller {
181169e1749cSDaniel Scheller 	struct i2c_adapter *i2c = &port->i2c->adap;
181269e1749cSDaniel Scheller 	int status;
181369e1749cSDaniel Scheller 
181469e1749cSDaniel Scheller 	status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0);
181569e1749cSDaniel Scheller 	if (status)
181669e1749cSDaniel Scheller 		return 0;
181769e1749cSDaniel Scheller 	status = i2c_read_reg(i2c, 0x6e, 0xfd, id);
181869e1749cSDaniel Scheller 	if (status)
181969e1749cSDaniel Scheller 		return 0;
182069e1749cSDaniel Scheller 	return 1;
182169e1749cSDaniel Scheller }
182269e1749cSDaniel Scheller 
182322e74389SDaniel Scheller static char *xo2names[] = {
182422e74389SDaniel Scheller 	"DUAL DVB-S2", "DUAL DVB-C/T/T2",
182522e74389SDaniel Scheller 	"DUAL DVB-ISDBT", "DUAL DVB-C/C2/T/T2",
182622e74389SDaniel Scheller 	"DUAL ATSC", "DUAL DVB-C/C2/T/T2,ISDB-T",
182722e74389SDaniel Scheller 	"", ""
182822e74389SDaniel Scheller };
182922e74389SDaniel Scheller 
183022e74389SDaniel Scheller static char *xo2types[] = {
183122e74389SDaniel Scheller 	"DVBS_ST", "DVBCT2_SONY",
183222e74389SDaniel Scheller 	"ISDBT_SONY", "DVBC2T2_SONY",
183322e74389SDaniel Scheller 	"ATSC_ST", "DVBC2T2I_SONY"
183422e74389SDaniel Scheller };
183522e74389SDaniel Scheller 
ddb_port_probe(struct ddb_port * port)183625aee3deSMauro Carvalho Chehab static void ddb_port_probe(struct ddb_port *port)
183725aee3deSMauro Carvalho Chehab {
183825aee3deSMauro Carvalho Chehab 	struct ddb *dev = port->dev;
183922e74389SDaniel Scheller 	u32 l = port->lnr;
18402957e53eSDaniel Scheller 	struct ddb_link *link = &dev->link[l];
184122e74389SDaniel Scheller 	u8 id, type;
184225aee3deSMauro Carvalho Chehab 
184322e74389SDaniel Scheller 	port->name = "NO MODULE";
184422e74389SDaniel Scheller 	port->type_name = "NONE";
184525aee3deSMauro Carvalho Chehab 	port->class = DDB_PORT_NONE;
184625aee3deSMauro Carvalho Chehab 
184722e74389SDaniel Scheller 	/* Handle missing ports and ports without I2C */
184822e74389SDaniel Scheller 
1849ab12397fSDaniel Scheller 	if (dummy_tuner && !port->nr &&
18502957e53eSDaniel Scheller 	    link->ids.device == 0x0005) {
1851ab12397fSDaniel Scheller 		port->name = "DUMMY";
1852ab12397fSDaniel Scheller 		port->class = DDB_PORT_TUNER;
1853ab12397fSDaniel Scheller 		port->type = DDB_TUNER_DUMMY;
1854ab12397fSDaniel Scheller 		port->type_name = "DUMMY";
1855ab12397fSDaniel Scheller 		return;
1856ab12397fSDaniel Scheller 	}
1857ab12397fSDaniel Scheller 
185822e74389SDaniel Scheller 	if (port->nr == ts_loop) {
185922e74389SDaniel Scheller 		port->name = "TS LOOP";
186022e74389SDaniel Scheller 		port->class = DDB_PORT_LOOP;
186122e74389SDaniel Scheller 		return;
186222e74389SDaniel Scheller 	}
186322e74389SDaniel Scheller 
18642957e53eSDaniel Scheller 	if (port->nr == 1 && link->info->type == DDB_OCTOPUS_CI &&
18652957e53eSDaniel Scheller 	    link->info->i2c_mask == 1) {
186622e74389SDaniel Scheller 		port->name = "NO TAB";
186722e74389SDaniel Scheller 		port->class = DDB_PORT_NONE;
186822e74389SDaniel Scheller 		return;
186922e74389SDaniel Scheller 	}
187022e74389SDaniel Scheller 
18712957e53eSDaniel Scheller 	if (link->info->type == DDB_OCTOPUS_MAX) {
1872bb4cec96SDaniel Scheller 		port->name = "DUAL DVB-S2 MAX";
1873bb4cec96SDaniel Scheller 		port->type_name = "MXL5XX";
1874bb4cec96SDaniel Scheller 		port->class = DDB_PORT_TUNER;
1875bb4cec96SDaniel Scheller 		port->type = DDB_TUNER_MXL5XX;
1876bb4cec96SDaniel Scheller 		if (port->i2c)
1877bb4cec96SDaniel Scheller 			ddbwritel(dev, I2C_SPEED_400,
1878bb4cec96SDaniel Scheller 				  port->i2c->regs + I2C_TIMING);
1879bb4cec96SDaniel Scheller 		return;
1880bb4cec96SDaniel Scheller 	}
1881bb4cec96SDaniel Scheller 
18822957e53eSDaniel Scheller 	if (link->info->type == DDB_OCTOPUS_MCI) {
188307b12de2SDaniel Scheller 		if (port->nr >= link->info->mci_ports)
1884879973e5SDaniel Scheller 			return;
1885879973e5SDaniel Scheller 		port->name = "DUAL MCI";
1886879973e5SDaniel Scheller 		port->type_name = "MCI";
1887879973e5SDaniel Scheller 		port->class = DDB_PORT_TUNER;
188807b12de2SDaniel Scheller 		port->type = DDB_TUNER_MCI + link->info->mci_type;
1889879973e5SDaniel Scheller 		return;
1890879973e5SDaniel Scheller 	}
1891879973e5SDaniel Scheller 
18922957e53eSDaniel Scheller 	if (port->nr > 1 && link->info->type == DDB_OCTOPUS_CI) {
189322e74389SDaniel Scheller 		port->name = "CI internal";
189422e74389SDaniel Scheller 		port->type_name = "INTERNAL";
189525aee3deSMauro Carvalho Chehab 		port->class = DDB_PORT_CI;
189622e74389SDaniel Scheller 		port->type = DDB_CI_INTERNAL;
189722e74389SDaniel Scheller 	}
1898e933a6f1SDaniel Scheller 
189922e74389SDaniel Scheller 	if (!port->i2c)
190022e74389SDaniel Scheller 		return;
1901e933a6f1SDaniel Scheller 
190222e74389SDaniel Scheller 	/* Probe ports with I2C */
190322e74389SDaniel Scheller 
190422e74389SDaniel Scheller 	if (port_has_cxd(port, &id)) {
190522e74389SDaniel Scheller 		if (id == 1) {
190622e74389SDaniel Scheller 			port->name = "CI";
190722e74389SDaniel Scheller 			port->type_name = "CXD2099";
190822e74389SDaniel Scheller 			port->class = DDB_PORT_CI;
190922e74389SDaniel Scheller 			port->type = DDB_CI_EXTERNAL_SONY;
191022e74389SDaniel Scheller 			ddbwritel(dev, I2C_SPEED_400,
191122e74389SDaniel Scheller 				  port->i2c->regs + I2C_TIMING);
191222e74389SDaniel Scheller 		} else {
191322e74389SDaniel Scheller 			dev_info(dev->dev, "Port %d: Uninitialized DuoFlex\n",
191422e74389SDaniel Scheller 				 port->nr);
191522e74389SDaniel Scheller 			return;
191622e74389SDaniel Scheller 		}
191722e74389SDaniel Scheller 	} else if (port_has_xo2(port, &type, &id)) {
191822e74389SDaniel Scheller 		ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
191922e74389SDaniel Scheller 		/*dev_info(dev->dev, "XO2 ID %02x\n", id);*/
192022e74389SDaniel Scheller 		if (type == 2) {
192122e74389SDaniel Scheller 			port->name = "DuoFlex CI";
192222e74389SDaniel Scheller 			port->class = DDB_PORT_CI;
192322e74389SDaniel Scheller 			port->type = DDB_CI_EXTERNAL_XO2;
192422e74389SDaniel Scheller 			port->type_name = "CI_XO2";
192522e74389SDaniel Scheller 			init_xo2_ci(port);
192622e74389SDaniel Scheller 			return;
192722e74389SDaniel Scheller 		}
192822e74389SDaniel Scheller 		id >>= 2;
192922e74389SDaniel Scheller 		if (id > 5) {
193022e74389SDaniel Scheller 			port->name = "unknown XO2 DuoFlex";
193122e74389SDaniel Scheller 			port->type_name = "UNKNOWN";
193222e74389SDaniel Scheller 		} else {
193322e74389SDaniel Scheller 			port->name = xo2names[id];
193422e74389SDaniel Scheller 			port->class = DDB_PORT_TUNER;
193522e74389SDaniel Scheller 			port->type = DDB_TUNER_XO2 + id;
193622e74389SDaniel Scheller 			port->type_name = xo2types[id];
1937e933a6f1SDaniel Scheller 			init_xo2(port);
1938e933a6f1SDaniel Scheller 		}
193922e74389SDaniel Scheller 	} else if (port_has_cxd28xx(port, &id)) {
194022e74389SDaniel Scheller 		switch (id) {
194169e1749cSDaniel Scheller 		case 0xa4:
194222e74389SDaniel Scheller 			port->name = "DUAL DVB-C2T2 CXD2843";
194369e1749cSDaniel Scheller 			port->type = DDB_TUNER_DVBC2T2_SONY_P;
194422e74389SDaniel Scheller 			port->type_name = "DVBC2T2_SONY";
194569e1749cSDaniel Scheller 			break;
194669e1749cSDaniel Scheller 		case 0xb1:
194722e74389SDaniel Scheller 			port->name = "DUAL DVB-CT2 CXD2837";
194869e1749cSDaniel Scheller 			port->type = DDB_TUNER_DVBCT2_SONY_P;
194922e74389SDaniel Scheller 			port->type_name = "DVBCT2_SONY";
195069e1749cSDaniel Scheller 			break;
195169e1749cSDaniel Scheller 		case 0xb0:
195222e74389SDaniel Scheller 			port->name = "DUAL ISDB-T CXD2838";
195369e1749cSDaniel Scheller 			port->type = DDB_TUNER_ISDBT_SONY_P;
195422e74389SDaniel Scheller 			port->type_name = "ISDBT_SONY";
195569e1749cSDaniel Scheller 			break;
195669e1749cSDaniel Scheller 		case 0xc1:
195722e74389SDaniel Scheller 			port->name = "DUAL DVB-C2T2 ISDB-T CXD2854";
195869e1749cSDaniel Scheller 			port->type = DDB_TUNER_DVBC2T2I_SONY_P;
195922e74389SDaniel Scheller 			port->type_name = "DVBC2T2I_ISDBT_SONY";
196069e1749cSDaniel Scheller 			break;
196169e1749cSDaniel Scheller 		default:
196222e74389SDaniel Scheller 			return;
196369e1749cSDaniel Scheller 		}
196422e74389SDaniel Scheller 		port->class = DDB_PORT_TUNER;
196522e74389SDaniel Scheller 		ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
196625aee3deSMauro Carvalho Chehab 	} else if (port_has_stv0900(port)) {
196722e74389SDaniel Scheller 		port->name = "DUAL DVB-S2";
196825aee3deSMauro Carvalho Chehab 		port->class = DDB_PORT_TUNER;
196925aee3deSMauro Carvalho Chehab 		port->type = DDB_TUNER_DVBS_ST;
197022e74389SDaniel Scheller 		port->type_name = "DVBS_ST";
197122e74389SDaniel Scheller 		ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
197222e74389SDaniel Scheller 	} else if (port_has_stv0900_aa(port, &id)) {
197322e74389SDaniel Scheller 		port->name = "DUAL DVB-S2";
197425aee3deSMauro Carvalho Chehab 		port->class = DDB_PORT_TUNER;
197522e74389SDaniel Scheller 		if (id == 0x51) {
197622e74389SDaniel Scheller 			if (port->nr == 0 &&
19772957e53eSDaniel Scheller 			    link->info->ts_quirks & TS_QUIRK_REVERSED)
1978df3082dfSDaniel Scheller 				port->type = DDB_TUNER_DVBS_STV0910_PR;
1979df3082dfSDaniel Scheller 			else
1980df3082dfSDaniel Scheller 				port->type = DDB_TUNER_DVBS_STV0910_P;
198122e74389SDaniel Scheller 			port->type_name = "DVBS_ST_0910";
198222e74389SDaniel Scheller 		} else {
198325aee3deSMauro Carvalho Chehab 			port->type = DDB_TUNER_DVBS_ST_AA;
198422e74389SDaniel Scheller 			port->type_name = "DVBS_ST_AA";
1985df3082dfSDaniel Scheller 		}
198622e74389SDaniel Scheller 		ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
198725aee3deSMauro Carvalho Chehab 	} else if (port_has_drxks(port)) {
198822e74389SDaniel Scheller 		port->name = "DUAL DVB-C/T";
198925aee3deSMauro Carvalho Chehab 		port->class = DDB_PORT_TUNER;
199025aee3deSMauro Carvalho Chehab 		port->type = DDB_TUNER_DVBCT_TR;
199122e74389SDaniel Scheller 		port->type_name = "DVBCT_TR";
199222e74389SDaniel Scheller 		ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
199305da9437SDaniel Scheller 	} else if (port_has_stv0367(port)) {
199422e74389SDaniel Scheller 		port->name = "DUAL DVB-C/T";
199505da9437SDaniel Scheller 		port->class = DDB_PORT_TUNER;
199605da9437SDaniel Scheller 		port->type = DDB_TUNER_DVBCT_ST;
199722e74389SDaniel Scheller 		port->type_name = "DVBCT_ST";
199822e74389SDaniel Scheller 		ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
199922e74389SDaniel Scheller 	} else if (port_has_encti(port)) {
200022e74389SDaniel Scheller 		port->name = "ENCTI";
200122e74389SDaniel Scheller 		port->class = DDB_PORT_LOOP;
200222e74389SDaniel Scheller 	}
200325aee3deSMauro Carvalho Chehab }
200405da9437SDaniel Scheller 
200522e74389SDaniel Scheller /****************************************************************************/
200622e74389SDaniel Scheller /****************************************************************************/
200722e74389SDaniel Scheller /****************************************************************************/
200822e74389SDaniel Scheller 
ddb_port_attach(struct ddb_port * port)2009335bb883SDaniel Scheller static int ddb_port_attach(struct ddb_port *port)
2010335bb883SDaniel Scheller {
2011335bb883SDaniel Scheller 	int ret = 0;
2012335bb883SDaniel Scheller 
2013335bb883SDaniel Scheller 	switch (port->class) {
2014335bb883SDaniel Scheller 	case DDB_PORT_TUNER:
2015335bb883SDaniel Scheller 		ret = dvb_input_attach(port->input[0]);
2016335bb883SDaniel Scheller 		if (ret < 0)
2017335bb883SDaniel Scheller 			break;
2018335bb883SDaniel Scheller 		ret = dvb_input_attach(port->input[1]);
2019c0e10260SDaniel Scheller 		if (ret < 0) {
2020c0e10260SDaniel Scheller 			dvb_input_detach(port->input[0]);
202122e74389SDaniel Scheller 			break;
2022c0e10260SDaniel Scheller 		}
202322e74389SDaniel Scheller 		port->input[0]->redi = port->input[0];
202422e74389SDaniel Scheller 		port->input[1]->redi = port->input[1];
2025335bb883SDaniel Scheller 		break;
2026335bb883SDaniel Scheller 	case DDB_PORT_CI:
202770d3ae1bSDaniel Scheller 		ret = ddb_ci_attach(port, ci_bitrate);
202822e74389SDaniel Scheller 		if (ret < 0)
202922e74389SDaniel Scheller 			break;
2030df561f66SGustavo A. R. Silva 		fallthrough;
203122e74389SDaniel Scheller 	case DDB_PORT_LOOP:
203222e74389SDaniel Scheller 		ret = dvb_register_device(port->dvb[0].adap,
203322e74389SDaniel Scheller 					  &port->dvb[0].dev,
203422e74389SDaniel Scheller 					  &dvbdev_ci, (void *)port->output,
203522e74389SDaniel Scheller 					  DVB_DEVICE_SEC, 0);
2036335bb883SDaniel Scheller 		break;
2037335bb883SDaniel Scheller 	default:
2038335bb883SDaniel Scheller 		break;
2039335bb883SDaniel Scheller 	}
2040335bb883SDaniel Scheller 	if (ret < 0)
204122e74389SDaniel Scheller 		dev_err(port->dev->dev, "port_attach on port %d failed\n",
204222e74389SDaniel Scheller 			port->nr);
2043335bb883SDaniel Scheller 	return ret;
2044335bb883SDaniel Scheller }
2045335bb883SDaniel Scheller 
ddb_ports_attach(struct ddb * dev)2046a96e5ab8SDaniel Scheller int ddb_ports_attach(struct ddb *dev)
2047335bb883SDaniel Scheller {
2048ae494328SDaniel Scheller 	int i, numports, err_ports = 0, ret = 0;
2049335bb883SDaniel Scheller 	struct ddb_port *port;
2050335bb883SDaniel Scheller 
205122e74389SDaniel Scheller 	if (dev->port_num) {
205222e74389SDaniel Scheller 		ret = dvb_register_adapters(dev);
205322e74389SDaniel Scheller 		if (ret < 0) {
205422e74389SDaniel Scheller 			dev_err(dev->dev, "Registering adapters failed. Check DVB_MAX_ADAPTERS in config.\n");
205522e74389SDaniel Scheller 			return ret;
205622e74389SDaniel Scheller 		}
205722e74389SDaniel Scheller 	}
2058ae494328SDaniel Scheller 
2059ae494328SDaniel Scheller 	numports = dev->port_num;
2060ae494328SDaniel Scheller 
206122e74389SDaniel Scheller 	for (i = 0; i < dev->port_num; i++) {
2062335bb883SDaniel Scheller 		port = &dev->port[i];
2063ae494328SDaniel Scheller 		if (port->class != DDB_PORT_NONE) {
2064335bb883SDaniel Scheller 			ret = ddb_port_attach(port);
2065ae494328SDaniel Scheller 			if (ret)
2066ae494328SDaniel Scheller 				err_ports++;
2067ae494328SDaniel Scheller 		} else {
2068ae494328SDaniel Scheller 			numports--;
2069335bb883SDaniel Scheller 		}
2070ae494328SDaniel Scheller 	}
2071ae494328SDaniel Scheller 
2072ae494328SDaniel Scheller 	if (err_ports) {
2073ae494328SDaniel Scheller 		if (err_ports == numports) {
2074ae494328SDaniel Scheller 			dev_err(dev->dev, "All connected ports failed to initialise!\n");
2075ae494328SDaniel Scheller 			return -ENODEV;
2076ae494328SDaniel Scheller 		}
2077ae494328SDaniel Scheller 
2078ae494328SDaniel Scheller 		dev_warn(dev->dev, "%d of %d connected ports failed to initialise!\n",
2079ae494328SDaniel Scheller 			 err_ports, numports);
2080ae494328SDaniel Scheller 	}
2081ae494328SDaniel Scheller 
2082ae494328SDaniel Scheller 	return 0;
2083335bb883SDaniel Scheller }
2084335bb883SDaniel Scheller 
ddb_ports_detach(struct ddb * dev)2085a96e5ab8SDaniel Scheller void ddb_ports_detach(struct ddb *dev)
2086335bb883SDaniel Scheller {
2087335bb883SDaniel Scheller 	int i;
2088335bb883SDaniel Scheller 	struct ddb_port *port;
2089335bb883SDaniel Scheller 
209022e74389SDaniel Scheller 	for (i = 0; i < dev->port_num; i++) {
2091335bb883SDaniel Scheller 		port = &dev->port[i];
209222e74389SDaniel Scheller 
2093335bb883SDaniel Scheller 		switch (port->class) {
2094335bb883SDaniel Scheller 		case DDB_PORT_TUNER:
2095335bb883SDaniel Scheller 			dvb_input_detach(port->input[1]);
209625ac563aSDaniel Scheller 			dvb_input_detach(port->input[0]);
2097335bb883SDaniel Scheller 			break;
2098335bb883SDaniel Scheller 		case DDB_PORT_CI:
209922e74389SDaniel Scheller 		case DDB_PORT_LOOP:
210012081a25SDaniel Scheller 			ddb_ci_detach(port);
2101335bb883SDaniel Scheller 			break;
2102335bb883SDaniel Scheller 		}
2103335bb883SDaniel Scheller 	}
210422e74389SDaniel Scheller 	dvb_unregister_adapters(dev);
2105335bb883SDaniel Scheller }
2106335bb883SDaniel Scheller 
210722e74389SDaniel Scheller /* Copy input DMA pointers to output DMA and ACK. */
210822e74389SDaniel Scheller 
input_write_output(struct ddb_input * input,struct ddb_output * output)210922e74389SDaniel Scheller static void input_write_output(struct ddb_input *input,
211022e74389SDaniel Scheller 			       struct ddb_output *output)
211122e74389SDaniel Scheller {
211222e74389SDaniel Scheller 	ddbwritel(output->port->dev,
211322e74389SDaniel Scheller 		  input->dma->stat, DMA_BUFFER_ACK(output->dma));
211422e74389SDaniel Scheller 	output->dma->cbuf = (input->dma->stat >> 11) & 0x1f;
211522e74389SDaniel Scheller 	output->dma->coff = (input->dma->stat & 0x7ff) << 7;
211622e74389SDaniel Scheller }
211722e74389SDaniel Scheller 
output_ack_input(struct ddb_output * output,struct ddb_input * input)211822e74389SDaniel Scheller static void output_ack_input(struct ddb_output *output,
211922e74389SDaniel Scheller 			     struct ddb_input *input)
212022e74389SDaniel Scheller {
212122e74389SDaniel Scheller 	ddbwritel(input->port->dev,
212222e74389SDaniel Scheller 		  output->dma->stat, DMA_BUFFER_ACK(input->dma));
212322e74389SDaniel Scheller }
212422e74389SDaniel Scheller 
input_write_dvb(struct ddb_input * input,struct ddb_input * input2)212522e74389SDaniel Scheller static void input_write_dvb(struct ddb_input *input,
212622e74389SDaniel Scheller 			    struct ddb_input *input2)
212722e74389SDaniel Scheller {
212822e74389SDaniel Scheller 	struct ddb_dvb *dvb = &input2->port->dvb[input2->nr & 1];
212922e74389SDaniel Scheller 	struct ddb_dma *dma, *dma2;
213022e74389SDaniel Scheller 	struct ddb *dev = input->port->dev;
213122e74389SDaniel Scheller 	int ack = 1;
213222e74389SDaniel Scheller 
2133757d78d3SDaniel Scheller 	dma = input->dma;
2134757d78d3SDaniel Scheller 	dma2 = input->dma;
2135757d78d3SDaniel Scheller 	/*
2136757d78d3SDaniel Scheller 	 * if there also is an output connected, do not ACK.
213722e74389SDaniel Scheller 	 * input_write_output will ACK.
213822e74389SDaniel Scheller 	 */
213922e74389SDaniel Scheller 	if (input->redo) {
214022e74389SDaniel Scheller 		dma2 = input->redo->dma;
214122e74389SDaniel Scheller 		ack = 0;
214222e74389SDaniel Scheller 	}
2143757d78d3SDaniel Scheller 	while (dma->cbuf != ((dma->stat >> 11) & 0x1f) ||
2144757d78d3SDaniel Scheller 	       (4 & dma->ctrl)) {
214522e74389SDaniel Scheller 		if (4 & dma->ctrl) {
214622e74389SDaniel Scheller 			/* dev_err(dev->dev, "Overflow dma %d\n", dma->nr); */
214722e74389SDaniel Scheller 			ack = 1;
214822e74389SDaniel Scheller 		}
214922e74389SDaniel Scheller 		if (alt_dma)
215022e74389SDaniel Scheller 			dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf],
215122e74389SDaniel Scheller 						dma2->size, DMA_FROM_DEVICE);
215222e74389SDaniel Scheller 		dvb_dmx_swfilter_packets(&dvb->demux,
215322e74389SDaniel Scheller 					 dma2->vbuf[dma->cbuf],
215422e74389SDaniel Scheller 					 dma2->size / 188);
215522e74389SDaniel Scheller 		dma->cbuf = (dma->cbuf + 1) % dma2->num;
215622e74389SDaniel Scheller 		if (ack)
215722e74389SDaniel Scheller 			ddbwritel(dev, (dma->cbuf << 11),
215822e74389SDaniel Scheller 				  DMA_BUFFER_ACK(dma));
215922e74389SDaniel Scheller 		dma->stat = safe_ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
216022e74389SDaniel Scheller 		dma->ctrl = safe_ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
216122e74389SDaniel Scheller 	}
216222e74389SDaniel Scheller }
216322e74389SDaniel Scheller 
input_work(struct work_struct * work)216422e74389SDaniel Scheller static void input_work(struct work_struct *work)
216522e74389SDaniel Scheller {
216622e74389SDaniel Scheller 	struct ddb_dma *dma = container_of(work, struct ddb_dma, work);
216722e74389SDaniel Scheller 	struct ddb_input *input = (struct ddb_input *)dma->io;
216822e74389SDaniel Scheller 	struct ddb *dev = input->port->dev;
216922e74389SDaniel Scheller 	unsigned long flags;
217022e74389SDaniel Scheller 
217122e74389SDaniel Scheller 	spin_lock_irqsave(&dma->lock, flags);
217222e74389SDaniel Scheller 	if (!dma->running) {
217322e74389SDaniel Scheller 		spin_unlock_irqrestore(&dma->lock, flags);
217422e74389SDaniel Scheller 		return;
217522e74389SDaniel Scheller 	}
217622e74389SDaniel Scheller 	dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
217722e74389SDaniel Scheller 	dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
217822e74389SDaniel Scheller 
217922e74389SDaniel Scheller 	if (input->redi)
218022e74389SDaniel Scheller 		input_write_dvb(input, input->redi);
218122e74389SDaniel Scheller 	if (input->redo)
218222e74389SDaniel Scheller 		input_write_output(input, input->redo);
218322e74389SDaniel Scheller 	wake_up(&dma->wq);
218422e74389SDaniel Scheller 	spin_unlock_irqrestore(&dma->lock, flags);
218522e74389SDaniel Scheller }
218622e74389SDaniel Scheller 
input_handler(void * data)21871dda87acSDaniel Scheller static void input_handler(void *data)
2188335bb883SDaniel Scheller {
2189335bb883SDaniel Scheller 	struct ddb_input *input = (struct ddb_input *)data;
219022e74389SDaniel Scheller 	struct ddb_dma *dma = input->dma;
2191335bb883SDaniel Scheller 
219222e74389SDaniel Scheller 	queue_work(ddb_wq, &dma->work);
2193335bb883SDaniel Scheller }
2194335bb883SDaniel Scheller 
output_work(struct work_struct * work)21951dda87acSDaniel Scheller static void output_work(struct work_struct *work)
2196335bb883SDaniel Scheller {
21971dda87acSDaniel Scheller 	struct ddb_dma *dma = container_of(work, struct ddb_dma, work);
21981dda87acSDaniel Scheller 	struct ddb_output *output = (struct ddb_output *)dma->io;
2199335bb883SDaniel Scheller 	struct ddb *dev = output->port->dev;
2200e415eec4SDaniel Scheller 	unsigned long flags;
2201335bb883SDaniel Scheller 
2202e415eec4SDaniel Scheller 	spin_lock_irqsave(&dma->lock, flags);
2203e415eec4SDaniel Scheller 	if (!dma->running)
2204e415eec4SDaniel Scheller 		goto unlock_exit;
220522e74389SDaniel Scheller 	dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
220622e74389SDaniel Scheller 	dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
220722e74389SDaniel Scheller 	if (output->redi)
220822e74389SDaniel Scheller 		output_ack_input(output, output->redi);
220922e74389SDaniel Scheller 	wake_up(&dma->wq);
2210e415eec4SDaniel Scheller unlock_exit:
2211e415eec4SDaniel Scheller 	spin_unlock_irqrestore(&dma->lock, flags);
2212335bb883SDaniel Scheller }
2213335bb883SDaniel Scheller 
output_handler(void * data)22141dda87acSDaniel Scheller static void output_handler(void *data)
22151dda87acSDaniel Scheller {
22161dda87acSDaniel Scheller 	struct ddb_output *output = (struct ddb_output *)data;
22171dda87acSDaniel Scheller 	struct ddb_dma *dma = output->dma;
22181dda87acSDaniel Scheller 
22191dda87acSDaniel Scheller 	queue_work(ddb_wq, &dma->work);
22201dda87acSDaniel Scheller }
22211dda87acSDaniel Scheller 
2222335bb883SDaniel Scheller /****************************************************************************/
2223335bb883SDaniel Scheller /****************************************************************************/
2224335bb883SDaniel Scheller 
io_regmap(struct ddb_io * io,int link)22250937e7e7SDaniel Scheller static const struct ddb_regmap *io_regmap(struct ddb_io *io, int link)
222622e74389SDaniel Scheller {
222766cc3d98SDaniel Scheller 	const struct ddb_info *info;
222822e74389SDaniel Scheller 
222922e74389SDaniel Scheller 	if (link)
223022e74389SDaniel Scheller 		info = io->port->dev->link[io->port->lnr].info;
223122e74389SDaniel Scheller 	else
223222e74389SDaniel Scheller 		info = io->port->dev->link[0].info;
223322e74389SDaniel Scheller 
223422e74389SDaniel Scheller 	if (!info)
223522e74389SDaniel Scheller 		return NULL;
223622e74389SDaniel Scheller 
223722e74389SDaniel Scheller 	return info->regmap;
223822e74389SDaniel Scheller }
223922e74389SDaniel Scheller 
ddb_dma_init(struct ddb_io * io,int nr,int out)224022e74389SDaniel Scheller static void ddb_dma_init(struct ddb_io *io, int nr, int out)
224122e74389SDaniel Scheller {
224222e74389SDaniel Scheller 	struct ddb_dma *dma;
22430937e7e7SDaniel Scheller 	const struct ddb_regmap *rm = io_regmap(io, 0);
224422e74389SDaniel Scheller 
224522e74389SDaniel Scheller 	dma = out ? &io->port->dev->odma[nr] : &io->port->dev->idma[nr];
224622e74389SDaniel Scheller 	io->dma = dma;
224722e74389SDaniel Scheller 	dma->io = io;
224822e74389SDaniel Scheller 
224922e74389SDaniel Scheller 	spin_lock_init(&dma->lock);
225022e74389SDaniel Scheller 	init_waitqueue_head(&dma->wq);
225122e74389SDaniel Scheller 	if (out) {
22521dda87acSDaniel Scheller 		INIT_WORK(&dma->work, output_work);
225322e74389SDaniel Scheller 		dma->regs = rm->odma->base + rm->odma->size * nr;
225422e74389SDaniel Scheller 		dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr;
22550a68fc44SDaniel Scheller 		dma->num = dma_buf_num;
22560a68fc44SDaniel Scheller 		dma->size = dma_buf_size * 128 * 47;
22570a68fc44SDaniel Scheller 		dma->div = 1;
225822e74389SDaniel Scheller 	} else {
225922e74389SDaniel Scheller 		INIT_WORK(&dma->work, input_work);
226022e74389SDaniel Scheller 		dma->regs = rm->idma->base + rm->idma->size * nr;
226122e74389SDaniel Scheller 		dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr;
22620a68fc44SDaniel Scheller 		dma->num = dma_buf_num;
22630a68fc44SDaniel Scheller 		dma->size = dma_buf_size * 128 * 47;
22640a68fc44SDaniel Scheller 		dma->div = 1;
226522e74389SDaniel Scheller 	}
226622e74389SDaniel Scheller 	ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma));
226722e74389SDaniel Scheller 	dev_dbg(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n",
226822e74389SDaniel Scheller 		io->port->lnr, io->nr, nr, dma->regs, dma->bufregs);
226922e74389SDaniel Scheller }
227022e74389SDaniel Scheller 
ddb_input_init(struct ddb_port * port,int nr,int pnr,int anr)227122e74389SDaniel Scheller static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
227225aee3deSMauro Carvalho Chehab {
227325aee3deSMauro Carvalho Chehab 	struct ddb *dev = port->dev;
227422e74389SDaniel Scheller 	struct ddb_input *input = &dev->input[anr];
22750937e7e7SDaniel Scheller 	const struct ddb_regmap *rm;
227625aee3deSMauro Carvalho Chehab 
227722e74389SDaniel Scheller 	port->input[pnr] = input;
227825aee3deSMauro Carvalho Chehab 	input->nr = nr;
227925aee3deSMauro Carvalho Chehab 	input->port = port;
228022e74389SDaniel Scheller 	rm = io_regmap(input, 1);
228122e74389SDaniel Scheller 	input->regs = DDB_LINK_TAG(port->lnr) |
228222e74389SDaniel Scheller 		(rm->input->base + rm->input->size * nr);
228322e74389SDaniel Scheller 	dev_dbg(dev->dev, "init link %u, input %u, regs %08x\n",
228422e74389SDaniel Scheller 		port->lnr, nr, input->regs);
228522e74389SDaniel Scheller 
228622e74389SDaniel Scheller 	if (dev->has_dma) {
22870937e7e7SDaniel Scheller 		const struct ddb_regmap *rm0 = io_regmap(input, 0);
228822e74389SDaniel Scheller 		u32 base = rm0->irq_base_idma;
228922e74389SDaniel Scheller 		u32 dma_nr = nr;
229022e74389SDaniel Scheller 
229122e74389SDaniel Scheller 		if (port->lnr)
229222e74389SDaniel Scheller 			dma_nr += 32 + (port->lnr - 1) * 8;
229322e74389SDaniel Scheller 
229422e74389SDaniel Scheller 		dev_dbg(dev->dev, "init link %u, input %u, handler %u\n",
229522e74389SDaniel Scheller 			port->lnr, nr, dma_nr + base);
229622e74389SDaniel Scheller 
22971dda87acSDaniel Scheller 		ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input);
229822e74389SDaniel Scheller 		ddb_dma_init(input, dma_nr, 0);
229922e74389SDaniel Scheller 	}
230025aee3deSMauro Carvalho Chehab }
230125aee3deSMauro Carvalho Chehab 
ddb_output_init(struct ddb_port * port,int nr)230225aee3deSMauro Carvalho Chehab static void ddb_output_init(struct ddb_port *port, int nr)
230325aee3deSMauro Carvalho Chehab {
230425aee3deSMauro Carvalho Chehab 	struct ddb *dev = port->dev;
230525aee3deSMauro Carvalho Chehab 	struct ddb_output *output = &dev->output[nr];
23060937e7e7SDaniel Scheller 	const struct ddb_regmap *rm;
230722e74389SDaniel Scheller 
230822e74389SDaniel Scheller 	port->output = output;
230925aee3deSMauro Carvalho Chehab 	output->nr = nr;
231025aee3deSMauro Carvalho Chehab 	output->port = port;
231122e74389SDaniel Scheller 	rm = io_regmap(output, 1);
231222e74389SDaniel Scheller 	output->regs = DDB_LINK_TAG(port->lnr) |
231322e74389SDaniel Scheller 		(rm->output->base + rm->output->size * nr);
231425aee3deSMauro Carvalho Chehab 
231522e74389SDaniel Scheller 	dev_dbg(dev->dev, "init link %u, output %u, regs %08x\n",
231622e74389SDaniel Scheller 		port->lnr, nr, output->regs);
231722e74389SDaniel Scheller 
231822e74389SDaniel Scheller 	if (dev->has_dma) {
23190937e7e7SDaniel Scheller 		const struct ddb_regmap *rm0 = io_regmap(output, 0);
232022e74389SDaniel Scheller 		u32 base = rm0->irq_base_odma;
232122e74389SDaniel Scheller 
23221dda87acSDaniel Scheller 		ddb_irq_set(dev, 0, nr + base, &output_handler, output);
232322e74389SDaniel Scheller 		ddb_dma_init(output, nr, 1);
232422e74389SDaniel Scheller 	}
232522e74389SDaniel Scheller }
232622e74389SDaniel Scheller 
ddb_port_match_i2c(struct ddb_port * port)232722e74389SDaniel Scheller static int ddb_port_match_i2c(struct ddb_port *port)
232822e74389SDaniel Scheller {
232922e74389SDaniel Scheller 	struct ddb *dev = port->dev;
233022e74389SDaniel Scheller 	u32 i;
233122e74389SDaniel Scheller 
233222e74389SDaniel Scheller 	for (i = 0; i < dev->i2c_num; i++) {
233322e74389SDaniel Scheller 		if (dev->i2c[i].link == port->lnr &&
233422e74389SDaniel Scheller 		    dev->i2c[i].nr == port->nr) {
233522e74389SDaniel Scheller 			port->i2c = &dev->i2c[i];
233622e74389SDaniel Scheller 			return 1;
233722e74389SDaniel Scheller 		}
233822e74389SDaniel Scheller 	}
233922e74389SDaniel Scheller 	return 0;
234025aee3deSMauro Carvalho Chehab }
234125aee3deSMauro Carvalho Chehab 
ddb_port_match_link_i2c(struct ddb_port * port)2342bb4cec96SDaniel Scheller static int ddb_port_match_link_i2c(struct ddb_port *port)
2343bb4cec96SDaniel Scheller {
2344bb4cec96SDaniel Scheller 	struct ddb *dev = port->dev;
2345bb4cec96SDaniel Scheller 	u32 i;
2346bb4cec96SDaniel Scheller 
2347bb4cec96SDaniel Scheller 	for (i = 0; i < dev->i2c_num; i++) {
2348bb4cec96SDaniel Scheller 		if (dev->i2c[i].link == port->lnr) {
2349bb4cec96SDaniel Scheller 			port->i2c = &dev->i2c[i];
2350bb4cec96SDaniel Scheller 			return 1;
2351bb4cec96SDaniel Scheller 		}
2352bb4cec96SDaniel Scheller 	}
2353bb4cec96SDaniel Scheller 	return 0;
2354bb4cec96SDaniel Scheller }
2355bb4cec96SDaniel Scheller 
ddb_ports_init(struct ddb * dev)2356a96e5ab8SDaniel Scheller void ddb_ports_init(struct ddb *dev)
235725aee3deSMauro Carvalho Chehab {
235822e74389SDaniel Scheller 	u32 i, l, p;
235925aee3deSMauro Carvalho Chehab 	struct ddb_port *port;
236066cc3d98SDaniel Scheller 	const struct ddb_info *info;
23610937e7e7SDaniel Scheller 	const struct ddb_regmap *rm;
236225aee3deSMauro Carvalho Chehab 
236322e74389SDaniel Scheller 	for (p = l = 0; l < DDB_MAX_LINK; l++) {
236422e74389SDaniel Scheller 		info = dev->link[l].info;
236522e74389SDaniel Scheller 		if (!info)
236622e74389SDaniel Scheller 			continue;
236722e74389SDaniel Scheller 		rm = info->regmap;
236822e74389SDaniel Scheller 		if (!rm)
236922e74389SDaniel Scheller 			continue;
237022e74389SDaniel Scheller 		for (i = 0; i < info->port_num; i++, p++) {
237122e74389SDaniel Scheller 			port = &dev->port[p];
237225aee3deSMauro Carvalho Chehab 			port->dev = dev;
237325aee3deSMauro Carvalho Chehab 			port->nr = i;
237422e74389SDaniel Scheller 			port->lnr = l;
237522e74389SDaniel Scheller 			port->pnr = p;
237622e74389SDaniel Scheller 			port->gap = 0xffffffff;
237722e74389SDaniel Scheller 			port->obr = ci_bitrate;
237825aee3deSMauro Carvalho Chehab 			mutex_init(&port->i2c_gate_lock);
237922e74389SDaniel Scheller 
2380bb4cec96SDaniel Scheller 			if (!ddb_port_match_i2c(port)) {
2381bb4cec96SDaniel Scheller 				if (info->type == DDB_OCTOPUS_MAX)
2382bb4cec96SDaniel Scheller 					ddb_port_match_link_i2c(port);
2383bb4cec96SDaniel Scheller 			}
2384bb4cec96SDaniel Scheller 
238525aee3deSMauro Carvalho Chehab 			ddb_port_probe(port);
238622e74389SDaniel Scheller 
238722e74389SDaniel Scheller 			port->dvb[0].adap = &dev->adap[2 * p];
238822e74389SDaniel Scheller 			port->dvb[1].adap = &dev->adap[2 * p + 1];
238922e74389SDaniel Scheller 
2390757d78d3SDaniel Scheller 			if (port->class == DDB_PORT_NONE && i && p &&
239122e74389SDaniel Scheller 			    dev->port[p - 1].type == DDB_CI_EXTERNAL_XO2) {
239222e74389SDaniel Scheller 				port->class = DDB_PORT_CI;
239322e74389SDaniel Scheller 				port->type = DDB_CI_EXTERNAL_XO2_B;
239422e74389SDaniel Scheller 				port->name = "DuoFlex CI_B";
239522e74389SDaniel Scheller 				port->i2c = dev->port[p - 1].i2c;
239625aee3deSMauro Carvalho Chehab 			}
239722e74389SDaniel Scheller 
239822e74389SDaniel Scheller 			dev_info(dev->dev, "Port %u: Link %u, Link Port %u (TAB %u): %s\n",
239922e74389SDaniel Scheller 				 port->pnr, port->lnr, port->nr, port->nr + 1,
240022e74389SDaniel Scheller 				 port->name);
240122e74389SDaniel Scheller 
240222e74389SDaniel Scheller 			if (port->class == DDB_PORT_CI &&
240322e74389SDaniel Scheller 			    port->type == DDB_CI_EXTERNAL_XO2) {
240422e74389SDaniel Scheller 				ddb_input_init(port, 2 * i, 0, 2 * i);
240522e74389SDaniel Scheller 				ddb_output_init(port, i);
240622e74389SDaniel Scheller 				continue;
240722e74389SDaniel Scheller 			}
240822e74389SDaniel Scheller 
240922e74389SDaniel Scheller 			if (port->class == DDB_PORT_CI &&
241022e74389SDaniel Scheller 			    port->type == DDB_CI_EXTERNAL_XO2_B) {
241122e74389SDaniel Scheller 				ddb_input_init(port, 2 * i - 1, 0, 2 * i - 1);
241222e74389SDaniel Scheller 				ddb_output_init(port, i);
241322e74389SDaniel Scheller 				continue;
241422e74389SDaniel Scheller 			}
241522e74389SDaniel Scheller 
241622e74389SDaniel Scheller 			if (port->class == DDB_PORT_NONE)
241722e74389SDaniel Scheller 				continue;
241822e74389SDaniel Scheller 
241922e74389SDaniel Scheller 			switch (dev->link[l].info->type) {
242022e74389SDaniel Scheller 			case DDB_OCTOPUS_CI:
242122e74389SDaniel Scheller 				if (i >= 2) {
242222e74389SDaniel Scheller 					ddb_input_init(port, 2 + i, 0, 2 + i);
242322e74389SDaniel Scheller 					ddb_input_init(port, 4 + i, 1, 4 + i);
242422e74389SDaniel Scheller 					ddb_output_init(port, i);
242522e74389SDaniel Scheller 					break;
2426df561f66SGustavo A. R. Silva 				}
2427df561f66SGustavo A. R. Silva 				fallthrough;
242822e74389SDaniel Scheller 			case DDB_OCTOPUS:
242922e74389SDaniel Scheller 				ddb_input_init(port, 2 * i, 0, 2 * i);
243022e74389SDaniel Scheller 				ddb_input_init(port, 2 * i + 1, 1, 2 * i + 1);
243122e74389SDaniel Scheller 				ddb_output_init(port, i);
243222e74389SDaniel Scheller 				break;
2433bb4cec96SDaniel Scheller 			case DDB_OCTOPUS_MAX:
243422e74389SDaniel Scheller 			case DDB_OCTOPUS_MAX_CT:
2435879973e5SDaniel Scheller 			case DDB_OCTOPUS_MCI:
243622e74389SDaniel Scheller 				ddb_input_init(port, 2 * i, 0, 2 * p);
243722e74389SDaniel Scheller 				ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1);
243822e74389SDaniel Scheller 				break;
243922e74389SDaniel Scheller 			default:
244022e74389SDaniel Scheller 				break;
244122e74389SDaniel Scheller 			}
244222e74389SDaniel Scheller 		}
244322e74389SDaniel Scheller 	}
244422e74389SDaniel Scheller 	dev->port_num = p;
244525aee3deSMauro Carvalho Chehab }
244625aee3deSMauro Carvalho Chehab 
ddb_ports_release(struct ddb * dev)2447a96e5ab8SDaniel Scheller void ddb_ports_release(struct ddb *dev)
244825aee3deSMauro Carvalho Chehab {
244925aee3deSMauro Carvalho Chehab 	int i;
245025aee3deSMauro Carvalho Chehab 	struct ddb_port *port;
245125aee3deSMauro Carvalho Chehab 
245222e74389SDaniel Scheller 	for (i = 0; i < dev->port_num; i++) {
245325aee3deSMauro Carvalho Chehab 		port = &dev->port[i];
245422e74389SDaniel Scheller 		if (port->input[0] && port->input[0]->dma)
245522e74389SDaniel Scheller 			cancel_work_sync(&port->input[0]->dma->work);
245622e74389SDaniel Scheller 		if (port->input[1] && port->input[1]->dma)
245722e74389SDaniel Scheller 			cancel_work_sync(&port->input[1]->dma->work);
245822e74389SDaniel Scheller 		if (port->output && port->output->dma)
245922e74389SDaniel Scheller 			cancel_work_sync(&port->output->dma->work);
246025aee3deSMauro Carvalho Chehab 	}
246125aee3deSMauro Carvalho Chehab }
246225aee3deSMauro Carvalho Chehab 
246325aee3deSMauro Carvalho Chehab /****************************************************************************/
246425aee3deSMauro Carvalho Chehab /****************************************************************************/
246525aee3deSMauro Carvalho Chehab /****************************************************************************/
246625aee3deSMauro Carvalho Chehab 
246722e74389SDaniel Scheller #define IRQ_HANDLE(_nr) \
24681dda87acSDaniel Scheller 	do { if ((s & (1UL << ((_nr) & 0x1f))) && \
24691dda87acSDaniel Scheller 		 dev->link[0].irq[_nr].handler) \
24701dda87acSDaniel Scheller 		dev->link[0].irq[_nr].handler(dev->link[0].irq[_nr].data); } \
247122e74389SDaniel Scheller 	while (0)
247222e74389SDaniel Scheller 
2473e8227689SDaniel Scheller #define IRQ_HANDLE_NIBBLE(_shift) {		     \
2474e8227689SDaniel Scheller 	if (s & (0x0000000f << ((_shift) & 0x1f))) { \
2475e8227689SDaniel Scheller 		IRQ_HANDLE(0 + (_shift));	     \
2476e8227689SDaniel Scheller 		IRQ_HANDLE(1 + (_shift));	     \
2477e8227689SDaniel Scheller 		IRQ_HANDLE(2 + (_shift));	     \
2478e8227689SDaniel Scheller 		IRQ_HANDLE(3 + (_shift));	     \
2479e8227689SDaniel Scheller 	}					     \
2480e8227689SDaniel Scheller }
2481e8227689SDaniel Scheller 
2482e8227689SDaniel Scheller #define IRQ_HANDLE_BYTE(_shift) {		     \
2483e8227689SDaniel Scheller 	if (s & (0x000000ff << ((_shift) & 0x1f))) { \
2484e8227689SDaniel Scheller 		IRQ_HANDLE(0 + (_shift));	     \
2485e8227689SDaniel Scheller 		IRQ_HANDLE(1 + (_shift));	     \
2486e8227689SDaniel Scheller 		IRQ_HANDLE(2 + (_shift));	     \
2487e8227689SDaniel Scheller 		IRQ_HANDLE(3 + (_shift));	     \
2488e8227689SDaniel Scheller 		IRQ_HANDLE(4 + (_shift));	     \
2489e8227689SDaniel Scheller 		IRQ_HANDLE(5 + (_shift));	     \
2490e8227689SDaniel Scheller 		IRQ_HANDLE(6 + (_shift));	     \
2491e8227689SDaniel Scheller 		IRQ_HANDLE(7 + (_shift));	     \
2492e8227689SDaniel Scheller 	}					     \
2493e8227689SDaniel Scheller }
2494e8227689SDaniel Scheller 
irq_handle_msg(struct ddb * dev,u32 s)249522e74389SDaniel Scheller static void irq_handle_msg(struct ddb *dev, u32 s)
249625aee3deSMauro Carvalho Chehab {
249722e74389SDaniel Scheller 	dev->i2c_irq++;
2498e8227689SDaniel Scheller 	IRQ_HANDLE_NIBBLE(0);
249925aee3deSMauro Carvalho Chehab }
250025aee3deSMauro Carvalho Chehab 
irq_handle_io(struct ddb * dev,u32 s)250122e74389SDaniel Scheller static void irq_handle_io(struct ddb *dev, u32 s)
250222e74389SDaniel Scheller {
250322e74389SDaniel Scheller 	dev->ts_irq++;
2504e8227689SDaniel Scheller 	IRQ_HANDLE_NIBBLE(4);
2505e8227689SDaniel Scheller 	IRQ_HANDLE_BYTE(8);
2506e8227689SDaniel Scheller 	IRQ_HANDLE_BYTE(16);
2507e8227689SDaniel Scheller 	IRQ_HANDLE_BYTE(24);
250822e74389SDaniel Scheller }
250922e74389SDaniel Scheller 
ddb_irq_handler0(int irq,void * dev_id)251022e74389SDaniel Scheller irqreturn_t ddb_irq_handler0(int irq, void *dev_id)
251125aee3deSMauro Carvalho Chehab {
251225aee3deSMauro Carvalho Chehab 	struct ddb *dev = (struct ddb *)dev_id;
2513285d490cSDaniel Scheller 	u32 mask = 0x8fffff00;
2514285d490cSDaniel Scheller 	u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS);
251525aee3deSMauro Carvalho Chehab 
2516285d490cSDaniel Scheller 	if (!s)
2517285d490cSDaniel Scheller 		return IRQ_NONE;
251825aee3deSMauro Carvalho Chehab 	do {
251922e74389SDaniel Scheller 		if (s & 0x80000000)
252022e74389SDaniel Scheller 			return IRQ_NONE;
2521285d490cSDaniel Scheller 		ddbwritel(dev, s, INTERRUPT_ACK);
252222e74389SDaniel Scheller 		irq_handle_io(dev, s);
2523285d490cSDaniel Scheller 	} while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS)));
252425aee3deSMauro Carvalho Chehab 
252525aee3deSMauro Carvalho Chehab 	return IRQ_HANDLED;
252625aee3deSMauro Carvalho Chehab }
252725aee3deSMauro Carvalho Chehab 
ddb_irq_handler1(int irq,void * dev_id)252822e74389SDaniel Scheller irqreturn_t ddb_irq_handler1(int irq, void *dev_id)
252922e74389SDaniel Scheller {
253022e74389SDaniel Scheller 	struct ddb *dev = (struct ddb *)dev_id;
2531285d490cSDaniel Scheller 	u32 mask = 0x8000000f;
2532285d490cSDaniel Scheller 	u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS);
253325aee3deSMauro Carvalho Chehab 
2534285d490cSDaniel Scheller 	if (!s)
2535285d490cSDaniel Scheller 		return IRQ_NONE;
253622e74389SDaniel Scheller 	do {
253722e74389SDaniel Scheller 		if (s & 0x80000000)
253822e74389SDaniel Scheller 			return IRQ_NONE;
2539285d490cSDaniel Scheller 		ddbwritel(dev, s, INTERRUPT_ACK);
254022e74389SDaniel Scheller 		irq_handle_msg(dev, s);
2541285d490cSDaniel Scheller 	} while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS)));
254222e74389SDaniel Scheller 
254322e74389SDaniel Scheller 	return IRQ_HANDLED;
254422e74389SDaniel Scheller }
254522e74389SDaniel Scheller 
ddb_irq_handler(int irq,void * dev_id)254622e74389SDaniel Scheller irqreturn_t ddb_irq_handler(int irq, void *dev_id)
254722e74389SDaniel Scheller {
254822e74389SDaniel Scheller 	struct ddb *dev = (struct ddb *)dev_id;
254922e74389SDaniel Scheller 	u32 s = ddbreadl(dev, INTERRUPT_STATUS);
255022e74389SDaniel Scheller 	int ret = IRQ_HANDLED;
255122e74389SDaniel Scheller 
255222e74389SDaniel Scheller 	if (!s)
255322e74389SDaniel Scheller 		return IRQ_NONE;
255422e74389SDaniel Scheller 	do {
255522e74389SDaniel Scheller 		if (s & 0x80000000)
255622e74389SDaniel Scheller 			return IRQ_NONE;
255722e74389SDaniel Scheller 		ddbwritel(dev, s, INTERRUPT_ACK);
255822e74389SDaniel Scheller 
255922e74389SDaniel Scheller 		if (s & 0x0000000f)
256022e74389SDaniel Scheller 			irq_handle_msg(dev, s);
256122e74389SDaniel Scheller 		if (s & 0x0fffff00)
256222e74389SDaniel Scheller 			irq_handle_io(dev, s);
256322e74389SDaniel Scheller 	} while ((s = ddbreadl(dev, INTERRUPT_STATUS)));
256422e74389SDaniel Scheller 
256522e74389SDaniel Scheller 	return ret;
256622e74389SDaniel Scheller }
256722e74389SDaniel Scheller 
256822e74389SDaniel Scheller /****************************************************************************/
256922e74389SDaniel Scheller /****************************************************************************/
257022e74389SDaniel Scheller /****************************************************************************/
257122e74389SDaniel Scheller 
reg_wait(struct ddb * dev,u32 reg,u32 bit)257222e74389SDaniel Scheller static int reg_wait(struct ddb *dev, u32 reg, u32 bit)
257322e74389SDaniel Scheller {
257422e74389SDaniel Scheller 	u32 count = 0;
257522e74389SDaniel Scheller 
257622e74389SDaniel Scheller 	while (safe_ddbreadl(dev, reg) & bit) {
257722e74389SDaniel Scheller 		ndelay(10);
257822e74389SDaniel Scheller 		if (++count == 100)
257922e74389SDaniel Scheller 			return -1;
258022e74389SDaniel Scheller 	}
258122e74389SDaniel Scheller 	return 0;
258222e74389SDaniel Scheller }
258322e74389SDaniel Scheller 
flashio(struct ddb * dev,u32 lnr,u8 * wbuf,u32 wlen,u8 * rbuf,u32 rlen)258422e74389SDaniel Scheller static int flashio(struct ddb *dev, u32 lnr, u8 *wbuf, u32 wlen, u8 *rbuf,
258522e74389SDaniel Scheller 		   u32 rlen)
258625aee3deSMauro Carvalho Chehab {
258725aee3deSMauro Carvalho Chehab 	u32 data, shift;
258822e74389SDaniel Scheller 	u32 tag = DDB_LINK_TAG(lnr);
258922e74389SDaniel Scheller 	struct ddb_link *link = &dev->link[lnr];
259025aee3deSMauro Carvalho Chehab 
259122e74389SDaniel Scheller 	mutex_lock(&link->flash_mutex);
259225aee3deSMauro Carvalho Chehab 	if (wlen > 4)
259322e74389SDaniel Scheller 		ddbwritel(dev, 1, tag | SPI_CONTROL);
259425aee3deSMauro Carvalho Chehab 	while (wlen > 4) {
259525aee3deSMauro Carvalho Chehab 		/* FIXME: check for big-endian */
259625aee3deSMauro Carvalho Chehab 		data = swab32(*(u32 *)wbuf);
259725aee3deSMauro Carvalho Chehab 		wbuf += 4;
259825aee3deSMauro Carvalho Chehab 		wlen -= 4;
259922e74389SDaniel Scheller 		ddbwritel(dev, data, tag | SPI_DATA);
260022e74389SDaniel Scheller 		if (reg_wait(dev, tag | SPI_CONTROL, 4))
260122e74389SDaniel Scheller 			goto fail;
260225aee3deSMauro Carvalho Chehab 	}
260325aee3deSMauro Carvalho Chehab 	if (rlen)
260422e74389SDaniel Scheller 		ddbwritel(dev, 0x0001 | ((wlen << (8 + 3)) & 0x1f00),
260522e74389SDaniel Scheller 			  tag | SPI_CONTROL);
260625aee3deSMauro Carvalho Chehab 	else
260722e74389SDaniel Scheller 		ddbwritel(dev, 0x0003 | ((wlen << (8 + 3)) & 0x1f00),
260822e74389SDaniel Scheller 			  tag | SPI_CONTROL);
260925aee3deSMauro Carvalho Chehab 
261025aee3deSMauro Carvalho Chehab 	data = 0;
261125aee3deSMauro Carvalho Chehab 	shift = ((4 - wlen) * 8);
261225aee3deSMauro Carvalho Chehab 	while (wlen) {
261325aee3deSMauro Carvalho Chehab 		data <<= 8;
261425aee3deSMauro Carvalho Chehab 		data |= *wbuf;
261525aee3deSMauro Carvalho Chehab 		wlen--;
261625aee3deSMauro Carvalho Chehab 		wbuf++;
261725aee3deSMauro Carvalho Chehab 	}
261825aee3deSMauro Carvalho Chehab 	if (shift)
261925aee3deSMauro Carvalho Chehab 		data <<= shift;
262022e74389SDaniel Scheller 	ddbwritel(dev, data, tag | SPI_DATA);
262122e74389SDaniel Scheller 	if (reg_wait(dev, tag | SPI_CONTROL, 4))
262222e74389SDaniel Scheller 		goto fail;
262325aee3deSMauro Carvalho Chehab 
262425aee3deSMauro Carvalho Chehab 	if (!rlen) {
262522e74389SDaniel Scheller 		ddbwritel(dev, 0, tag | SPI_CONTROL);
262622e74389SDaniel Scheller 		goto exit;
262725aee3deSMauro Carvalho Chehab 	}
262825aee3deSMauro Carvalho Chehab 	if (rlen > 4)
262922e74389SDaniel Scheller 		ddbwritel(dev, 1, tag | SPI_CONTROL);
263025aee3deSMauro Carvalho Chehab 
263125aee3deSMauro Carvalho Chehab 	while (rlen > 4) {
263222e74389SDaniel Scheller 		ddbwritel(dev, 0xffffffff, tag | SPI_DATA);
263322e74389SDaniel Scheller 		if (reg_wait(dev, tag | SPI_CONTROL, 4))
263422e74389SDaniel Scheller 			goto fail;
263522e74389SDaniel Scheller 		data = ddbreadl(dev, tag | SPI_DATA);
263625aee3deSMauro Carvalho Chehab 		*(u32 *)rbuf = swab32(data);
263725aee3deSMauro Carvalho Chehab 		rbuf += 4;
263825aee3deSMauro Carvalho Chehab 		rlen -= 4;
263925aee3deSMauro Carvalho Chehab 	}
264022e74389SDaniel Scheller 	ddbwritel(dev, 0x0003 | ((rlen << (8 + 3)) & 0x1F00),
264122e74389SDaniel Scheller 		  tag | SPI_CONTROL);
264222e74389SDaniel Scheller 	ddbwritel(dev, 0xffffffff, tag | SPI_DATA);
264322e74389SDaniel Scheller 	if (reg_wait(dev, tag | SPI_CONTROL, 4))
264422e74389SDaniel Scheller 		goto fail;
264525aee3deSMauro Carvalho Chehab 
264622e74389SDaniel Scheller 	data = ddbreadl(dev, tag | SPI_DATA);
264722e74389SDaniel Scheller 	ddbwritel(dev, 0, tag | SPI_CONTROL);
264825aee3deSMauro Carvalho Chehab 
264925aee3deSMauro Carvalho Chehab 	if (rlen < 4)
265025aee3deSMauro Carvalho Chehab 		data <<= ((4 - rlen) * 8);
265125aee3deSMauro Carvalho Chehab 
265225aee3deSMauro Carvalho Chehab 	while (rlen > 0) {
265325aee3deSMauro Carvalho Chehab 		*rbuf = ((data >> 24) & 0xff);
265425aee3deSMauro Carvalho Chehab 		data <<= 8;
265525aee3deSMauro Carvalho Chehab 		rbuf++;
265625aee3deSMauro Carvalho Chehab 		rlen--;
265725aee3deSMauro Carvalho Chehab 	}
265822e74389SDaniel Scheller exit:
265922e74389SDaniel Scheller 	mutex_unlock(&link->flash_mutex);
266025aee3deSMauro Carvalho Chehab 	return 0;
266122e74389SDaniel Scheller fail:
266222e74389SDaniel Scheller 	mutex_unlock(&link->flash_mutex);
266322e74389SDaniel Scheller 	return -1;
266425aee3deSMauro Carvalho Chehab }
266525aee3deSMauro Carvalho Chehab 
ddbridge_flashread(struct ddb * dev,u32 link,u8 * buf,u32 addr,u32 len)266622e74389SDaniel Scheller int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len)
266722e74389SDaniel Scheller {
266822e74389SDaniel Scheller 	u8 cmd[4] = {0x03, (addr >> 16) & 0xff,
266922e74389SDaniel Scheller 		     (addr >> 8) & 0xff, addr & 0xff};
267025aee3deSMauro Carvalho Chehab 
267122e74389SDaniel Scheller 	return flashio(dev, link, cmd, 4, buf, len);
267222e74389SDaniel Scheller }
267325aee3deSMauro Carvalho Chehab 
267422e74389SDaniel Scheller /*
267522e74389SDaniel Scheller  * TODO/FIXME: add/implement IOCTLs from upstream driver
267622e74389SDaniel Scheller  */
267725aee3deSMauro Carvalho Chehab 
267825aee3deSMauro Carvalho Chehab #define DDB_NAME "ddbridge"
267925aee3deSMauro Carvalho Chehab 
268025aee3deSMauro Carvalho Chehab static u32 ddb_num;
268125aee3deSMauro Carvalho Chehab static int ddb_major;
268222e74389SDaniel Scheller static DEFINE_MUTEX(ddb_mutex);
268322e74389SDaniel Scheller 
ddb_release(struct inode * inode,struct file * file)268422e74389SDaniel Scheller static int ddb_release(struct inode *inode, struct file *file)
268522e74389SDaniel Scheller {
268622e74389SDaniel Scheller 	struct ddb *dev = file->private_data;
268722e74389SDaniel Scheller 
268822e74389SDaniel Scheller 	dev->ddb_dev_users--;
268922e74389SDaniel Scheller 	return 0;
269022e74389SDaniel Scheller }
269125aee3deSMauro Carvalho Chehab 
ddb_open(struct inode * inode,struct file * file)269225aee3deSMauro Carvalho Chehab static int ddb_open(struct inode *inode, struct file *file)
269325aee3deSMauro Carvalho Chehab {
269425aee3deSMauro Carvalho Chehab 	struct ddb *dev = ddbs[iminor(inode)];
269525aee3deSMauro Carvalho Chehab 
269622e74389SDaniel Scheller 	if (dev->ddb_dev_users)
269722e74389SDaniel Scheller 		return -EBUSY;
269822e74389SDaniel Scheller 	dev->ddb_dev_users++;
269925aee3deSMauro Carvalho Chehab 	file->private_data = dev;
270025aee3deSMauro Carvalho Chehab 	return 0;
270125aee3deSMauro Carvalho Chehab }
270225aee3deSMauro Carvalho Chehab 
ddb_ioctl(struct file * file,unsigned int cmd,unsigned long arg)270325aee3deSMauro Carvalho Chehab static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
270425aee3deSMauro Carvalho Chehab {
270525aee3deSMauro Carvalho Chehab 	struct ddb *dev = file->private_data;
270625aee3deSMauro Carvalho Chehab 
270722e74389SDaniel Scheller 	dev_warn(dev->dev, "DDB IOCTLs unsupported (cmd: %d, arg: %lu)\n",
270822e74389SDaniel Scheller 		 cmd, arg);
270925aee3deSMauro Carvalho Chehab 
271025aee3deSMauro Carvalho Chehab 	return -ENOTTY;
271125aee3deSMauro Carvalho Chehab }
271225aee3deSMauro Carvalho Chehab 
271325aee3deSMauro Carvalho Chehab static const struct file_operations ddb_fops = {
271425aee3deSMauro Carvalho Chehab 	.unlocked_ioctl = ddb_ioctl,
271525aee3deSMauro Carvalho Chehab 	.open           = ddb_open,
271622e74389SDaniel Scheller 	.release        = ddb_release,
271725aee3deSMauro Carvalho Chehab };
271825aee3deSMauro Carvalho Chehab 
ddb_devnode(const struct device * device,umode_t * mode)2719*ff62b8e6SGreg Kroah-Hartman static char *ddb_devnode(const struct device *device, umode_t *mode)
272025aee3deSMauro Carvalho Chehab {
2721*ff62b8e6SGreg Kroah-Hartman 	const struct ddb *dev = dev_get_drvdata(device);
272225aee3deSMauro Carvalho Chehab 
272325aee3deSMauro Carvalho Chehab 	return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr);
272425aee3deSMauro Carvalho Chehab }
272525aee3deSMauro Carvalho Chehab 
272622e74389SDaniel Scheller #define __ATTR_MRO(_name, _show) {				\
272722e74389SDaniel Scheller 	.attr	= { .name = __stringify(_name), .mode = 0444 },	\
272822e74389SDaniel Scheller 	.show	= _show,					\
272922e74389SDaniel Scheller }
273022e74389SDaniel Scheller 
273122e74389SDaniel Scheller #define __ATTR_MWO(_name, _store) {				\
273222e74389SDaniel Scheller 	.attr	= { .name = __stringify(_name), .mode = 0222 },	\
273322e74389SDaniel Scheller 	.store	= _store,					\
273422e74389SDaniel Scheller }
273522e74389SDaniel Scheller 
ports_show(struct device * device,struct device_attribute * attr,char * buf)273622e74389SDaniel Scheller static ssize_t ports_show(struct device *device,
273722e74389SDaniel Scheller 			  struct device_attribute *attr, char *buf)
273822e74389SDaniel Scheller {
273922e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
274022e74389SDaniel Scheller 
274122e74389SDaniel Scheller 	return sprintf(buf, "%d\n", dev->port_num);
274222e74389SDaniel Scheller }
274322e74389SDaniel Scheller 
ts_irq_show(struct device * device,struct device_attribute * attr,char * buf)274422e74389SDaniel Scheller static ssize_t ts_irq_show(struct device *device,
274522e74389SDaniel Scheller 			   struct device_attribute *attr, char *buf)
274622e74389SDaniel Scheller {
274722e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
274822e74389SDaniel Scheller 
274922e74389SDaniel Scheller 	return sprintf(buf, "%d\n", dev->ts_irq);
275022e74389SDaniel Scheller }
275122e74389SDaniel Scheller 
i2c_irq_show(struct device * device,struct device_attribute * attr,char * buf)275222e74389SDaniel Scheller static ssize_t i2c_irq_show(struct device *device,
275322e74389SDaniel Scheller 			    struct device_attribute *attr, char *buf)
275422e74389SDaniel Scheller {
275522e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
275622e74389SDaniel Scheller 
275722e74389SDaniel Scheller 	return sprintf(buf, "%d\n", dev->i2c_irq);
275822e74389SDaniel Scheller }
275922e74389SDaniel Scheller 
fan_show(struct device * device,struct device_attribute * attr,char * buf)276022e74389SDaniel Scheller static ssize_t fan_show(struct device *device,
276122e74389SDaniel Scheller 			struct device_attribute *attr, char *buf)
276222e74389SDaniel Scheller {
276322e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
276422e74389SDaniel Scheller 	u32 val;
276522e74389SDaniel Scheller 
276622e74389SDaniel Scheller 	val = ddbreadl(dev, GPIO_OUTPUT) & 1;
276722e74389SDaniel Scheller 	return sprintf(buf, "%d\n", val);
276822e74389SDaniel Scheller }
276922e74389SDaniel Scheller 
fan_store(struct device * device,struct device_attribute * d,const char * buf,size_t count)277022e74389SDaniel Scheller static ssize_t fan_store(struct device *device, struct device_attribute *d,
277122e74389SDaniel Scheller 			 const char *buf, size_t count)
277222e74389SDaniel Scheller {
277322e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
277422e74389SDaniel Scheller 	u32 val;
277522e74389SDaniel Scheller 
277622e74389SDaniel Scheller 	if (sscanf(buf, "%u\n", &val) != 1)
277722e74389SDaniel Scheller 		return -EINVAL;
277822e74389SDaniel Scheller 	ddbwritel(dev, 1, GPIO_DIRECTION);
277922e74389SDaniel Scheller 	ddbwritel(dev, val & 1, GPIO_OUTPUT);
278022e74389SDaniel Scheller 	return count;
278122e74389SDaniel Scheller }
278222e74389SDaniel Scheller 
fanspeed_show(struct device * device,struct device_attribute * attr,char * buf)278322e74389SDaniel Scheller static ssize_t fanspeed_show(struct device *device,
278422e74389SDaniel Scheller 			     struct device_attribute *attr, char *buf)
278522e74389SDaniel Scheller {
278622e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
278722e74389SDaniel Scheller 	int num = attr->attr.name[8] - 0x30;
278822e74389SDaniel Scheller 	struct ddb_link *link = &dev->link[num];
278922e74389SDaniel Scheller 	u32 spd;
279022e74389SDaniel Scheller 
279122e74389SDaniel Scheller 	spd = ddblreadl(link, TEMPMON_FANCONTROL) & 0xff;
279222e74389SDaniel Scheller 	return sprintf(buf, "%u\n", spd * 100);
279322e74389SDaniel Scheller }
279422e74389SDaniel Scheller 
temp_show(struct device * device,struct device_attribute * attr,char * buf)279522e74389SDaniel Scheller static ssize_t temp_show(struct device *device,
279622e74389SDaniel Scheller 			 struct device_attribute *attr, char *buf)
279722e74389SDaniel Scheller {
279822e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
279922e74389SDaniel Scheller 	struct ddb_link *link = &dev->link[0];
280022e74389SDaniel Scheller 	struct i2c_adapter *adap;
280122e74389SDaniel Scheller 	int temp, temp2;
280222e74389SDaniel Scheller 	u8 tmp[2];
280322e74389SDaniel Scheller 
280422e74389SDaniel Scheller 	if (!link->info->temp_num)
280522e74389SDaniel Scheller 		return sprintf(buf, "no sensor\n");
280622e74389SDaniel Scheller 	adap = &dev->i2c[link->info->temp_bus].adap;
280722e74389SDaniel Scheller 	if (i2c_read_regs(adap, 0x48, 0, tmp, 2) < 0)
280822e74389SDaniel Scheller 		return sprintf(buf, "read_error\n");
280922e74389SDaniel Scheller 	temp = (tmp[0] << 3) | (tmp[1] >> 5);
281022e74389SDaniel Scheller 	temp *= 125;
281122e74389SDaniel Scheller 	if (link->info->temp_num == 2) {
281222e74389SDaniel Scheller 		if (i2c_read_regs(adap, 0x49, 0, tmp, 2) < 0)
281322e74389SDaniel Scheller 			return sprintf(buf, "read_error\n");
281422e74389SDaniel Scheller 		temp2 = (tmp[0] << 3) | (tmp[1] >> 5);
281522e74389SDaniel Scheller 		temp2 *= 125;
281622e74389SDaniel Scheller 		return sprintf(buf, "%d %d\n", temp, temp2);
281722e74389SDaniel Scheller 	}
281822e74389SDaniel Scheller 	return sprintf(buf, "%d\n", temp);
281922e74389SDaniel Scheller }
282022e74389SDaniel Scheller 
ctemp_show(struct device * device,struct device_attribute * attr,char * buf)282122e74389SDaniel Scheller static ssize_t ctemp_show(struct device *device,
282222e74389SDaniel Scheller 			  struct device_attribute *attr, char *buf)
282322e74389SDaniel Scheller {
282422e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
282522e74389SDaniel Scheller 	struct i2c_adapter *adap;
282622e74389SDaniel Scheller 	int temp;
282722e74389SDaniel Scheller 	u8 tmp[2];
282822e74389SDaniel Scheller 	int num = attr->attr.name[4] - 0x30;
282922e74389SDaniel Scheller 
283022e74389SDaniel Scheller 	adap = &dev->i2c[num].adap;
283122e74389SDaniel Scheller 	if (!adap)
283222e74389SDaniel Scheller 		return 0;
283322e74389SDaniel Scheller 	if (i2c_read_regs(adap, 0x49, 0, tmp, 2) < 0)
283422e74389SDaniel Scheller 		if (i2c_read_regs(adap, 0x4d, 0, tmp, 2) < 0)
283522e74389SDaniel Scheller 			return sprintf(buf, "no sensor\n");
283622e74389SDaniel Scheller 	temp = tmp[0] * 1000;
283722e74389SDaniel Scheller 	return sprintf(buf, "%d\n", temp);
283822e74389SDaniel Scheller }
283922e74389SDaniel Scheller 
led_show(struct device * device,struct device_attribute * attr,char * buf)284022e74389SDaniel Scheller static ssize_t led_show(struct device *device,
284122e74389SDaniel Scheller 			struct device_attribute *attr, char *buf)
284222e74389SDaniel Scheller {
284322e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
284422e74389SDaniel Scheller 	int num = attr->attr.name[3] - 0x30;
284522e74389SDaniel Scheller 
284622e74389SDaniel Scheller 	return sprintf(buf, "%d\n", dev->leds & (1 << num) ? 1 : 0);
284722e74389SDaniel Scheller }
284822e74389SDaniel Scheller 
ddb_set_led(struct ddb * dev,int num,int val)284922e74389SDaniel Scheller static void ddb_set_led(struct ddb *dev, int num, int val)
285022e74389SDaniel Scheller {
285122e74389SDaniel Scheller 	if (!dev->link[0].info->led_num)
285222e74389SDaniel Scheller 		return;
285322e74389SDaniel Scheller 	switch (dev->port[num].class) {
285422e74389SDaniel Scheller 	case DDB_PORT_TUNER:
285522e74389SDaniel Scheller 		switch (dev->port[num].type) {
285622e74389SDaniel Scheller 		case DDB_TUNER_DVBS_ST:
285722e74389SDaniel Scheller 			i2c_write_reg16(&dev->i2c[num].adap,
285822e74389SDaniel Scheller 					0x69, 0xf14c, val ? 2 : 0);
285922e74389SDaniel Scheller 			break;
286022e74389SDaniel Scheller 		case DDB_TUNER_DVBCT_ST:
286122e74389SDaniel Scheller 			i2c_write_reg16(&dev->i2c[num].adap,
286222e74389SDaniel Scheller 					0x1f, 0xf00e, 0);
286322e74389SDaniel Scheller 			i2c_write_reg16(&dev->i2c[num].adap,
286422e74389SDaniel Scheller 					0x1f, 0xf00f, val ? 1 : 0);
286522e74389SDaniel Scheller 			break;
286622e74389SDaniel Scheller 		case DDB_TUNER_XO2 ... DDB_TUNER_DVBC2T2I_SONY:
286722e74389SDaniel Scheller 		{
286822e74389SDaniel Scheller 			u8 v;
286922e74389SDaniel Scheller 
287022e74389SDaniel Scheller 			i2c_read_reg(&dev->i2c[num].adap, 0x10, 0x08, &v);
287122e74389SDaniel Scheller 			v = (v & ~0x10) | (val ? 0x10 : 0);
287222e74389SDaniel Scheller 			i2c_write_reg(&dev->i2c[num].adap, 0x10, 0x08, v);
287322e74389SDaniel Scheller 			break;
287422e74389SDaniel Scheller 		}
287522e74389SDaniel Scheller 		default:
287622e74389SDaniel Scheller 			break;
287722e74389SDaniel Scheller 		}
287822e74389SDaniel Scheller 		break;
287922e74389SDaniel Scheller 	}
288022e74389SDaniel Scheller }
288122e74389SDaniel Scheller 
led_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)288222e74389SDaniel Scheller static ssize_t led_store(struct device *device,
288322e74389SDaniel Scheller 			 struct device_attribute *attr,
288422e74389SDaniel Scheller 			 const char *buf, size_t count)
288522e74389SDaniel Scheller {
288622e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
288722e74389SDaniel Scheller 	int num = attr->attr.name[3] - 0x30;
288822e74389SDaniel Scheller 	u32 val;
288922e74389SDaniel Scheller 
289022e74389SDaniel Scheller 	if (sscanf(buf, "%u\n", &val) != 1)
289122e74389SDaniel Scheller 		return -EINVAL;
289222e74389SDaniel Scheller 	if (val)
289322e74389SDaniel Scheller 		dev->leds |= (1 << num);
289422e74389SDaniel Scheller 	else
289522e74389SDaniel Scheller 		dev->leds &= ~(1 << num);
289622e74389SDaniel Scheller 	ddb_set_led(dev, num, val);
289722e74389SDaniel Scheller 	return count;
289822e74389SDaniel Scheller }
289922e74389SDaniel Scheller 
snr_show(struct device * device,struct device_attribute * attr,char * buf)290022e74389SDaniel Scheller static ssize_t snr_show(struct device *device,
290122e74389SDaniel Scheller 			struct device_attribute *attr, char *buf)
290222e74389SDaniel Scheller {
290322e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
290422e74389SDaniel Scheller 	char snr[32];
290522e74389SDaniel Scheller 	int num = attr->attr.name[3] - 0x30;
290622e74389SDaniel Scheller 
290722e74389SDaniel Scheller 	if (dev->port[num].type >= DDB_TUNER_XO2) {
290822e74389SDaniel Scheller 		if (i2c_read_regs(&dev->i2c[num].adap, 0x10, 0x10, snr, 16) < 0)
290922e74389SDaniel Scheller 			return sprintf(buf, "NO SNR\n");
291022e74389SDaniel Scheller 		snr[16] = 0;
291122e74389SDaniel Scheller 	} else {
291222e74389SDaniel Scheller 		/* serial number at 0x100-0x11f */
291322e74389SDaniel Scheller 		if (i2c_read_regs16(&dev->i2c[num].adap,
291422e74389SDaniel Scheller 				    0x57, 0x100, snr, 32) < 0)
291522e74389SDaniel Scheller 			if (i2c_read_regs16(&dev->i2c[num].adap,
291622e74389SDaniel Scheller 					    0x50, 0x100, snr, 32) < 0)
291722e74389SDaniel Scheller 				return sprintf(buf, "NO SNR\n");
291822e74389SDaniel Scheller 		snr[31] = 0; /* in case it is not terminated on EEPROM */
291922e74389SDaniel Scheller 	}
292022e74389SDaniel Scheller 	return sprintf(buf, "%s\n", snr);
292122e74389SDaniel Scheller }
292222e74389SDaniel Scheller 
bsnr_show(struct device * device,struct device_attribute * attr,char * buf)292322e74389SDaniel Scheller static ssize_t bsnr_show(struct device *device,
292422e74389SDaniel Scheller 			 struct device_attribute *attr, char *buf)
292522e74389SDaniel Scheller {
292622e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
292722e74389SDaniel Scheller 	char snr[16];
292822e74389SDaniel Scheller 
292922e74389SDaniel Scheller 	ddbridge_flashread(dev, 0, snr, 0x10, 15);
293022e74389SDaniel Scheller 	snr[15] = 0; /* in case it is not terminated on EEPROM */
293122e74389SDaniel Scheller 	return sprintf(buf, "%s\n", snr);
293222e74389SDaniel Scheller }
293322e74389SDaniel Scheller 
bpsnr_show(struct device * device,struct device_attribute * attr,char * buf)293422e74389SDaniel Scheller static ssize_t bpsnr_show(struct device *device,
293522e74389SDaniel Scheller 			  struct device_attribute *attr, char *buf)
293622e74389SDaniel Scheller {
293722e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
2938adb57f60SDaniel Scheller 	unsigned char snr[32];
293922e74389SDaniel Scheller 
294022e74389SDaniel Scheller 	if (!dev->i2c_num)
294122e74389SDaniel Scheller 		return 0;
294222e74389SDaniel Scheller 
294322e74389SDaniel Scheller 	if (i2c_read_regs16(&dev->i2c[0].adap,
294422e74389SDaniel Scheller 			    0x50, 0x0000, snr, 32) < 0 ||
294522e74389SDaniel Scheller 	    snr[0] == 0xff)
294622e74389SDaniel Scheller 		return sprintf(buf, "NO SNR\n");
294722e74389SDaniel Scheller 	snr[31] = 0; /* in case it is not terminated on EEPROM */
294822e74389SDaniel Scheller 	return sprintf(buf, "%s\n", snr);
294922e74389SDaniel Scheller }
295022e74389SDaniel Scheller 
redirect_show(struct device * device,struct device_attribute * attr,char * buf)295122e74389SDaniel Scheller static ssize_t redirect_show(struct device *device,
295222e74389SDaniel Scheller 			     struct device_attribute *attr, char *buf)
295322e74389SDaniel Scheller {
295422e74389SDaniel Scheller 	return 0;
295522e74389SDaniel Scheller }
295622e74389SDaniel Scheller 
redirect_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)295722e74389SDaniel Scheller static ssize_t redirect_store(struct device *device,
295822e74389SDaniel Scheller 			      struct device_attribute *attr,
295922e74389SDaniel Scheller 			      const char *buf, size_t count)
296022e74389SDaniel Scheller {
296122e74389SDaniel Scheller 	unsigned int i, p;
296222e74389SDaniel Scheller 	int res;
296322e74389SDaniel Scheller 
296422e74389SDaniel Scheller 	if (sscanf(buf, "%x %x\n", &i, &p) != 2)
296522e74389SDaniel Scheller 		return -EINVAL;
296622e74389SDaniel Scheller 	res = ddb_redirect(i, p);
296722e74389SDaniel Scheller 	if (res < 0)
296822e74389SDaniel Scheller 		return res;
296922e74389SDaniel Scheller 	dev_info(device, "redirect: %02x, %02x\n", i, p);
297022e74389SDaniel Scheller 	return count;
297122e74389SDaniel Scheller }
297222e74389SDaniel Scheller 
gap_show(struct device * device,struct device_attribute * attr,char * buf)297322e74389SDaniel Scheller static ssize_t gap_show(struct device *device,
297422e74389SDaniel Scheller 			struct device_attribute *attr, char *buf)
297522e74389SDaniel Scheller {
297622e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
297722e74389SDaniel Scheller 	int num = attr->attr.name[3] - 0x30;
297822e74389SDaniel Scheller 
297922e74389SDaniel Scheller 	return sprintf(buf, "%d\n", dev->port[num].gap);
298022e74389SDaniel Scheller }
298122e74389SDaniel Scheller 
gap_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)298222e74389SDaniel Scheller static ssize_t gap_store(struct device *device, struct device_attribute *attr,
298322e74389SDaniel Scheller 			 const char *buf, size_t count)
298422e74389SDaniel Scheller {
298522e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
298622e74389SDaniel Scheller 	int num = attr->attr.name[3] - 0x30;
298722e74389SDaniel Scheller 	unsigned int val;
298822e74389SDaniel Scheller 
298922e74389SDaniel Scheller 	if (sscanf(buf, "%u\n", &val) != 1)
299022e74389SDaniel Scheller 		return -EINVAL;
2991bae7c75bSDaniel Scheller 	if (val > 128)
299222e74389SDaniel Scheller 		return -EINVAL;
2993bae7c75bSDaniel Scheller 	if (val == 128)
2994bae7c75bSDaniel Scheller 		val = 0xffffffff;
299522e74389SDaniel Scheller 	dev->port[num].gap = val;
299622e74389SDaniel Scheller 	return count;
299722e74389SDaniel Scheller }
299822e74389SDaniel Scheller 
version_show(struct device * device,struct device_attribute * attr,char * buf)299922e74389SDaniel Scheller static ssize_t version_show(struct device *device,
300022e74389SDaniel Scheller 			    struct device_attribute *attr, char *buf)
300122e74389SDaniel Scheller {
300222e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
300322e74389SDaniel Scheller 
300422e74389SDaniel Scheller 	return sprintf(buf, "%08x %08x\n",
300522e74389SDaniel Scheller 		       dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
300622e74389SDaniel Scheller }
300722e74389SDaniel Scheller 
hwid_show(struct device * device,struct device_attribute * attr,char * buf)300822e74389SDaniel Scheller static ssize_t hwid_show(struct device *device,
300922e74389SDaniel Scheller 			 struct device_attribute *attr, char *buf)
301022e74389SDaniel Scheller {
301122e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
301222e74389SDaniel Scheller 
301322e74389SDaniel Scheller 	return sprintf(buf, "0x%08X\n", dev->link[0].ids.hwid);
301422e74389SDaniel Scheller }
301522e74389SDaniel Scheller 
regmap_show(struct device * device,struct device_attribute * attr,char * buf)301622e74389SDaniel Scheller static ssize_t regmap_show(struct device *device,
301722e74389SDaniel Scheller 			   struct device_attribute *attr, char *buf)
301822e74389SDaniel Scheller {
301922e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
302022e74389SDaniel Scheller 
302122e74389SDaniel Scheller 	return sprintf(buf, "0x%08X\n", dev->link[0].ids.regmapid);
302222e74389SDaniel Scheller }
302322e74389SDaniel Scheller 
fmode_show(struct device * device,struct device_attribute * attr,char * buf)3024bb4cec96SDaniel Scheller static ssize_t fmode_show(struct device *device,
3025bb4cec96SDaniel Scheller 			  struct device_attribute *attr, char *buf)
3026bb4cec96SDaniel Scheller {
3027bb4cec96SDaniel Scheller 	int num = attr->attr.name[5] - 0x30;
3028bb4cec96SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
3029bb4cec96SDaniel Scheller 
3030bb4cec96SDaniel Scheller 	return sprintf(buf, "%u\n", dev->link[num].lnb.fmode);
3031bb4cec96SDaniel Scheller }
3032bb4cec96SDaniel Scheller 
devid_show(struct device * device,struct device_attribute * attr,char * buf)303322e74389SDaniel Scheller static ssize_t devid_show(struct device *device,
303422e74389SDaniel Scheller 			  struct device_attribute *attr, char *buf)
303522e74389SDaniel Scheller {
303622e74389SDaniel Scheller 	int num = attr->attr.name[5] - 0x30;
303722e74389SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
303822e74389SDaniel Scheller 
303922e74389SDaniel Scheller 	return sprintf(buf, "%08x\n", dev->link[num].ids.devid);
304022e74389SDaniel Scheller }
304122e74389SDaniel Scheller 
fmode_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)3042bb4cec96SDaniel Scheller static ssize_t fmode_store(struct device *device, struct device_attribute *attr,
3043bb4cec96SDaniel Scheller 			   const char *buf, size_t count)
3044bb4cec96SDaniel Scheller {
3045bb4cec96SDaniel Scheller 	struct ddb *dev = dev_get_drvdata(device);
3046bb4cec96SDaniel Scheller 	int num = attr->attr.name[5] - 0x30;
3047bb4cec96SDaniel Scheller 	unsigned int val;
3048bb4cec96SDaniel Scheller 
3049bb4cec96SDaniel Scheller 	if (sscanf(buf, "%u\n", &val) != 1)
3050bb4cec96SDaniel Scheller 		return -EINVAL;
3051bb4cec96SDaniel Scheller 	if (val > 3)
3052bb4cec96SDaniel Scheller 		return -EINVAL;
30531c714501SDaniel Scheller 	ddb_lnb_init_fmode(dev, &dev->link[num], val);
3054bb4cec96SDaniel Scheller 	return count;
3055bb4cec96SDaniel Scheller }
3056bb4cec96SDaniel Scheller 
305722e74389SDaniel Scheller static struct device_attribute ddb_attrs[] = {
305822e74389SDaniel Scheller 	__ATTR_RO(version),
305922e74389SDaniel Scheller 	__ATTR_RO(ports),
306022e74389SDaniel Scheller 	__ATTR_RO(ts_irq),
306122e74389SDaniel Scheller 	__ATTR_RO(i2c_irq),
306222e74389SDaniel Scheller 	__ATTR(gap0, 0664, gap_show, gap_store),
306322e74389SDaniel Scheller 	__ATTR(gap1, 0664, gap_show, gap_store),
306422e74389SDaniel Scheller 	__ATTR(gap2, 0664, gap_show, gap_store),
306522e74389SDaniel Scheller 	__ATTR(gap3, 0664, gap_show, gap_store),
3066bb4cec96SDaniel Scheller 	__ATTR(fmode0, 0664, fmode_show, fmode_store),
3067bb4cec96SDaniel Scheller 	__ATTR(fmode1, 0664, fmode_show, fmode_store),
3068bb4cec96SDaniel Scheller 	__ATTR(fmode2, 0664, fmode_show, fmode_store),
3069bb4cec96SDaniel Scheller 	__ATTR(fmode3, 0664, fmode_show, fmode_store),
307022e74389SDaniel Scheller 	__ATTR_MRO(devid0, devid_show),
307122e74389SDaniel Scheller 	__ATTR_MRO(devid1, devid_show),
307222e74389SDaniel Scheller 	__ATTR_MRO(devid2, devid_show),
307322e74389SDaniel Scheller 	__ATTR_MRO(devid3, devid_show),
307422e74389SDaniel Scheller 	__ATTR_RO(hwid),
307522e74389SDaniel Scheller 	__ATTR_RO(regmap),
307622e74389SDaniel Scheller 	__ATTR(redirect, 0664, redirect_show, redirect_store),
307722e74389SDaniel Scheller 	__ATTR_MRO(snr,  bsnr_show),
307822e74389SDaniel Scheller 	__ATTR_RO(bpsnr),
307922e74389SDaniel Scheller 	__ATTR_NULL,
308022e74389SDaniel Scheller };
308122e74389SDaniel Scheller 
308222e74389SDaniel Scheller static struct device_attribute ddb_attrs_temp[] = {
308322e74389SDaniel Scheller 	__ATTR_RO(temp),
308422e74389SDaniel Scheller };
308522e74389SDaniel Scheller 
308622e74389SDaniel Scheller static struct device_attribute ddb_attrs_fan[] = {
308722e74389SDaniel Scheller 	__ATTR(fan, 0664, fan_show, fan_store),
308822e74389SDaniel Scheller };
308922e74389SDaniel Scheller 
309022e74389SDaniel Scheller static struct device_attribute ddb_attrs_snr[] = {
30911bdafdf0SDaniel Scheller 	__ATTR_MRO(snr0, snr_show),
30921bdafdf0SDaniel Scheller 	__ATTR_MRO(snr1, snr_show),
30931bdafdf0SDaniel Scheller 	__ATTR_MRO(snr2, snr_show),
30941bdafdf0SDaniel Scheller 	__ATTR_MRO(snr3, snr_show),
309522e74389SDaniel Scheller };
309622e74389SDaniel Scheller 
309722e74389SDaniel Scheller static struct device_attribute ddb_attrs_ctemp[] = {
309822e74389SDaniel Scheller 	__ATTR_MRO(temp0, ctemp_show),
309922e74389SDaniel Scheller 	__ATTR_MRO(temp1, ctemp_show),
310022e74389SDaniel Scheller 	__ATTR_MRO(temp2, ctemp_show),
310122e74389SDaniel Scheller 	__ATTR_MRO(temp3, ctemp_show),
310222e74389SDaniel Scheller };
310322e74389SDaniel Scheller 
310422e74389SDaniel Scheller static struct device_attribute ddb_attrs_led[] = {
310522e74389SDaniel Scheller 	__ATTR(led0, 0664, led_show, led_store),
310622e74389SDaniel Scheller 	__ATTR(led1, 0664, led_show, led_store),
310722e74389SDaniel Scheller 	__ATTR(led2, 0664, led_show, led_store),
310822e74389SDaniel Scheller 	__ATTR(led3, 0664, led_show, led_store),
310922e74389SDaniel Scheller };
311022e74389SDaniel Scheller 
311122e74389SDaniel Scheller static struct device_attribute ddb_attrs_fanspeed[] = {
311222e74389SDaniel Scheller 	__ATTR_MRO(fanspeed0, fanspeed_show),
311322e74389SDaniel Scheller 	__ATTR_MRO(fanspeed1, fanspeed_show),
311422e74389SDaniel Scheller 	__ATTR_MRO(fanspeed2, fanspeed_show),
311522e74389SDaniel Scheller 	__ATTR_MRO(fanspeed3, fanspeed_show),
311622e74389SDaniel Scheller };
311722e74389SDaniel Scheller 
311822e74389SDaniel Scheller static struct class ddb_class = {
311922e74389SDaniel Scheller 	.name		= "ddbridge",
312022e74389SDaniel Scheller 	.devnode        = ddb_devnode,
312122e74389SDaniel Scheller };
312222e74389SDaniel Scheller 
ddb_class_create(void)312305ed62daSDaniel Scheller static int ddb_class_create(void)
312425aee3deSMauro Carvalho Chehab {
312525aee3deSMauro Carvalho Chehab 	ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
312625aee3deSMauro Carvalho Chehab 	if (ddb_major < 0)
312725aee3deSMauro Carvalho Chehab 		return ddb_major;
312822e74389SDaniel Scheller 	if (class_register(&ddb_class) < 0)
312922e74389SDaniel Scheller 		return -1;
313025aee3deSMauro Carvalho Chehab 	return 0;
313125aee3deSMauro Carvalho Chehab }
313225aee3deSMauro Carvalho Chehab 
ddb_class_destroy(void)313305ed62daSDaniel Scheller static void ddb_class_destroy(void)
313425aee3deSMauro Carvalho Chehab {
313522e74389SDaniel Scheller 	class_unregister(&ddb_class);
313625aee3deSMauro Carvalho Chehab 	unregister_chrdev(ddb_major, DDB_NAME);
313725aee3deSMauro Carvalho Chehab }
313825aee3deSMauro Carvalho Chehab 
ddb_device_attrs_del(struct ddb * dev)313922e74389SDaniel Scheller static void ddb_device_attrs_del(struct ddb *dev)
314022e74389SDaniel Scheller {
314122e74389SDaniel Scheller 	int i;
314222e74389SDaniel Scheller 
314322e74389SDaniel Scheller 	for (i = 0; i < 4; i++)
314422e74389SDaniel Scheller 		if (dev->link[i].info && dev->link[i].info->tempmon_irq)
314522e74389SDaniel Scheller 			device_remove_file(dev->ddb_dev,
314622e74389SDaniel Scheller 					   &ddb_attrs_fanspeed[i]);
314722e74389SDaniel Scheller 	for (i = 0; i < dev->link[0].info->temp_num; i++)
314822e74389SDaniel Scheller 		device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]);
314922e74389SDaniel Scheller 	for (i = 0; i < dev->link[0].info->fan_num; i++)
315022e74389SDaniel Scheller 		device_remove_file(dev->ddb_dev, &ddb_attrs_fan[i]);
315122e74389SDaniel Scheller 	for (i = 0; i < dev->i2c_num && i < 4; i++) {
315222e74389SDaniel Scheller 		if (dev->link[0].info->led_num)
315322e74389SDaniel Scheller 			device_remove_file(dev->ddb_dev, &ddb_attrs_led[i]);
315422e74389SDaniel Scheller 		device_remove_file(dev->ddb_dev, &ddb_attrs_snr[i]);
315522e74389SDaniel Scheller 		device_remove_file(dev->ddb_dev, &ddb_attrs_ctemp[i]);
315622e74389SDaniel Scheller 	}
3157757d78d3SDaniel Scheller 	for (i = 0; ddb_attrs[i].attr.name; i++)
315822e74389SDaniel Scheller 		device_remove_file(dev->ddb_dev, &ddb_attrs[i]);
315922e74389SDaniel Scheller }
316022e74389SDaniel Scheller 
ddb_device_attrs_add(struct ddb * dev)316122e74389SDaniel Scheller static int ddb_device_attrs_add(struct ddb *dev)
316222e74389SDaniel Scheller {
316322e74389SDaniel Scheller 	int i;
316422e74389SDaniel Scheller 
3165757d78d3SDaniel Scheller 	for (i = 0; ddb_attrs[i].attr.name; i++)
316622e74389SDaniel Scheller 		if (device_create_file(dev->ddb_dev, &ddb_attrs[i]))
316722e74389SDaniel Scheller 			goto fail;
316822e74389SDaniel Scheller 	for (i = 0; i < dev->link[0].info->temp_num; i++)
316922e74389SDaniel Scheller 		if (device_create_file(dev->ddb_dev, &ddb_attrs_temp[i]))
317022e74389SDaniel Scheller 			goto fail;
317122e74389SDaniel Scheller 	for (i = 0; i < dev->link[0].info->fan_num; i++)
317222e74389SDaniel Scheller 		if (device_create_file(dev->ddb_dev, &ddb_attrs_fan[i]))
317322e74389SDaniel Scheller 			goto fail;
317422e74389SDaniel Scheller 	for (i = 0; (i < dev->i2c_num) && (i < 4); i++) {
317522e74389SDaniel Scheller 		if (device_create_file(dev->ddb_dev, &ddb_attrs_snr[i]))
317622e74389SDaniel Scheller 			goto fail;
317722e74389SDaniel Scheller 		if (device_create_file(dev->ddb_dev, &ddb_attrs_ctemp[i]))
317822e74389SDaniel Scheller 			goto fail;
317922e74389SDaniel Scheller 		if (dev->link[0].info->led_num)
318022e74389SDaniel Scheller 			if (device_create_file(dev->ddb_dev,
318122e74389SDaniel Scheller 					       &ddb_attrs_led[i]))
318222e74389SDaniel Scheller 				goto fail;
318322e74389SDaniel Scheller 	}
318422e74389SDaniel Scheller 	for (i = 0; i < 4; i++)
318522e74389SDaniel Scheller 		if (dev->link[i].info && dev->link[i].info->tempmon_irq)
318622e74389SDaniel Scheller 			if (device_create_file(dev->ddb_dev,
318722e74389SDaniel Scheller 					       &ddb_attrs_fanspeed[i]))
318822e74389SDaniel Scheller 				goto fail;
318922e74389SDaniel Scheller 	return 0;
319022e74389SDaniel Scheller fail:
319122e74389SDaniel Scheller 	return -1;
319222e74389SDaniel Scheller }
319322e74389SDaniel Scheller 
ddb_device_create(struct ddb * dev)3194a96e5ab8SDaniel Scheller int ddb_device_create(struct ddb *dev)
319525aee3deSMauro Carvalho Chehab {
319622e74389SDaniel Scheller 	int res = 0;
319722e74389SDaniel Scheller 
319822e74389SDaniel Scheller 	if (ddb_num == DDB_MAX_ADAPTER)
319922e74389SDaniel Scheller 		return -ENOMEM;
320022e74389SDaniel Scheller 	mutex_lock(&ddb_mutex);
320122e74389SDaniel Scheller 	dev->nr = ddb_num;
320222e74389SDaniel Scheller 	ddbs[dev->nr] = dev;
320322e74389SDaniel Scheller 	dev->ddb_dev = device_create(&ddb_class, dev->dev,
320425aee3deSMauro Carvalho Chehab 				     MKDEV(ddb_major, dev->nr),
320525aee3deSMauro Carvalho Chehab 				     dev, "ddbridge%d", dev->nr);
320622e74389SDaniel Scheller 	if (IS_ERR(dev->ddb_dev)) {
320722e74389SDaniel Scheller 		res = PTR_ERR(dev->ddb_dev);
320822e74389SDaniel Scheller 		dev_info(dev->dev, "Could not create ddbridge%d\n", dev->nr);
320922e74389SDaniel Scheller 		goto fail;
321022e74389SDaniel Scheller 	}
321122e74389SDaniel Scheller 	res = ddb_device_attrs_add(dev);
321222e74389SDaniel Scheller 	if (res) {
321322e74389SDaniel Scheller 		ddb_device_attrs_del(dev);
321422e74389SDaniel Scheller 		device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr));
3215b5967860SDaniel Scheller 		ddbs[dev->nr] = NULL;
321622e74389SDaniel Scheller 		dev->ddb_dev = ERR_PTR(-ENODEV);
3217757d78d3SDaniel Scheller 	} else {
321822e74389SDaniel Scheller 		ddb_num++;
3219757d78d3SDaniel Scheller 	}
322022e74389SDaniel Scheller fail:
322122e74389SDaniel Scheller 	mutex_unlock(&ddb_mutex);
322222e74389SDaniel Scheller 	return res;
322325aee3deSMauro Carvalho Chehab }
322425aee3deSMauro Carvalho Chehab 
ddb_device_destroy(struct ddb * dev)3225a96e5ab8SDaniel Scheller void ddb_device_destroy(struct ddb *dev)
322625aee3deSMauro Carvalho Chehab {
322725aee3deSMauro Carvalho Chehab 	if (IS_ERR(dev->ddb_dev))
322825aee3deSMauro Carvalho Chehab 		return;
322922e74389SDaniel Scheller 	ddb_device_attrs_del(dev);
323022e74389SDaniel Scheller 	device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr));
323122e74389SDaniel Scheller }
323222e74389SDaniel Scheller 
323322e74389SDaniel Scheller /****************************************************************************/
323422e74389SDaniel Scheller /****************************************************************************/
323522e74389SDaniel Scheller /****************************************************************************/
323622e74389SDaniel Scheller 
tempmon_setfan(struct ddb_link * link)323722e74389SDaniel Scheller static void tempmon_setfan(struct ddb_link *link)
323822e74389SDaniel Scheller {
323922e74389SDaniel Scheller 	u32 temp, temp2, pwm;
324022e74389SDaniel Scheller 
324122e74389SDaniel Scheller 	if ((ddblreadl(link, TEMPMON_CONTROL) &
324222e74389SDaniel Scheller 	    TEMPMON_CONTROL_OVERTEMP) != 0) {
324322e74389SDaniel Scheller 		dev_info(link->dev->dev, "Over temperature condition\n");
324422e74389SDaniel Scheller 		link->overtemperature_error = 1;
324522e74389SDaniel Scheller 	}
324622e74389SDaniel Scheller 	temp  = (ddblreadl(link, TEMPMON_SENSOR0) >> 8) & 0xFF;
324722e74389SDaniel Scheller 	if (temp & 0x80)
324822e74389SDaniel Scheller 		temp = 0;
324922e74389SDaniel Scheller 	temp2  = (ddblreadl(link, TEMPMON_SENSOR1) >> 8) & 0xFF;
325022e74389SDaniel Scheller 	if (temp2 & 0x80)
325122e74389SDaniel Scheller 		temp2 = 0;
325222e74389SDaniel Scheller 	if (temp2 > temp)
325322e74389SDaniel Scheller 		temp = temp2;
325422e74389SDaniel Scheller 
325522e74389SDaniel Scheller 	pwm = (ddblreadl(link, TEMPMON_FANCONTROL) >> 8) & 0x0F;
325622e74389SDaniel Scheller 	if (pwm > 10)
325722e74389SDaniel Scheller 		pwm = 10;
325822e74389SDaniel Scheller 
325922e74389SDaniel Scheller 	if (temp >= link->temp_tab[pwm]) {
326022e74389SDaniel Scheller 		while (pwm < 10 && temp >= link->temp_tab[pwm + 1])
326122e74389SDaniel Scheller 			pwm += 1;
326222e74389SDaniel Scheller 	} else {
326322e74389SDaniel Scheller 		while (pwm > 1 && temp < link->temp_tab[pwm - 2])
326422e74389SDaniel Scheller 			pwm -= 1;
326522e74389SDaniel Scheller 	}
326622e74389SDaniel Scheller 	ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL);
326722e74389SDaniel Scheller }
326822e74389SDaniel Scheller 
temp_handler(void * data)32691dda87acSDaniel Scheller static void temp_handler(void *data)
327022e74389SDaniel Scheller {
327122e74389SDaniel Scheller 	struct ddb_link *link = (struct ddb_link *)data;
327222e74389SDaniel Scheller 
327322e74389SDaniel Scheller 	spin_lock(&link->temp_lock);
327422e74389SDaniel Scheller 	tempmon_setfan(link);
327522e74389SDaniel Scheller 	spin_unlock(&link->temp_lock);
327622e74389SDaniel Scheller }
327722e74389SDaniel Scheller 
tempmon_init(struct ddb_link * link,int first_time)327822e74389SDaniel Scheller static int tempmon_init(struct ddb_link *link, int first_time)
327922e74389SDaniel Scheller {
328022e74389SDaniel Scheller 	struct ddb *dev = link->dev;
328122e74389SDaniel Scheller 	int status = 0;
328222e74389SDaniel Scheller 	u32 l = link->nr;
328322e74389SDaniel Scheller 
328422e74389SDaniel Scheller 	spin_lock_irq(&link->temp_lock);
328522e74389SDaniel Scheller 	if (first_time) {
328622e74389SDaniel Scheller 		static u8 temperature_table[11] = {
328722e74389SDaniel Scheller 			30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80 };
328822e74389SDaniel Scheller 
328922e74389SDaniel Scheller 		memcpy(link->temp_tab, temperature_table,
329022e74389SDaniel Scheller 		       sizeof(temperature_table));
329122e74389SDaniel Scheller 	}
32921dda87acSDaniel Scheller 	ddb_irq_set(dev, l, link->info->tempmon_irq, temp_handler, link);
329322e74389SDaniel Scheller 	ddblwritel(link, (TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN |
329422e74389SDaniel Scheller 			  TEMPMON_CONTROL_INTENABLE),
329522e74389SDaniel Scheller 		   TEMPMON_CONTROL);
329622e74389SDaniel Scheller 	ddblwritel(link, (3 << 8), TEMPMON_FANCONTROL);
329722e74389SDaniel Scheller 
329822e74389SDaniel Scheller 	link->overtemperature_error =
329922e74389SDaniel Scheller 		((ddblreadl(link, TEMPMON_CONTROL) &
330022e74389SDaniel Scheller 			TEMPMON_CONTROL_OVERTEMP) != 0);
330122e74389SDaniel Scheller 	if (link->overtemperature_error) {
330222e74389SDaniel Scheller 		dev_info(link->dev->dev, "Over temperature condition\n");
330322e74389SDaniel Scheller 		status = -1;
330422e74389SDaniel Scheller 	}
330522e74389SDaniel Scheller 	tempmon_setfan(link);
330622e74389SDaniel Scheller 	spin_unlock_irq(&link->temp_lock);
330722e74389SDaniel Scheller 	return status;
330822e74389SDaniel Scheller }
330922e74389SDaniel Scheller 
ddb_init_tempmon(struct ddb_link * link)331022e74389SDaniel Scheller static int ddb_init_tempmon(struct ddb_link *link)
331122e74389SDaniel Scheller {
331266cc3d98SDaniel Scheller 	const struct ddb_info *info = link->info;
331322e74389SDaniel Scheller 
331422e74389SDaniel Scheller 	if (!info->tempmon_irq)
331522e74389SDaniel Scheller 		return 0;
331622e74389SDaniel Scheller 	if (info->type == DDB_OCTOPUS_MAX_CT)
331722e74389SDaniel Scheller 		if (link->ids.regmapid < 0x00010002)
331822e74389SDaniel Scheller 			return 0;
331922e74389SDaniel Scheller 	spin_lock_init(&link->temp_lock);
332022e74389SDaniel Scheller 	dev_dbg(link->dev->dev, "init_tempmon\n");
332122e74389SDaniel Scheller 	return tempmon_init(link, 1);
332222e74389SDaniel Scheller }
332322e74389SDaniel Scheller 
332422e74389SDaniel Scheller /****************************************************************************/
332522e74389SDaniel Scheller /****************************************************************************/
332622e74389SDaniel Scheller /****************************************************************************/
332722e74389SDaniel Scheller 
ddb_init_boards(struct ddb * dev)332822e74389SDaniel Scheller static int ddb_init_boards(struct ddb *dev)
332922e74389SDaniel Scheller {
333066cc3d98SDaniel Scheller 	const struct ddb_info *info;
333122e74389SDaniel Scheller 	struct ddb_link *link;
333222e74389SDaniel Scheller 	u32 l;
333322e74389SDaniel Scheller 
333422e74389SDaniel Scheller 	for (l = 0; l < DDB_MAX_LINK; l++) {
333522e74389SDaniel Scheller 		link = &dev->link[l];
333622e74389SDaniel Scheller 		info = link->info;
333722e74389SDaniel Scheller 
333822e74389SDaniel Scheller 		if (!info)
333922e74389SDaniel Scheller 			continue;
334022e74389SDaniel Scheller 		if (info->board_control) {
334122e74389SDaniel Scheller 			ddbwritel(dev, 0, DDB_LINK_TAG(l) | BOARD_CONTROL);
334222e74389SDaniel Scheller 			msleep(100);
334322e74389SDaniel Scheller 			ddbwritel(dev, info->board_control_2,
334422e74389SDaniel Scheller 				  DDB_LINK_TAG(l) | BOARD_CONTROL);
334522e74389SDaniel Scheller 			usleep_range(2000, 3000);
334622e74389SDaniel Scheller 			ddbwritel(dev,
334722e74389SDaniel Scheller 				  info->board_control_2 | info->board_control,
334822e74389SDaniel Scheller 				  DDB_LINK_TAG(l) | BOARD_CONTROL);
334922e74389SDaniel Scheller 			usleep_range(2000, 3000);
335022e74389SDaniel Scheller 		}
335122e74389SDaniel Scheller 		ddb_init_tempmon(link);
335222e74389SDaniel Scheller 	}
335322e74389SDaniel Scheller 	return 0;
335422e74389SDaniel Scheller }
335522e74389SDaniel Scheller 
ddb_init(struct ddb * dev)335622e74389SDaniel Scheller int ddb_init(struct ddb *dev)
335722e74389SDaniel Scheller {
3358bb4cec96SDaniel Scheller 	mutex_init(&dev->link[0].lnb.lock);
335922e74389SDaniel Scheller 	mutex_init(&dev->link[0].flash_mutex);
336022e74389SDaniel Scheller 	if (no_init) {
336122e74389SDaniel Scheller 		ddb_device_create(dev);
336222e74389SDaniel Scheller 		return 0;
336322e74389SDaniel Scheller 	}
336422e74389SDaniel Scheller 
336522e74389SDaniel Scheller 	ddb_init_boards(dev);
336622e74389SDaniel Scheller 
336722e74389SDaniel Scheller 	if (ddb_i2c_init(dev) < 0)
3368b7b9a5a9SDaniel Scheller 		goto fail1;
336922e74389SDaniel Scheller 	ddb_ports_init(dev);
337022e74389SDaniel Scheller 	if (ddb_buffers_alloc(dev) < 0) {
337122e74389SDaniel Scheller 		dev_info(dev->dev, "Could not allocate buffer memory\n");
337222e74389SDaniel Scheller 		goto fail2;
337322e74389SDaniel Scheller 	}
337422e74389SDaniel Scheller 	if (ddb_ports_attach(dev) < 0)
337522e74389SDaniel Scheller 		goto fail3;
337622e74389SDaniel Scheller 
337722e74389SDaniel Scheller 	ddb_device_create(dev);
337822e74389SDaniel Scheller 
337922e74389SDaniel Scheller 	if (dev->link[0].info->fan_num)	{
338022e74389SDaniel Scheller 		ddbwritel(dev, 1, GPIO_DIRECTION);
338122e74389SDaniel Scheller 		ddbwritel(dev, 1, GPIO_OUTPUT);
338222e74389SDaniel Scheller 	}
338322e74389SDaniel Scheller 	return 0;
338422e74389SDaniel Scheller 
338522e74389SDaniel Scheller fail3:
338622e74389SDaniel Scheller 	dev_err(dev->dev, "fail3\n");
3387b7b9a5a9SDaniel Scheller 	ddb_ports_detach(dev);
3388b7b9a5a9SDaniel Scheller 	ddb_buffers_free(dev);
338922e74389SDaniel Scheller fail2:
339022e74389SDaniel Scheller 	dev_err(dev->dev, "fail2\n");
3391b7b9a5a9SDaniel Scheller 	ddb_ports_release(dev);
339222e74389SDaniel Scheller 	ddb_i2c_release(dev);
3393b7b9a5a9SDaniel Scheller fail1:
339422e74389SDaniel Scheller 	dev_err(dev->dev, "fail1\n");
339522e74389SDaniel Scheller 	return -1;
339625aee3deSMauro Carvalho Chehab }
33978e4eef22SDaniel Scheller 
ddb_unmap(struct ddb * dev)33988e4eef22SDaniel Scheller void ddb_unmap(struct ddb *dev)
33998e4eef22SDaniel Scheller {
34008e4eef22SDaniel Scheller 	if (dev->regs)
34018e4eef22SDaniel Scheller 		iounmap(dev->regs);
34028e4eef22SDaniel Scheller 	vfree(dev);
34038e4eef22SDaniel Scheller }
340405ed62daSDaniel Scheller 
ddb_exit_ddbridge(int stage,int error)340505ed62daSDaniel Scheller int ddb_exit_ddbridge(int stage, int error)
340605ed62daSDaniel Scheller {
340705ed62daSDaniel Scheller 	switch (stage) {
340805ed62daSDaniel Scheller 	default:
340905ed62daSDaniel Scheller 	case 2:
341005ed62daSDaniel Scheller 		destroy_workqueue(ddb_wq);
3411df561f66SGustavo A. R. Silva 		fallthrough;
341205ed62daSDaniel Scheller 	case 1:
341305ed62daSDaniel Scheller 		ddb_class_destroy();
341405ed62daSDaniel Scheller 		break;
341505ed62daSDaniel Scheller 	}
341605ed62daSDaniel Scheller 
341705ed62daSDaniel Scheller 	return error;
341805ed62daSDaniel Scheller }
341905ed62daSDaniel Scheller 
ddb_init_ddbridge(void)342005ed62daSDaniel Scheller int ddb_init_ddbridge(void)
342105ed62daSDaniel Scheller {
34220a68fc44SDaniel Scheller 	if (dma_buf_num < 8)
34230a68fc44SDaniel Scheller 		dma_buf_num = 8;
34240a68fc44SDaniel Scheller 	if (dma_buf_num > 32)
34250a68fc44SDaniel Scheller 		dma_buf_num = 32;
34260a68fc44SDaniel Scheller 	if (dma_buf_size < 1)
34270a68fc44SDaniel Scheller 		dma_buf_size = 1;
34280a68fc44SDaniel Scheller 	if (dma_buf_size > 43)
34290a68fc44SDaniel Scheller 		dma_buf_size = 43;
34300a68fc44SDaniel Scheller 
343105ed62daSDaniel Scheller 	if (ddb_class_create() < 0)
343205ed62daSDaniel Scheller 		return -1;
343305ed62daSDaniel Scheller 	ddb_wq = alloc_workqueue("ddbridge", 0, 0);
343405ed62daSDaniel Scheller 	if (!ddb_wq)
343505ed62daSDaniel Scheller 		return ddb_exit_ddbridge(1, -1);
343605ed62daSDaniel Scheller 
343705ed62daSDaniel Scheller 	return 0;
343805ed62daSDaniel Scheller }
3439