diff options
Diffstat (limited to 'drivers/media/pci/mantis')
44 files changed, 5342 insertions, 0 deletions
diff --git a/drivers/media/pci/mantis/Kconfig b/drivers/media/pci/mantis/Kconfig new file mode 100644 index 00000000000..d3cc21633b9 --- /dev/null +++ b/drivers/media/pci/mantis/Kconfig @@ -0,0 +1,38 @@ +config MANTIS_CORE +	tristate "Mantis/Hopper PCI bridge based devices" +	depends on PCI && I2C && INPUT && RC_CORE + +	help +	  Support for PCI cards based on the Mantis and Hopper PCi bridge. + +	  Say Y if you own such a device and want to use it. + +config DVB_MANTIS +	tristate "MANTIS based cards" +	depends on MANTIS_CORE && DVB_CORE && PCI && I2C +	select DVB_MB86A16 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_TDA665x if MEDIA_SUBDRV_AUTOSELECT +	select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_PLL +	help +	  Support for PCI cards based on the Mantis PCI bridge. +	  Say Y when you have a Mantis based DVB card and want to use it. + +	  If unsure say N. + +config DVB_HOPPER +	tristate "HOPPER based cards" +	depends on MANTIS_CORE && DVB_CORE && PCI && I2C +	select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT +	select DVB_PLL +	help +	  Support for PCI cards based on the Hopper  PCI bridge. +	  Say Y when you have a Hopper based DVB card and want to use it. + +	  If unsure say N diff --git a/drivers/media/pci/mantis/Makefile b/drivers/media/pci/mantis/Makefile new file mode 100644 index 00000000000..f715051e445 --- /dev/null +++ b/drivers/media/pci/mantis/Makefile @@ -0,0 +1,28 @@ +mantis_core-objs :=	mantis_ioc.o	\ +			mantis_uart.o	\ +			mantis_dma.o	\ +			mantis_pci.o	\ +			mantis_i2c.o	\ +			mantis_dvb.o	\ +			mantis_evm.o	\ +			mantis_hif.o	\ +			mantis_ca.o	\ +			mantis_pcmcia.o	\ +			mantis_input.o + +mantis-objs	:=	mantis_cards.o	\ +			mantis_vp1033.o	\ +			mantis_vp1034.o	\ +			mantis_vp1041.o	\ +			mantis_vp2033.o	\ +			mantis_vp2040.o	\ +			mantis_vp3030.o + +hopper-objs	:=	hopper_cards.o	\ +			hopper_vp3028.o + +obj-$(CONFIG_MANTIS_CORE)	+= mantis_core.o +obj-$(CONFIG_DVB_MANTIS)	+= mantis.o +obj-$(CONFIG_DVB_HOPPER)	+= hopper.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c new file mode 100644 index 00000000000..104914a5bf0 --- /dev/null +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -0,0 +1,267 @@ +/* +	Hopper PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <asm/irq.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "hopper_vp3028.h" +#include "mantis_dma.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); + +#define DRIVER_NAME	"Hopper" + +static char *label[10] = { +	"DMA", +	"IRQ-0", +	"IRQ-1", +	"OCERR", +	"PABRT", +	"RIPRR", +	"PPERR", +	"FTRGT", +	"RISCI", +	"RACK" +}; + +static int devs; + +static irqreturn_t hopper_irq_handler(int irq, void *dev_id) +{ +	u32 stat = 0, mask = 0; +	u32 rst_stat = 0, rst_mask = 0; + +	struct mantis_pci *mantis; +	struct mantis_ca *ca; + +	mantis = (struct mantis_pci *) dev_id; +	if (unlikely(mantis == NULL)) { +		dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); +		return IRQ_NONE; +	} +	ca = mantis->mantis_ca; + +	stat = mmread(MANTIS_INT_STAT); +	mask = mmread(MANTIS_INT_MASK); +	if (!(stat & mask)) +		return IRQ_NONE; + +	rst_mask  = MANTIS_GPIF_WRACK  | +		    MANTIS_GPIF_OTHERR | +		    MANTIS_SBUF_WSTO   | +		    MANTIS_GPIF_EXTIRQ; + +	rst_stat  = mmread(MANTIS_GPIF_STATUS); +	rst_stat &= rst_mask; +	mmwrite(rst_stat, MANTIS_GPIF_STATUS); + +	mantis->mantis_int_stat = stat; +	mantis->mantis_int_mask = mask; +	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); +	if (stat & MANTIS_INT_RISCEN) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); +	} +	if (stat & MANTIS_INT_IRQ0) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); +		mantis->gpif_status = rst_stat; +		wake_up(&ca->hif_write_wq); +		schedule_work(&ca->hif_evm_work); +	} +	if (stat & MANTIS_INT_IRQ1) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); +		schedule_work(&mantis->uart_work); +	} +	if (stat & MANTIS_INT_OCERR) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); +	} +	if (stat & MANTIS_INT_PABORT) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); +	} +	if (stat & MANTIS_INT_RIPERR) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); +	} +	if (stat & MANTIS_INT_PPERR) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); +	} +	if (stat & MANTIS_INT_FTRGT) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); +	} +	if (stat & MANTIS_INT_RISCI) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); +		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; +		tasklet_schedule(&mantis->tasklet); +	} +	if (stat & MANTIS_INT_I2CDONE) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); +		wake_up(&mantis->i2c_wq); +	} +	mmwrite(stat, MANTIS_INT_STAT); +	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE | +		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 | +		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 | +		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 | +		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 | +		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   | +		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   | +		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  | +		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   | +		  MANTIS_INT_RISCI); + +	if (stat) +		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask); + +	dprintk(MANTIS_DEBUG, 0, "\n"); +	return IRQ_HANDLED; +} + +static int hopper_pci_probe(struct pci_dev *pdev, +			    const struct pci_device_id *pci_id) +{ +	struct mantis_pci *mantis; +	struct mantis_hwconfig *config; +	int err = 0; + +	mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); +	if (mantis == NULL) { +		printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); +		err = -ENOMEM; +		goto fail0; +	} + +	mantis->num		= devs; +	mantis->verbose		= verbose; +	mantis->pdev		= pdev; +	config			= (struct mantis_hwconfig *) pci_id->driver_data; +	config->irq_handler	= &hopper_irq_handler; +	mantis->hwconfig	= config; + +	err = mantis_pci_init(mantis); +	if (err) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); +		goto fail1; +	} + +	err = mantis_stream_control(mantis, STREAM_TO_HIF); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); +		goto fail1; +	} + +	err = mantis_i2c_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); +		goto fail2; +	} + +	err = mantis_get_mac(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); +		goto fail2; +	} + +	err = mantis_dma_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); +		goto fail3; +	} + +	err = mantis_dvb_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); +		goto fail4; +	} +	devs++; + +	return err; + +fail4: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); +	mantis_dma_exit(mantis); + +fail3: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); +	mantis_i2c_exit(mantis); + +fail2: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); +	mantis_pci_exit(mantis); + +fail1: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); +	kfree(mantis); + +fail0: +	return err; +} + +static void hopper_pci_remove(struct pci_dev *pdev) +{ +	struct mantis_pci *mantis = pci_get_drvdata(pdev); + +	if (mantis) { +		mantis_dvb_exit(mantis); +		mantis_dma_exit(mantis); +		mantis_i2c_exit(mantis); +		mantis_pci_exit(mantis); +		kfree(mantis); +	} +	return; + +} + +static struct pci_device_id hopper_pci_table[] = { +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), +	{ } +}; + +MODULE_DEVICE_TABLE(pci, hopper_pci_table); + +static struct pci_driver hopper_pci_driver = { +	.name		= DRIVER_NAME, +	.id_table	= hopper_pci_table, +	.probe		= hopper_pci_probe, +	.remove		= hopper_pci_remove, +}; + +module_pci_driver(hopper_pci_driver); + +MODULE_DESCRIPTION("HOPPER driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c new file mode 100644 index 00000000000..68a29f8bdf7 --- /dev/null +++ b/drivers/media/pci/mantis/hopper_vp3028.c @@ -0,0 +1,88 @@ +/* +	Hopper VP-3028 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "hopper_vp3028.h" + +struct zl10353_config hopper_vp3028_config = { +	.demod_address	= 0x0f, +}; + +#define MANTIS_MODEL_NAME	"VP-3028" +#define MANTIS_DEV_TYPE		"DVB-T" + +static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter	= &mantis->adapter; +	struct mantis_hwconfig *config	= mantis->hwconfig; +	int err = 0; + +	mantis_gpio_set_bits(mantis, config->reset, 0); +	msleep(100); +	err = mantis_frontend_power(mantis, POWER_ON); +	msleep(100); +	mantis_gpio_set_bits(mantis, config->reset, 1); + +	err = mantis_frontend_power(mantis, POWER_ON); +	if (err == 0) { +		msleep(250); +		dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); +		fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter); + +		if (!fe) +			return -1; +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; +	} +	dprintk(MANTIS_ERROR, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp3028_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_188, + +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, + +	.frontend_init	= vp3028_frontend_init, +	.power		= GPIF_A00, +	.reset		= GPIF_A03, +}; diff --git a/drivers/media/pci/mantis/hopper_vp3028.h b/drivers/media/pci/mantis/hopper_vp3028.h new file mode 100644 index 00000000000..57239498bc8 --- /dev/null +++ b/drivers/media/pci/mantis/hopper_vp3028.h @@ -0,0 +1,30 @@ +/* +	Hopper VP-3028 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "mantis_common.h" + +#define MANTIS_VP_3028_DVB_T	0x0028 + +extern struct mantis_hwconfig vp3028_config; + +#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/pci/mantis/mantis_ca.c b/drivers/media/pci/mantis/mantis_ca.c new file mode 100644 index 00000000000..60c6c2f2406 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ca.c @@ -0,0 +1,210 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +#include "mantis_ca.h" + +static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot); + +	if (slot != 0) +		return -EINVAL; + +	return mantis_hif_read_mem(ca, addr); +} + +static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot); + +	if (slot != 0) +		return -EINVAL; + +	return mantis_hif_write_mem(ca, addr, data); +} + +static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot); + +	if (slot != 0) +		return -EINVAL; + +	return mantis_hif_read_iom(ca, addr); +} + +static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot); + +	if (slot != 0) +		return -EINVAL; + +	return mantis_hif_write_iom(ca, addr, data); +} + +static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot); +	udelay(500); /* Wait.. */ +	mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ +	udelay(500); +	mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ +	msleep(1000); +	dvb_ca_en50221_camready_irq(&ca->en50221, 0); + +	return 0; +} + +static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot); + +	return 0; +} + +static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); +/*	mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ + +	return 0; +} + +static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) +{ +	struct mantis_ca *ca = en50221->data; +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot); + +	if (ca->slot_state == MODULE_INSERTED) { +		dprintk(MANTIS_DEBUG, 1, "CA Module present and ready"); +		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; +	} else { +		dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready"); +	} + +	return 0; +} + +int mantis_ca_init(struct mantis_pci *mantis) +{ +	struct dvb_adapter *dvb_adapter	= &mantis->dvb_adapter; +	struct mantis_ca *ca; +	int ca_flags = 0, result; + +	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA"); +	ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL); +	if (!ca) { +		dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .."); +		result = -ENOMEM; +		goto err; +	} + +	ca->ca_priv		= mantis; +	mantis->mantis_ca	= ca; +	ca_flags		= DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; +	/* register CA interface */ +	ca->en50221.owner		= THIS_MODULE; +	ca->en50221.read_attribute_mem	= mantis_ca_read_attr_mem; +	ca->en50221.write_attribute_mem	= mantis_ca_write_attr_mem; +	ca->en50221.read_cam_control	= mantis_ca_read_cam_ctl; +	ca->en50221.write_cam_control	= mantis_ca_write_cam_ctl; +	ca->en50221.slot_reset		= mantis_ca_slot_reset; +	ca->en50221.slot_shutdown	= mantis_ca_slot_shutdown; +	ca->en50221.slot_ts_enable	= mantis_ts_control; +	ca->en50221.poll_slot_status	= mantis_slot_status; +	ca->en50221.data		= ca; + +	mutex_init(&ca->ca_lock); + +	init_waitqueue_head(&ca->hif_data_wq); +	init_waitqueue_head(&ca->hif_opdone_wq); +	init_waitqueue_head(&ca->hif_write_wq); + +	dprintk(MANTIS_ERROR, 1, "Registering EN50221 device"); +	result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1); +	if (result != 0) { +		dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result); +		goto err; +	} +	dprintk(MANTIS_ERROR, 1, "Registered EN50221 device"); +	mantis_evmgr_init(ca); +	return 0; +err: +	kfree(ca); +	return result; +} +EXPORT_SYMBOL_GPL(mantis_ca_init); + +void mantis_ca_exit(struct mantis_pci *mantis) +{ +	struct mantis_ca *ca = mantis->mantis_ca; + +	dprintk(MANTIS_DEBUG, 1, "Mantis CA exit"); +	if (!ca) +		return; + +	mantis_evmgr_exit(ca); +	dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device"); +	dvb_ca_en50221_release(&ca->en50221); + +	kfree(ca); +} +EXPORT_SYMBOL_GPL(mantis_ca_exit); diff --git a/drivers/media/pci/mantis/mantis_ca.h b/drivers/media/pci/mantis/mantis_ca.h new file mode 100644 index 00000000000..dc63e55f7ec --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ca.h @@ -0,0 +1,27 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_CA_H +#define __MANTIS_CA_H + +extern int mantis_ca_init(struct mantis_pci *mantis); +extern void mantis_ca_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CA_H */ diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c new file mode 100644 index 00000000000..801fc55b616 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -0,0 +1,297 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <asm/irq.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); + +static int devs; + +#define DRIVER_NAME	"Mantis" + +static char *label[10] = { +	"DMA", +	"IRQ-0", +	"IRQ-1", +	"OCERR", +	"PABRT", +	"RIPRR", +	"PPERR", +	"FTRGT", +	"RISCI", +	"RACK" +}; + +static irqreturn_t mantis_irq_handler(int irq, void *dev_id) +{ +	u32 stat = 0, mask = 0; +	u32 rst_stat = 0, rst_mask = 0; + +	struct mantis_pci *mantis; +	struct mantis_ca *ca; + +	mantis = (struct mantis_pci *) dev_id; +	if (unlikely(mantis == NULL)) { +		dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); +		return IRQ_NONE; +	} +	ca = mantis->mantis_ca; + +	stat = mmread(MANTIS_INT_STAT); +	mask = mmread(MANTIS_INT_MASK); +	if (!(stat & mask)) +		return IRQ_NONE; + +	rst_mask  = MANTIS_GPIF_WRACK  | +		    MANTIS_GPIF_OTHERR | +		    MANTIS_SBUF_WSTO   | +		    MANTIS_GPIF_EXTIRQ; + +	rst_stat  = mmread(MANTIS_GPIF_STATUS); +	rst_stat &= rst_mask; +	mmwrite(rst_stat, MANTIS_GPIF_STATUS); + +	mantis->mantis_int_stat = stat; +	mantis->mantis_int_mask = mask; +	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); +	if (stat & MANTIS_INT_RISCEN) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); +	} +	if (stat & MANTIS_INT_IRQ0) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); +		mantis->gpif_status = rst_stat; +		wake_up(&ca->hif_write_wq); +		schedule_work(&ca->hif_evm_work); +	} +	if (stat & MANTIS_INT_IRQ1) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); +		schedule_work(&mantis->uart_work); +	} +	if (stat & MANTIS_INT_OCERR) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); +	} +	if (stat & MANTIS_INT_PABORT) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); +	} +	if (stat & MANTIS_INT_RIPERR) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); +	} +	if (stat & MANTIS_INT_PPERR) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); +	} +	if (stat & MANTIS_INT_FTRGT) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); +	} +	if (stat & MANTIS_INT_RISCI) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); +		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; +		tasklet_schedule(&mantis->tasklet); +	} +	if (stat & MANTIS_INT_I2CDONE) { +		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); +		wake_up(&mantis->i2c_wq); +	} +	mmwrite(stat, MANTIS_INT_STAT); +	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE | +		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 | +		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 | +		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 | +		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 | +		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   | +		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   | +		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  | +		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   | +		  MANTIS_INT_RISCI); + +	if (stat) +		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask); + +	dprintk(MANTIS_DEBUG, 0, "\n"); +	return IRQ_HANDLED; +} + +static int mantis_pci_probe(struct pci_dev *pdev, +			    const struct pci_device_id *pci_id) +{ +	struct mantis_pci *mantis; +	struct mantis_hwconfig *config; +	int err = 0; + +	mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); +	if (mantis == NULL) { +		printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); +		err = -ENOMEM; +		goto fail0; +	} + +	mantis->num		= devs; +	mantis->verbose		= verbose; +	mantis->pdev		= pdev; +	config			= (struct mantis_hwconfig *) pci_id->driver_data; +	config->irq_handler	= &mantis_irq_handler; +	mantis->hwconfig	= config; + +	err = mantis_pci_init(mantis); +	if (err) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); +		goto fail1; +	} + +	err = mantis_stream_control(mantis, STREAM_TO_HIF); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); +		goto fail1; +	} + +	err = mantis_i2c_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); +		goto fail2; +	} + +	err = mantis_get_mac(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); +		goto fail2; +	} + +	err = mantis_dma_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); +		goto fail3; +	} + +	err = mantis_dvb_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); +		goto fail4; +	} +	err = mantis_uart_init(mantis); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); +		goto fail6; +	} + +	devs++; + +	return err; + + +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); +	mantis_uart_exit(mantis); + +fail6: +fail4: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); +	mantis_dma_exit(mantis); + +fail3: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); +	mantis_i2c_exit(mantis); + +fail2: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); +	mantis_pci_exit(mantis); + +fail1: +	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); +	kfree(mantis); + +fail0: +	return err; +} + +static void mantis_pci_remove(struct pci_dev *pdev) +{ +	struct mantis_pci *mantis = pci_get_drvdata(pdev); + +	if (mantis) { + +		mantis_uart_exit(mantis); +		mantis_dvb_exit(mantis); +		mantis_dma_exit(mantis); +		mantis_i2c_exit(mantis); +		mantis_pci_exit(mantis); +		kfree(mantis); +	} +	return; +} + +static struct pci_device_id mantis_pci_table[] = { +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), +	MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), +	MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), +	MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), +	MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), +	MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config), +	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), +	{ } +}; + +MODULE_DEVICE_TABLE(pci, mantis_pci_table); + +static struct pci_driver mantis_pci_driver = { +	.name		= DRIVER_NAME, +	.id_table	= mantis_pci_table, +	.probe		= mantis_pci_probe, +	.remove		= mantis_pci_remove, +}; + +module_pci_driver(mantis_pci_driver); + +MODULE_DESCRIPTION("MANTIS driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h new file mode 100644 index 00000000000..f2410cf0a6b --- /dev/null +++ b/drivers/media/pci/mantis/mantis_common.h @@ -0,0 +1,179 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_COMMON_H +#define __MANTIS_COMMON_H + +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> + +#include "mantis_uart.h" + +#include "mantis_link.h" + +#define MANTIS_ERROR		0 +#define MANTIS_NOTICE		1 +#define MANTIS_INFO		2 +#define MANTIS_DEBUG		3 +#define MANTIS_TMG		9 + +#define dprintk(y, z, format, arg...) do {								\ +	if (z) {											\ +		if	((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y))			\ +			printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\ +		else if	((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y))			\ +			printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\ +		else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y))			\ +			printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\ +		else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y))			\ +			printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\ +		else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y))			\ +			printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\ +	} else {											\ +		if (mantis->verbose > y)								\ +			printk(format , ##arg);								\ +	}												\ +} while(0) + +#define mwrite(dat, addr)	writel((dat), addr) +#define mread(addr)		readl(addr) + +#define mmwrite(dat, addr)	mwrite((dat), (mantis->mmio + (addr))) +#define mmread(addr)		mread(mantis->mmio + (addr)) + +#define MANTIS_TS_188		0 +#define MANTIS_TS_204		1 + +#define TWINHAN_TECHNOLOGIES	0x1822 +#define MANTIS			0x4e35 + +#define TECHNISAT		0x1ae4 +#define TERRATEC		0x153b + +#define MAKE_ENTRY(__subven, __subdev, __configptr) {			\ +		.vendor		= TWINHAN_TECHNOLOGIES,			\ +		.device		= MANTIS,				\ +		.subvendor	= (__subven),				\ +		.subdevice	= (__subdev),				\ +		.driver_data	= (unsigned long) (__configptr)		\ +} + +enum mantis_i2c_mode { +	MANTIS_PAGE_MODE = 0, +	MANTIS_BYTE_MODE, +}; + +struct mantis_pci; + +struct mantis_hwconfig { +	char			*model_name; +	char			*dev_type; +	u32			ts_size; + +	enum mantis_baud	baud_rate; +	enum mantis_parity	parity; +	u32			bytes; + +	irqreturn_t (*irq_handler)(int irq, void *dev_id); +	int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe); + +	u8			power; +	u8			reset; + +	enum mantis_i2c_mode	i2c_mode; +}; + +struct mantis_pci { +	unsigned int		verbose; + +	/*	PCI stuff		*/ +	u16			vendor_id; +	u16			device_id; +	u16			subsystem_vendor; +	u16			subsystem_device; + +	u8			latency; + +	struct pci_dev		*pdev; + +	unsigned long		mantis_addr; +	void __iomem		*mmio; + +	u8			irq; +	u8			revision; + +	unsigned int		num; + +	/*	RISC Core		*/ +	u32			busy_block; +	u32			last_block; +	u8			*buf_cpu; +	dma_addr_t		buf_dma; +	u32			*risc_cpu; +	dma_addr_t		risc_dma; + +	struct tasklet_struct	tasklet; + +	struct i2c_adapter	adapter; +	int			i2c_rc; +	wait_queue_head_t	i2c_wq; +	struct mutex		i2c_lock; + +	/*	DVB stuff		*/ +	struct dvb_adapter	dvb_adapter; +	struct dvb_frontend	*fe; +	struct dvb_demux	demux; +	struct dmxdev		dmxdev; +	struct dmx_frontend	fe_hw; +	struct dmx_frontend	fe_mem; +	struct dvb_net		dvbnet; + +	u8			feeds; + +	struct mantis_hwconfig	*hwconfig; + +	u32			mantis_int_stat; +	u32			mantis_int_mask; + +	/*	board specific		*/ +	u8			mac_address[8]; +	u32			sub_vendor_id; +	u32			sub_device_id; + +	 /*	A12 A13 A14		*/ +	u32			gpio_status; + +	u32			gpif_status; + +	struct mantis_ca	*mantis_ca; + +	wait_queue_head_t	uart_wq; +	struct work_struct	uart_work; +	spinlock_t		uart_lock; + +	struct rc_dev		*rc; +	char			input_name[80]; +	char			input_phys[80]; +}; + +#define MANTIS_HIF_STATUS	(mantis->gpio_status) + +#endif /* __MANTIS_COMMON_H */ diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c new file mode 100644 index 00000000000..684d9061fe2 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_core.c @@ -0,0 +1,235 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "mantis_common.h" +#include "mantis_core.h" +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ +	int err; +	struct i2c_msg msg[] = { +		{ +			.addr = 0x50, +			.flags = 0, +			.buf = data, +			.len = 1 +		}, { +			.addr = 0x50, +			.flags = I2C_M_RD, +			.buf = data, +			.len = length +		}, +	}; + +	err = i2c_transfer(&mantis->adapter, msg, 2); +	if (err < 0) { +		dprintk(verbose, MANTIS_ERROR, 1, +			"ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", +			err, data[0], data[1]); + +		return err; +	} + +	return 0; +} + +static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ +	int err; + +	struct i2c_msg msg = { +		.addr = 0x50, +		.flags = 0, +		.buf = data, +		.len = length +	}; + +	err = i2c_transfer(&mantis->adapter, &msg, 1); +	if (err < 0) { +		dprintk(verbose, MANTIS_ERROR, 1, +			"ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", +			err, length, data[0], data[1]); + +		return err; +	} + +	return 0; +} + +static int get_mac_address(struct mantis_pci *mantis) +{ +	int err; + +	mantis->mac_address[0] = 0x08; +	err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); +	if (err < 0) { +		dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); + +		return err; +	} +	dprintk(verbose, MANTIS_ERROR, 0, +		"    MAC Address=[%pM]\n", mantis->mac_address); + +	return 0; +} + +#define MANTIS_MODEL_UNKNOWN	"UNKNOWN" +#define MANTIS_DEV_UNKNOWN	"UNKNOWN" + +struct mantis_hwconfig unknown_device = { +	.model_name	= MANTIS_MODEL_UNKNOWN, +	.dev_type	= MANTIS_DEV_UNKNOWN, +}; + +static void mantis_load_config(struct mantis_pci *mantis) +{ +	switch (mantis->subsystem_device) { +	case MANTIS_VP_1033_DVB_S:	/* VP-1033 */ +		mantis->hwconfig = &vp1033_mantis_config; +		break; +	case MANTIS_VP_1034_DVB_S:	/* VP-1034 */ +		mantis->hwconfig = &vp1034_mantis_config; +		break; +	case MANTIS_VP_1041_DVB_S2:	/* VP-1041 */ +	case TECHNISAT_SKYSTAR_HD2: +		mantis->hwconfig = &vp1041_mantis_config; +		break; +	case MANTIS_VP_2033_DVB_C:	/* VP-2033 */ +		mantis->hwconfig = &vp2033_mantis_config; +		break; +	case MANTIS_VP_2040_DVB_C:	/* VP-2040 */ +	case CINERGY_C:	/* VP-2040 clone */ +	case TECHNISAT_CABLESTAR_HD2: +		mantis->hwconfig = &vp2040_mantis_config; +		break; +	case MANTIS_VP_3030_DVB_T:	/* VP-3030 */ +		mantis->hwconfig = &vp3030_mantis_config; +		break; +	default: +		mantis->hwconfig = &unknown_device; +		break; +	} +} + +int mantis_core_init(struct mantis_pci *mantis) +{ +	int err = 0; + +	mantis_load_config(mantis); +	dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", +		mantis->hwconfig->model_name, mantis->hwconfig->dev_type, +		mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); +	dprintk(verbose, MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ", +		mantis->revision, +		mantis->subsystem_vendor, mantis->subsystem_device); +	dprintk(verbose, MANTIS_ERROR, 0, +		"irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n", +		mantis->pdev->irq, mantis->latency, +		mantis->mantis_addr, mantis->mantis_mmio); + +	err = mantis_i2c_init(mantis); +	if (err < 0) { +		dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); +		return err; +	} +	err = get_mac_address(mantis); +	if (err < 0) { +		dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); +		return err; +	} +	err = mantis_dma_init(mantis); +	if (err < 0) { +		dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); +		return err; +	} +	err = mantis_dvb_init(mantis); +	if (err < 0) { +		dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); +		return err; +	} +	err = mantis_uart_init(mantis); +	if (err < 0) { +		dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); +		return err; +	} + +	return 0; +} + +int mantis_core_exit(struct mantis_pci *mantis) +{ +	mantis_dma_stop(mantis); +	dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); + +	mantis_uart_exit(mantis); +	dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); + +	if (mantis_dma_exit(mantis) < 0) +		dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); +	if (mantis_dvb_exit(mantis) < 0) +		dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); +	if (mantis_i2c_exit(mantis) < 0) +		dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); + +	return 0; +} + +/* Turn the given bit on or off. */ +void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ +	u32 cur; + +	cur = mmread(MANTIS_GPIF_ADDR); +	if (value) +		mantis->gpio_status = cur | (1 << bitpos); +	else +		mantis->gpio_status = cur & (~(1 << bitpos)); + +	mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); +	mmwrite(0x00, MANTIS_GPIF_DOUT); +	udelay(100); +} + +/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ +void mantis_set_direction(struct mantis_pci *mantis, int direction) +{ +	u32 reg; + +	reg = mmread(0x28); +	dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); +	if (direction == 0x01) { +		/* to CI */ +		reg |= 0x04; +		mmwrite(reg, 0x28); +		reg &= 0xff - 0x04; +		mmwrite(reg, 0x28); +	} else { +		reg &= 0xff - 0x04; +		mmwrite(reg, 0x28); +		reg |= 0x04; +		mmwrite(reg, 0x28); +	} +} diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h new file mode 100644 index 00000000000..833ee42e694 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_core.h @@ -0,0 +1,57 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_CORE_H +#define __MANTIS_CORE_H + +#include "mantis_common.h" + + +#define FE_TYPE_SAT	0 +#define FE_TYPE_CAB	1 +#define FE_TYPE_TER	2 + +#define FE_TYPE_TS204	0 +#define FE_TYPE_TS188	1 + + +struct vendorname { +	u8  *sub_vendor_name; +	u32 sub_vendor_id; +}; + +struct devicetype { +	u8  *sub_device_name; +	u32 sub_device_id; +	u8  device_type; +	u32 type_flags; +}; + + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); +extern int mantis_core_init(struct mantis_pci *mantis); +extern int mantis_core_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c new file mode 100644 index 00000000000..566c407175a --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dma.c @@ -0,0 +1,230 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> +#include <asm/page.h> +#include <linux/vmalloc.h> +#include <linux/pci.h> + +#include <asm/irq.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_dma.h" + +#define RISC_WRITE		(0x01 << 28) +#define RISC_JUMP		(0x07 << 28) +#define RISC_IRQ		(0x01 << 24) + +#define RISC_STATUS(status)	((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) +#define RISC_FLUSH(risc_pos)		(risc_pos = 0) +#define RISC_INSTR(risc_pos, opcode)	(mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode)) + +#define MANTIS_BUF_SIZE		(64 * 1024) +#define MANTIS_BLOCK_BYTES      (MANTIS_BUF_SIZE / 4) +#define MANTIS_DMA_TR_BYTES     (2 * 1024) /* upper limit: 4095 bytes. */ +#define MANTIS_BLOCK_COUNT	(MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES) + +#define MANTIS_DMA_TR_UNITS     (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES) +/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */ +#define MANTIS_RISC_SIZE	PAGE_SIZE /* RISC program must fit here. */ + +int mantis_dma_exit(struct mantis_pci *mantis) +{ +	if (mantis->buf_cpu) { +		dprintk(MANTIS_ERROR, 1, +			"DMA=0x%lx cpu=0x%p size=%d", +			(unsigned long) mantis->buf_dma, +			 mantis->buf_cpu, +			 MANTIS_BUF_SIZE); + +		pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, +				    mantis->buf_cpu, mantis->buf_dma); + +		mantis->buf_cpu = NULL; +	} +	if (mantis->risc_cpu) { +		dprintk(MANTIS_ERROR, 1, +			"RISC=0x%lx cpu=0x%p size=%lx", +			(unsigned long) mantis->risc_dma, +			mantis->risc_cpu, +			MANTIS_RISC_SIZE); + +		pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, +				    mantis->risc_cpu, mantis->risc_dma); + +		mantis->risc_cpu = NULL; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_dma_exit); + +static inline int mantis_alloc_buffers(struct mantis_pci *mantis) +{ +	if (!mantis->buf_cpu) { +		mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, +						       MANTIS_BUF_SIZE, +						       &mantis->buf_dma); +		if (!mantis->buf_cpu) { +			dprintk(MANTIS_ERROR, 1, +				"DMA buffer allocation failed"); + +			goto err; +		} +		dprintk(MANTIS_ERROR, 1, +			"DMA=0x%lx cpu=0x%p size=%d", +			(unsigned long) mantis->buf_dma, +			mantis->buf_cpu, MANTIS_BUF_SIZE); +	} +	if (!mantis->risc_cpu) { +		mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, +							MANTIS_RISC_SIZE, +							&mantis->risc_dma); + +		if (!mantis->risc_cpu) { +			dprintk(MANTIS_ERROR, 1, +				"RISC program allocation failed"); + +			mantis_dma_exit(mantis); + +			goto err; +		} +		dprintk(MANTIS_ERROR, 1, +			"RISC=0x%lx cpu=0x%p size=%lx", +			(unsigned long) mantis->risc_dma, +			mantis->risc_cpu, MANTIS_RISC_SIZE); +	} + +	return 0; +err: +	dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); +	return -ENOMEM; +} + +int mantis_dma_init(struct mantis_pci *mantis) +{ +	int err = 0; + +	dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); +	if (mantis_alloc_buffers(mantis) < 0) { +		dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); + +		/* Stop RISC Engine */ +		mmwrite(0, MANTIS_DMA_CTL); + +		goto err; +	} + +	return 0; +err: +	return err; +} +EXPORT_SYMBOL_GPL(mantis_dma_init); + +static inline void mantis_risc_program(struct mantis_pci *mantis) +{ +	u32 buf_pos = 0; +	u32 line, step; +	u32 risc_pos; + +	dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); +	RISC_FLUSH(risc_pos); + +	dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u", +		MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES); + +	for (line = 0; line < MANTIS_BLOCK_COUNT; line++) { +		for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) { +			dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step); +			if (step == 0) { +				RISC_INSTR(risc_pos, RISC_WRITE	| +					   RISC_IRQ	| +					   RISC_STATUS(line) | +					   MANTIS_DMA_TR_BYTES); +			} else { +				RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES); +			} +			RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos); +			buf_pos += MANTIS_DMA_TR_BYTES; +		  } +	} +	RISC_INSTR(risc_pos, RISC_JUMP); +	RISC_INSTR(risc_pos, mantis->risc_dma); +} + +void mantis_dma_start(struct mantis_pci *mantis) +{ +	dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); + +	mantis_risc_program(mantis); +	mmwrite(mantis->risc_dma, MANTIS_RISC_START); +	mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + +	mmwrite(0, MANTIS_DMA_CTL); +	mantis->last_block = mantis->busy_block = 0; + +	mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); + +	mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN +			       | MANTIS_RISC_EN, MANTIS_DMA_CTL); + +} + +void mantis_dma_stop(struct mantis_pci *mantis) +{ +	dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); + +	mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); + +	mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | +					    MANTIS_DCAP_EN | +					    MANTIS_RISC_EN)), MANTIS_DMA_CTL); + +	mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); + +	mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | +					    MANTIS_INT_RISCEN), MANTIS_INT_MASK); +} + + +void mantis_dma_xfer(unsigned long data) +{ +	struct mantis_pci *mantis = (struct mantis_pci *) data; +	struct mantis_hwconfig *config = mantis->hwconfig; + +	while (mantis->last_block != mantis->busy_block) { +		dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", +			mantis->last_block, mantis->busy_block); + +		(config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) +		(&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); +		mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; +	} +} diff --git a/drivers/media/pci/mantis/mantis_dma.h b/drivers/media/pci/mantis/mantis_dma.h new file mode 100644 index 00000000000..6be00fa8209 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dma.h @@ -0,0 +1,30 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_DMA_H +#define __MANTIS_DMA_H + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern void mantis_dma_xfer(unsigned long data); + +#endif /* __MANTIS_DMA_H */ diff --git a/drivers/media/pci/mantis/mantis_dvb.c b/drivers/media/pci/mantis/mantis_dvb.c new file mode 100644 index 00000000000..5a71e1791cf --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dvb.c @@ -0,0 +1,301 @@ +/* +	Mantis PCI bridge driver +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> +#include <linux/bitops.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/i2c.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) +{ +	struct mantis_hwconfig *config = mantis->hwconfig; + +	switch (power) { +	case POWER_ON: +		dprintk(MANTIS_DEBUG, 1, "Power ON"); +		mantis_gpio_set_bits(mantis, config->power, POWER_ON); +		msleep(100); +		mantis_gpio_set_bits(mantis, config->power, POWER_ON); +		msleep(100); +		break; + +	case POWER_OFF: +		dprintk(MANTIS_DEBUG, 1, "Power OFF"); +		mantis_gpio_set_bits(mantis, config->power, POWER_OFF); +		msleep(100); +		break; + +	default: +		dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); +		return -1; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_frontend_power); + +void mantis_frontend_soft_reset(struct mantis_pci *mantis) +{ +	struct mantis_hwconfig *config = mantis->hwconfig; + +	dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); +	mantis_gpio_set_bits(mantis, config->reset, 0); +	msleep(100); +	mantis_gpio_set_bits(mantis, config->reset, 0); +	msleep(100); +	mantis_gpio_set_bits(mantis, config->reset, 1); +	msleep(100); +	mantis_gpio_set_bits(mantis, config->reset, 1); +	msleep(100); + +	return; +} +EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); + +static int mantis_frontend_shutdown(struct mantis_pci *mantis) +{ +	int err; + +	mantis_frontend_soft_reset(mantis); +	err = mantis_frontend_power(mantis, POWER_OFF); +	if (err != 0) { +		dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); +		return 1; +	} + +	return 0; +} + +static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ +	struct dvb_demux *dvbdmx = dvbdmxfeed->demux; +	struct mantis_pci *mantis = dvbdmx->priv; + +	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); +	if (!dvbdmx->dmx.frontend) { +		dprintk(MANTIS_DEBUG, 1, "no frontend ?"); +		return -EINVAL; +	} + +	mantis->feeds++; +	dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d",	mantis->feeds); + +	if (mantis->feeds == 1)	 { +		dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); +		mantis_dma_start(mantis); +		tasklet_enable(&mantis->tasklet); +	} + +	return mantis->feeds; +} + +static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ +	struct dvb_demux *dvbdmx = dvbdmxfeed->demux; +	struct mantis_pci *mantis = dvbdmx->priv; + +	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); +	if (!dvbdmx->dmx.frontend) { +		dprintk(MANTIS_DEBUG, 1, "no frontend ?"); +		return -EINVAL; +	} + +	mantis->feeds--; +	if (mantis->feeds == 0) { +		dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); +		tasklet_disable(&mantis->tasklet); +		mantis_dma_stop(mantis); +	} + +	return 0; +} + +int mantis_dvb_init(struct mantis_pci *mantis) +{ +	struct mantis_hwconfig *config = mantis->hwconfig; +	int result = -1; + +	dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); + +	result = dvb_register_adapter(&mantis->dvb_adapter, +				      "Mantis DVB adapter", +				      THIS_MODULE, +				      &mantis->pdev->dev, +				      adapter_nr); + +	if (result < 0) { + +		dprintk(MANTIS_ERROR, 1, "Error registering adapter"); +		return -ENODEV; +	} + +	mantis->dvb_adapter.priv	= mantis; +	mantis->demux.dmx.capabilities	= DMX_TS_FILTERING	| +					 DMX_SECTION_FILTERING	| +					 DMX_MEMORY_BASED_FILTERING; + +	mantis->demux.priv		= mantis; +	mantis->demux.filternum		= 256; +	mantis->demux.feednum		= 256; +	mantis->demux.start_feed	= mantis_dvb_start_feed; +	mantis->demux.stop_feed		= mantis_dvb_stop_feed; +	mantis->demux.write_to_decoder	= NULL; + +	dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); +	result = dvb_dmx_init(&mantis->demux); +	if (result < 0) { +		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + +		goto err0; +	} + +	mantis->dmxdev.filternum	= 256; +	mantis->dmxdev.demux		= &mantis->demux.dmx; +	mantis->dmxdev.capabilities	= 0; +	dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); + +	result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); +	if (result < 0) { + +		dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); +		goto err1; +	} + +	mantis->fe_hw.source		= DMX_FRONTEND_0; +	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); +	if (result < 0) { + +		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); +		goto err2; +	} + +	mantis->fe_mem.source		= DMX_MEMORY_FE; +	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); +	if (result < 0) { +		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); +		goto err3; +	} + +	result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); +	if (result < 0) { +		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); +		goto err4; +	} + +	dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); +	tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); +	tasklet_disable(&mantis->tasklet); +	if (mantis->hwconfig) { +		result = config->frontend_init(mantis, mantis->fe); +		if (result < 0) { +			dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); +			goto err5; +		} else { +			if (mantis->fe == NULL) { +				dprintk(MANTIS_ERROR, 1, "FE <NULL>"); +				goto err5; +			} + +			if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { +				dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); + +				if (mantis->fe->ops.release) +					mantis->fe->ops.release(mantis->fe); + +				mantis->fe = NULL; +				goto err5; +			} +		} +	} + +	return 0; + +	/* Error conditions ..	*/ +err5: +	tasklet_kill(&mantis->tasklet); +	dvb_net_release(&mantis->dvbnet); +	if (mantis->fe) { +		dvb_unregister_frontend(mantis->fe); +		dvb_frontend_detach(mantis->fe); +	} +err4: +	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + +err3: +	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + +err2: +	dvb_dmxdev_release(&mantis->dmxdev); + +err1: +	dvb_dmx_release(&mantis->demux); + +err0: +	dvb_unregister_adapter(&mantis->dvb_adapter); + +	return result; +} +EXPORT_SYMBOL_GPL(mantis_dvb_init); + +int mantis_dvb_exit(struct mantis_pci *mantis) +{ +	int err; + +	if (mantis->fe) { +		/* mantis_ca_exit(mantis); */ +		err = mantis_frontend_shutdown(mantis); +		if (err != 0) +			dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); +		dvb_unregister_frontend(mantis->fe); +		dvb_frontend_detach(mantis->fe); +	} + +	tasklet_kill(&mantis->tasklet); +	dvb_net_release(&mantis->dvbnet); + +	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); +	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + +	dvb_dmxdev_release(&mantis->dmxdev); +	dvb_dmx_release(&mantis->demux); + +	dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); +	dvb_unregister_adapter(&mantis->dvb_adapter); + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_dvb_exit); diff --git a/drivers/media/pci/mantis/mantis_dvb.h b/drivers/media/pci/mantis/mantis_dvb.h new file mode 100644 index 00000000000..464199db304 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dvb.h @@ -0,0 +1,35 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_DVB_H +#define __MANTIS_DVB_H + +enum mantis_power { +	POWER_OFF	= 0, +	POWER_ON	= 1 +}; + +extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power); +extern void mantis_frontend_soft_reset(struct mantis_pci *mantis); + +extern int mantis_dvb_init(struct mantis_pci *mantis); +extern int mantis_dvb_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_DVB_H */ diff --git a/drivers/media/pci/mantis/mantis_evm.c b/drivers/media/pci/mantis/mantis_evm.c new file mode 100644 index 00000000000..909ff54868a --- /dev/null +++ b/drivers/media/pci/mantis/mantis_evm.c @@ -0,0 +1,117 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +static void mantis_hifevm_work(struct work_struct *work) +{ +	struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); +	struct mantis_pci *mantis = ca->ca_priv; + +	u32 gpif_stat; + +	gpif_stat = mmread(MANTIS_GPIF_STATUS); + +	if (gpif_stat & MANTIS_GPIF_DETSTAT) { +		if (gpif_stat & MANTIS_CARD_PLUGIN) { +			dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num); +			mmwrite(0xdada0000, MANTIS_CARD_RESET); +			mantis_event_cam_plugin(ca); +			dvb_ca_en50221_camchange_irq(&ca->en50221, +						     0, +						     DVB_CA_EN50221_CAMCHANGE_INSERTED); +		} +	} else { +		if (gpif_stat & MANTIS_CARD_PLUGOUT) { +			dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num); +			mmwrite(0xdada0000, MANTIS_CARD_RESET); +			mantis_event_cam_unplug(ca); +			dvb_ca_en50221_camchange_irq(&ca->en50221, +						     0, +						     DVB_CA_EN50221_CAMCHANGE_REMOVED); +		} +	} + +	if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num); + +	if (mantis->gpif_status & MANTIS_SBUF_WSTO) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num); + +	if (mantis->gpif_status & MANTIS_GPIF_OTHERR) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num); + +	if (gpif_stat & MANTIS_SBUF_OVFLW) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num); + +	if (gpif_stat & MANTIS_GPIF_BRRDY) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num); + +	if (gpif_stat & MANTIS_GPIF_INTSTAT) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num); + +	if (gpif_stat & MANTIS_SBUF_EMPTY) +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num); + +	if (gpif_stat & MANTIS_SBUF_OPDONE) { +		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num); +		ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL; +		ca->hif_event = MANTIS_SBUF_OPDONE; +		wake_up(&ca->hif_opdone_wq); +	} +} + +int mantis_evmgr_init(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager"); +	INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work); +	mantis_pcmcia_init(ca); +	schedule_work(&ca->hif_evm_work); +	mantis_hif_init(ca); +	return 0; +} + +void mantis_evmgr_exit(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; + +	dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); +	flush_work(&ca->hif_evm_work); +	mantis_hif_exit(ca); +	mantis_pcmcia_exit(ca); +} diff --git a/drivers/media/pci/mantis/mantis_hif.c b/drivers/media/pci/mantis/mantis_hif.c new file mode 100644 index 00000000000..10c68df7e16 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_hif.c @@ -0,0 +1,239 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> + +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_hif.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ + +#include "mantis_reg.h" + + +static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; +	int rc = 0; + +	if (wait_event_timeout(ca->hif_opdone_wq, +			       ca->hif_event & MANTIS_SBUF_OPDONE, +			       msecs_to_jiffies(500)) == -ERESTARTSYS) { + +		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num); +		rc = -EREMOTEIO; +	} +	dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete"); +	ca->hif_event &= ~MANTIS_SBUF_OPDONE; +	return rc; +} + +static int mantis_hif_write_wait(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; +	u32 opdone = 0, timeout = 0; +	int rc = 0; + +	if (wait_event_timeout(ca->hif_write_wq, +			       mantis->gpif_status & MANTIS_GPIF_WRACK, +			       msecs_to_jiffies(500)) == -ERESTARTSYS) { + +		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num); +		rc = -EREMOTEIO; +	} +	dprintk(MANTIS_DEBUG, 1, "Write Acknowledged"); +	mantis->gpif_status &= ~MANTIS_GPIF_WRACK; +	while (!opdone) { +		opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE); +		udelay(500); +		timeout++; +		if (timeout > 100) { +			dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num); +			rc = -ETIMEDOUT; +			break; +		} +	} +	dprintk(MANTIS_DEBUG, 1, "HIF Write success"); +	return rc; +} + + +int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr) +{ +	struct mantis_pci *mantis = ca->ca_priv; +	u32 hif_addr = 0, data, count = 4; + +	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num); +	mutex_lock(&ca->ca_lock); +	hif_addr &= ~MANTIS_GPIF_PCMCIAREG; +	hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; +	hif_addr |=  MANTIS_HIF_STATUS; +	hif_addr |=  addr; + +	mmwrite(hif_addr, MANTIS_GPIF_BRADDR); +	mmwrite(count, MANTIS_GPIF_BRBYTES); +	udelay(20); +	mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + +	if (mantis_hif_sbuf_opdone_wait(ca) != 0) { +		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num); +		mutex_unlock(&ca->ca_lock); +		return -EREMOTEIO; +	} +	data = mmread(MANTIS_GPIF_DIN); +	mutex_unlock(&ca->ca_lock); +	dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data); +	return (data >> 24) & 0xff; +} + +int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data) +{ +	struct mantis_slot *slot = ca->slot; +	struct mantis_pci *mantis = ca->ca_priv; +	u32 hif_addr = 0; + +	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num); +	mutex_lock(&ca->ca_lock); +	hif_addr &= ~MANTIS_GPIF_HIFRDWRN; +	hif_addr &= ~MANTIS_GPIF_PCMCIAREG; +	hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; +	hif_addr |=  MANTIS_HIF_STATUS; +	hif_addr |=  addr; + +	mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */ +	mmwrite(hif_addr, MANTIS_GPIF_ADDR); +	mmwrite(data, MANTIS_GPIF_DOUT); + +	if (mantis_hif_write_wait(ca) != 0) { +		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); +		mutex_unlock(&ca->ca_lock); +		return -EREMOTEIO; +	} +	dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr); +	mutex_unlock(&ca->ca_lock); + +	return 0; +} + +int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr) +{ +	struct mantis_pci *mantis = ca->ca_priv; +	u32 data, hif_addr = 0; + +	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num); +	mutex_lock(&ca->ca_lock); +	hif_addr &= ~MANTIS_GPIF_PCMCIAREG; +	hif_addr |=  MANTIS_GPIF_PCMCIAIOM; +	hif_addr |=  MANTIS_HIF_STATUS; +	hif_addr |=  addr; + +	mmwrite(hif_addr, MANTIS_GPIF_BRADDR); +	mmwrite(1, MANTIS_GPIF_BRBYTES); +	udelay(20); +	mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + +	if (mantis_hif_sbuf_opdone_wait(ca) != 0) { +		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); +		mutex_unlock(&ca->ca_lock); +		return -EREMOTEIO; +	} +	data = mmread(MANTIS_GPIF_DIN); +	dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data); +	udelay(50); +	mutex_unlock(&ca->ca_lock); + +	return (u8) data; +} + +int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data) +{ +	struct mantis_pci *mantis = ca->ca_priv; +	u32 hif_addr = 0; + +	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num); +	mutex_lock(&ca->ca_lock); +	hif_addr &= ~MANTIS_GPIF_PCMCIAREG; +	hif_addr &= ~MANTIS_GPIF_HIFRDWRN; +	hif_addr |=  MANTIS_GPIF_PCMCIAIOM; +	hif_addr |=  MANTIS_HIF_STATUS; +	hif_addr |=  addr; + +	mmwrite(hif_addr, MANTIS_GPIF_ADDR); +	mmwrite(data, MANTIS_GPIF_DOUT); + +	if (mantis_hif_write_wait(ca) != 0) { +		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); +		mutex_unlock(&ca->ca_lock); +		return -EREMOTEIO; +	} +	dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr); +	mutex_unlock(&ca->ca_lock); +	udelay(50); + +	return 0; +} + +int mantis_hif_init(struct mantis_ca *ca) +{ +	struct mantis_slot *slot = ca->slot; +	struct mantis_pci *mantis = ca->ca_priv; +	u32 irqcfg; + +	slot[0].slave_cfg = 0x70773028; +	dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num); + +	mutex_lock(&ca->ca_lock); +	irqcfg = mmread(MANTIS_GPIF_IRQCFG); +	irqcfg = MANTIS_MASK_BRRDY	| +		 MANTIS_MASK_WRACK	| +		 MANTIS_MASK_EXTIRQ	| +		 MANTIS_MASK_WSTO	| +		 MANTIS_MASK_OTHERR	| +		 MANTIS_MASK_OVFLW; + +	mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); +	mutex_unlock(&ca->ca_lock); + +	return 0; +} + +void mantis_hif_exit(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; +	u32 irqcfg; + +	dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num); +	mutex_lock(&ca->ca_lock); +	irqcfg = mmread(MANTIS_GPIF_IRQCFG); +	irqcfg &= ~MANTIS_MASK_BRRDY; +	mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); +	mutex_unlock(&ca->ca_lock); +} diff --git a/drivers/media/pci/mantis/mantis_hif.h b/drivers/media/pci/mantis/mantis_hif.h new file mode 100644 index 00000000000..9094f9ed236 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_hif.h @@ -0,0 +1,29 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_HIF_H +#define __MANTIS_HIF_H + +#define MANTIS_HIF_MEMRD		1 +#define MANTIS_HIF_MEMWR		2 +#define MANTIS_HIF_IOMRD		3 +#define MANTIS_HIF_IOMWR		4 + +#endif /* __MANTIS_HIF_H */ diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c new file mode 100644 index 00000000000..895ddba3c0f --- /dev/null +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -0,0 +1,268 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <asm/io.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/i2c.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_i2c.h" + +#define TRIALS			10000 + +static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ +	u32 rxd, i, stat, trials; + +	dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ", +		__func__, msg->addr); + +	for (i = 0; i < msg->len; i++) { +		rxd = (msg->addr << 25) | (1 << 24) +					| MANTIS_I2C_RATE_3 +					| MANTIS_I2C_STOP +					| MANTIS_I2C_PGMODE; + +		if (i == (msg->len - 1)) +			rxd &= ~MANTIS_I2C_STOP; + +		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); +		mmwrite(rxd, MANTIS_I2CDATA_CTL); + +		/* wait for xfer completion */ +		for (trials = 0; trials < TRIALS; trials++) { +			stat = mmread(MANTIS_INT_STAT); +			if (stat & MANTIS_INT_I2CDONE) +				break; +		} + +		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + +		/* wait for xfer completion */ +		for (trials = 0; trials < TRIALS; trials++) { +			stat = mmread(MANTIS_INT_STAT); +			if (stat & MANTIS_INT_I2CRACK) +				break; +		} + +		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + +		rxd = mmread(MANTIS_I2CDATA_CTL); +		msg->buf[i] = (u8)((rxd >> 8) & 0xFF); +		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); +	} +	dprintk(MANTIS_INFO, 0, "]\n"); + +	return 0; +} + +static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ +	int i; +	u32 txd = 0, stat, trials; + +	dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ", +		__func__, msg->addr); + +	for (i = 0; i < msg->len; i++) { +		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); +		txd = (msg->addr << 25) | (msg->buf[i] << 8) +					| MANTIS_I2C_RATE_3 +					| MANTIS_I2C_STOP +					| MANTIS_I2C_PGMODE; + +		if (i == (msg->len - 1)) +			txd &= ~MANTIS_I2C_STOP; + +		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); +		mmwrite(txd, MANTIS_I2CDATA_CTL); + +		/* wait for xfer completion */ +		for (trials = 0; trials < TRIALS; trials++) { +			stat = mmread(MANTIS_INT_STAT); +			if (stat & MANTIS_INT_I2CDONE) +				break; +		} + +		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + +		/* wait for xfer completion */ +		for (trials = 0; trials < TRIALS; trials++) { +			stat = mmread(MANTIS_INT_STAT); +			if (stat & MANTIS_INT_I2CRACK) +				break; +		} + +		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); +	} +	dprintk(MANTIS_INFO, 0, "]\n"); + +	return 0; +} + +static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ +	int ret = 0, i = 0, trials; +	u32 stat, data, txd; +	struct mantis_pci *mantis; +	struct mantis_hwconfig *config; + +	mantis = i2c_get_adapdata(adapter); +	BUG_ON(!mantis); +	config = mantis->hwconfig; +	BUG_ON(!config); + +	dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); +	mutex_lock(&mantis->i2c_lock); + +	while (i < num) { +		/* Byte MODE */ +		if ((config->i2c_mode & MANTIS_BYTE_MODE) && +		    ((i + 1) < num)			&& +		    (msgs[i].len < 2)			&& +		    (msgs[i + 1].len < 2)		&& +		    (msgs[i + 1].flags & I2C_M_RD)) { + +			dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n"); + +			/* Read operation */ +			txd = msgs[i].addr << 25 | (0x1 << 24) +						 | (msgs[i].buf[0] << 16) +						 | MANTIS_I2C_RATE_3; + +			mmwrite(txd, MANTIS_I2CDATA_CTL); +			/* wait for xfer completion */ +			for (trials = 0; trials < TRIALS; trials++) { +				stat = mmread(MANTIS_INT_STAT); +				if (stat & MANTIS_INT_I2CDONE) +					break; +			} + +			/* check for xfer completion */ +			if (stat & MANTIS_INT_I2CDONE) { +				/* check xfer was acknowledged */ +				if (stat & MANTIS_INT_I2CRACK) { +					data = mmread(MANTIS_I2CDATA_CTL); +					msgs[i + 1].buf[0] = (data >> 8) & 0xff; +					dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); +				} else { +					/* I/O error */ +					dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__); +					ret = -EIO; +					break; +				} +			} else { +				/* I/O error */ +				dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__); +				ret = -EIO; +				break; +			} +			i += 2; /* Write/Read operation in one go */ +		} + +		if (i < num) { +			if (msgs[i].flags & I2C_M_RD) +				ret = mantis_i2c_read(mantis, &msgs[i]); +			else +				ret = mantis_i2c_write(mantis, &msgs[i]); + +			i++; +			if (ret < 0) +				goto bail_out; +		} + +	} + +	mutex_unlock(&mantis->i2c_lock); + +	return num; + +bail_out: +	mutex_unlock(&mantis->i2c_lock); +	return ret; +} + +static u32 mantis_i2c_func(struct i2c_adapter *adapter) +{ +	return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm mantis_algo = { +	.master_xfer		= mantis_i2c_xfer, +	.functionality		= mantis_i2c_func, +}; + +int mantis_i2c_init(struct mantis_pci *mantis) +{ +	u32 intstat, intmask; +	struct i2c_adapter *i2c_adapter = &mantis->adapter; +	struct pci_dev *pdev		= mantis->pdev; + +	init_waitqueue_head(&mantis->i2c_wq); +	mutex_init(&mantis->i2c_lock); +	strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); +	i2c_set_adapdata(i2c_adapter, mantis); + +	i2c_adapter->owner	= THIS_MODULE; +	i2c_adapter->algo	= &mantis_algo; +	i2c_adapter->algo_data	= NULL; +	i2c_adapter->timeout	= 500; +	i2c_adapter->retries	= 3; +	i2c_adapter->dev.parent	= &pdev->dev; + +	mantis->i2c_rc		= i2c_add_adapter(i2c_adapter); +	if (mantis->i2c_rc < 0) +		return mantis->i2c_rc; + +	dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); + +	intstat = mmread(MANTIS_INT_STAT); +	intmask = mmread(MANTIS_INT_MASK); +	mmwrite(intstat, MANTIS_INT_STAT); +	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); +	intmask = mmread(MANTIS_INT_MASK); +	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_i2c_init); + +int mantis_i2c_exit(struct mantis_pci *mantis) +{ +	u32 intmask; + +	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); +	intmask = mmread(MANTIS_INT_MASK); +	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + +	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); +	i2c_del_adapter(&mantis->adapter); + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff --git a/drivers/media/pci/mantis/mantis_i2c.h b/drivers/media/pci/mantis/mantis_i2c.h new file mode 100644 index 00000000000..1342df2faed --- /dev/null +++ b/drivers/media/pci/mantis/mantis_i2c.h @@ -0,0 +1,30 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_I2C_H +#define __MANTIS_I2C_H + +#define I2C_STOP		(1 <<  0) +#define I2C_READ		(1 <<  1) + +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_I2C_H */ diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c new file mode 100644 index 00000000000..0e5252e5c0e --- /dev/null +++ b/drivers/media/pci/mantis/mantis_input.c @@ -0,0 +1,162 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if 0 /* Currently unused */ + +#include <media/rc-core.h> +#include <linux/pci.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +#define MODULE_NAME "mantis_core" +#define RC_MAP_MANTIS "rc-mantis" + +static struct rc_map_table mantis_ir_table[] = { +	{ 0x29, KEY_POWER	}, +	{ 0x28, KEY_FAVORITES	}, +	{ 0x30, KEY_TEXT	}, +	{ 0x17, KEY_INFO	}, /* Preview */ +	{ 0x23, KEY_EPG		}, +	{ 0x3b, KEY_F22		}, /* Record List */ +	{ 0x3c, KEY_1		}, +	{ 0x3e, KEY_2		}, +	{ 0x39, KEY_3		}, +	{ 0x36, KEY_4		}, +	{ 0x22, KEY_5		}, +	{ 0x20, KEY_6		}, +	{ 0x32, KEY_7		}, +	{ 0x26, KEY_8		}, +	{ 0x24, KEY_9		}, +	{ 0x2a, KEY_0		}, + +	{ 0x33, KEY_CANCEL	}, +	{ 0x2c, KEY_BACK	}, +	{ 0x15, KEY_CLEAR	}, +	{ 0x3f, KEY_TAB		}, +	{ 0x10, KEY_ENTER	}, +	{ 0x14, KEY_UP		}, +	{ 0x0d, KEY_RIGHT	}, +	{ 0x0e, KEY_DOWN	}, +	{ 0x11, KEY_LEFT	}, + +	{ 0x21, KEY_VOLUMEUP	}, +	{ 0x35, KEY_VOLUMEDOWN	}, +	{ 0x3d, KEY_CHANNELDOWN	}, +	{ 0x3a, KEY_CHANNELUP	}, +	{ 0x2e, KEY_RECORD	}, +	{ 0x2b, KEY_PLAY	}, +	{ 0x13, KEY_PAUSE	}, +	{ 0x25, KEY_STOP	}, + +	{ 0x1f, KEY_REWIND	}, +	{ 0x2d, KEY_FASTFORWARD	}, +	{ 0x1e, KEY_PREVIOUS	}, /* Replay |< */ +	{ 0x1d, KEY_NEXT	}, /* Skip   >| */ + +	{ 0x0b, KEY_CAMERA	}, /* Capture */ +	{ 0x0f, KEY_LANGUAGE	}, /* SAP */ +	{ 0x18, KEY_MODE	}, /* PIP */ +	{ 0x12, KEY_ZOOM	}, /* Full screen */ +	{ 0x1c, KEY_SUBTITLE	}, +	{ 0x2f, KEY_MUTE	}, +	{ 0x16, KEY_F20		}, /* L/R */ +	{ 0x38, KEY_F21		}, /* Hibernate */ + +	{ 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ +	{ 0x31, KEY_AGAIN	}, /* Recall */ +	{ 0x1a, KEY_KPPLUS	}, /* Zoom+ */ +	{ 0x19, KEY_KPMINUS	}, /* Zoom- */ +	{ 0x27, KEY_RED		}, +	{ 0x0C, KEY_GREEN	}, +	{ 0x01, KEY_YELLOW	}, +	{ 0x00, KEY_BLUE	}, +}; + +static struct rc_map_list ir_mantis_map = { +	.map = { +		.scan = mantis_ir_table, +		.size = ARRAY_SIZE(mantis_ir_table), +		.rc_type = RC_TYPE_UNKNOWN, +		.name = RC_MAP_MANTIS, +	} +}; + +int mantis_input_init(struct mantis_pci *mantis) +{ +	struct rc_dev *dev; +	int err; + +	err = rc_map_register(&ir_mantis_map); +	if (err) +		goto out; + +	dev = rc_allocate_device(); +	if (!dev) { +		dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); +		err = -ENOMEM; +		goto out_map; +	} + +	sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); +	sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); + +	dev->input_name         = mantis->input_name; +	dev->input_phys         = mantis->input_phys; +	dev->input_id.bustype   = BUS_PCI; +	dev->input_id.vendor    = mantis->vendor_id; +	dev->input_id.product   = mantis->device_id; +	dev->input_id.version   = 1; +	dev->driver_name        = MODULE_NAME; +	dev->map_name           = RC_MAP_MANTIS; +	dev->dev.parent         = &mantis->pdev->dev; + +	err = rc_register_device(dev); +	if (err) { +		dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err); +		goto out_dev; +	} + +	mantis->rc = dev; +	return 0; + +out_dev: +	rc_free_device(dev); +out_map: +	rc_map_unregister(&ir_mantis_map); +out: +	return err; +} + +int mantis_init_exit(struct mantis_pci *mantis) +{ +	rc_unregister_device(mantis->rc); +	rc_map_unregister(&ir_mantis_map); +	return 0; +} + +#endif diff --git a/drivers/media/pci/mantis/mantis_ioc.c b/drivers/media/pci/mantis/mantis_ioc.c new file mode 100644 index 00000000000..24fcdc63d6d --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ioc.c @@ -0,0 +1,124 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> +#include <linux/i2c.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_ioc.h" + +static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length) +{ +	struct i2c_adapter *adapter = &mantis->adapter; +	int err; +	u8 buf = reg; + +	struct i2c_msg msg[] = { +		{ .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 }, +		{ .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length }, +	}; + +	err = i2c_transfer(adapter, msg, 2); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", +			err, data[0], data[1]); + +		return err; +	} + +	return 0; +} +int mantis_get_mac(struct mantis_pci *mantis) +{ +	int err; +	u8 mac_addr[6] = {0}; + +	err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6); +	if (err < 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err); + +		return err; +	} + +	dprintk(MANTIS_ERROR, 0, "    MAC Address=[%pM]\n", mac_addr); + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_get_mac); + +/* Turn the given bit on or off. */ +void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ +	u32 cur; + +	dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value); +	cur = mmread(MANTIS_GPIF_ADDR); +	if (value) +		mantis->gpio_status = cur | (1 << bitpos); +	else +		mantis->gpio_status = cur & (~(1 << bitpos)); + +	dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status); +	mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); +	mmwrite(0x00, MANTIS_GPIF_DOUT); +} +EXPORT_SYMBOL_GPL(mantis_gpio_set_bits); + +int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl) +{ +	u32 reg; + +	reg = mmread(MANTIS_CONTROL); +	switch (stream_ctl) { +	case STREAM_TO_HIF: +		dprintk(MANTIS_DEBUG, 1, "Set stream to HIF"); +		reg &= 0xff - MANTIS_BYPASS; +		mmwrite(reg, MANTIS_CONTROL); +		reg |= MANTIS_BYPASS; +		mmwrite(reg, MANTIS_CONTROL); +		break; + +	case STREAM_TO_CAM: +		dprintk(MANTIS_DEBUG, 1, "Set stream to CAM"); +		reg |= MANTIS_BYPASS; +		mmwrite(reg, MANTIS_CONTROL); +		reg &= 0xff - MANTIS_BYPASS; +		mmwrite(reg, MANTIS_CONTROL); +		break; +	default: +		dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl); +		return -1; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_stream_control); diff --git a/drivers/media/pci/mantis/mantis_ioc.h b/drivers/media/pci/mantis/mantis_ioc.h new file mode 100644 index 00000000000..d56e002b295 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ioc.h @@ -0,0 +1,51 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_IOC_H +#define __MANTIS_IOC_H + +#define GPIF_A00		0x00 +#define GPIF_A01		0x01 +#define GPIF_A02		0x02 +#define GPIF_A03		0x03 +#define GPIF_A04		0x04 +#define GPIF_A05		0x05 +#define GPIF_A06		0x06 +#define GPIF_A07		0x07 +#define GPIF_A08		0x08 +#define GPIF_A09		0x09 +#define GPIF_A10		0x0a +#define GPIF_A11		0x0b + +#define GPIF_A12		0x0c +#define GPIF_A13		0x0d +#define GPIF_A14		0x0e + +enum mantis_stream_control { +	STREAM_TO_HIF = 0, +	STREAM_TO_CAM +}; + +extern int mantis_get_mac(struct mantis_pci *mantis); +extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value); + +extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl); + +#endif /* __MANTIS_IOC_H */ diff --git a/drivers/media/pci/mantis/mantis_link.h b/drivers/media/pci/mantis/mantis_link.h new file mode 100644 index 00000000000..2a814774a00 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_link.h @@ -0,0 +1,83 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_LINK_H +#define __MANTIS_LINK_H + +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include "dvb_ca_en50221.h" + +enum mantis_sbuf_status { +	MANTIS_SBUF_DATA_AVAIL		= 1, +	MANTIS_SBUF_DATA_EMPTY		= 2, +	MANTIS_SBUF_DATA_OVFLW		= 3 +}; + +struct mantis_slot { +	u32				timeout; +	u32				slave_cfg; +	u32				bar; +}; + +/* Physical layer */ +enum mantis_slot_state { +	MODULE_INSERTED			= 3, +	MODULE_XTRACTED			= 4 +}; + +struct mantis_ca { +	struct mantis_slot		slot[4]; + +	struct work_struct		hif_evm_work; + +	u32				hif_event; +	wait_queue_head_t		hif_opdone_wq; +	wait_queue_head_t		hif_brrdyw_wq; +	wait_queue_head_t		hif_data_wq; +	wait_queue_head_t		hif_write_wq; /* HIF Write op */ + +	enum mantis_sbuf_status		sbuf_status; + +	enum mantis_slot_state		slot_state; + +	void				*ca_priv; + +	struct dvb_ca_en50221		en50221; +	struct mutex			ca_lock; +}; + +/* CA */ +extern void mantis_event_cam_plugin(struct mantis_ca *ca); +extern void mantis_event_cam_unplug(struct mantis_ca *ca); +extern int mantis_pcmcia_init(struct mantis_ca *ca); +extern void mantis_pcmcia_exit(struct mantis_ca *ca); +extern int mantis_evmgr_init(struct mantis_ca *ca); +extern void mantis_evmgr_exit(struct mantis_ca *ca); + +/* HIF */ +extern int mantis_hif_init(struct mantis_ca *ca); +extern void mantis_hif_exit(struct mantis_ca *ca); +extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data); +extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data); + +#endif /* __MANTIS_LINK_H */ diff --git a/drivers/media/pci/mantis/mantis_pci.c b/drivers/media/pci/mantis/mantis_pci.c new file mode 100644 index 00000000000..9e89e045213 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_pci.c @@ -0,0 +1,168 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <asm/io.h> +#include <asm/page.h> +#include <linux/kmod.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/pci.h> + +#include <asm/irq.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_pci.h" + +#define DRIVER_NAME		"Mantis Core" + +int mantis_pci_init(struct mantis_pci *mantis) +{ +	u8 latency; +	struct mantis_hwconfig *config	= mantis->hwconfig; +	struct pci_dev *pdev		= mantis->pdev; +	int err, ret = 0; + +	dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", +		config->model_name, +		config->dev_type, +		mantis->pdev->bus->number, +		PCI_SLOT(mantis->pdev->devfn), +		PCI_FUNC(mantis->pdev->devfn)); + +	err = pci_enable_device(pdev); +	if (err != 0) { +		ret = -ENODEV; +		dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err); +		goto fail0; +	} + +	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); +	if (err != 0) { +		dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); +		ret = -ENOMEM; +		goto fail1; +	} + +	pci_set_master(pdev); + +	if (!request_mem_region(pci_resource_start(pdev, 0), +				pci_resource_len(pdev, 0), +				DRIVER_NAME)) { + +		dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !"); +		ret = -ENODEV; +		goto fail1; +	} + +	mantis->mmio = ioremap(pci_resource_start(pdev, 0), +			       pci_resource_len(pdev, 0)); + +	if (!mantis->mmio) { +		dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !"); +		ret = -ENODEV; +		goto fail2; +	} + +	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); +	mantis->latency = latency; +	mantis->revision = pdev->revision; + +	dprintk(MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ", +		mantis->revision, +		mantis->pdev->subsystem_vendor, +		mantis->pdev->subsystem_device); + +	dprintk(MANTIS_ERROR, 0, +		"irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n", +		mantis->pdev->irq, +		mantis->latency, +		mantis->mantis_addr, +		mantis->mmio); + +	err = request_irq(pdev->irq, +			  config->irq_handler, +			  IRQF_SHARED, +			  DRIVER_NAME, +			  mantis); + +	if (err != 0) { + +		dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err); +		ret = -ENODEV; +		goto fail3; +	} + +	pci_set_drvdata(pdev, mantis); +	return ret; + +	/* Error conditions */ +fail3: +	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret); +	if (mantis->mmio) +		iounmap(mantis->mmio); + +fail2: +	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret); +	release_mem_region(pci_resource_start(pdev, 0), +			   pci_resource_len(pdev, 0)); + +fail1: +	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret); +	pci_disable_device(pdev); + +fail0: +	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret); +	return ret; +} +EXPORT_SYMBOL_GPL(mantis_pci_init); + +void mantis_pci_exit(struct mantis_pci *mantis) +{ +	struct pci_dev *pdev = mantis->pdev; + +	dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio); +	free_irq(pdev->irq, mantis); +	if (mantis->mmio) { +		iounmap(mantis->mmio); +		release_mem_region(pci_resource_start(pdev, 0), +				   pci_resource_len(pdev, 0)); +	} + +	pci_disable_device(pdev); +} +EXPORT_SYMBOL_GPL(mantis_pci_exit); + +MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/mantis_pci.h b/drivers/media/pci/mantis/mantis_pci.h new file mode 100644 index 00000000000..65f00451908 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_pci.h @@ -0,0 +1,27 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_PCI_H +#define __MANTIS_PCI_H + +extern int mantis_pci_init(struct mantis_pci *mantis); +extern void mantis_pci_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_PCI_H */ diff --git a/drivers/media/pci/mantis/mantis_pcmcia.c b/drivers/media/pci/mantis/mantis_pcmcia.c new file mode 100644 index 00000000000..2f188c08966 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_pcmcia.c @@ -0,0 +1,121 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ +#include "mantis_reg.h" + +/* + * If Slot state is already PLUG_IN event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_plugin(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; + +	u32 gpif_irqcfg; + +	if (ca->slot_state == MODULE_XTRACTED) { +		dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num); +		udelay(50); +		mmwrite(0xda000000, MANTIS_CARD_RESET); +		gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG); +		gpif_irqcfg |= MANTIS_MASK_PLUGOUT; +		gpif_irqcfg &= ~MANTIS_MASK_PLUGIN; +		mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); +		udelay(500); +		ca->slot_state = MODULE_INSERTED; +	} +	udelay(100); +} + +/* + * If Slot state is already UN_PLUG event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_unplug(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; + +	u32 gpif_irqcfg; + +	if (ca->slot_state == MODULE_INSERTED) { +		dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num); +		udelay(50); +		mmwrite(0x00da0000, MANTIS_CARD_RESET); +		gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG); +		gpif_irqcfg |= MANTIS_MASK_PLUGIN; +		gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT; +		mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); +		udelay(500); +		ca->slot_state = MODULE_XTRACTED; +	} +	udelay(100); +} + +int mantis_pcmcia_init(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; + +	u32 gpif_stat, card_stat; + +	mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); +	gpif_stat = mmread(MANTIS_GPIF_STATUS); +	card_stat = mmread(MANTIS_GPIF_IRQCFG); + +	if (gpif_stat & MANTIS_GPIF_DETSTAT) { +		dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num); +		mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG); +		ca->slot_state = MODULE_INSERTED; +		dvb_ca_en50221_camchange_irq(&ca->en50221, +					     0, +					     DVB_CA_EN50221_CAMCHANGE_INSERTED); +	} else { +		dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num); +		mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG); +		ca->slot_state = MODULE_XTRACTED; +		dvb_ca_en50221_camchange_irq(&ca->en50221, +					     0, +					     DVB_CA_EN50221_CAMCHANGE_REMOVED); +	} + +	return 0; +} + +void mantis_pcmcia_exit(struct mantis_ca *ca) +{ +	struct mantis_pci *mantis = ca->ca_priv; + +	mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); +	mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); +} diff --git a/drivers/media/pci/mantis/mantis_reg.h b/drivers/media/pci/mantis/mantis_reg.h new file mode 100644 index 00000000000..7761f9dc7fe --- /dev/null +++ b/drivers/media/pci/mantis/mantis_reg.h @@ -0,0 +1,197 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_REG_H +#define __MANTIS_REG_H + +/* Interrupts */ +#define MANTIS_INT_STAT			0x00 +#define MANTIS_INT_MASK			0x04 + +#define MANTIS_INT_RISCSTAT		(0x0f << 28) +#define MANTIS_INT_RISCEN		(0x01 << 27) +#define MANTIS_INT_I2CRACK		(0x01 << 26) + +/* #define MANTIS_INT_GPIF			(0xff << 12) */ + +#define MANTIS_INT_PCMCIA7		(0x01 << 19) +#define MANTIS_INT_PCMCIA6		(0x01 << 18) +#define MANTIS_INT_PCMCIA5		(0x01 << 17) +#define MANTIS_INT_PCMCIA4		(0x01 << 16) +#define MANTIS_INT_PCMCIA3		(0x01 << 15) +#define MANTIS_INT_PCMCIA2		(0x01 << 14) +#define MANTIS_INT_PCMCIA1		(0x01 << 13) +#define MANTIS_INT_PCMCIA0		(0x01 << 12) +#define MANTIS_INT_IRQ1			(0x01 << 11) +#define MANTIS_INT_IRQ0			(0x01 << 10) +#define MANTIS_INT_OCERR		(0x01 <<  8) +#define MANTIS_INT_PABORT		(0x01 <<  7) +#define MANTIS_INT_RIPERR		(0x01 <<  6) +#define MANTIS_INT_PPERR		(0x01 <<  5) +#define MANTIS_INT_FTRGT		(0x01 <<  3) +#define MANTIS_INT_RISCI		(0x01 <<  1) +#define MANTIS_INT_I2CDONE		(0x01 <<  0) + +/* DMA */ +#define MANTIS_DMA_CTL			0x08 +#define MANTIS_GPIF_RD			(0xff << 24) +#define MANTIS_GPIF_WR			(0xff << 16) +#define MANTIS_CPU_DO			(0x01 << 10) +#define MANTIS_DRV_DO			(0x01 <<  9) +#define	MANTIS_I2C_RD			(0x01 <<  7) +#define MANTIS_I2C_WR			(0x01 <<  6) +#define MANTIS_DCAP_MODE		(0x01 <<  5) +#define MANTIS_FIFO_TP_4		(0x00 <<  3) +#define MANTIS_FIFO_TP_8		(0x01 <<  3) +#define MANTIS_FIFO_TP_16		(0x02 <<  3) +#define MANTIS_FIFO_EN			(0x01 <<  2) +#define MANTIS_DCAP_EN			(0x01 <<  1) +#define MANTIS_RISC_EN			(0x01 <<  0) + +/* DEBUG */ +#define MANTIS_DEBUGREG			0x0c +#define MANTIS_DATINV			(0x0e <<  7) +#define MANTIS_TOP_DEBUGSEL		(0x07 <<  4) +#define MANTIS_PCMCIA_DEBUGSEL		(0x0f <<  0) + +#define MANTIS_RISC_START		0x10 +#define MANTIS_RISC_PC			0x14 + +/* I2C */ +#define MANTIS_I2CDATA_CTL		0x18 +#define MANTIS_I2C_RATE_1		(0x00 <<  6) +#define MANTIS_I2C_RATE_2		(0x01 <<  6) +#define MANTIS_I2C_RATE_3		(0x02 <<  6) +#define MANTIS_I2C_RATE_4		(0x03 <<  6) +#define MANTIS_I2C_STOP			(0x01 <<  5) +#define MANTIS_I2C_PGMODE		(0x01 <<  3) + +/* DATA */ +#define MANTIS_CMD_DATA_R1		0x20 +#define MANTIS_CMD_DATA_3		(0xff << 24) +#define MANTIS_CMD_DATA_2		(0xff << 16) +#define MANTIS_CMD_DATA_1		(0xff <<  8) +#define MANTIS_CMD_DATA_0		(0xff <<  0) + +#define MANTIS_CMD_DATA_R2		0x24 +#define MANTIS_CMD_DATA_7		(0xff << 24) +#define MANTIS_CMD_DATA_6		(0xff << 16) +#define MANTIS_CMD_DATA_5		(0xff <<  8) +#define MANTIS_CMD_DATA_4		(0xff <<  0) + +#define MANTIS_CONTROL			0x28 +#define MANTIS_DET			(0x01 <<  7) +#define MANTIS_DAT_CF_EN		(0x01 <<  6) +#define MANTIS_ACS			(0x03 <<  4) +#define MANTIS_VCCEN			(0x01 <<  3) +#define MANTIS_BYPASS			(0x01 <<  2) +#define MANTIS_MRST			(0x01 <<  1) +#define MANTIS_CRST_INT			(0x01 <<  0) + +#define MANTIS_GPIF_CFGSLA		0x84 +#define MANTIS_GPIF_WAITSMPL		(0x07 << 28) +#define MANTIS_GPIF_BYTEADDRSUB		(0x01 << 25) +#define MANTIS_GPIF_WAITPOL		(0x01 << 24) +#define MANTIS_GPIF_NCDELAY		(0x07 << 20) +#define MANTIS_GPIF_RW2CSDELAY		(0x07 << 16) +#define MANTIS_GPIF_SLFTIMEDMODE	(0x01 << 15) +#define MANTIS_GPIF_SLFTIMEDDELY	(0x7f <<  8) +#define MANTIS_GPIF_DEVTYPE		(0x07 <<  4) +#define MANTIS_GPIF_BIGENDIAN		(0x01 <<  3) +#define MANTIS_GPIF_FETCHCMD		(0x03 <<  1) +#define MANTIS_GPIF_HWORDDEV		(0x01 <<  0) + +#define MANTIS_GPIF_WSTOPER		0x90 +#define MANTIS_GPIF_WSTOPERWREN3	(0x01 << 31) +#define MANTIS_GPIF_PARBOOTN		(0x01 << 29) +#define MANTIS_GPIF_WSTOPERSLID3	(0x1f << 24) +#define MANTIS_GPIF_WSTOPERWREN2	(0x01 << 23) +#define MANTIS_GPIF_WSTOPERSLID2	(0x1f << 16) +#define MANTIS_GPIF_WSTOPERWREN1	(0x01 << 15) +#define MANTIS_GPIF_WSTOPERSLID1	(0x1f <<  8) +#define MANTIS_GPIF_WSTOPERWREN0	(0x01 <<  7) +#define MANTIS_GPIF_WSTOPERSLID0	(0x1f <<  0) + +#define MANTIS_GPIF_CS2RW		0x94 +#define MANTIS_GPIF_CS2RWWREN3		(0x01 << 31) +#define MANTIS_GPIF_CS2RWDELY3		(0x3f << 24) +#define MANTIS_GPIF_CS2RWWREN2		(0x01 << 23) +#define MANTIS_GPIF_CS2RWDELY2		(0x3f << 16) +#define MANTIS_GPIF_CS2RWWREN1		(0x01 << 15) +#define MANTIS_GPIF_CS2RWDELY1		(0x3f <<  8) +#define MANTIS_GPIF_CS2RWWREN0		(0x01 <<  7) +#define MANTIS_GPIF_CS2RWDELY0		(0x3f <<  0) + +#define MANTIS_GPIF_IRQCFG		0x98 +#define MANTIS_GPIF_IRQPOL		(0x01 <<  8) +#define MANTIS_MASK_WRACK		(0x01 <<  7) +#define MANTIS_MASK_BRRDY		(0x01 <<  6) +#define MANTIS_MASK_OVFLW		(0x01 <<  5) +#define MANTIS_MASK_OTHERR		(0x01 <<  4) +#define MANTIS_MASK_WSTO		(0x01 <<  3) +#define MANTIS_MASK_EXTIRQ		(0x01 <<  2) +#define MANTIS_MASK_PLUGIN		(0x01 <<  1) +#define MANTIS_MASK_PLUGOUT		(0x01 <<  0) + +#define MANTIS_GPIF_STATUS		0x9c +#define MANTIS_SBUF_KILLOP		(0x01 << 15) +#define MANTIS_SBUF_OPDONE		(0x01 << 14) +#define MANTIS_SBUF_EMPTY		(0x01 << 13) +#define MANTIS_GPIF_DETSTAT		(0x01 <<  9) +#define MANTIS_GPIF_INTSTAT		(0x01 <<  8) +#define MANTIS_GPIF_WRACK		(0x01 <<  7) +#define MANTIS_GPIF_BRRDY		(0x01 <<  6) +#define MANTIS_SBUF_OVFLW		(0x01 <<  5) +#define MANTIS_GPIF_OTHERR		(0x01 <<  4) +#define MANTIS_SBUF_WSTO		(0x01 <<  3) +#define MANTIS_GPIF_EXTIRQ		(0x01 <<  2) +#define MANTIS_CARD_PLUGIN		(0x01 <<  1) +#define MANTIS_CARD_PLUGOUT		(0x01 <<  0) + +#define MANTIS_GPIF_BRADDR		0xa0 +#define MANTIS_GPIF_PCMCIAREG		(0x01 		<< 27) +#define MANTIS_GPIF_PCMCIAIOM		(0x01 		<< 26) +#define MANTIS_GPIF_BR_ADDR		(0xfffffff	<<  0) + +#define MANTIS_GPIF_BRBYTES		0xa4 +#define MANTIS_GPIF_BRCNT		(0xfff 		<<  0) + +#define MANTIS_PCMCIA_RESET		0xa8 +#define MANTIS_PCMCIA_RSTVAL		(0xff << 0) + +#define MANTIS_CARD_RESET		0xac + +#define MANTIS_GPIF_ADDR		0xb0 +#define MANTIS_GPIF_HIFRDWRN		(0x01		<< 31) +#define MANTIS_GPIF_PCMCIAREG		(0x01		<< 27) +#define MANTIS_GPIF_PCMCIAIOM		(0x01		<< 26) +#define MANTIS_GPIF_HIFADDR		(0xfffffff	<<  0) + +#define MANTIS_GPIF_DOUT		0xb4 +#define MANTIS_GPIF_HIFDOUT		(0xfffffff	<<  0) + +#define MANTIS_GPIF_DIN			0xb8 +#define MANTIS_GPIF_HIFDIN		(0xfffffff	<<  0) + +#define MANTIS_GPIF_SPARE		0xbc +#define MANTIS_GPIF_LOGICRD		(0xffff		<< 16) +#define MANTIS_GPIF_LOGICRW		(0xffff		<<  0) + +#endif /* __MANTIS_REG_H */ diff --git a/drivers/media/pci/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c new file mode 100644 index 00000000000..a7071921863 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_uart.c @@ -0,0 +1,188 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <asm/io.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +struct mantis_uart_params { +	enum mantis_baud	baud_rate; +	enum mantis_parity	parity; +}; + +static struct { +	char string[7]; +} rates[5] = { +	{ "9600" }, +	{ "19200" }, +	{ "38400" }, +	{ "57600" }, +	{ "115200" } +}; + +static struct { +	char string[5]; +} parity[3] = { +	{ "NONE" }, +	{ "ODD" }, +	{ "EVEN" } +}; + +#define UART_MAX_BUF			16 + +static int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +{ +	struct mantis_hwconfig *config = mantis->hwconfig; +	u32 stat = 0, i; + +	/* get data */ +	for (i = 0; i < (config->bytes + 1); i++) { + +		stat = mmread(MANTIS_UART_STAT); + +		if (stat & MANTIS_UART_RXFIFO_FULL) { +			dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); +		} +		data[i] = mmread(MANTIS_UART_RXD) & 0x3f; + +		dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); + +		if (data[i] & (1 << 7)) { +			dprintk(MANTIS_ERROR, 1, "UART framing error"); +			return -EINVAL; +		} +		if (data[i] & (1 << 6)) { +			dprintk(MANTIS_ERROR, 1, "UART parity error"); +			return -EINVAL; +		} +	} + +	return 0; +} + +static void mantis_uart_work(struct work_struct *work) +{ +	struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); +	struct mantis_hwconfig *config = mantis->hwconfig; +	u8 buf[16]; +	int i; + +	mantis_uart_read(mantis, buf); + +	for (i = 0; i < (config->bytes + 1); i++) +		dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); + +	dprintk(MANTIS_DEBUG, 0, "\n"); +} + +static int mantis_uart_setup(struct mantis_pci *mantis, +			     struct mantis_uart_params *params) +{ +	u32 reg; + +	mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); + +	reg = mmread(MANTIS_UART_BAUD); + +	switch (params->baud_rate) { +	case MANTIS_BAUD_9600: +		reg |= 0xd8; +		break; +	case MANTIS_BAUD_19200: +		reg |= 0x6c; +		break; +	case MANTIS_BAUD_38400: +		reg |= 0x36; +		break; +	case MANTIS_BAUD_57600: +		reg |= 0x23; +		break; +	case MANTIS_BAUD_115200: +		reg |= 0x11; +		break; +	default: +		return -EINVAL; +	} + +	mmwrite(reg, MANTIS_UART_BAUD); + +	return 0; +} + +int mantis_uart_init(struct mantis_pci *mantis) +{ +	struct mantis_hwconfig *config = mantis->hwconfig; +	struct mantis_uart_params params; + +	/* default parity: */ +	params.baud_rate = config->baud_rate; +	params.parity = config->parity; +	dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s", +		rates[params.baud_rate].string, +		parity[params.parity].string); + +	init_waitqueue_head(&mantis->uart_wq); +	spin_lock_init(&mantis->uart_lock); + +	INIT_WORK(&mantis->uart_work, mantis_uart_work); + +	/* disable interrupt */ +	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); + +	mantis_uart_setup(mantis, ¶ms); + +	/* default 1 byte */ +	mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); + +	/* flush buffer */ +	mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); + +	/* enable interrupt */ +	mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); +	mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); + +	schedule_work(&mantis->uart_work); +	dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); + +	return 0; +} +EXPORT_SYMBOL_GPL(mantis_uart_init); + +void mantis_uart_exit(struct mantis_pci *mantis) +{ +	/* disable interrupt */ +	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); +	flush_work(&mantis->uart_work); +} +EXPORT_SYMBOL_GPL(mantis_uart_exit); diff --git a/drivers/media/pci/mantis/mantis_uart.h b/drivers/media/pci/mantis/mantis_uart.h new file mode 100644 index 00000000000..ffb62a0a5a1 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_uart.h @@ -0,0 +1,58 @@ +/* +	Mantis PCI bridge driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_UART_H +#define __MANTIS_UART_H + +#define MANTIS_UART_CTL			0xe0 +#define MANTIS_UART_RXINT		(1 << 4) +#define MANTIS_UART_RXFLUSH		(1 << 2) + +#define MANTIS_UART_RXD			0xe8 +#define MANTIS_UART_BAUD		0xec + +#define MANTIS_UART_STAT		0xf0 +#define MANTIS_UART_RXFIFO_DATA		(1 << 7) +#define MANTIS_UART_RXFIFO_EMPTY	(1 << 6) +#define MANTIS_UART_RXFIFO_FULL		(1 << 3) +#define MANTIS_UART_FRAME_ERR		(1 << 2) +#define MANTIS_UART_PARITY_ERR		(1 << 1) +#define MANTIS_UART_RXTHRESH_INT	(1 << 0) + +enum mantis_baud { +	MANTIS_BAUD_9600	= 0, +	MANTIS_BAUD_19200, +	MANTIS_BAUD_38400, +	MANTIS_BAUD_57600, +	MANTIS_BAUD_115200 +}; + +enum mantis_parity { +	MANTIS_PARITY_NONE	= 0, +	MANTIS_PARITY_EVEN, +	MANTIS_PARITY_ODD, +}; + +struct mantis_pci; + +extern int mantis_uart_init(struct mantis_pci *mantis); +extern void mantis_uart_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_UART_H */ diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c new file mode 100644 index 00000000000..115003e8d19 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1033.c @@ -0,0 +1,212 @@ +/* +	Mantis VP-1033 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "stv0299.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1033.h" +#include "mantis_reg.h" + +u8 lgtdqcs001f_inittab[] = { +	0x01, 0x15, +	0x02, 0x30, +	0x03, 0x00, +	0x04, 0x2a, +	0x05, 0x85, +	0x06, 0x02, +	0x07, 0x00, +	0x08, 0x00, +	0x0c, 0x01, +	0x0d, 0x81, +	0x0e, 0x44, +	0x0f, 0x94, +	0x10, 0x3c, +	0x11, 0x84, +	0x12, 0xb9, +	0x13, 0xb5, +	0x14, 0x4f, +	0x15, 0xc9, +	0x16, 0x80, +	0x17, 0x36, +	0x18, 0xfb, +	0x19, 0xcf, +	0x1a, 0xbc, +	0x1c, 0x2b, +	0x1d, 0x27, +	0x1e, 0x00, +	0x1f, 0x0b, +	0x20, 0xa1, +	0x21, 0x60, +	0x22, 0x00, +	0x23, 0x00, +	0x28, 0x00, +	0x29, 0x28, +	0x2a, 0x14, +	0x2b, 0x0f, +	0x2c, 0x09, +	0x2d, 0x05, +	0x31, 0x1f, +	0x32, 0x19, +	0x33, 0xfc, +	0x34, 0x13, +	0xff, 0xff, +}; + +#define MANTIS_MODEL_NAME	"VP-1033" +#define MANTIS_DEV_TYPE		"DVB-S/DSS" + +static int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) +{ +	struct dtv_frontend_properties *p = &fe->dtv_property_cache; +	struct mantis_pci *mantis	= fe->dvb->priv; +	struct i2c_adapter *adapter	= &mantis->adapter; + +	u8 buf[4]; +	u32 div; + + +	struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; + +	div = p->frequency / 250; + +	buf[0] = (div >> 8) & 0x7f; +	buf[1] =  div & 0xff; +	buf[2] =  0x83; +	buf[3] =  0xc0; + +	if (p->frequency < 1531000) +		buf[3] |= 0x04; +	else +		buf[3] &= ~0x04; +	if (i2c_transfer(adapter, &msg, 1) < 0) { +		dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed"); +		return -EIO; +	} +	msleep_interruptible(100); + +	return 0; +} + +static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, +				       u32 srate, u32 ratio) +{ +	u8 aclk = 0; +	u8 bclk = 0; + +	if (srate < 1500000) { +		aclk = 0xb7; +		bclk = 0x47; +	} else if (srate < 3000000) { +		aclk = 0xb7; +		bclk = 0x4b; +	} else if (srate < 7000000) { +		aclk = 0xb7; +		bclk = 0x4f; +	} else if (srate < 14000000) { +		aclk = 0xb7; +		bclk = 0x53; +	} else if (srate < 30000000) { +		aclk = 0xb6; +		bclk = 0x53; +	} else if (srate < 45000000) { +		aclk = 0xb4; +		bclk = 0x51; +	} +	stv0299_writereg(fe, 0x13, aclk); +	stv0299_writereg(fe, 0x14, bclk); + +	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); +	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff); +	stv0299_writereg(fe, 0x21,  ratio & 0xf0); + +	return 0; +} + +struct stv0299_config lgtdqcs001f_config = { +	.demod_address		= 0x68, +	.inittab		= lgtdqcs001f_inittab, +	.mclk			= 88000000UL, +	.invert			= 0, +	.skip_reinit		= 0, +	.volt13_op0_op1		= STV0299_VOLT13_OP0, +	.min_delay_ms		= 100, +	.set_symbol_rate	= lgtdqcs001f_set_symbol_rate, +}; + +static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter	= &mantis->adapter; + +	int err = 0; + +	err = mantis_frontend_power(mantis, POWER_ON); +	if (err == 0) { +		mantis_frontend_soft_reset(mantis); +		msleep(250); + +		dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)"); +		fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter); + +		if (fe) { +			fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set; +			dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", +				lgtdqcs001f_config.demod_address); + +			dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success"); +		} else { +			return -1; +		} +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; +	} +	mantis->fe = fe; +	dprintk(MANTIS_ERROR, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp1033_config = { +	.model_name		= MANTIS_MODEL_NAME, +	.dev_type		= MANTIS_DEV_TYPE, +	.ts_size		= MANTIS_TS_204, + +	.baud_rate		= MANTIS_BAUD_9600, +	.parity			= MANTIS_PARITY_NONE, +	.bytes			= 0, + +	.frontend_init		= vp1033_frontend_init, +	.power			= GPIF_A12, +	.reset			= GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp1033.h b/drivers/media/pci/mantis/mantis_vp1033.h new file mode 100644 index 00000000000..7daaa1bf127 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1033.h @@ -0,0 +1,30 @@ +/* +	Mantis VP-1033 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1033_H +#define __MANTIS_VP1033_H + +#include "mantis_common.h" + +#define MANTIS_VP_1033_DVB_S	0x0016 + +extern struct mantis_hwconfig vp1033_config; + +#endif /* __MANTIS_VP1033_H */ diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c new file mode 100644 index 00000000000..430ae84ce52 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1034.c @@ -0,0 +1,120 @@ +/* +	Mantis VP-1034 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mb86a16.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1034.h" +#include "mantis_reg.h" + +struct mb86a16_config vp1034_mb86a16_config = { +	.demod_address	= 0x08, +	.set_voltage	= vp1034_set_voltage, +}; + +#define MANTIS_MODEL_NAME	"VP-1034" +#define MANTIS_DEV_TYPE		"DVB-S/DSS" + +int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ +	struct mantis_pci *mantis = fe->dvb->priv; + +	switch (voltage) { +	case SEC_VOLTAGE_13: +		dprintk(MANTIS_ERROR, 1, "Polarization=[13V]"); +		mantis_gpio_set_bits(mantis, 13, 1); +		mantis_gpio_set_bits(mantis, 14, 0); +		break; +	case SEC_VOLTAGE_18: +		dprintk(MANTIS_ERROR, 1, "Polarization=[18V]"); +		mantis_gpio_set_bits(mantis, 13, 1); +		mantis_gpio_set_bits(mantis, 14, 1); +		break; +	case SEC_VOLTAGE_OFF: +		dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN"); +		break; +	default: +		dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage); +		return -EINVAL; +	} +	mmwrite(0x00, MANTIS_GPIF_DOUT); + +	return 0; +} + +static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter	= &mantis->adapter; + +	int err = 0; + +	err = mantis_frontend_power(mantis, POWER_ON); +	if (err == 0) { +		mantis_frontend_soft_reset(mantis); +		msleep(250); + +		dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); +		fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter); +		if (fe) { +			dprintk(MANTIS_ERROR, 1, +			"found MB86A16 DVB-S/DSS frontend @0x%02x", +			vp1034_mb86a16_config.demod_address); + +		} else { +			return -1; +		} +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; +	} +	mantis->fe = fe; +	dprintk(MANTIS_ERROR, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp1034_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_204, + +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, + +	.frontend_init	= vp1034_frontend_init, +	.power		= GPIF_A12, +	.reset		= GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp1034.h b/drivers/media/pci/mantis/mantis_vp1034.h new file mode 100644 index 00000000000..323f38ef8e3 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1034.h @@ -0,0 +1,33 @@ +/* +	Mantis VP-1034 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1034_H +#define __MANTIS_VP1034_H + +#include "dvb_frontend.h" +#include "mantis_common.h" + + +#define MANTIS_VP_1034_DVB_S	0x0014 + +extern struct mantis_hwconfig vp1034_config; +extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + +#endif /* __MANTIS_VP1034_H */ diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c new file mode 100644 index 00000000000..07a20748b70 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1041.c @@ -0,0 +1,357 @@ +/* +	Mantis VP-1041 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1041.h" +#include "stb0899_reg.h" +#include "stb0899_drv.h" +#include "stb0899_cfg.h" +#include "stb6100_cfg.h" +#include "stb6100.h" +#include "lnbp21.h" + +#define MANTIS_MODEL_NAME	"VP-1041" +#define MANTIS_DEV_TYPE		"DSS/DVB-S/DVB-S2" + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { + +	/* 0x0000000b, *//* SYSREG */ +	{ STB0899_DEV_ID		, 0x30 }, +	{ STB0899_DISCNTRL1		, 0x32 }, +	{ STB0899_DISCNTRL2     	, 0x80 }, +	{ STB0899_DISRX_ST0     	, 0x04 }, +	{ STB0899_DISRX_ST1     	, 0x00 }, +	{ STB0899_DISPARITY     	, 0x00 }, +	{ STB0899_DISSTATUS		, 0x20 }, +	{ STB0899_DISF22        	, 0x99 }, +	{ STB0899_DISF22RX      	, 0xa8 }, +	/* SYSREG ? */ +	{ STB0899_ACRPRESC      	, 0x11 }, +	{ STB0899_ACRDIV1       	, 0x0a }, +	{ STB0899_ACRDIV2       	, 0x05 }, +	{ STB0899_DACR1         	, 0x00 }, +	{ STB0899_DACR2         	, 0x00 }, +	{ STB0899_OUTCFG        	, 0x00 }, +	{ STB0899_MODECFG       	, 0x00 }, +	{ STB0899_IRQSTATUS_3		, 0xfe }, +	{ STB0899_IRQSTATUS_2		, 0x03 }, +	{ STB0899_IRQSTATUS_1		, 0x7c }, +	{ STB0899_IRQSTATUS_0		, 0xf4 }, +	{ STB0899_IRQMSK_3      	, 0xf3 }, +	{ STB0899_IRQMSK_2      	, 0xfc }, +	{ STB0899_IRQMSK_1      	, 0xff }, +	{ STB0899_IRQMSK_0		, 0xff }, +	{ STB0899_IRQCFG		, 0x00 }, +	{ STB0899_I2CCFG        	, 0x88 }, +	{ STB0899_I2CRPT        	, 0x58 }, +	{ STB0899_IOPVALUE5		, 0x00 }, +	{ STB0899_IOPVALUE4		, 0x33 }, +	{ STB0899_IOPVALUE3		, 0x6d }, +	{ STB0899_IOPVALUE2		, 0x90 }, +	{ STB0899_IOPVALUE1		, 0x60 }, +	{ STB0899_IOPVALUE0		, 0x00 }, +	{ STB0899_GPIO00CFG     	, 0x82 }, +	{ STB0899_GPIO01CFG     	, 0x82 }, +	{ STB0899_GPIO02CFG     	, 0x82 }, +	{ STB0899_GPIO03CFG     	, 0x82 }, +	{ STB0899_GPIO04CFG     	, 0x82 }, +	{ STB0899_GPIO05CFG     	, 0x82 }, +	{ STB0899_GPIO06CFG     	, 0x82 }, +	{ STB0899_GPIO07CFG     	, 0x82 }, +	{ STB0899_GPIO08CFG     	, 0x82 }, +	{ STB0899_GPIO09CFG     	, 0x82 }, +	{ STB0899_GPIO10CFG     	, 0x82 }, +	{ STB0899_GPIO11CFG     	, 0x82 }, +	{ STB0899_GPIO12CFG     	, 0x82 }, +	{ STB0899_GPIO13CFG     	, 0x82 }, +	{ STB0899_GPIO14CFG     	, 0x82 }, +	{ STB0899_GPIO15CFG     	, 0x82 }, +	{ STB0899_GPIO16CFG     	, 0x82 }, +	{ STB0899_GPIO17CFG     	, 0x82 }, +	{ STB0899_GPIO18CFG     	, 0x82 }, +	{ STB0899_GPIO19CFG     	, 0x82 }, +	{ STB0899_GPIO20CFG     	, 0x82 }, +	{ STB0899_SDATCFG       	, 0xb8 }, +	{ STB0899_SCLTCFG       	, 0xba }, +	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */ +	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */ +	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */ +	{ STB0899_DIRCLKCFG     	, 0x82 }, +	{ STB0899_CLKOUT27CFG   	, 0x7e }, +	{ STB0899_STDBYCFG      	, 0x82 }, +	{ STB0899_CS0CFG        	, 0x82 }, +	{ STB0899_CS1CFG        	, 0x82 }, +	{ STB0899_DISEQCOCFG    	, 0x20 }, +	{ STB0899_GPIO32CFG		, 0x82 }, +	{ STB0899_GPIO33CFG		, 0x82 }, +	{ STB0899_GPIO34CFG		, 0x82 }, +	{ STB0899_GPIO35CFG		, 0x82 }, +	{ STB0899_GPIO36CFG		, 0x82 }, +	{ STB0899_GPIO37CFG		, 0x82 }, +	{ STB0899_GPIO38CFG		, 0x82 }, +	{ STB0899_GPIO39CFG		, 0x82 }, +	{ STB0899_NCOARSE       	, 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ +	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ +	{ STB0899_FILTCTRL      	, 0x00 }, +	{ STB0899_SYSCTRL       	, 0x01 }, +	{ STB0899_STOPCLK1      	, 0x20 }, +	{ STB0899_STOPCLK2      	, 0x00 }, +	{ STB0899_INTBUFSTATUS		, 0x00 }, +	{ STB0899_INTBUFCTRL    	, 0x0a }, +	{ 0xffff			, 0xff }, +}; + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { +	{ STB0899_DEMOD         	, 0x00 }, +	{ STB0899_RCOMPC        	, 0xc9 }, +	{ STB0899_AGC1CN        	, 0x01 }, +	{ STB0899_AGC1REF       	, 0x10 }, +	{ STB0899_RTC			, 0x23 }, +	{ STB0899_TMGCFG        	, 0x4e }, +	{ STB0899_AGC2REF       	, 0x34 }, +	{ STB0899_TLSR          	, 0x84 }, +	{ STB0899_CFD           	, 0xf7 }, +	{ STB0899_ACLC			, 0x87 }, +	{ STB0899_BCLC          	, 0x94 }, +	{ STB0899_EQON          	, 0x41 }, +	{ STB0899_LDT           	, 0xf1 }, +	{ STB0899_LDT2          	, 0xe3 }, +	{ STB0899_EQUALREF      	, 0xb4 }, +	{ STB0899_TMGRAMP       	, 0x10 }, +	{ STB0899_TMGTHD        	, 0x30 }, +	{ STB0899_IDCCOMP		, 0xfd }, +	{ STB0899_QDCCOMP		, 0xff }, +	{ STB0899_POWERI		, 0x0c }, +	{ STB0899_POWERQ		, 0x0f }, +	{ STB0899_RCOMP			, 0x6c }, +	{ STB0899_AGCIQIN		, 0x80 }, +	{ STB0899_AGC2I1		, 0x06 }, +	{ STB0899_AGC2I2		, 0x00 }, +	{ STB0899_TLIR			, 0x30 }, +	{ STB0899_RTF			, 0x7f }, +	{ STB0899_DSTATUS		, 0x00 }, +	{ STB0899_LDI			, 0xbc }, +	{ STB0899_CFRM			, 0xea }, +	{ STB0899_CFRL			, 0x31 }, +	{ STB0899_NIRM			, 0x2b }, +	{ STB0899_NIRL			, 0x80 }, +	{ STB0899_ISYMB			, 0x1d }, +	{ STB0899_QSYMB			, 0xa6 }, +	{ STB0899_SFRH          	, 0x2f }, +	{ STB0899_SFRM          	, 0x68 }, +	{ STB0899_SFRL          	, 0x40 }, +	{ STB0899_SFRUPH        	, 0x2f }, +	{ STB0899_SFRUPM        	, 0x68 }, +	{ STB0899_SFRUPL        	, 0x40 }, +	{ STB0899_EQUAI1		, 0x02 }, +	{ STB0899_EQUAQ1		, 0xff }, +	{ STB0899_EQUAI2		, 0x04 }, +	{ STB0899_EQUAQ2		, 0x05 }, +	{ STB0899_EQUAI3		, 0x02 }, +	{ STB0899_EQUAQ3		, 0xfd }, +	{ STB0899_EQUAI4		, 0x03 }, +	{ STB0899_EQUAQ4		, 0x07 }, +	{ STB0899_EQUAI5		, 0x08 }, +	{ STB0899_EQUAQ5		, 0xf5 }, +	{ STB0899_DSTATUS2		, 0x00 }, +	{ STB0899_VSTATUS       	, 0x00 }, +	{ STB0899_VERROR		, 0x86 }, +	{ STB0899_IQSWAP		, 0x2a }, +	{ STB0899_ECNT1M		, 0x00 }, +	{ STB0899_ECNT1L		, 0x00 }, +	{ STB0899_ECNT2M		, 0x00 }, +	{ STB0899_ECNT2L		, 0x00 }, +	{ STB0899_ECNT3M		, 0x0a }, +	{ STB0899_ECNT3L		, 0xad }, +	{ STB0899_FECAUTO1      	, 0x06 }, +	{ STB0899_FECM			, 0x01 }, +	{ STB0899_VTH12         	, 0xb0 }, +	{ STB0899_VTH23         	, 0x7a }, +	{ STB0899_VTH34			, 0x58 }, +	{ STB0899_VTH56         	, 0x38 }, +	{ STB0899_VTH67         	, 0x34 }, +	{ STB0899_VTH78         	, 0x24 }, +	{ STB0899_PRVIT         	, 0xff }, +	{ STB0899_VITSYNC       	, 0x19 }, +	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ +	{ STB0899_TSULC         	, 0x42 }, +	{ STB0899_RSLLC         	, 0x41 }, +	{ STB0899_TSLPL			, 0x12 }, +	{ STB0899_TSCFGH        	, 0x0c }, +	{ STB0899_TSCFGM        	, 0x00 }, +	{ STB0899_TSCFGL        	, 0x00 }, +	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */ +	{ STB0899_RSSYNCDEL     	, 0x00 }, +	{ STB0899_TSINHDELH     	, 0x02 }, +	{ STB0899_TSINHDELM		, 0x00 }, +	{ STB0899_TSINHDELL		, 0x00 }, +	{ STB0899_TSLLSTKM		, 0x1b }, +	{ STB0899_TSLLSTKL		, 0xb3 }, +	{ STB0899_TSULSTKM		, 0x00 }, +	{ STB0899_TSULSTKL		, 0x00 }, +	{ STB0899_PCKLENUL		, 0xbc }, +	{ STB0899_PCKLENLL		, 0xcc }, +	{ STB0899_RSPCKLEN		, 0xbd }, +	{ STB0899_TSSTATUS		, 0x90 }, +	{ STB0899_ERRCTRL1      	, 0xb6 }, +	{ STB0899_ERRCTRL2      	, 0x95 }, +	{ STB0899_ERRCTRL3      	, 0x8d }, +	{ STB0899_DMONMSK1		, 0x27 }, +	{ STB0899_DMONMSK0		, 0x03 }, +	{ STB0899_DEMAPVIT      	, 0x5c }, +	{ STB0899_PLPARM		, 0x19 }, +	{ STB0899_PDELCTRL      	, 0x48 }, +	{ STB0899_PDELCTRL2     	, 0x00 }, +	{ STB0899_BBHCTRL1      	, 0x00 }, +	{ STB0899_BBHCTRL2      	, 0x00 }, +	{ STB0899_HYSTTHRESH    	, 0x77 }, +	{ STB0899_MATCSTM		, 0x00 }, +	{ STB0899_MATCSTL		, 0x00 }, +	{ STB0899_UPLCSTM		, 0x00 }, +	{ STB0899_UPLCSTL		, 0x00 }, +	{ STB0899_DFLCSTM		, 0x00 }, +	{ STB0899_DFLCSTL		, 0x00 }, +	{ STB0899_SYNCCST		, 0x00 }, +	{ STB0899_SYNCDCSTM		, 0x00 }, +	{ STB0899_SYNCDCSTL		, 0x00 }, +	{ STB0899_ISI_ENTRY		, 0x00 }, +	{ STB0899_ISI_BIT_EN		, 0x00 }, +	{ STB0899_MATSTRM		, 0xf0 }, +	{ STB0899_MATSTRL		, 0x02 }, +	{ STB0899_UPLSTRM		, 0x45 }, +	{ STB0899_UPLSTRL		, 0x60 }, +	{ STB0899_DFLSTRM		, 0xe3 }, +	{ STB0899_DFLSTRL		, 0x00 }, +	{ STB0899_SYNCSTR		, 0x47 }, +	{ STB0899_SYNCDSTRM		, 0x05 }, +	{ STB0899_SYNCDSTRL		, 0x18 }, +	{ STB0899_CFGPDELSTATUS1	, 0x19 }, +	{ STB0899_CFGPDELSTATUS2	, 0x2b }, +	{ STB0899_BBFERRORM		, 0x00 }, +	{ STB0899_BBFERRORL		, 0x01 }, +	{ STB0899_UPKTERRORM		, 0x00 }, +	{ STB0899_UPKTERRORL		, 0x00 }, +	{ 0xffff			, 0xff }, +}; + +struct stb0899_config vp1041_stb0899_config = { +	.init_dev		= vp1041_stb0899_s1_init_1, +	.init_s2_demod		= stb0899_s2_init_2, +	.init_s1_demod		= vp1041_stb0899_s1_init_3, +	.init_s2_fec		= stb0899_s2_init_4, +	.init_tst		= stb0899_s1_init_5, + +	.demod_address 		= 0x68, /*  0xd0 >> 1 */ + +	.xtal_freq		= 27000000, +	.inversion		= IQ_SWAP_ON, + +	.lo_clk			= 76500000, +	.hi_clk			= 99000000, + +	.esno_ave		= STB0899_DVBS2_ESNO_AVE, +	.esno_quant		= STB0899_DVBS2_ESNO_QUANT, +	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE, +	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE, +	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD, +	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ, +	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK, +	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF, +	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + +	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS, +	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, +	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS, +	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER, + +	.tuner_get_frequency	= stb6100_get_frequency, +	.tuner_set_frequency	= stb6100_set_frequency, +	.tuner_set_bandwidth	= stb6100_set_bandwidth, +	.tuner_get_bandwidth	= stb6100_get_bandwidth, +	.tuner_set_rfsiggain	= NULL, +}; + +struct stb6100_config vp1041_stb6100_config = { +	.tuner_address	= 0x60, +	.refclock	= 27000000, +}; + +static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter	= &mantis->adapter; + +	int err = 0; + +	err = mantis_frontend_power(mantis, POWER_ON); +	if (err == 0) { +		mantis_frontend_soft_reset(mantis); +		msleep(250); +		mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter); +		if (mantis->fe) { +			dprintk(MANTIS_ERROR, 1, +				"found STB0899 DVB-S/DVB-S2 frontend @0x%02x", +				vp1041_stb0899_config.demod_address); + +			if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) { +				if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0)) +					dprintk(MANTIS_ERROR, 1, "No LNBP21 found!"); +			} +		} else { +			return -EREMOTEIO; +		} +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; +	} + + +	dprintk(MANTIS_ERROR, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp1041_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_188, + +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, + +	.frontend_init	= vp1041_frontend_init, +	.power		= GPIF_A12, +	.reset		= GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp1041.h b/drivers/media/pci/mantis/mantis_vp1041.h new file mode 100644 index 00000000000..1ae5b3de808 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1041.h @@ -0,0 +1,33 @@ +/* +	Mantis VP-1041 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1041_H +#define __MANTIS_VP1041_H + +#include "mantis_common.h" + +#define MANTIS_VP_1041_DVB_S2	0x0031 +#define SKYSTAR_HD2_10		0x0001 +#define SKYSTAR_HD2_20		0x0003 +#define CINERGY_S2_PCI_HD	0x1179 + +extern struct mantis_hwconfig vp1041_config; + +#endif /* __MANTIS_VP1041_H */ diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c new file mode 100644 index 00000000000..1ca6837fbe4 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2033.c @@ -0,0 +1,188 @@ +/* +	Mantis VP-2033 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2033.h" + +#define MANTIS_MODEL_NAME	"VP-2033" +#define MANTIS_DEV_TYPE		"DVB-C" + +struct tda1002x_config vp2033_tda1002x_cu1216_config = { +	.demod_address = 0x18 >> 1, +	.invert = 1, +}; + +struct tda10023_config vp2033_tda10023_cu1216_config = { +	.demod_address = 0x18 >> 1, +	.invert = 1, +}; + +static u8 read_pwm(struct mantis_pci *mantis) +{ +	struct i2c_adapter *adapter = &mantis->adapter; + +	u8 b = 0xff; +	u8 pwm; +	struct i2c_msg msg[] = { +		{.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, +		{.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} +	}; + +	if ((i2c_transfer(adapter, msg, 2) != 2) +	    || (pwm == 0xff)) +		pwm = 0x48; + +	return pwm; +} + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) +{ +	struct dtv_frontend_properties *p = &fe->dtv_property_cache; +	struct mantis_pci *mantis = fe->dvb->priv; +	struct i2c_adapter *adapter = &mantis->adapter; + +	u8 buf[6]; +	struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; +	int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + +	u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + +	buf[0] = (div >> 8) & 0x7f; +	buf[1] = div & 0xff; +	buf[2] = 0xce; +	buf[3] = (p->frequency < 150000000 ? 0x01 : +		  p->frequency < 445000000 ? 0x02 : 0x04); +	buf[4] = 0xde; +	buf[5] = 0x20; + +	if (fe->ops.i2c_gate_ctrl) +		fe->ops.i2c_gate_ctrl(fe, 1); + +	if (i2c_transfer(adapter, &msg, 1) != 1) +		return -EIO; + +	/* wait for the pll lock */ +	msg.flags = I2C_M_RD; +	msg.len = 1; +	for (i = 0; i < 20; i++) { +		if (fe->ops.i2c_gate_ctrl) +			fe->ops.i2c_gate_ctrl(fe, 1); + +		if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) +			break; + +		msleep(10); +	} + +	/* switch the charge pump to the lower current */ +	msg.flags = 0; +	msg.len = 2; +	msg.buf = &buf[2]; +	buf[2] &= ~0x40; +	if (fe->ops.i2c_gate_ctrl) +		fe->ops.i2c_gate_ctrl(fe, 1); + +	if (i2c_transfer(adapter, &msg, 1) != 1) +		return -EIO; + +	return 0; +} + +static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter = &mantis->adapter; + +	int err = 0; + +	err = mantis_frontend_power(mantis, POWER_ON); +	if (err == 0) { +		mantis_frontend_soft_reset(mantis); +		msleep(250); + +		dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); +		fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config, +				     adapter, +				     read_pwm(mantis)); + +		if (fe) { +			dprintk(MANTIS_ERROR, 1, +				"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", +				vp2033_tda1002x_cu1216_config.demod_address); +		} else { +			fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config, +					     adapter, +					     read_pwm(mantis)); + +			if (fe) { +				dprintk(MANTIS_ERROR, 1, +					"found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", +					vp2033_tda1002x_cu1216_config.demod_address); +			} +		} + +		if (fe) { +			fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; +			dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); +		} else { +			return -1; +		} +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; +	} + +	mantis->fe = fe; +	dprintk(MANTIS_DEBUG, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp2033_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_204, + +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, + +	.frontend_init	= vp2033_frontend_init, +	.power		= GPIF_A12, +	.reset		= GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp2033.h b/drivers/media/pci/mantis/mantis_vp2033.h new file mode 100644 index 00000000000..c55242b79d5 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2033.h @@ -0,0 +1,30 @@ +/* +	Mantis VP-2033 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP2033_H +#define __MANTIS_VP2033_H + +#include "mantis_common.h" + +#define MANTIS_VP_2033_DVB_C	0x0008 + +extern struct mantis_hwconfig vp2033_config; + +#endif /* __MANTIS_VP2033_H */ diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c new file mode 100644 index 00000000000..d480741afd7 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2040.c @@ -0,0 +1,187 @@ +/* +	Mantis VP-2040 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2040.h" + +#define MANTIS_MODEL_NAME	"VP-2040" +#define MANTIS_DEV_TYPE		"DVB-C" + +struct tda1002x_config vp2040_tda1002x_cu1216_config = { +	.demod_address	= 0x18 >> 1, +	.invert		= 1, +}; + +struct tda10023_config vp2040_tda10023_cu1216_config = { +	.demod_address	= 0x18 >> 1, +	.invert		= 1, +}; + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) +{ +	struct dtv_frontend_properties *p = &fe->dtv_property_cache; +	struct mantis_pci *mantis	= fe->dvb->priv; +	struct i2c_adapter *adapter	= &mantis->adapter; + +	u8 buf[6]; +	struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; +	int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + +	u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + +	buf[0] = (div >> 8) & 0x7f; +	buf[1] = div & 0xff; +	buf[2] = 0xce; +	buf[3] = (p->frequency < 150000000 ? 0x01 : +		  p->frequency < 445000000 ? 0x02 : 0x04); +	buf[4] = 0xde; +	buf[5] = 0x20; + +	if (fe->ops.i2c_gate_ctrl) +		fe->ops.i2c_gate_ctrl(fe, 1); + +	if (i2c_transfer(adapter, &msg, 1) != 1) +		return -EIO; + +	/* wait for the pll lock */ +	msg.flags = I2C_M_RD; +	msg.len = 1; +	for (i = 0; i < 20; i++) { +		if (fe->ops.i2c_gate_ctrl) +			fe->ops.i2c_gate_ctrl(fe, 1); + +		if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) +			break; + +		msleep(10); +	} + +	/* switch the charge pump to the lower current */ +	msg.flags = 0; +	msg.len = 2; +	msg.buf = &buf[2]; +	buf[2] &= ~0x40; +	if (fe->ops.i2c_gate_ctrl) +		fe->ops.i2c_gate_ctrl(fe, 1); + +	if (i2c_transfer(adapter, &msg, 1) != 1) +		return -EIO; + +	return 0; +} + +static u8 read_pwm(struct mantis_pci *mantis) +{ +	struct i2c_adapter *adapter = &mantis->adapter; + +	u8 b = 0xff; +	u8 pwm; +	struct i2c_msg msg[] = { +		{.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, +		{.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} +	}; + +	if ((i2c_transfer(adapter, msg, 2) != 2) +	    || (pwm == 0xff)) +		pwm = 0x48; + +	return pwm; +} + +static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter = &mantis->adapter; + +	int err = 0; + +	err = mantis_frontend_power(mantis, POWER_ON); +	if (err == 0) { +		mantis_frontend_soft_reset(mantis); +		msleep(250); + +		dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); +		fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config, +				     adapter, +				     read_pwm(mantis)); + +		if (fe) { +			dprintk(MANTIS_ERROR, 1, +				"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", +				vp2040_tda1002x_cu1216_config.demod_address); +		} else { +			fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config, +					     adapter, +					     read_pwm(mantis)); + +			if (fe) { +				dprintk(MANTIS_ERROR, 1, +					"found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", +					vp2040_tda1002x_cu1216_config.demod_address); +			} +		} + +		if (fe) { +			fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; +			dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); +		} else { +			return -1; +		} +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; +	} +	mantis->fe = fe; +	dprintk(MANTIS_DEBUG, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp2040_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_204, + +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, + +	.frontend_init	= vp2040_frontend_init, +	.power		= GPIF_A12, +	.reset		= GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp2040.h b/drivers/media/pci/mantis/mantis_vp2040.h new file mode 100644 index 00000000000..d125e219b68 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2040.h @@ -0,0 +1,32 @@ +/* +	Mantis VP-2040 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP2040_H +#define __MANTIS_VP2040_H + +#include "mantis_common.h" + +#define MANTIS_VP_2040_DVB_C	0x0043 +#define CINERGY_C		0x1178 +#define CABLESTAR_HD2		0x0002 + +extern struct mantis_hwconfig vp2040_config; + +#endif /* __MANTIS_VP2040_H */ diff --git a/drivers/media/pci/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c new file mode 100644 index 00000000000..4155c838a18 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3028.c @@ -0,0 +1,38 @@ +/* +	Mantis VP-3028 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "mantis_common.h" +#include "mantis_vp3028.h" + +struct zl10353_config mantis_vp3028_config = { +	.demod_address	= 0x0f, +}; + +#define MANTIS_MODEL_NAME	"VP-3028" +#define MANTIS_DEV_TYPE		"DVB-T" + +struct mantis_hwconfig vp3028_mantis_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_188, +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, +}; diff --git a/drivers/media/pci/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h new file mode 100644 index 00000000000..b07be6adc52 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3028.h @@ -0,0 +1,33 @@ +/* +	Mantis VP-3028 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "dvb_frontend.h" +#include "mantis_common.h" +#include "zl10353.h" + +#define MANTIS_VP_3028_DVB_T	0x0028 + +extern struct zl10353_config mantis_vp3028_config; +extern struct mantis_hwconfig vp3028_mantis_config; + +#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c new file mode 100644 index 00000000000..c09308cd3ac --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3030.c @@ -0,0 +1,105 @@ +/* +	Mantis VP-3030 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "tda665x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp3030.h" + +struct zl10353_config mantis_vp3030_config = { +	.demod_address		= 0x0f, +}; + +struct tda665x_config env57h12d5_config = { +	.name			= "ENV57H12D5 (ET-50DT)", +	.addr			= 0x60, +	.frequency_min		=  47000000, +	.frequency_max		= 862000000, +	.frequency_offst	=   3616667, +	.ref_multiplier		= 6, /* 1/6 MHz */ +	.ref_divider		= 100000, /* 1/6 MHz */ +}; + +#define MANTIS_MODEL_NAME	"VP-3030" +#define MANTIS_DEV_TYPE		"DVB-T" + + +static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ +	struct i2c_adapter *adapter	= &mantis->adapter; +	struct mantis_hwconfig *config	= mantis->hwconfig; +	int err = 0; + +	mantis_gpio_set_bits(mantis, config->reset, 0); +	msleep(100); +	err = mantis_frontend_power(mantis, POWER_ON); +	msleep(100); +	mantis_gpio_set_bits(mantis, config->reset, 1); + +	if (err == 0) { +		msleep(250); +		dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); +		fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter); + +		if (!fe) +			return -1; + +		dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter); +	} else { +		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", +			adapter->name, +			err); + +		return -EIO; + +	} +	mantis->fe = fe; +	dprintk(MANTIS_ERROR, 1, "Done!"); + +	return 0; +} + +struct mantis_hwconfig vp3030_config = { +	.model_name	= MANTIS_MODEL_NAME, +	.dev_type	= MANTIS_DEV_TYPE, +	.ts_size	= MANTIS_TS_188, + +	.baud_rate	= MANTIS_BAUD_9600, +	.parity		= MANTIS_PARITY_NONE, +	.bytes		= 0, + +	.frontend_init	= vp3030_frontend_init, +	.power		= GPIF_A12, +	.reset		= GPIF_A13, + +	.i2c_mode	= MANTIS_BYTE_MODE +}; diff --git a/drivers/media/pci/mantis/mantis_vp3030.h b/drivers/media/pci/mantis/mantis_vp3030.h new file mode 100644 index 00000000000..5f12c426627 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3030.h @@ -0,0 +1,30 @@ +/* +	Mantis VP-3030 driver + +	Copyright (C) Manu Abraham (abraham.manu@gmail.com) + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the Free Software +	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3030_H +#define __MANTIS_VP3030_H + +#include "mantis_common.h" + +#define MANTIS_VP_3030_DVB_T	0x0024 + +extern struct mantis_hwconfig vp3030_config; + +#endif /* __MANTIS_VP3030_H */  | 
