/*
 *  File Name       : linux/drivers/char/mp200_spi.h
 *  Function        : MP200 SPI interface
 *  Release Version : Ver 1.02
 *  Release Date    : 2006/03/06
 *
 *  Copyright (C) NEC Electronics Corporation 2005-2006
 *
 *
 *  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 Free Softwere Foundation; either version 2
 *  of 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 warrnty 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., 59 Temple Place - Suite 330, Boston,
 *  MA 02111-1307, USA.
 *
 */

#ifndef __DRIVERS_CHAR_MP200_SPI_H
#define __DRIVERS_CHAR_MP200_SPI_H

#include <asm/arch/spi.h>

/*
 * SPI register
 */
#define SPI_REG(ADDR, OFF)		(*(unsigned int volatile *)((unsigned char *)(ADDR) + OFF))

#define SPx_MODE(ADDR)			SPI_REG(IO_ADDRESS(ADDR), 0x00000000)
#define SPx_POL(ADDR)			SPI_REG(IO_ADDRESS(ADDR), 0x00000004)
#define SPx_CONTROL(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x00000008)
#define SPx_TX_TIM(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x0000000C)
#define SPx_TX_DATA(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x00000010)
#define SPx_RX_DATA(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x00000014)
#define SPx_STATUS(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x00000018)
#define SPx_RAW_STATUS(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x0000001C)
#define SPx_ENSET(ADDR)			SPI_REG(IO_ADDRESS(ADDR), 0x00000020)
#define SPx_ENCLR(ADDR)			SPI_REG(IO_ADDRESS(ADDR), 0x00000024)
#define SPx_FFCLR(ADDR)			SPI_REG(IO_ADDRESS(ADDR), 0x00000028)
#define SPx_TX_FIFO_P(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x0000002C)
#define SPx_RX_FIFO_P(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x00000030)
#ifdef CONFIG_MP201 /* fixed length */
#define SPx_CONTROL2(ADDR)		SPI_REG(IO_ADDRESS(ADDR), 0x00000034)
#endif

#define SPx_TX_DATA_PHYS(ADDR)		((ADDR) + 0x00000010)
#define SPx_RX_DATA_PHYS(ADDR)		((ADDR) + 0x00000014)

#ifdef CONFIG_MP201 /* 0602 */
#define SPx_POL_VAL_SPI0		SPI_POL_VAL_SPI0
#define SPx_POL_VAL_SPI1		SPI_POL_VAL_SPI1
#else
#define SPx_POL_CSW_16SCLK		(0x0F << 12)
#define SPx_POL_CSW_8SCLK		(0x07 << 12)
#define SPx_POL_CSW_4SCLK		(0x03 << 12)
#define SPx_POL_CSW_2SCLK		(0x01 << 12)

#define SPx_POL_CK3_DLY_ON		(0x01 << 11)
#define SPx_POL_CK3_DLY_OFF		(0x00 << 11)
#define SPx_POL_CK3_POL_NEG		(0x01 << 10)
#define SPx_POL_CK3_POL_POS		(0x00 << 10)
#define SPx_POL_CS3_POL_NEG		(0x01 << 9)
#define SPx_POL_CS3_POL_POS		(0x00 << 9)

#define SPx_POL_CK2_DLY_ON		(0x01 << 8)
#define SPx_POL_CK2_DLY_OFF		(0x00 << 8)
#define SPx_POL_CK2_POL_NEG		(0x01 << 7)
#define SPx_POL_CK2_POL_POS		(0x00 << 7)
#define SPx_POL_CS2_POL_NEG		(0x01 << 6)
#define SPx_POL_CS2_POL_POS		(0x00 << 6)

#define SPx_POL_CK1_DLY_ON		(0x01 << 5)
#define SPx_POL_CK1_DLY_OFF		(0x00 << 5)
#define SPx_POL_CK1_POL_NEG		(0x01 << 4)
#define SPx_POL_CK1_POL_POS		(0x00 << 4)
#define SPx_POL_CS1_POL_NEG		(0x01 << 3)
#define SPx_POL_CS1_POL_POS		(0x00 << 3)

#define SPx_POL_CK0_DLY_ON		(0x01 << 2)
#define SPx_POL_CK0_DLY_OFF		(0x00 << 2)
#define SPx_POL_CK0_POL_NEG		(0x01 << 1)
#define SPx_POL_CK0_POL_POS		(0x00 << 1)
#define SPx_POL_CS0_POL_NEG		(0x01 << 0)
#define SPx_POL_CS0_POL_POS		(0x00 << 0)

