/*
 * Copyright (C) 2014 Yoshinori Sato <ysato@users.sourceforge.jp>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/gpio.h>

static u8 ddr[H8300_NR_PORT] = CONFIG_H8300_INIT_DDR;
static const u8 gpio_mask[H8300_NR_PORT] = CONFIG_H8300_GPIO;
static u8 reserve[H8300_NR_PORT];

void h8300_gpio_init(void)
{
	int i;
	for(i = 0; i < H8300_NR_PORT; i++)
		writeb(ddr[i], P1DDR + i);
}

int gpio_request(unsigned gpio, const char *name)
{
	int port = (gpio >> 8) & 0xff;
	int bit = gpio & 0x07;
	if (port >= H8300_NR_PORT)
		return -EINVAL;
	if ((reserve[port] & (1 << bit)) || 
	    !(gpio_mask[port] & (1 << bit)))
		return -EBUSY;
	reserve[port] |=  1 << bit;
	return 0;
}

int gpio_free(unsigned gpio)
{
	int port = (gpio >> 8) & 0xff;
	int bit = gpio & 0x07;
	if (port >= H8300_NR_PORT)
		return -EINVAL;
	reserve[port] &=  ~(1 << bit);
	return 0;
}

int gpio_set_value(unsigned gpio, int value)
{
	int port = (gpio >> 8) & 0xff;
	int bit = gpio & 0x07;
	if (port >= H8300_NR_PORT)
		return -EINVAL;
	if (!(reserve[port] & (1 << bit)))
		return -EIO;
	if (value)
		writeb(readb(P1DR + port) | (1 << bit), P1DR + port);
	else
		writeb(readb(P1DR + port) & ~(1 << bit), P1DR + port);
	return 0;
}

int gpio_get_value(unsigned gpio)
{
	int port = (gpio >> 8) & 0xff;
	int bit = gpio & 0x07;
	return (readb(P1DR + port) >> bit) & 1;
}

int gpio_direction_output(unsigned int gpio, int value)
{
	int port = (gpio >> 8) & 0xff;
	int bit = gpio & 0x07;
	if (port >= H8300_NR_PORT)
		return -EINVAL;
	if (!(reserve[port] & (1 << bit)))
		return -EIO;
	ddr[port] |= 1 << bit;
	writeb(ddr[port], P1DDR + port);
	gpio_set_value(gpio, value);
	return 0;
}

int gpio_direction_input(unsigned int gpio)
{
	int port = (gpio >> 8) & 0xff;
	int bit = gpio & 0x07;
	if (port >= H8300_NR_PORT)
		return -EINVAL;
	if (!(reserve[port] & (1 << bit)))
		return -EIO;
	ddr[port] &= ~(1 << bit);
	return 0;
}
