#ifndef __LIBWR_CPU_IO_H
#define __LIBWR_CPU_IO_H

#include <stdint.h>

#define FPGA_GPIO_BASE		0x400000000
#define FPGA_GPIO_SIZE		0x100
#define FPGA_GPIO_BANK_SIZE 0x20

/* wb_gpio_port registers offset */
#define FPGA_GPIO_CODR		0x00	/* Clear Output Data Register */
#define FPGA_GPIO_SODR		0x04	/* Set Output Data Register */
#define FPGA_GPIO_DDR		0x08	/* Data Direction Register */
#define FPGA_GPIO_PSR		0x0C	/* Pin State Register */

/* Number of 32 GPIO banks */
#define NUM_GPIO_BANKS		2

/* Pin direction */
#define PIO_IN				0
#define PIO_OUT				1

/* Pin value */
#define PIO_OUT_0			1
#define PIO_OUT_1			2


#define IDX_REG_CODR		0
#define IDX_REG_SODR		1
#define IDX_REG_DDR			2
#define IDX_REG_PSR			3

#define _writel(reg, val) *(volatile uint32_t *)(reg) = (val)
#define _readl(reg) (*(volatile uint32_t *)(reg))

typedef struct pio_pin {
	int port;
	int pin;
	int mode;
	int dir;
} pio_pin_t;


extern volatile uint8_t *_sys_base;
extern volatile uint8_t *_pio_base[4][NUM_GPIO_BANKS + 1];

int shw_pio_mmap_init(void);
void shw_pio_configure(const pio_pin_t * pin);
void shw_pio_toggle_pin(pio_pin_t * pin, uint32_t udelay);


static inline void shw_pio_set(const pio_pin_t * pin, int state)
{
	if (state)
		_writel(_pio_base[IDX_REG_SODR][pin->port], (1 << pin->pin));
	else
		_writel(_pio_base[IDX_REG_CODR][pin->port], (1 << pin->pin));
}

static inline void shw_pio_set1(const pio_pin_t * pin)
{
	_writel(_pio_base[IDX_REG_SODR][pin->port], (1 << pin->pin));
}

static inline void shw_pio_set0(const pio_pin_t * pin)
{
	_writel(_pio_base[IDX_REG_CODR][pin->port], (1 << pin->pin));
}

static inline int shw_pio_get(const pio_pin_t * pin)
{
	return (_readl(_pio_base[IDX_REG_PSR][pin->port]) & (1 << pin->pin)) ?
	    1 : 0;
}

static inline int shw_pio_setdir(const pio_pin_t * pin, int dir)
{
	uint32_t mask;
	uint32_t ddr;

	mask = (1 << pin->pin);
	ddr = _readl(_pio_base[IDX_REG_DDR][pin->port]);

	if(dir == PIO_IN)
		ddr &= ~mask;
	else
		ddr |= mask;

	_writel(_pio_base[IDX_REG_DDR][pin->port], ddr);
}

#endif /* __LIBWR_CPU_IO_H */
