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