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 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 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 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 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 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 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); 20825aee3deSMauro Carvalho Chehab tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); 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 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