Re: PCI driver

Manu Abraham
2005-10-10T13:02:04Z

[-- Attachment #1: Type: text/plain, Size: 571 bytes --]

Rolf Eike Beer wrote:

>IIRC the call to pci_enable_device() must be the first thing you do. This will
>do the things like assigning memory regions to the device and so on.
>
>
>
I fixed this one

>Returning 0 in error cases is just wrong. And you free the assignments even in
>case of success AFAICS. Try the return I introduced above and see what
>happens.
>
>
>
I fixed this one too ..

I have fixed most of the stuff, it is partly working, not ready yet as
there are some more things to be added to ..
I have attached what i was working on.

Thanks,
Manu

[-- Attachment #2: mantis_common.h --]
[-- Type: text/plain, Size: 3500 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/pci.h>

#include "dvbdev.h"
#include "dvb_demux.h"
#include "dmxdev.h"
#include "dvb_frontend.h"
#include "dvb_net.h"
#include <linux/i2c.h>
#include "mantis_reg.h"

#define MANTIS_ERROR 0
#define MANTIS_NOTICE 1
#define MANTIS_INFO 2
#define MANTIS_DEBUG 3

#define dprintk(x, y, z, format, arg...) do { \
if (z) { \
if ((x > MANTIS_ERROR) && (x > y)) \
printk(KERN_ERR "%s: " format "\n" , __FUNCTION__ , ##arg); \
else if ((x > MANTIS_NOTICE) && (x > y)) \
printk(KERN_NOTICE "%s: " format "\n" , __FUNCTION__ , ##arg); \
else if ((x > MANTIS_INFO) && (x > y)) \
printk(KERN_INFO "%s: " format "\n" , __FUNCTION__ , ##arg); \
else if ((x > MANTIS_DEBUG) && (x > y)) \
printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ##arg); \
} else { \
if (x > 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->mantis_mmio + (addr)))
#define mmread(addr) mread(mantis->mantis_mmio + (addr))
#define mmand(dat, addr) mmwrite((dat) & mmread(addr), addr)
#define mmor(dat, addr) mmwrite((dat) | mmread(addr), addr)
#define mmaor(dat, addr) mmwrite((dat) | ((mask) & mmread(addr)), addr)

struct mantis_pci {
/* PCI stuff */
__u16 vendor_id;
__u16 device_id;
__u8 latency;

/* Linux PCI */
struct pci_dev *pdev;

unsigned long mantis_addr;
volatile void __iomem *mantis_mmio;

__u8 irq;
__u8 revision;

__u16 mantis_card_num;
__u16 ts_size;

/* RISC Core */
volatile __u32 finished_block;
volatile __u32 last_block;

__u32 block_count;
__u32 block_bytes;
__u32 line_bytes;
__u32 line_count;

__u32 risc_pos;

__u32 buf_size;
__u8 *buf_cpu;
dma_addr_t buf_dma;

__u32 risc_size;
__u32 *risc_cpu;
dma_addr_t risc_dma;

struct tasklet_struct tasklet;

struct i2c_adapter adapter;
int i2c_rc;

/* 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_config *config;

__u32 mantis_int_stat;
__u32 mantis_int_mask;

/* board specific */
__u8 mac_address[8];
__u32 sub_vendor_id;
__u32 sub_device_id;
};

extern unsigned int verbose;
extern int mantis_dvb_init(struct mantis_pci *mantis);
extern int mantis_frontend_init(struct mantis_pci *mantis);
extern int mantis_dvb_exit(struct mantis_pci *mantis);
extern void mantis_dma_xfer(unsigned long data);

#endif

[-- Attachment #3: mantis_core.c --]
[-- Type: text/plain, Size: 5022 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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"

static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
{
int err;
struct i2c_msg msg = {
.addr = 0x50,
.flags = I2C_M_RD,
.buf = data,
.len = length
};
if ((err = i2c_transfer(&mantis->adapter, &msg, 1)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", err, data[0], data[1]);
return err;
}
msleep(2);

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
};
if ((err = i2c_transfer(&mantis->adapter, &msg, 1)) < 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_subdevice_id(struct mantis_pci *mantis)
{
int err;
static u8 sub_device_id[2];

mantis->sub_device_id = 0;
sub_device_id[0] = 0xfc;
if ((err = read_eeprom_byte(mantis, &sub_device_id[0], 2)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
return err;
}
mantis->sub_device_id = (sub_device_id[0] << 8) | sub_device_id[1];
dprintk(verbose, MANTIS_ERROR, 1, "Sub Device ID=[0x%04x]", mantis->sub_device_id);

return 0;
}

static int get_subvendor_id(struct mantis_pci *mantis)
{
int err;
static u8 sub_vendor_id[2];

mantis->sub_vendor_id = 0;
sub_vendor_id[0] = 0xfe;
if ((err = read_eeprom_byte(mantis, &sub_vendor_id[0], 2)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
return err;
}
mantis->sub_vendor_id = (sub_vendor_id[0] << 8) | sub_vendor_id[1];
dprintk(verbose, MANTIS_ERROR, 1, "Sub Vendor ID=[0x%04x]", mantis->sub_vendor_id);

return 0;
}

static int get_mac_address(struct mantis_pci *mantis)
{
int err;

mantis->mac_address[0] = 0x08;
if ((err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
return err;
}
dprintk(verbose, MANTIS_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]",
mantis->mac_address[0], mantis->mac_address[1], mantis->mac_address[2],
mantis->mac_address[3], mantis->mac_address[4], mantis->mac_address[5]);

return 0;
}

struct vendorname vendorlist[] = {

{
.sub_vendor_name = "Twinhan",
.sub_vendor_id = 0x1822,
},

{ }
};

struct devicetype devicelist[] = {

{
.sub_device_name = "VP-1033",
.sub_device_id = 0x0016,
.device_type = FE_TYPE_SAT,
.type_flags = FE_TYPE_TS204,
},

{ }
};

int mantis_core_init(struct mantis_pci *mantis)
{
int err;

if ((err = mantis_i2c_init(mantis)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
goto err;
}
if ((err = get_mac_address(mantis)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
goto err;
}
if ((err = get_subvendor_id(mantis)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "get Sub vendor ID failed");
goto err;
}
if ((err = get_subdevice_id(mantis)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "get Sub device ID failed");
goto err;
}
if ((err = mantis_dvb_init(mantis)) < 0) {
dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
goto err;
}

return 0;

err:
return err;
}

int mantis_core_exit(struct mantis_pci *mantis)
{
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;
}

static void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
{
u32 reg;

if (value)
reg = 0x0000;
else
reg = 0xffff;

reg = (value << bitpos);

mmwrite(mmread(MANTIS_GPIF_HIFADDR) | reg, MANTIS_GPIF_HIFADDR);
mmwrite(0x00, MANTIS_GPIF_HIFDOUT);
udelay(100);
mmwrite(mmread(MANTIS_GPIF_HIFADDR) | reg, MANTIS_GPIF_HIFADDR);
mmwrite(0x00, MANTIS_GPIF_HIFDOUT);
}

/*
* Tuner power supply control
* Note: this is different from the LNB power control
*
*/
void mantis_fe_powerup(struct mantis_pci *mantis)
{
gpio_set_bits(mantis, 0x0c, 1);
mdelay(100);
gpio_set_bits(mantis, 0x0c, 1);
}

void mantis_fe_powerdown(struct mantis_pci *mantis)
{
gpio_set_bits(mantis, 0x0c, 0);
}

[-- Attachment #4: mantis_core.h --]
[-- Type: text/plain, Size: 1707 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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);
extern void mantis_fe_powerup(struct mantis_pci *mantis);
extern void mantis_fe_powerdown(struct mantis_pci *mantis);

#endif

[-- Attachment #5: mantis_dma.c --]
[-- Type: text/plain, Size: 6909 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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/page.h>
#include <linux/vmalloc.h>
#include "mantis_common.h"

#define RISC_WRITE (0x01 << 28)
#define RISC_JUMP (0x07 << 28)
#define RISC_SYNC (0x08 << 28)

#define RISC_WR_SOL (1 << 27)
#define RISC_WR_EOL (1 << 26)
#define RISC_IRQ (1 << 24)

#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))

#define RISC_FLUSH() mantis->risc_pos = 0
#define RISC_INSTR(opcode) mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)

static void mantis_free(struct mantis_pci *mantis)
{
if (mantis->buf_cpu) {
dprintk(verbose, MANTIS_ERROR, 1, "DMA=%lx", (unsigned long) mantis->buf_dma);
pci_free_consistent(mantis->pdev, mantis->buf_size, mantis->buf_cpu, mantis->buf_dma);
mantis->buf_cpu = NULL;
}
if (mantis->risc_cpu) {
dprintk(verbose, MANTIS_ERROR, 1, "RISC=%lx", (unsigned long) mantis->risc_dma);
pci_free_consistent(mantis->pdev, mantis->risc_size, mantis->risc_cpu, mantis->risc_dma);
mantis->risc_cpu = NULL;
}
}

static int mantis_alloc_buffers(struct mantis_pci *mantis)
{
if (!mantis->buf_cpu) {
mantis->buf_size = 128 * 1024;
mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, mantis->buf_size, &mantis->buf_dma);
if (!mantis->buf_cpu) {
dprintk(verbose, MANTIS_ERROR, 1, "DMA buffer allocation failed");
goto err;
}
dprintk(verbose, 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_size = PAGE_SIZE;
mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, mantis->risc_size, &mantis->risc_dma);
if (!mantis->risc_cpu) {
dprintk(verbose, MANTIS_ERROR, 1, "RISC program allocation failed");
mantis_free(mantis);
goto err;
}
dprintk(verbose, MANTIS_ERROR, 1, "RISC=0x%lx cpu=0x%p size=%d",
(unsigned long) mantis->risc_dma, mantis->risc_cpu, mantis->risc_size);
}

return 0;
err:
dprintk(verbose, MANTIS_ERROR, 1, "Out of memory (?) .....");
return -ENOMEM;
}

static int mantis_calc_lines(struct mantis_pci *mantis)
{
mantis->block_bytes = mantis->buf_size >> 4;
mantis->block_count = 1 << 4;
mantis->line_bytes = mantis->block_bytes;
mantis->line_count = mantis->block_count;

while (mantis->line_bytes > 4095) {
mantis->line_bytes >>= 1;
mantis->line_count <<= 1;
}
dprintk(verbose, MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
mantis->block_bytes, mantis->line_bytes, mantis->line_count);

if (mantis->line_count > 255) {
dprintk(verbose, MANTIS_ERROR, 1, "Buffer size error");
return -EINVAL;
}

return 0;
}

static void mantis_risc_program(struct mantis_pci *mantis)
{
u32 buf_pos = 0;
u32 line;

dprintk(verbose, MANTIS_DEBUG, 1, "Mantis create RISC program");
RISC_FLUSH();
RISC_INSTR(RISC_SYNC);
RISC_INSTR(0);

dprintk(verbose, MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", mantis->line_count, mantis->line_bytes);
for (line = 0; line < mantis->line_count; line++) {
dprintk(verbose, MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
if (!(buf_pos % mantis->block_bytes))
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | RISC_IRQ |
RISC_STATUS(((buf_pos / mantis->block_bytes) +
(mantis->block_count - 1)) % mantis->block_count) | mantis->line_bytes);
else
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | mantis->line_bytes);
RISC_INSTR(mantis->buf_dma + buf_pos);
buf_pos += mantis->line_bytes;
}
RISC_INSTR(RISC_SYNC);
RISC_INSTR(0);
RISC_INSTR(RISC_JUMP);
RISC_INSTR(mantis->risc_dma);
}

void mantis_dma_start(struct mantis_pci *mantis)
{
dprintk(verbose, MANTIS_DEBUG, 1, "Mantis Start DMA engine");
/*
* Create RISC program to be loaded to the RISC core
*/
mantis_risc_program(mantis);

/*
* Load the RISC program from Host to RISC
*/
mmwrite(cpu_to_le32(mantis->risc_dma), MANTIS_RISC_START);

/*
* Enable INT's, start DMA engine
* DMA engine: Enable FIFO, Enable Data Capture
* Enable RISC engine
*/
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_FIFO_EN | MANTIS_DCAP_EN | MANTIS_RISC_EN, MANTIS_INT_MASK);
mmwrite(mmread(MANTIS_DMA_CTL) | MANTIS_FIFO_EN | MANTIS_DCAP_EN | MANTIS_RISC_EN, MANTIS_DMA_CTL);

}

void mantis_dma_stop(struct mantis_pci *mantis)
{
dprintk(verbose, MANTIS_DEBUG, 1, "Mantis Stop DMA engine");

/*
* Stop only the DMA engine, do not clear
* the other interrupts
*/
mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | MANTIS_DCAP_EN | MANTIS_RISC_EN)), MANTIS_DMA_CTL);
}

int mantis_dma_init(struct mantis_pci *mantis)
{
int err = 0;

dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DMA init");
if (mantis_alloc_buffers(mantis) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Error allocating DMA buffer");

/*
* Disable all interrupts during initialization
* to avoid spurious interrupts creating hell.
* Clear all INT's, disable FIFO RISC.
*/
mmwrite(0x00, MANTIS_INT_MASK);
mmwrite(0x00, MANTIS_DMA_CTL);

goto err;
}
if ((err = mantis_calc_lines(mantis)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis calc lines failed");
goto err;
}

return 0;
err:
return err;
}

void mantis_dma_xfer(unsigned long data)
{
struct mantis_pci *mantis = (struct mantis_pci *) data;

while (mantis->last_block != mantis->finished_block) {
(mantis->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;
}
}

int mantis_dma_exit(struct mantis_pci *mantis)
{
if (mantis->buf_cpu) {
dprintk(verbose, 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(verbose, MANTIS_ERROR, 1, "RISC=0x%lx cpu=0x%p size=%d",
(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;
}

[-- Attachment #6: mantis_i2c.c --]
[-- Type: text/plain, Size: 8748 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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/init.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include "mantis_common.h"

#define I2C_HW_B_MANTIS 0x1c

/*
* Wait till we receive INT I2CRACK. I2CDONE will follow suit,
* since we save the states, we would have both I2CRACK and I2CDONE set
* we don't wait till eternity though.
*/
static int mantis_ack_wait(struct mantis_pci *mantis)
{
u8 timeout = 0;

/*
* I2CRACK will be reset when I2CDONE is set
*
*
*/
while (!(mantis->mantis_int_stat & MANTIS_INT_I2CRACK)) {
udelay(1000);
timeout++;
dprintk(verbose, MANTIS_DEBUG, 0, ".");
if (timeout > 50)
return -1;
}

/*
* Reset STATUS flags, before we leave.
* since we save states.
*/
dprintk(verbose, MANTIS_DEBUG, 1, "Status ... MANTIS_INT_STAT=[0x%08x]", mantis->mantis_int_stat);
mantis->mantis_int_stat &= (~MANTIS_INT_I2CRACK | ~MANTIS_INT_I2CDONE);

return 0;
}

static inline void mantis_i2cint_set(struct mantis_pci *mantis)
{
/*
* We don't have a mask for I2CRACK
* I2CRACK is cleared on setting I2CDONE (?)
*/
// mmwrite(mmread(MANTIS_INT_STAT) & MANTIS_INT_I2CRACK, MANTIS_INT_STAT);
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_I2CDONE, MANTIS_INT_MASK);
udelay(1000);
}

static int mantis_i2c_pagewrite(struct mantis_pci *mantis, struct i2c_msg *msg)
{
u8 i;
u32 txd = 0;

dprintk(verbose, MANTIS_DEBUG, 1, "Writing to [0x%02x]", msg->addr);

for (i = 0; i < msg->len; i++) {
dprintk(verbose, MANTIS_DEBUG, 1, "Data<W[%d]>=[0x%02x]", i, msg->buf[i]);
txd |= (msg->addr << 25) | (msg->buf[i] << 8) | MANTIS_I2C_RATE_3 | MANTIS_I2C_STOP | MANTIS_I2C_PGMODE;
if (i == 3)
txd &= ~MANTIS_I2C_STOP;

mantis_i2cint_set(mantis);
mmwrite(txd, MANTIS_I2CDATA_CTL);

if (mantis_ack_wait(mantis) < 0) {
dprintk(verbose, MANTIS_DEBUG, 1, "ACK failed");
return -1;
}
udelay(10);
}

return 0;
}

/* FIXME! needs to be fixed, we need to put things back */
static int mantis_i2c_pageread(struct mantis_pci *mantis, struct i2c_msg *msg)
{
u8 i;
u32 rxd = 0;

for (i = 0; i < 2; i++) {
rxd |= ((msg->addr << 25) | (1 << 24)) | MANTIS_I2C_RATE_3 | MANTIS_I2C_STOP | MANTIS_I2C_PGMODE;
if (i == 1)
rxd &= ~MANTIS_I2C_STOP;
mmwrite(mmread(MANTIS_INT_STAT) | MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_I2CDONE, MANTIS_INT_MASK);
udelay(1000);
if (mantis_ack_wait(mantis) < 0)
return -EIO;
rxd = mmread(MANTIS_I2CDATA_CTL);
udelay(500);
}

return 0;
}

///* FIXME ! Right now writes only a byte */
static int mantis_i2c_writebyte(struct mantis_pci *mantis, struct i2c_msg *msg)
{
u32 txd = 0;
mantis->mantis_int_stat = 0;

txd = (msg->addr << 25) | (msg->buf[0] << 16) | (msg->buf[1] << 8) | MANTIS_I2C_RATE_3;
dprintk(verbose, MANTIS_DEBUG, 1, "Writing to [0x%02x], Data<W>=[%02x]", msg->addr, msg->buf[1]);
mmwrite(txd, MANTIS_I2CDATA_CTL);

if (mantis_ack_wait(mantis) < 0) {
dprintk(verbose, MANTIS_DEBUG, 1, "Slave did not ACK !");
return -EIO;
}

return 0;
}

static int mantis_i2c_readbyte(struct mantis_pci *mantis, struct i2c_msg *msg)
{
u32 rxd;
u16 i;
u8 subaddr;

/*
* Clear saved previous states
*/
mantis->mantis_int_stat &= (~MANTIS_INT_I2CDONE | ~MANTIS_INT_I2CRACK);
subaddr = msg->buf[0];

for (i = 0; i < msg->len; i++) {
/* Rate settings */
rxd = ((msg->addr << 25) | (1 << 24)) | (subaddr << 16) | MANTIS_I2C_RATE_3;

mmwrite(rxd, MANTIS_I2CDATA_CTL);

/*
* Enable INT_I2CDONE
*/
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_I2CDONE, MANTIS_INT_MASK);
udelay(1000);

/* Slave ACK */
if (mantis_ack_wait(mantis) < 0)
return -EIO;

rxd = mmread(MANTIS_I2CDATA_CTL);
udelay(500);
msg->buf[i] = (rxd >> 8) & 0xff;
dprintk(verbose, MANTIS_DEBUG, 1, "Reading from [0x%02x], Data<R[%d]>=[0x%02x]", msg->addr, i, msg->buf[i]);
subaddr++;
}

return 0;
}

static int mantis_i2c_readbytes(struct mantis_pci *mantis, struct i2c_msg *msg)
{
u32 rxd;
u16 i;

mantis->mantis_int_stat = 0;

for (i = 0; i < msg[1].len; i++) {
/* Rate settings */
rxd = ((msg[0].addr << 25) | (1 << 24)) | (msg[0].buf[0] << 16) | MANTIS_I2C_RATE_3;

mmwrite(rxd, MANTIS_I2CDATA_CTL);

/*
* Need to wait till I2CDONE, rather than slave I2CRACK
*/
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_I2CDONE, MANTIS_INT_MASK);
udelay(1000);
if (mantis_ack_wait(mantis) < 0)
return -EIO;

rxd = mmread(MANTIS_I2CDATA_CTL);
udelay(500);
msg[1].buf[i] = (rxd >> 8) & 0xff;
dprintk(verbose, MANTIS_DEBUG, 1, "Reading from [0x%02x], Data<R[%d]>=[0x%02x]", msg[0].addr, i, msg[1].buf[i]);
msg[0].buf[0]++;
}

return 0;
}

/* FIXME ! Right now writes only a byte */
static int mantis_i2c_writebytes(struct mantis_pci *mantis, struct i2c_msg *msg)
{
u32 txd = 0;
mantis->mantis_int_stat = 0;

txd = (msg->addr << 25) | (msg->buf[0] << 16) | (msg->buf[1] << 8) | MANTIS_I2C_RATE_3;
dprintk(verbose, MANTIS_DEBUG, 1, "Writing to [0x%02x], Data<W>=[%02x]", msg->addr, msg->buf[1]);
mmwrite(txd, MANTIS_I2CDATA_CTL);

if (mantis_ack_wait(mantis) < 0)
return -EIO;

return 0;
}

static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, int num)
{
int retval = 0;
struct mantis_pci *mantis;

mantis = i2c_get_adapdata(adapter);

if (num == 4) {
if (msg[0].flags & I2C_M_RD) {
if ((retval = mantis_i2c_pageread(mantis, msg)) < 0)
return retval;
} else {
if ((retval = mantis_i2c_pagewrite(mantis, msg)) < 0)
return retval;
}
/* STV0299 operation (???) */
} else if (num == 2) {
mantis_i2cint_set(mantis);
/* Sanity check */
if (msg[0].buf != NULL && msg[1].buf != NULL) {
/* I2C operation type */
if (msg[0].flags == 0 && msg[1].flags == I2C_M_RD) {
/* Read */
if ((retval = mantis_i2c_readbytes(mantis, msg)) < 0)
return retval;
} else {
/* Write */
if ((retval = mantis_i2c_writebytes(mantis, msg)) < 0)
return retval;
}
}
/* Normal case operation */
} else {
mantis_i2cint_set(mantis);
if (msg[0].flags & I2C_M_RD) {
if ((retval = mantis_i2c_readbyte(mantis, msg)) < 0)
return retval;
} else {
if ((retval = mantis_i2c_writebyte(mantis, msg)) < 0)
return retval;
}
}

return num;
}

static __u32 mantis_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_EMUL;
}

static int mantis_attach_inform(struct i2c_client *client)
{
struct mantis_pci *mantis;

mantis = i2c_get_adapdata(client->adapter);
dprintk(verbose, MANTIS_ERROR, 1, "mantis: %s i2c attach [addr = 0x%x, client=%s]",
client->driver->name, client->addr, i2c_clientname(client));

return 0;
}

static struct i2c_algorithm mantis_algo = {
.name = "Mantis I2C",
.id = I2C_HW_B_MANTIS,
.master_xfer = mantis_i2c_xfer,
.functionality = mantis_i2c_func,
};

static struct i2c_adapter mantis_i2c_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_TV_DIGITAL,
.algo = &mantis_algo,
.client_register = mantis_attach_inform,
};

int __devinit mantis_i2c_init(struct mantis_pci *mantis)
{
memcpy(&mantis->adapter, &mantis_i2c_adapter, sizeof (mantis_i2c_adapter));
i2c_set_adapdata(&mantis->adapter, mantis);
mantis->i2c_rc = i2c_add_adapter(&mantis->adapter);
if (mantis->i2c_rc < 0)
return mantis->i2c_rc;

dprintk(verbose, MANTIS_DEBUG, 1, "Initializing I2C ..");

/*
* I2CRACK will be reset when I2CDONE is set
* Clear and setup I2C int mask
*/
mmwrite(mmread(MANTIS_INT_STAT) & ( ~MANTIS_INT_I2CDONE | ~MANTIS_INT_I2CRACK), MANTIS_INT_STAT);
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_I2CDONE | MANTIS_INT_I2CRACK, MANTIS_INT_MASK);
dprintk(verbose, MANTIS_DEBUG, 1, "INT_STAT=[0x%08x], INT_MASK=[0x%08x]", mmread(MANTIS_INT_STAT), mmread(MANTIS_INT_MASK));

return 0;
}

int __devexit mantis_i2c_exit(struct mantis_pci *mantis)
{
dprintk(verbose, MANTIS_DEBUG, 1, "Removing I2C adapter");
return i2c_del_adapter(&mantis->adapter);
}

[-- Attachment #7: mantis_pci.c --]
[-- Type: text/plain, Size: 9216 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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 <asm/pgtable.h>
#include <asm/page.h>
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/device.h>
#include "mantis_common.h"
#include "mantis_core.h"

#include <asm/irq.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>

unsigned int verbose = 1;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");

#define PCI_VENDOR_ID_MANTIS 0x1822
#define PCI_DEVICE_ID_MANTIS_R11 0x4e35
#define DRIVER_NAME "Mantis"

static struct pci_device_id mantis_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MANTIS, PCI_DEVICE_ID_MANTIS_R11) },
{ 0 },
};

MODULE_DEVICE_TABLE(pci, mantis_pci_table);

static irqreturn_t mantis_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
{
int count = 0, interrupts = 0;
u32 stat = 0, mask = 0, temp;

struct mantis_pci *mantis;

mantis = (struct mantis_pci *) dev_id;
if (mantis == NULL)
dprintk(verbose, MANTIS_DEBUG, 1, "Aeio, mantis ISR");

/*
* Don't read each and everytime, but read in one shot
* We need to save the states for later too ..
*
*/

stat = mmread(MANTIS_INT_STAT);
mask = mmread(MANTIS_INT_MASK);

/*
* To speed up things, do a basic check whether it is our
* interrupt.
* Also, we don't have a mask for I2CRACK
*/
if (!(stat & (mask | MANTIS_INT_I2CRACK)) ) {
dprintk(verbose, MANTIS_ERROR, 1, "Not ours !");
return IRQ_NONE;
}

/*
* The int is for us, clear int condition
*/
mmwrite(stat, MANTIS_INT_STAT);

/*
* Check how many 1's are in the INT_STAT, Count will reflect
* no. of interrupts, we should loop count times.
*
*/
temp = stat;
while (temp) {
if (temp & 0x01) {
interrupts++;
dprintk(verbose, MANTIS_DEBUG, 1, "Interrupt @ %d", interrupts);
}
temp >>= 1;
count++;

/*
* We should never loop more than reg. width
* else, Bail out
*/
if (count > 32) {
dprintk(verbose, MANTIS_ERROR, 1, "Bailing out !!");
break;
}
}
count = 0;
while (count < interrupts) {
if ((stat & mask) & MANTIS_INT_RISCEN) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** DMA enabl ****");
mantis->mantis_int_stat |= MANTIS_INT_RISCEN;
stat &= ~MANTIS_INT_RISCEN;

/*
* It's a shame that there is no mask for I2CRACK !
*/
} else if (stat & MANTIS_INT_I2CRACK) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** I2C R-ACK ****");
mantis->mantis_int_stat |= MANTIS_INT_I2CRACK;
stat &= ~MANTIS_INT_I2CRACK;

} else if ((stat & mask) & MANTIS_INT_IRQ0) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT IRQ-0 ****");
mantis->mantis_int_stat |= MANTIS_INT_IRQ0;
stat &= ~MANTIS_INT_IRQ0;

} else if ((stat & mask) & MANTIS_INT_IRQ1) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT IRQ-1 ****");
mantis->mantis_int_stat |= MANTIS_INT_IRQ1;
stat &= ~MANTIS_INT_IRQ1;

} else if ((stat & mask) & MANTIS_INT_OCERR) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT OCERR ****");
mantis->mantis_int_stat |= MANTIS_INT_OCERR;
stat &= ~MANTIS_INT_OCERR;

} else if ((stat & mask) & MANTIS_INT_PABORT) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT PABRT ****");
mantis->mantis_int_stat |= MANTIS_INT_PABORT;
stat &= ~MANTIS_INT_PABORT;

} else if ((stat & mask) & MANTIS_INT_RIPERR) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT RIPRR ****");
mantis->mantis_int_stat |= MANTIS_INT_RIPERR;
stat &= ~MANTIS_INT_RIPERR;

} else if ((stat & mask) & MANTIS_INT_PPERR) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT PPERR ****");
mantis->mantis_int_stat |= MANTIS_INT_PPERR;
stat &= ~MANTIS_INT_PPERR;

} else if ((stat & mask) & MANTIS_INT_FTRGT) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** INT FTRGT ****");
mantis->mantis_int_stat |= MANTIS_INT_FTRGT;
stat &= ~MANTIS_INT_FTRGT;

} else if ((stat & mask) & MANTIS_INT_RISCI) {
mantis->finished_block = (mantis->mantis_int_stat & MANTIS_INT_RISCSTAT) >> 28;
tasklet_schedule(&mantis->tasklet);
stat &= ~MANTIS_INT_RISCI;

} else if ((stat & mask) & MANTIS_INT_I2CDONE) {
dprintk(verbose, MANTIS_DEBUG, 1, "**** I2C DONE ****");
mantis->mantis_int_stat |= MANTIS_INT_I2CDONE;
stat &= ~MANTIS_INT_I2CDONE;

} else {
dprintk(verbose, MANTIS_DEBUG, 1, "Unknown INT ???");
}

count++;

/*
* Being paranoid, check whether we are too loopy !
*/
if (count > 32) {
dprintk(verbose, MANTIS_ERROR, 1, "IRQ Lockup, clearing INT mask");
dprintk(verbose, MANTIS_ERROR, 1, "Count=%d, Interrupts=%d, stat=[0x%08x]", count, interrupts, stat);
mmwrite(0, MANTIS_INT_MASK);
stat = 0, interrupts = 0;

break;
}
}

return IRQ_HANDLED;
}

static int __devinit mantis_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *mantis_pci_table)
{
u8 revision, latency;
struct mantis_pci *mantis;

if (pci_enable_device(pdev)) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis PCI enable failed");
goto err;
}
mantis = kmalloc(sizeof (struct mantis_pci), GFP_KERNEL);
if (mantis == NULL) {
dprintk(verbose, MANTIS_ERROR, 1, "Out of memory");
return -ENOMEM;
}
memset(mantis, 0, sizeof (struct mantis_pci));

mantis->mantis_addr = pci_resource_start(pdev, 0);
if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), DRIVER_NAME)) {
goto err0;
}

