/*
 * Timberdale FPGA GPIO driver
 * Author: Mocean Laboratories
 * Copyright (c) 2009 Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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.
 */

/* Supports:
 * Timberdale FPGA GPIO
 */

#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/timb_gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>

#define DRIVER_NAME "timb-gpio"

#define TGPIOVAL	0x00
#define TGPIODIR	0x04
#define TGPIO_IER	0x08
#define TGPIO_ISR	0x0c
#define TGPIO_IPR	0x10
#define TGPIO_ICR	0x14
#define TGPIO_FLR	0x18
#define TGPIO_LVR	0x1c
#define TGPIO_VER	0x20
#define TGPIO_BFLR	0x24

struct timbgpio {
	void __iomem		*membase;
	spinlock_t		lock; /* mutual exclusion */
	struct gpio_chip	gpio;
	int			irq_base;
	unsigned long		last_ier;
};

static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
	unsigned offset, bool enabled)
{
	struct timbgpio *tgpio = gpiochip_get_data(gpio);
	u32 reg;

	spin_lock(&tgpio->lock);
	reg = ioread32(tgpio->membase + offset);

	if (enabled)
		reg |= (1 << index);
	else
		reg &= ~(1 << index);

	iowrite32(reg, tgpio->membase + offset);
	spin_unlock(&tgpio->lock);

	return 0;
}

static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
	return timbgpio_update_bit(gpio, nr, TGPIODIR, true);
}

static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
	struct timbgpio *tgpio = gpiochip_get_data(gpio);
	u32 value;

	value = ioread32(tgpio->membase + TGPIOVAL);
	return (value & (1 << nr)) ? 1 : 0;
}

static int timbgpio_gpio_direction_output(struct gpio_chip *gpio,
						unsigned nr, int val)
{
	return timbgpio_update_bit(gpio, nr, TGPIODIR, false);
}

static void timbgpio_gpio_set(struct gpio_chip *gpio,
				unsigned nr, int val)
{
	timbgpio_update_bit(gpio, nr, TGPIOVAL, val != 0);
}

static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
	struct timbgpio *tgpio = gpiochip_get_data(gpio);

	if (tgpio->irq_base <= 0)
		return -EINVAL;

	return tgpio->irq_base + offset;
}

/*
 * GPIO IRQ
 */
static void timbgpio_irq_disable(struct irq_data *d)
{
	struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);
	int offset = d->irq - tgpio->irq_base;
	unsigned long flags;

	spin_lock_irqsave(&tgpio->lock, flags);
	tgpio->last_ier &= ~(1UL << offset);
	iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
	spin_unlock_irqrestore(&tgpio->lock, flags);
}

static void timbgpio_irq_enable(struct irq_data *d)
{
	struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);
	int offset = d->irq - tgpio->irq_base;
	unsigned long flags;

	spin_lock_irqsave(&tgpio->lock, flags);
	tgpio->last_ier |= 1UL << offset;
	iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
	spin_unlock_irqrestore(&tgpio->lock, flags);
}

static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)
{
	struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);
	int offset = d->irq - tgpio->irq_base;
	unsigned long flags;
	u32 lvr, flr, bflr = 0;
	u32 ver;
	int ret = 0;

	if (offset < 0 || offset > tgpio->gpio.ngpio)
		return -EINVAL;

	ver = ioread32(tgpio->membase + TGPIO_VER);

	spin_lock_irqsave(&tgpio->lock, flags);

	lvr = ioread32(tgpio->membase + TGPIO_LVR);
	flr = ioread32(tgpio->membase + TGPIO_FLR);
	if (ver > 2)
		bflr = ioread32(tgpio->membase + TGPIO_BFLR);

	if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
		bflr &= ~(1 << offset);
		flr &= ~(1 << offset);
		if (trigger & IRQ_TYPE_LEVEL_HIGH)
			lvr |= 1 << offset;
		else
			lvr &= ~(1 << offset);
	}

	if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
		if (ver < 3) {
			ret = -EINVAL;
			goto out;
		} else {
			flr |= 1 << offset;
			bflr |= 1 << offset;
		}
	} else {
		bflr &= ~(1 << offset);
		flr |= 1 << offset;
		if (trigger & IRQ_TYPE_EDGE_FALLING)
			lvr &= ~(1 << offset);
		else
			lvr |= 1 << offset;
	}

	iowrite32(lvr, tgpio->membase + TGPIO_LVR);
	iowrite32(flr, tgpio->membase + TGPIO_FLR);
	if (ver > 2)
		iowrite32(bflr, tgpio->membase + TGPIO_BFLR);

	iowrite32(1 << offset, tgpio->membase + TGPIO_ICR);

