/*
  Copyright 2004 Feyd
  Copyright 2004, 2005 Jean-Baptiste Note

  This file is part of prism54usb.

  prism54usb 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.

  prism54usb 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 prism54usb; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef _HAS_ISLUSB_NET2280_H
#define _HAS_ISLUSB_NET2280_H

#include <linux/firmware.h>
#include "islusb_dev.h"
#include "net2280.h"

struct islsm;

/* read/write transactions are initiated according
   to the size of the packet sent to the endpoint.
*/
#define P54U_REG_WSIZE		(sizeof(struct p54u_reg))
#define P54U_REG_RSIZE		(P54U_REG_WSIZE - (sizeof(u32)))

/* Access through CFGOUT (DEP_CFG register :
   P54U_PIPE_BRG =		0x0d) */
/* access to memory mapped config registers */
#define P54U_PORT_BRG		0x0010
/* access to PCI configuration registers */
#define P54U_PORT_BRG_CFG	0x0000

/* Access through PCIOUT ( DEP_CFG register :
   P54U_PIPE_DEV =		0x0e) */
/* p54u-specific configuration (reserved bits used) */
/* 7.6.5.3 in net2280 doc */
/* 11.7.1 for bit signification */
/* read/writes to the device pci address space */
/* 0x8000 means : DMA_READ_LINE_ENABLE */
/* 0x0000 means : memory space read/write */
#define P54U_PORT_DEV		0x0800
/* read/writes to the device pci
   0x0080 means : read / write in CFG space space */
#define P54U_PORT_DEV_CFG	0x0880

/* this is actually a byte enable mask */
/* first 4 bits, byte enable mask */
/* bit 4 0x10, means read/write -- unused here, as well as
 * master_start */
#define P54U_PORT_U16		0x0003
#define P54U_PORT_U32		0x000f

#define P54U_PORT_BRG_U32	(P54U_PORT_BRG | P54U_PORT_U32)
#define P54U_PORT_BRG_CFG_U32	(P54U_PORT_BRG_CFG | P54U_PORT_U32)
#define P54U_PORT_BRG_CFG_U16	(P54U_PORT_BRG_CFG | P54U_PORT_U16)

#define P54U_PORT_DEV_U32	(P54U_PORT_DEV | P54U_PORT_U32)
#define P54U_PORT_DEV_CFG_U32	(P54U_PORT_DEV_CFG | P54U_PORT_U32)
#define P54U_PORT_DEV_CFG_U16	(P54U_PORT_DEV_CFG | P54U_PORT_U16)

/* pci */
#define NET2280_BASE		0x10000000
#define NET2280_BASE2		0x20000000

/* gpio */
#define P54U_BRG_POWER_UP	(1 << GPIO0_DATA)
#define P54U_BRG_POWER_DOWN	(1 << GPIO1_DATA)

/* devinit */
#define NET2280_CLK_4Mhz	(15 << LOCAL_CLOCK_FREQUENCY)
#define NET2280_CLK_30Mhz	(2 << LOCAL_CLOCK_FREQUENCY)
#define NET2280_CLK_60Mhz	(1 << LOCAL_CLOCK_FREQUENCY)
#define NET2280_CLK_STOP	(0 << LOCAL_CLOCK_FREQUENCY)
#define NET2280_PCI_ENABLE	(1 << PCI_ENABLE)
#define NET2280_PCI_SOFT_RESET	(1 << PCI_SOFT_RESET)

/* enpoints */
#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE	(1 << CLEAR_NAK_OUT_PACKETS_MODE)
#define NET2280_FIFO_FLUSH			(1 << FIFO_FLUSH)

/* irq */
#define NET2280_USB_INTERRUPT_ENABLE		(1 << USB_INTERRUPT_ENABLE)
#define NET2280_PCI_INTA_INTERRUPT		(1 << PCI_INTA_INTERRUPT)
#define NET2280_PCI_INTA_INTERRUPT_ENABLE	(1 << PCI_INTA_INTERRUPT_ENABLE)

/* registers */
#define NET2280_DEVINIT		0x00
#define NET2280_USBIRQENB1	0x24
#define NET2280_IRQSTAT1	0x2c
#define NET2280_FIFOCTL         0x38
#define NET2280_GPIOCTL		0x50
#define NET2280_RELNUM		0x88
#define NET2280_EPA_RSP		0x324
#define NET2280_EPA_STAT	0x32c
#define NET2280_EPB_STAT	0x34c
#define NET2280_EPC_RSP		0x364
#define NET2280_EPC_STAT	0x36c
#define NET2280_EPD_STAT	0x38c

