18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci	Mantis PCI bridge driver
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci*/
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/signal.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/sched.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <asm/io.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <media/dmxdev.h>
168c2ecf20Sopenharmony_ci#include <media/dvbdev.h>
178c2ecf20Sopenharmony_ci#include <media/dvb_demux.h>
188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
198c2ecf20Sopenharmony_ci#include <media/dvb_net.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "mantis_common.h"
228c2ecf20Sopenharmony_ci#include "mantis_link.h"
238c2ecf20Sopenharmony_ci#include "mantis_hif.h"
248c2ecf20Sopenharmony_ci#include "mantis_reg.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "mantis_ca.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
318c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (slot != 0)
368c2ecf20Sopenharmony_ci		return -EINVAL;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	return mantis_hif_read_mem(ca, addr);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
448c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (slot != 0)
498c2ecf20Sopenharmony_ci		return -EINVAL;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return mantis_hif_write_mem(ca, addr, data);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
578c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (slot != 0)
628c2ecf20Sopenharmony_ci		return -EINVAL;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return mantis_hif_read_iom(ca, addr);
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
708c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (slot != 0)
758c2ecf20Sopenharmony_ci		return -EINVAL;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return mantis_hif_write_iom(ca, addr, data);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
838c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
868c2ecf20Sopenharmony_ci	udelay(500); /* Wait.. */
878c2ecf20Sopenharmony_ci	mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
888c2ecf20Sopenharmony_ci	udelay(500);
898c2ecf20Sopenharmony_ci	mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
908c2ecf20Sopenharmony_ci	msleep(1000);
918c2ecf20Sopenharmony_ci	dvb_ca_en50221_camready_irq(&ca->en50221, 0);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return 0;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
998c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
1098c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
1128c2ecf20Sopenharmony_ci/*	mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
1208c2ecf20Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (ca->slot_state == MODULE_INSERTED) {
1258c2ecf20Sopenharmony_ci		dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
1268c2ecf20Sopenharmony_ci		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
1278c2ecf20Sopenharmony_ci	} else {
1288c2ecf20Sopenharmony_ci		dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciint mantis_ca_init(struct mantis_pci *mantis)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct dvb_adapter *dvb_adapter	= &mantis->dvb_adapter;
1378c2ecf20Sopenharmony_ci	struct mantis_ca *ca;
1388c2ecf20Sopenharmony_ci	int ca_flags = 0, result;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
1418c2ecf20Sopenharmony_ci	ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
1428c2ecf20Sopenharmony_ci	if (!ca) {
1438c2ecf20Sopenharmony_ci		dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
1448c2ecf20Sopenharmony_ci		result = -ENOMEM;
1458c2ecf20Sopenharmony_ci		goto err;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	ca->ca_priv		= mantis;
1498c2ecf20Sopenharmony_ci	mantis->mantis_ca	= ca;
1508c2ecf20Sopenharmony_ci	ca_flags		= DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
1518c2ecf20Sopenharmony_ci	/* register CA interface */
1528c2ecf20Sopenharmony_ci	ca->en50221.owner		= THIS_MODULE;
1538c2ecf20Sopenharmony_ci	ca->en50221.read_attribute_mem	= mantis_ca_read_attr_mem;
1548c2ecf20Sopenharmony_ci	ca->en50221.write_attribute_mem	= mantis_ca_write_attr_mem;
1558c2ecf20Sopenharmony_ci	ca->en50221.read_cam_control	= mantis_ca_read_cam_ctl;
1568c2ecf20Sopenharmony_ci	ca->en50221.write_cam_control	= mantis_ca_write_cam_ctl;
1578c2ecf20Sopenharmony_ci	ca->en50221.slot_reset		= mantis_ca_slot_reset;
1588c2ecf20Sopenharmony_ci	ca->en50221.slot_shutdown	= mantis_ca_slot_shutdown;
1598c2ecf20Sopenharmony_ci	ca->en50221.slot_ts_enable	= mantis_ts_control;
1608c2ecf20Sopenharmony_ci	ca->en50221.poll_slot_status	= mantis_slot_status;
1618c2ecf20Sopenharmony_ci	ca->en50221.data		= ca;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	mutex_init(&ca->ca_lock);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	init_waitqueue_head(&ca->hif_data_wq);
1668c2ecf20Sopenharmony_ci	init_waitqueue_head(&ca->hif_opdone_wq);
1678c2ecf20Sopenharmony_ci	init_waitqueue_head(&ca->hif_write_wq);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
1708c2ecf20Sopenharmony_ci	result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
1718c2ecf20Sopenharmony_ci	if (result != 0) {
1728c2ecf20Sopenharmony_ci		dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
1738c2ecf20Sopenharmony_ci		goto err;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
1768c2ecf20Sopenharmony_ci	mantis_evmgr_init(ca);
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_cierr:
1798c2ecf20Sopenharmony_ci	kfree(ca);
1808c2ecf20Sopenharmony_ci	return result;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_ca_init);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_civoid mantis_ca_exit(struct mantis_pci *mantis)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct mantis_ca *ca = mantis->mantis_ca;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
1898c2ecf20Sopenharmony_ci	if (!ca)
1908c2ecf20Sopenharmony_ci		return;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	mantis_evmgr_exit(ca);
1938c2ecf20Sopenharmony_ci	dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
1948c2ecf20Sopenharmony_ci	dvb_ca_en50221_release(&ca->en50221);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	kfree(ca);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_ca_exit);
199