out:
	spin_unlock_irqrestore(&tgpio->lock, flags);
	return ret;
}

static void timbgpio_irq(struct irq_desc *desc)
{
	struct timbgpio *tgpio = irq_desc_get_handler_data(desc);
	struct irq_data *data = irq_desc_get_irq_data(desc);
	unsigned long ipr;
	int offset;

	data->chip->irq_ack(data);
	ipr = ioread32(tgpio->membase + TGPIO_IPR);
	iowrite32(ipr, tgpio->membase + TGPIO_ICR);

	/*
	 * Some versions of the hardware trash the IER register if more than
	 * one interrupt is received simultaneously.
	 */
	iowrite32(0, tgpio->membase + TGPIO_IER);

	for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio)
		generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));

	iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
}

static struct irq_chip timbgpio_irqchip = {
	.name		= "GPIO",
	.irq_enable	= timbgpio_irq_enable,
	.irq_disable	= timbgpio_irq_disable,
	.irq_set_type	= timbgpio_irq_type,
};

static int timbgpio_probe(struct platform_device *pdev)
{
	int err, i;
	struct device *dev = &pdev->dev;
	struct gpio_chip *gc;
	struct timbgpio *tgpio;
	struct resource *iomem;
	struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
	int irq = platform_get_irq(pdev, 0);

	if (!pdata || pdata->nr_pins > 32) {
		dev_err(dev, "Invalid platform data\n");
		return -EINVAL;
	}

	tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL);
	if (!tgpio) {
		dev_err(dev, "Memory alloc failed\n");
		return -EINVAL;
	}
	tgpio->irq_base = pdata->irq_base;

	spin_lock_init(&tgpio->lock);

	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	tgpio->membase = devm_ioremap_resource(dev, iomem);
	if (IS_ERR(tgpio->membase))
		return PTR_ERR(tgpio->membase);

	gc = &tgpio->gpio;

	gc->label = dev_name(&pdev->dev);
	gc->owner = THIS_MODULE;
	gc->parent = &pdev->dev;
	gc->direction_input = timbgpio_gpio_direction_input;
	gc->get = timbgpio_gpio_get;
	gc->direction_output = timbgpio_gpio_direction_output;
	gc->set = timbgpio_gpio_set;
	gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL;
	gc->dbg_show = NULL;
	gc->base = pdata->gpio_base;
	gc->ngpio = pdata->nr_pins;
	gc->can_sleep = false;

	err = devm_gpiochip_add_data(&pdev->dev, gc, tgpio);
	if (err)
		return err;

	platform_set_drvdata(pdev, tgpio);

	/* make sure to disable interrupts */
	iowrite32(0x0, tgpio->membase + TGPIO_IER);

	if (irq < 0 || tgpio->irq_base <= 0)
		return 0;

	for (i = 0; i < pdata->nr_pins; i++) {
		irq_set_chip_and_handler(tgpio->irq_base + i,
			&timbgpio_irqchip, handle_simple_irq);
		irq_set_chip_data(tgpio->irq_base + i, tgpio);
		irq_clear_status_flags(tgpio->irq_base + i, IRQ_NOREQUEST | IRQ_NOPROBE);
	}

	irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio);

	return 0;
}

static struct platform_driver timbgpio_platform_driver = {
	.driver = {
		.name			= DRIVER_NAME,
		.suppress_bind_attrs	= true,
	},
	.probe		= timbgpio_probe,
};

/*--------------------------------------------------------------------------*/

builtin_platform_driver(timbgpio_platform_driver);