if ((mantis->mantis_mmio =
ioremap(mantis->mantis_addr, 0x1000)) == NULL) {
dprintk(verbose, MANTIS_ERROR, 1, "IO remap failed");
goto err1;
}
/*
* Clear and disable all interrupts at startup
* to avoid lockup situations
*/
mmwrite(0x00, MANTIS_INT_STAT);
mmwrite(0x00, MANTIS_INT_MASK);
if (request_irq(pdev->irq, mantis_pci_irq, SA_SHIRQ | SA_INTERRUPT,
DRIVER_NAME, mantis) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis IRQ reg failed");
goto err2;
}
pci_set_master(pdev);
pci_set_drvdata(pdev, mantis);
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
mantis->latency = latency;
mantis->revision = revision;
mantis->pdev = pdev;

/*
* Setup default latency 32 if none specified
*/
if (!latency)
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 32);
dprintk(verbose, MANTIS_ERROR, 0, "Mantis Rev %d, ", mantis->revision);
dprintk(verbose, MANTIS_ERROR, 0, "irq: %d, latency: %d \
\nmemory: 0x%lx, mmio: 0x%p\n", pdev->irq, mantis->latency, \
mantis->mantis_addr, mantis->mantis_mmio);
if ((mantis_dma_init(mantis)) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
goto err0;
}