#define SPx_POL_VAL_SPI1		(SPx_POL_CSW_8SCLK | \
					 SPx_POL_CK3_DLY_OFF | SPx_POL_CK3_POL_POS | SPx_POL_CS3_POL_POS | \
					 SPx_POL_CK2_DLY_OFF | SPx_POL_CK2_POL_POS | SPx_POL_CS2_POL_POS | \
					 SPx_POL_CK1_DLY_OFF | SPx_POL_CK1_POL_POS | SPx_POL_CS1_POL_POS | \
					 SPx_POL_CK0_DLY_OFF | SPx_POL_CK0_POL_POS | SPx_POL_CS0_POL_POS)

#define SPx_POL_VAL_SPI2		(SPx_POL_CSW_8SCLK | \
					 SPx_POL_CK3_DLY_OFF | SPx_POL_CK3_POL_POS | SPx_POL_CS3_POL_POS | \
					 SPx_POL_CK2_DLY_OFF | SPx_POL_CK2_POL_POS | SPx_POL_CS2_POL_POS | \
					 SPx_POL_CK1_DLY_OFF | SPx_POL_CK1_POL_POS | SPx_POL_CS1_POL_POS | \
					 SPx_POL_CK0_DLY_OFF | SPx_POL_CK0_POL_POS | SPx_POL_CS0_POL_POS)
#endif

#ifdef CONFIG_MP201 /* fixed length */
#define SPx_CONTROL_TX_EMP		(0x01 << 15)
#define SPx_CONTROL_RX_FULL		(0x01 << 14)
#endif
#define SPx_CONTROL_TX_FULL		(0x01 << 7)
#define SPx_CONTROL_RX_EMP		(0x01 << 6)
#define SPx_CONTROL_RST			(0x01 << 4)
#define SPx_CONTROL_WRT			(0x01 << 3)
#define SPx_CONTROL_RD			(0x01 << 2)
#define SPx_CONTROL_STOP		(0x01 << 1)
#define SPx_CONTROL_START		(0x01 << 0)

#ifdef CONFIG_MP201 /* fixed length */
#define SPx_STATUS_TX_STOP		(0x01 << 6)
#define SPx_STATUS_RX_STOP		(0x01 << 5)
#endif
#define SPx_STATUS_TERR			(0x01 << 4)
#define SPx_STATUS_RDV			(0x01 << 3)
#define SPx_STATUS_END			(0x01 << 2)
#define SPx_STATUS_TX_UDR		(0x01 << 1)
#define SPx_STATUS_RX_OVR		(0x01 << 0)
#define SPx_STATUS_ALLERR		(SPx_STATUS_TERR | SPx_STATUS_TX_UDR | SPx_STATUS_RX_OVR)

#ifdef CONFIG_MP201 /* fixed length */
#define SPx_RAW_STATUS_TX_STOP_RAW	(0x01 << 6)
#define SPx_RAW_STATUS_RX_STOP_RAW	(0x01 << 5)
#endif
#define SPx_RAW_STATUS_TERR_RAW		(0x01 << 4)
#define SPx_RAW_STATUS_RDV_RAW		(0x01 << 3)
#define SPx_RAW_STATUS_END_RAW		(0x01 << 2)
#define SPx_RAW_STATUS_TX_UDR_RAW	(0x01 << 1)
#define SPx_RAW_STATUS_RX_OVR_RAW	(0x01 << 0)

#ifdef CONFIG_MP201 /* fixed length */
#define SPx_ENSET_TX_STOP_EN		(0x01 << 6)
#define SPx_ENSET_RX_STOP_EN		(0x01 << 5)
#endif
#define SPx_ENSET_TERR_EN		(0x01 << 4)
#define SPx_ENSET_RDV_EN		(0x01 << 3)
#define SPx_ENSET_END_EN		(0x01 << 2)
#define SPx_ENSET_TX_UDR_EN		(0x01 << 1)
#define SPx_ENSET_RX_OVR_EN		(0x01 << 0)
#define SPx_ENSET_ALLERR_EN		(SPx_ENSET_TERR_EN | SPx_ENSET_TX_UDR_EN | SPx_ENSET_RX_OVR_EN)

