174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
225aee3deSMauro Carvalho Chehab /*
325aee3deSMauro Carvalho Chehab Mantis PCI bridge driver
425aee3deSMauro Carvalho Chehab Copyright (C) Manu Abraham (abraham.manu@gmail.com)
525aee3deSMauro Carvalho Chehab
625aee3deSMauro Carvalho Chehab */
725aee3deSMauro Carvalho Chehab
825aee3deSMauro Carvalho Chehab #include <linux/kernel.h>
925aee3deSMauro Carvalho Chehab #include <linux/bitops.h>
1025aee3deSMauro Carvalho Chehab
1125aee3deSMauro Carvalho Chehab #include <linux/signal.h>
1225aee3deSMauro Carvalho Chehab #include <linux/sched.h>
1325aee3deSMauro Carvalho Chehab #include <linux/interrupt.h>
1425aee3deSMauro Carvalho Chehab #include <linux/pci.h>
1525aee3deSMauro Carvalho Chehab #include <linux/i2c.h>
1625aee3deSMauro Carvalho Chehab
17fada1935SMauro Carvalho Chehab #include <media/dmxdev.h>
18fada1935SMauro Carvalho Chehab #include <media/dvbdev.h>
19fada1935SMauro Carvalho Chehab #include <media/dvb_demux.h>
20fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
21fada1935SMauro Carvalho Chehab #include <media/dvb_net.h>
2225aee3deSMauro Carvalho Chehab
2325aee3deSMauro Carvalho Chehab #include "mantis_common.h"
2425aee3deSMauro Carvalho Chehab #include "mantis_dma.h"
2525aee3deSMauro Carvalho Chehab #include "mantis_ca.h"
2625aee3deSMauro Carvalho Chehab #include "mantis_ioc.h"
2725aee3deSMauro Carvalho Chehab #include "mantis_dvb.h"
2825aee3deSMauro Carvalho Chehab
2925aee3deSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
3025aee3deSMauro Carvalho Chehab
mantis_frontend_power(struct mantis_pci * mantis,enum mantis_power power)3125aee3deSMauro Carvalho Chehab int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
3225aee3deSMauro Carvalho Chehab {
3325aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config = mantis->hwconfig;
3425aee3deSMauro Carvalho Chehab
3525aee3deSMauro Carvalho Chehab switch (power) {
3625aee3deSMauro Carvalho Chehab case POWER_ON:
3725aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Power ON");
3825aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->power, POWER_ON);
3925aee3deSMauro Carvalho Chehab msleep(100);
4025aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->power, POWER_ON);
4125aee3deSMauro Carvalho Chehab msleep(100);
4225aee3deSMauro Carvalho Chehab break;
4325aee3deSMauro Carvalho Chehab
4425aee3deSMauro Carvalho Chehab case POWER_OFF:
4525aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Power OFF");
4625aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
4725aee3deSMauro Carvalho Chehab msleep(100);
4825aee3deSMauro Carvalho Chehab break;
4925aee3deSMauro Carvalho Chehab
5025aee3deSMauro Carvalho Chehab default:
5125aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
5225aee3deSMauro Carvalho Chehab return -1;
5325aee3deSMauro Carvalho Chehab }
5425aee3deSMauro Carvalho Chehab
5525aee3deSMauro Carvalho Chehab return 0;
5625aee3deSMauro Carvalho Chehab }
5725aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_frontend_power);
5825aee3deSMauro Carvalho Chehab
mantis_frontend_soft_reset(struct mantis_pci * mantis)5925aee3deSMauro Carvalho Chehab void mantis_frontend_soft_reset(struct mantis_pci *mantis)
6025aee3deSMauro Carvalho Chehab {
6125aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config = mantis->hwconfig;
6225aee3deSMauro Carvalho Chehab
6325aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
6425aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 0);
6525aee3deSMauro Carvalho Chehab msleep(100);
6625aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 0);
6725aee3deSMauro Carvalho Chehab msleep(100);
6825aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 1);
6925aee3deSMauro Carvalho Chehab msleep(100);
7025aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 1);
7125aee3deSMauro Carvalho Chehab msleep(100);
7225aee3deSMauro Carvalho Chehab
7325aee3deSMauro Carvalho Chehab return;
7425aee3deSMauro Carvalho Chehab }
7525aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
7625aee3deSMauro Carvalho Chehab
mantis_frontend_shutdown(struct mantis_pci * mantis)7725aee3deSMauro Carvalho Chehab static int mantis_frontend_shutdown(struct mantis_pci *mantis)
7825aee3deSMauro Carvalho Chehab {
7925aee3deSMauro Carvalho Chehab int err;
8025aee3deSMauro Carvalho Chehab
8125aee3deSMauro Carvalho Chehab mantis_frontend_soft_reset(mantis);
8225aee3deSMauro Carvalho Chehab err = mantis_frontend_power(mantis, POWER_OFF);
8325aee3deSMauro Carvalho Chehab if (err != 0) {
8425aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
8525aee3deSMauro Carvalho Chehab return 1;
8625aee3deSMauro Carvalho Chehab }
8725aee3deSMauro Carvalho Chehab
8825aee3deSMauro Carvalho Chehab return 0;
8925aee3deSMauro Carvalho Chehab }
9025aee3deSMauro Carvalho Chehab
mantis_dvb_start_feed(struct dvb_demux_feed * dvbdmxfeed)9125aee3deSMauro Carvalho Chehab static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
9225aee3deSMauro Carvalho Chehab {
9325aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
9425aee3deSMauro Carvalho Chehab struct mantis_pci *mantis = dvbdmx->priv;
9525aee3deSMauro Carvalho Chehab
9625aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
9725aee3deSMauro Carvalho Chehab if (!dvbdmx->dmx.frontend) {
9825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "no frontend ?");
9925aee3deSMauro Carvalho Chehab return -EINVAL;
10025aee3deSMauro Carvalho Chehab }
10125aee3deSMauro Carvalho Chehab
10225aee3deSMauro Carvalho Chehab mantis->feeds++;
10325aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
10425aee3deSMauro Carvalho Chehab
10525aee3deSMauro Carvalho Chehab if (mantis->feeds == 1) {
10625aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
10725aee3deSMauro Carvalho Chehab mantis_dma_start(mantis);
10825aee3deSMauro Carvalho Chehab tasklet_enable(&mantis->tasklet);
10925aee3deSMauro Carvalho Chehab }
11025aee3deSMauro Carvalho Chehab
11125aee3deSMauro Carvalho Chehab return mantis->feeds;
11225aee3deSMauro Carvalho Chehab }
11325aee3deSMauro Carvalho Chehab
mantis_dvb_stop_feed(struct dvb_demux_feed * dvbdmxfeed)11425aee3deSMauro Carvalho Chehab static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
11525aee3deSMauro Carvalho Chehab {
11625aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
11725aee3deSMauro Carvalho Chehab struct mantis_pci *mantis = dvbdmx->priv;
11825aee3deSMauro Carvalho Chehab
11925aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
12025aee3deSMauro Carvalho Chehab if (!dvbdmx->dmx.frontend) {
12125aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "no frontend ?");
12225aee3deSMauro Carvalho Chehab return -EINVAL;
12325aee3deSMauro Carvalho Chehab }
12425aee3deSMauro Carvalho Chehab
12525aee3deSMauro Carvalho Chehab mantis->feeds--;
12625aee3deSMauro Carvalho Chehab if (mantis->feeds == 0) {
12725aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
12825aee3deSMauro Carvalho Chehab tasklet_disable(&mantis->tasklet);
12925aee3deSMauro Carvalho Chehab mantis_dma_stop(mantis);
13025aee3deSMauro Carvalho Chehab }
13125aee3deSMauro Carvalho Chehab
13225aee3deSMauro Carvalho Chehab return 0;
13325aee3deSMauro Carvalho Chehab }
13425aee3deSMauro Carvalho Chehab
mantis_dvb_init(struct mantis_pci * mantis)1354c62e976SGreg Kroah-Hartman int mantis_dvb_init(struct mantis_pci *mantis)
13625aee3deSMauro Carvalho Chehab {
13725aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config = mantis->hwconfig;
13877d30eabSColin Ian King int result;
13925aee3deSMauro Carvalho Chehab
14025aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
14125aee3deSMauro Carvalho Chehab
14225aee3deSMauro Carvalho Chehab result = dvb_register_adapter(&mantis->dvb_adapter,
14325aee3deSMauro Carvalho Chehab "Mantis DVB adapter",
14425aee3deSMauro Carvalho Chehab THIS_MODULE,
14525aee3deSMauro Carvalho Chehab &mantis->pdev->dev,
14625aee3deSMauro Carvalho Chehab adapter_nr);
14725aee3deSMauro Carvalho Chehab
14825aee3deSMauro Carvalho Chehab if (result < 0) {
14925aee3deSMauro Carvalho Chehab
15025aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Error registering adapter");
15125aee3deSMauro Carvalho Chehab return -ENODEV;
15225aee3deSMauro Carvalho Chehab }
15325aee3deSMauro Carvalho Chehab
15425aee3deSMauro Carvalho Chehab mantis->dvb_adapter.priv = mantis;
15525aee3deSMauro Carvalho Chehab mantis->demux.dmx.capabilities = DMX_TS_FILTERING |
15625aee3deSMauro Carvalho Chehab DMX_SECTION_FILTERING |
15725aee3deSMauro Carvalho Chehab DMX_MEMORY_BASED_FILTERING;
15825aee3deSMauro Carvalho Chehab
15925aee3deSMauro Carvalho Chehab mantis->demux.priv = mantis;
16025aee3deSMauro Carvalho Chehab mantis->demux.filternum = 256;
16125aee3deSMauro Carvalho Chehab mantis->demux.feednum = 256;
16225aee3deSMauro Carvalho Chehab mantis->demux.start_feed = mantis_dvb_start_feed;
16325aee3deSMauro Carvalho Chehab mantis->demux.stop_feed = mantis_dvb_stop_feed;
16425aee3deSMauro Carvalho Chehab mantis->demux.write_to_decoder = NULL;
16525aee3deSMauro Carvalho Chehab
16625aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
16725aee3deSMauro Carvalho Chehab result = dvb_dmx_init(&mantis->demux);
16825aee3deSMauro Carvalho Chehab if (result < 0) {
16925aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
17025aee3deSMauro Carvalho Chehab
17125aee3deSMauro Carvalho Chehab goto err0;
17225aee3deSMauro Carvalho Chehab }
17325aee3deSMauro Carvalho Chehab
17425aee3deSMauro Carvalho Chehab mantis->dmxdev.filternum = 256;
17525aee3deSMauro Carvalho Chehab mantis->dmxdev.demux = &mantis->demux.dmx;
17625aee3deSMauro Carvalho Chehab mantis->dmxdev.capabilities = 0;
17725aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
17825aee3deSMauro Carvalho Chehab
17925aee3deSMauro Carvalho Chehab result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
18025aee3deSMauro Carvalho Chehab if (result < 0) {
18125aee3deSMauro Carvalho Chehab
18225aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
18325aee3deSMauro Carvalho Chehab goto err1;
18425aee3deSMauro Carvalho Chehab }
18525aee3deSMauro Carvalho Chehab
18625aee3deSMauro Carvalho Chehab mantis->fe_hw.source = DMX_FRONTEND_0;
18725aee3deSMauro Carvalho Chehab result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
18825aee3deSMauro Carvalho Chehab if (result < 0) {
18925aee3deSMauro Carvalho Chehab
19025aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
19125aee3deSMauro Carvalho Chehab goto err2;
19225aee3deSMauro Carvalho Chehab }
19325aee3deSMauro Carvalho Chehab
19425aee3deSMauro Carvalho Chehab mantis->fe_mem.source = DMX_MEMORY_FE;
19525aee3deSMauro Carvalho Chehab result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
19625aee3deSMauro Carvalho Chehab if (result < 0) {
19725aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
19825aee3deSMauro Carvalho Chehab goto err3;
19925aee3deSMauro Carvalho Chehab }
20025aee3deSMauro Carvalho Chehab
20125aee3deSMauro Carvalho Chehab result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
20225aee3deSMauro Carvalho Chehab if (result < 0) {
20325aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
20425aee3deSMauro Carvalho Chehab goto err4;
20525aee3deSMauro Carvalho Chehab }
20625aee3deSMauro Carvalho Chehab
20725aee3deSMauro Carvalho Chehab dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
2084cf709c9SAllen Pais tasklet_setup(&mantis->tasklet, mantis_dma_xfer);
20925aee3deSMauro Carvalho Chehab tasklet_disable(&mantis->tasklet);
21025aee3deSMauro Carvalho Chehab if (mantis->hwconfig) {
21125aee3deSMauro Carvalho Chehab result = config->frontend_init(mantis, mantis->fe);
21225aee3deSMauro Carvalho Chehab if (result < 0) {
21325aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
21425aee3deSMauro Carvalho Chehab goto err5;
21525aee3deSMauro Carvalho Chehab } else {
21625aee3deSMauro Carvalho Chehab if (mantis->fe == NULL) {
21779a2eda8SDan Carpenter result = -ENOMEM;
21825aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "FE <NULL>");
21925aee3deSMauro Carvalho Chehab goto err5;
22025aee3deSMauro Carvalho Chehab }
22179a2eda8SDan Carpenter result = dvb_register_frontend(&mantis->dvb_adapter, mantis->fe);
22279a2eda8SDan Carpenter if (result) {
22325aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
22425aee3deSMauro Carvalho Chehab
22525aee3deSMauro Carvalho Chehab if (mantis->fe->ops.release)
22625aee3deSMauro Carvalho Chehab mantis->fe->ops.release(mantis->fe);
22725aee3deSMauro Carvalho Chehab
22825aee3deSMauro Carvalho Chehab mantis->fe = NULL;
22925aee3deSMauro Carvalho Chehab goto err5;
23025aee3deSMauro Carvalho Chehab }
23125aee3deSMauro Carvalho Chehab }
23225aee3deSMauro Carvalho Chehab }
23325aee3deSMauro Carvalho Chehab
23425aee3deSMauro Carvalho Chehab return 0;
23525aee3deSMauro Carvalho Chehab
23625aee3deSMauro Carvalho Chehab /* Error conditions .. */
23725aee3deSMauro Carvalho Chehab err5:
23825aee3deSMauro Carvalho Chehab tasklet_kill(&mantis->tasklet);
23925aee3deSMauro Carvalho Chehab dvb_net_release(&mantis->dvbnet);
24025aee3deSMauro Carvalho Chehab if (mantis->fe) {
24125aee3deSMauro Carvalho Chehab dvb_unregister_frontend(mantis->fe);
24225aee3deSMauro Carvalho Chehab dvb_frontend_detach(mantis->fe);
24325aee3deSMauro Carvalho Chehab }
24425aee3deSMauro Carvalho Chehab err4:
24525aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
24625aee3deSMauro Carvalho Chehab
24725aee3deSMauro Carvalho Chehab err3:
24825aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
24925aee3deSMauro Carvalho Chehab
25025aee3deSMauro Carvalho Chehab err2:
25125aee3deSMauro Carvalho Chehab dvb_dmxdev_release(&mantis->dmxdev);
25225aee3deSMauro Carvalho Chehab
25325aee3deSMauro Carvalho Chehab err1:
25425aee3deSMauro Carvalho Chehab dvb_dmx_release(&mantis->demux);
25525aee3deSMauro Carvalho Chehab
25625aee3deSMauro Carvalho Chehab err0:
25725aee3deSMauro Carvalho Chehab dvb_unregister_adapter(&mantis->dvb_adapter);
25825aee3deSMauro Carvalho Chehab
25925aee3deSMauro Carvalho Chehab return result;
26025aee3deSMauro Carvalho Chehab }
26125aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_dvb_init);
26225aee3deSMauro Carvalho Chehab
mantis_dvb_exit(struct mantis_pci * mantis)2634c62e976SGreg Kroah-Hartman int mantis_dvb_exit(struct mantis_pci *mantis)
26425aee3deSMauro Carvalho Chehab {
26525aee3deSMauro Carvalho Chehab int err;
26625aee3deSMauro Carvalho Chehab
26725aee3deSMauro Carvalho Chehab if (mantis->fe) {
26825aee3deSMauro Carvalho Chehab /* mantis_ca_exit(mantis); */
26925aee3deSMauro Carvalho Chehab err = mantis_frontend_shutdown(mantis);
27025aee3deSMauro Carvalho Chehab if (err != 0)
27125aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
27225aee3deSMauro Carvalho Chehab dvb_unregister_frontend(mantis->fe);
27325aee3deSMauro Carvalho Chehab dvb_frontend_detach(mantis->fe);
27425aee3deSMauro Carvalho Chehab }
27525aee3deSMauro Carvalho Chehab
27625aee3deSMauro Carvalho Chehab tasklet_kill(&mantis->tasklet);
27725aee3deSMauro Carvalho Chehab dvb_net_release(&mantis->dvbnet);
27825aee3deSMauro Carvalho Chehab
27925aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
28025aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
28125aee3deSMauro Carvalho Chehab
28225aee3deSMauro Carvalho Chehab dvb_dmxdev_release(&mantis->dmxdev);
28325aee3deSMauro Carvalho Chehab dvb_dmx_release(&mantis->demux);
28425aee3deSMauro Carvalho Chehab
28525aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
28625aee3deSMauro Carvalho Chehab dvb_unregister_adapter(&mantis->dvb_adapter);
28725aee3deSMauro Carvalho Chehab
28825aee3deSMauro Carvalho Chehab return 0;
28925aee3deSMauro Carvalho Chehab }
29025aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_dvb_exit);
291