/*
* No more PCI specific stuff !
*/
if (mantis_core_init(mantis) < 0) {
dprintk(verbose, MANTIS_ERROR, 1, "Mantis core init failed");
goto err2;
}

return 0;

/*
* Error conditions ..
*/

err2:
if (mantis_dma_exit(mantis) < 0)
dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA exit failed");

dprintk(verbose, MANTIS_DEBUG, 1, "Err: IO Unmap");
if (mantis->mantis_mmio)
iounmap(mantis->mantis_mmio);
err1:
dprintk(verbose, MANTIS_DEBUG, 1, "Err: Release regions");
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
pci_disable_device(pdev);
err0:
dprintk(verbose, MANTIS_DEBUG, 1, "Err: Free");
kfree(mantis);
err:
dprintk(verbose, MANTIS_DEBUG, 1, "Err:");
return -ENODEV;
}

static void __devexit mantis_pci_remove(struct pci_dev *pdev)
{
struct mantis_pci *mantis = pci_get_drvdata(pdev);
if (mantis == NULL) {
dprintk(verbose, MANTIS_ERROR, 1, "Aeio, Mantis NULL ptr");
return;
}
mantis_core_exit(mantis);
dprintk(verbose, MANTIS_ERROR, 1, "Removing -->Mantis irq: %d, \
latency: %d\n memory: 0x%lx, mmio: 0x%p",
pdev->irq, mantis->latency, mantis->mantis_addr,
mantis->mantis_mmio);

free_irq(pdev->irq, mantis);
pci_release_regions(pdev);
if (mantis_dma_exit(mantis) < 0)
dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");

pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
kfree(mantis);
}