#ifdef CONFIG_MP201 /* fixed length */
#define SPx_ENCLR_TX_STOP_MASK		(0x01 << 6)
#define SPx_ENCLR_RX_STOP_MASK		(0x01 << 5)
#endif
#define SPx_ENCLR_TERR_MASK		(0x01 << 4)
#define SPx_ENCLR_RDV_MASK		(0x01 << 3)
#define SPx_ENCLR_END_MASK		(0x01 << 2)
#define SPx_ENCLR_TX_UDR_MASK		(0x01 << 1)
#define SPx_ENCLR_RX_OVR_MASK		(0x01 << 0)
#define SPx_ENCLR_ALLERR_MASK		(SPx_ENCLR_TERR_MASK | SPx_ENCLR_TX_UDR_MASK | SPx_ENCLR_RX_OVR_MASK)
#if 1
#ifdef CONFIG_MP201 /* fixed length */
#define SPx_ENCLR_ALL_MASK		(SPx_ENCLR_TX_STOP_MASK   \
					 | SPx_ENCLR_RX_STOP_MASK \
					 | SPx_ENCLR_TERR_MASK    \
					 | SPx_ENCLR_RDV_MASK     \
					 | SPx_ENCLR_END_MASK     \
					 | SPx_ENCLR_TX_UDR_MASK  \
					 | SPx_ENCLR_RX_OVR_MASK)
#else
#define SPx_ENCLR_ALL_MASK		(SPx_ENCLR_TERR_MASK      \
					 | SPx_ENCLR_RDV_MASK     \
					 | SPx_ENCLR_END_MASK     \
					 | SPx_ENCLR_TX_UDR_MASK  \
					 | SPx_ENCLR_RX_OVR_MASK)
#endif
#endif


#ifdef CONFIG_MP201 /* fixed length */
#define SPx_FFCLR_TX_STOP_CLR		(0x01 << 6)
#define SPx_FFCLR_RX_STOP_CLR		(0x01 << 5)
#endif
#define SPx_FFCLR_TERR_CLR		(0x01 << 4)
#define SPx_FFCLR_RDV_CLR		(0x01 << 3)
#define SPx_FFCLR_END_CLR		(0x01 << 2)
#define SPx_FFCLR_TX_UDR_CLR		(0x01 << 1)
#define SPx_FFCLR_RX_OVR_CLR		(0x01 << 0)
#if 1
#ifdef CONFIG_MP201 /* fixed length */
#define SPx_FFCLR_ALL_CLR		(SPx_FFCLR_TX_STOP_CLR   \
					 | SPx_FFCLR_RX_STOP_CLR \
					 | SPx_FFCLR_TERR_CLR    \
					 | SPx_FFCLR_RDV_CLR     \
					 | SPx_FFCLR_END_CLR     \
					 | SPx_FFCLR_TX_UDR_CLR  \
					 | SPx_FFCLR_RX_OVR_CLR)

#else
#define SPx_FFCLR_ALL_CLR		(SPx_FFCLR_TERR_CLR      \
					 | SPx_FFCLR_RDV_CLR     \
					 | SPx_FFCLR_END_CLR     \
					 | SPx_FFCLR_TX_UDR_CLR  \
					 | SPx_FFCLR_RX_OVR_CLR)
#endif
#else
#define SPx_FFCLR_ALLERR_CLR		(SPx_FFCLR_TERR_CLR | SPx_FFCLR_TX_UDR_CLR | SPx_FFCLR_RX_OVR_CLR)
#endif

#define SPx_TX_FIFO_P_TX_FIFO_WP	(0x1F << 8)
#define SPx_TX_FIFO_P_TX_FIFO_RP	(0x1F << 0)

#define SPx_RX_FIFO_P_RX_FIFO_WP	(0x1F << 8)
#define SPx_RX_FIFO_P_RX_FIFO_RP	(0x1F << 0)

#ifdef CONFIG_MP201 /* fixed length */
#define SPx_CONTROL2_TX_STOP_MODE	(0x01 << 9)
#define SPx_CONTROL2_RX_STOP_MODE	(0x01 << 8)
#define SPx_CONTROL2_RX_FIFO_FULL	(0x1F << 0)
#endif

/*
 * device info
 */
#define SPI_NAME			"spi"
#define SPI_DIR				"spi"

#ifdef CONFIG_MP201
#define SPI_MINOR_SPI0			0
#define SPI_MINOR_SPI1			1

#define SPI_DEV_SPI0			0
#define SPI_DEV_SPI1			1
#define SPI_DEV_MAX			1

#else
#define SPI_MINOR_SPI1			1
#define SPI_MINOR_SPI2			2

#define SPI_DEV_SPI1			0
#define SPI_DEV_SPI2			1
#define SPI_DEV_MAX			1
#endif

/*
 * transfer status
 */
#define SPI_STOP			0
#define SPI_ACTIVE			1

/*
 * buffer status
 */
#define SPI_BUFF_FULL			(0x01 << 0)
#define SPI_BUFF_EMPTY			(0x01 << 1)
#define SPI_BUFF_OVER_ERR		(0x01 << 2)

/*
 * other define
 */
