162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Mantis PCI bridge driver
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci*/
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/signal.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <asm/io.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <media/dmxdev.h>
1662306a36Sopenharmony_ci#include <media/dvbdev.h>
1762306a36Sopenharmony_ci#include <media/dvb_demux.h>
1862306a36Sopenharmony_ci#include <media/dvb_frontend.h>
1962306a36Sopenharmony_ci#include <media/dvb_net.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "mantis_common.h"
2262306a36Sopenharmony_ci#include "mantis_link.h"
2362306a36Sopenharmony_ci#include "mantis_hif.h"
2462306a36Sopenharmony_ci#include "mantis_reg.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "mantis_ca.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
3162306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (slot != 0)
3662306a36Sopenharmony_ci		return -EINVAL;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return mantis_hif_read_mem(ca, addr);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
4462306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (slot != 0)
4962306a36Sopenharmony_ci		return -EINVAL;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return mantis_hif_write_mem(ca, addr, data);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
5762306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (slot != 0)
6262306a36Sopenharmony_ci		return -EINVAL;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return mantis_hif_read_iom(ca, addr);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
7062306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (slot != 0)
7562306a36Sopenharmony_ci		return -EINVAL;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return mantis_hif_write_iom(ca, addr, data);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
8362306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
8662306a36Sopenharmony_ci	udelay(500); /* Wait.. */
8762306a36Sopenharmony_ci	mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
8862306a36Sopenharmony_ci	udelay(500);
8962306a36Sopenharmony_ci	mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
9062306a36Sopenharmony_ci	msleep(1000);
9162306a36Sopenharmony_ci	dvb_ca_en50221_camready_irq(&ca->en50221, 0);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return 0;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
9962306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
10962306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct mantis_ca *ca = en50221->data;
11962306a36Sopenharmony_ci	struct mantis_pci *mantis = ca->ca_priv;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (ca->slot_state == MODULE_INSERTED) {
12462306a36Sopenharmony_ci		dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
12562306a36Sopenharmony_ci		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
12662306a36Sopenharmony_ci	} else {
12762306a36Sopenharmony_ci		dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciint mantis_ca_init(struct mantis_pci *mantis)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct dvb_adapter *dvb_adapter	= &mantis->dvb_adapter;
13662306a36Sopenharmony_ci	struct mantis_ca *ca;
13762306a36Sopenharmony_ci	int ca_flags = 0, result;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
14062306a36Sopenharmony_ci	ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
14162306a36Sopenharmony_ci	if (!ca) {
14262306a36Sopenharmony_ci		dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
14362306a36Sopenharmony_ci		result = -ENOMEM;
14462306a36Sopenharmony_ci		goto err;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	ca->ca_priv		= mantis;
14862306a36Sopenharmony_ci	mantis->mantis_ca	= ca;
14962306a36Sopenharmony_ci	ca_flags		= DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
15062306a36Sopenharmony_ci	/* register CA interface */
15162306a36Sopenharmony_ci	ca->en50221.owner		= THIS_MODULE;
15262306a36Sopenharmony_ci	ca->en50221.read_attribute_mem	= mantis_ca_read_attr_mem;
15362306a36Sopenharmony_ci	ca->en50221.write_attribute_mem	= mantis_ca_write_attr_mem;
15462306a36Sopenharmony_ci	ca->en50221.read_cam_control	= mantis_ca_read_cam_ctl;
15562306a36Sopenharmony_ci	ca->en50221.write_cam_control	= mantis_ca_write_cam_ctl;
15662306a36Sopenharmony_ci	ca->en50221.slot_reset		= mantis_ca_slot_reset;
15762306a36Sopenharmony_ci	ca->en50221.slot_shutdown	= mantis_ca_slot_shutdown;
15862306a36Sopenharmony_ci	ca->en50221.slot_ts_enable	= mantis_ts_control;
15962306a36Sopenharmony_ci	ca->en50221.poll_slot_status	= mantis_slot_status;
16062306a36Sopenharmony_ci	ca->en50221.data		= ca;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	mutex_init(&ca->ca_lock);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	init_waitqueue_head(&ca->hif_data_wq);
16562306a36Sopenharmony_ci	init_waitqueue_head(&ca->hif_opdone_wq);
16662306a36Sopenharmony_ci	init_waitqueue_head(&ca->hif_write_wq);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
16962306a36Sopenharmony_ci	result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
17062306a36Sopenharmony_ci	if (result != 0) {
17162306a36Sopenharmony_ci		dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
17262306a36Sopenharmony_ci		goto err;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
17562306a36Sopenharmony_ci	mantis_evmgr_init(ca);
17662306a36Sopenharmony_ci	return 0;
17762306a36Sopenharmony_cierr:
17862306a36Sopenharmony_ci	kfree(ca);
17962306a36Sopenharmony_ci	return result;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_ca_init);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_civoid mantis_ca_exit(struct mantis_pci *mantis)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct mantis_ca *ca = mantis->mantis_ca;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
18862306a36Sopenharmony_ci	if (!ca)
18962306a36Sopenharmony_ci		return;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mantis_evmgr_exit(ca);
19262306a36Sopenharmony_ci	dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
19362306a36Sopenharmony_ci	dvb_ca_en50221_release(&ca->en50221);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	kfree(ca);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_ca_exit);
198