static struct pci_driver mantis_pci_driver = {
.name = DRIVER_NAME,
.id_table = mantis_pci_table,
.probe = mantis_pci_probe,
.remove = mantis_pci_remove,
};

static int __devinit mantis_pci_init(void)
{
return pci_register_driver(&mantis_pci_driver);
}

static void __devexit mantis_pci_exit(void)
{
pci_unregister_driver(&mantis_pci_driver);
}

module_init(mantis_pci_init);
module_exit(mantis_pci_exit);

MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
MODULE_AUTHOR("Manu Abraham");
MODULE_LICENSE("GPL");

[-- Attachment #8: mantis_reg.h --]
[-- Type: text/plain, Size: 2074 bytes --]

/*
Mantis PCI bridge driver

Copyright (C) 2005 Manu Abraham (manu@kromtek.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 (0xf << 28)
#define MANTIS_INT_RISCEN (1 << 27)
#define MANTIS_INT_I2CRACK (1 << 26)
#define MANTIS_INT_IRQ0 (1 << 11)
#define MANTIS_INT_IRQ1 (1 << 10)
#define MANTIS_INT_OCERR (1 << 8)
#define MANTIS_INT_PABORT (1 << 7)
#define MANTIS_INT_RIPERR (1 << 6)
#define MANTIS_INT_PPERR (1 << 5)
#define MANTIS_INT_FTRGT (1 << 3)
#define MANTIS_INT_RISCI (1 << 1)
#define MANTIS_INT_I2CDONE (1 << 0)

/* DMA */
#define MANTIS_DMA_CTL 0x08
#define MANTIS_I2C_RD (1 << 7)
#define MANTIS_I2C_WR (1 << 6)
#define MANTIS_DCAP_MODE (1 << 5)
#define MANTIS_FIFO_TP_4 (0 << 3)
#define MANTIS_FIFO_TP_8 (1 << 3)
#define MANTIS_FIFO_TP_16 (2 << 3)
#define MANTIS_FIFO_EN (1 << 2)
#define MANTIS_DCAP_EN (1 << 1)
#define MANTIS_RISC_EN (1 << 0)

#define MANTIS_RISC_START 0x10
#define MANTIS_RISC_PC 0x14

/* I2C */
#define MANTIS_I2CDATA_CTL 0x18
#define MANTIS_I2C_RATE_1 (0 << 6)
#define MANTIS_I2C_RATE_2 (1 << 6)
#define MANTIS_I2C_RATE_3 (2 << 6)
#define MANTIS_I2C_RATE_4 (3 << 6)
#define MANTIS_I2C_STOP (1 << 5)
#define MANTIS_I2C_PGMODE (1 << 3)

#define MANTIS_GPIF_HIFADDR 0xb0
#define MANTIS_GPIF_HIFDOUT 0xb4

#endif