#define SPI_BUFSIZE_MAX			65536	/* buffer size max [byte] */
#define SPI_BLKSIZE_MAX			32768	/* block size max [byte] */
#define SPI_BLKNUM_MAX			16	/* block number max */
#define SPI_BLKSIZE			1024	/* block size default [byte] */

#define SPI_OFF				0	/* clock/reset off */
#define SPI_ON				1	/* clock/reset on */
#define SPI_RESET			2	/* reset on->off */

#define SPI_FIFO_MAX			32	/* fifo count max */
#define SPI_DMA_BLOCK_SIZE_MAX		65534	/* dma block size max [byte] */

#ifdef CONFIG_MP201
#define SPI_SMU_PCTL_SPI1		0x1    /* PCTL SPI1 */
#define SPI_SMU_PCTL_SPI0_SK		0x2    /* SPIO_SK CS0-2 floating */
#define SPI_SMU_PCTL_SPI1_SK		0x4    /* SPI1_SK CS0-2 floating */
#endif

/*
 * spi register info
 */
typedef struct {
	unsigned int volatile *const mode;	/* SPx_MODE */
	unsigned int volatile *const pol;	/* SPx_POL */
	unsigned int volatile *const control;	/* SPx_CONTROL */
	unsigned int volatile *const tx_tim;	/* SPx_TX_TIM */
	unsigned int volatile *const tx_data;	/* SPx_TX_DATA */
	unsigned int volatile *const rx_data;	/* SPx_RX_DATA */
	unsigned int volatile *const status;	/* SPx_STATUS */
	unsigned int volatile *const raw_status;	/* SPx_RAW_STATUS */
	unsigned int volatile *const enset;	/* SPx_ENSET */
	unsigned int volatile *const enclr;	/* SPx_ENCLR */
	unsigned int volatile *const ffclr;	/* SPx_FFCLR */
	unsigned int volatile *const tx_fifo_p;	/* SPx_ENCLR */
	unsigned int volatile *const rx_fifo_p;	/* SPx_FFCLR */
#ifdef CONFIG_MP201 /* fixed length */
	unsigned int volatile *const control2;	/* SPx_CONTROL2 */
#endif
} spi_regs_t;

/*
 * buffer info
 */
typedef struct {
	dma_addr_t dma_addr;	/* dma transfer start address (physics) */
	unsigned int top;	/* buffer top address (virtual) */
	unsigned int end;	/* buffer end address (virtual) */
	unsigned int dma_ptr;	/* buffer pointer for dma/cpu transfer */
	unsigned int usr_ptr;	/* buffer pointer for read/write */
	unsigned int blknum;	/* block number */
	unsigned int state;	/* buffer status */
} spi_buf_t;

/*
 * transfer info
 */
typedef struct {
	dma_regs_t *dma_regs;	/* dma_regs_t */
	int const rx_lch;	/* dma rx channel no */
	int const tx_lch;	/* dma tx channel no */
	unsigned int const rx_data;	/* rx data transfer address (physics) */
	unsigned int const tx_data;	/* tx data transfer address (physics) */
	unsigned int int_spi;	/* int spi no */
	unsigned int dma_err;	/* dma error status */
	unsigned int spi_err;	/* spi error status */
#ifdef CONFIG_MP201 /* fixed length */
/* comment: DMAモード保持変数削除 */
#else
	unsigned int dma;	/* dma on/off status */
#endif
	unsigned int state;	/* transfer status */
	wait_queue_head_t wait;	/* wait queue */
	spinlock_t spinlock;	/* spin lock */
	spi_buf_t buf;		/* buffer info */
} spi_trans_t;

/*
 * smu info
 */
typedef struct {
	unsigned int pclk;	/* pclk */
	unsigned int sclk;	/* sclk */
	unsigned int pclk_ctrl;	/* pclk ctrl */
	unsigned int sclk_ctrl;	/* sclk ctrl */
	unsigned int reset;	/* reset */
	unsigned int div_sclk;	/* divsclk */
} spi_smu_t;

/*
 * spi data info
 */
typedef struct {
	spi_regs_t *regs;	/* spi register info */
	spi_mode_t *mode;	/* spi mode info */
	unsigned int pol;	/* spi pol info */
	spi_smu_t *smu;		/* smu info */
	spi_trans_t *trans;	/* transfer info */
	mode_t opened;		/* open flag */
#ifdef CONFIG_MP201
	unsigned int pctl_spi;		/* smu PCTL_SPI BIT */
	unsigned int k_flag;            /* kernel flag */
	struct semaphore sem_rw;        /* semaphore for open/release */
#endif
	struct semaphore sem_open;	/* semaphore for open/release */
} spi_data_t;

#endif				/* __DRIVERS_CHAR_MP200_SPI_H */