#define NET2280_EPA_CFG     0x320
#define NET2280_EPB_CFG     0x340
#define NET2280_EPC_CFG     0x360
#define NET2280_EPD_CFG     0x380
#define NET2280_EPE_CFG     0x3A0
#define NET2280_EPF_CFG     0x3C0

#define P54U_DEV_BASE		0x40000000

#define P54U_TRDY_TIMEOUT	0x40
#define P54U_RETRY_TIMEOUTG	0x41

int                     islusb_net2280_write_reg(struct p54u *p54u,
						 int ep, int port,
						 u32 val, u32 addr);
int                     islusb_net2280_read_reg(struct p54u *p54u,
						int ep, int port,
						u32 *retval, u32 addr);

/* helper functions for accessing net2280 and pci-behind-net2280
   registers */

static inline int
p54u_brg_writel(struct p54u *dev, u32 val, u32 addr) {
	return islusb_net2280_write_reg(dev, P54U_PIPE_BRG,
					P54U_PORT_BRG_U32,
					val, addr);
}

static inline int
p54u_pcicfg_brg_writel(struct p54u *dev, u32 val, u32 addr) {
	return islusb_net2280_write_reg(dev, P54U_PIPE_BRG,
					P54U_PORT_BRG_CFG_U32,
					val, addr);
}

static inline int
p54u_pcicfg_brg_writew(struct p54u *dev, u16 val, u32 addr) {
	return p54u_pcicfg_brg_writel(dev, val, addr);
}

static inline int
p54u_dev_writel(struct p54u *dev, u32 val, u32 addr) {
	return islusb_net2280_write_reg(dev, P54U_PIPE_DEV,
					P54U_PORT_DEV_U32,
					val, P54U_DEV_BASE | addr);
}

static inline int
p54u_pcicfg_dev_writel(struct p54u *dev, u32 val, u32 addr) {
	return islusb_net2280_write_reg(dev, P54U_PIPE_DEV,
					P54U_PORT_DEV_CFG_U32,
					val, addr);
}

static inline int
p54u_pcicfg_dev_writew(struct p54u *dev, u16 val, u32 addr) {
	return p54u_pcicfg_dev_writel(dev, val, addr);
}

static inline int
p54u_brg_readl(struct p54u *dev, u32 *val, u32 addr) {
	return islusb_net2280_read_reg(dev, P54U_PIPE_BRG,
				       P54U_PORT_BRG_U32, val, addr);
}

static inline int
p54u_pcicfg_brg_readl(struct p54u *dev, u32 *val, u32 addr) {
	return islusb_net2280_read_reg(dev, P54U_PIPE_BRG,
				       P54U_PORT_BRG_CFG_U32, val, addr);
}

static inline int
p54u_pcicfg_brg_readw(struct p54u *dev, u16 *val, u32 addr) {
	int err;
	u32 relay;
	err = islusb_net2280_read_reg(dev, P54U_PIPE_BRG,
				      P54U_PORT_BRG_CFG_U16, &relay, addr);
	*val = (u16)relay;
	return err;
}

static inline int
p54u_dev_readl(struct p54u *dev, u32 *val, u32 reg) {
	return islusb_net2280_read_reg(dev, P54U_PIPE_DEV, P54U_PORT_DEV_U32,
				       val, P54U_DEV_BASE | reg);
}

static inline int
p54u_pcicfg_dev_readl(struct p54u *dev, u32 *val, u32 addr) {
	return islusb_net2280_read_reg(dev, P54U_PIPE_DEV,
				       P54U_PORT_DEV_CFG_U32, val, addr);
}

static inline int
p54u_pcicfg_dev_readw(struct p54u *dev, u32 *val, u32 addr) {
	u32 relay;
	int err;
	err = islusb_net2280_read_reg(dev, P54U_PIPE_DEV,
				      P54U_PORT_DEV_CFG_U16, &relay, addr);
	*val = (u16)relay;
	return err;
}

void islusb_fill_net2280(struct islsm *islsm);
int  p54u_setup_rom(struct p54u *);
int  p54u_int_queue_init(struct p54u * p54u,
			 const struct usb_endpoint_descriptor *desc);
void p54u_int_queue_destroy(struct p54u *p54u);

#endif /* _HAS_ISLUSB_NET2280_H */
