Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55fe14ab authored by Alexander Shiyan's avatar Alexander Shiyan Committed by Olof Johansson
Browse files

GPIO: clps711x: Rewrite driver for using generic GPIO code



This patch provides rewritten driver for CLPS711X GPIO which uses
generic GPIO code.

Signed-off-by: default avatarAlexander Shiyan <shc_work@mail.ru>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parent d683b96b
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -109,8 +109,11 @@ config GPIO_MAX730X
comment "Memory mapped GPIO drivers:"

config GPIO_CLPS711X
	def_bool y
	tristate "CLPS711X GPIO support"
	depends on ARCH_CLPS711X
	select GPIO_GENERIC
	help
	  Say yes here to support GPIO on CLPS711X SoCs.

config GPIO_GENERIC_PLATFORM
	tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
+59 −167
Original line number Diff line number Diff line
/*
 *  CLPS711X GPIO driver
 *
 *  Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
 *  Copyright (C) 2012,2013 Alexander Shiyan <shc_work@mail.ru>
 *
 * 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
@@ -9,191 +9,83 @@
 * (at your option) any later version.
 */

#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/basic_mmio_gpio.h>
#include <linux/platform_device.h>

#include <mach/hardware.h>

#define CLPS711X_GPIO_PORTS	5
#define CLPS711X_GPIO_NAME	"gpio-clps711x"

struct clps711x_gpio {
	struct gpio_chip	chip[CLPS711X_GPIO_PORTS];
	spinlock_t		lock;
};

static void __iomem *clps711x_ports[] = {
	CLPS711X_VIRT_BASE + PADR,
	CLPS711X_VIRT_BASE + PBDR,
	CLPS711X_VIRT_BASE + PCDR,
	CLPS711X_VIRT_BASE + PDDR,
	CLPS711X_VIRT_BASE + PEDR,
};

static void __iomem *clps711x_pdirs[] = {
	CLPS711X_VIRT_BASE + PADDR,
	CLPS711X_VIRT_BASE + PBDDR,
	CLPS711X_VIRT_BASE + PCDDR,
	CLPS711X_VIRT_BASE + PDDDR,
	CLPS711X_VIRT_BASE + PEDDR,
};

#define clps711x_port(x)	clps711x_ports[x->base / 8]
#define clps711x_pdir(x)	clps711x_pdirs[x->base / 8]

static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset)
static int clps711x_gpio_probe(struct platform_device *pdev)
{
	return !!(readb(clps711x_port(chip)) & (1 << offset));
}
	void __iomem *dat, *dir;
	struct bgpio_chip *bgc;
	struct resource *res;
	int err, id = pdev->id;

static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset,
			      int value)
{
	int tmp;
	unsigned long flags;
	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);

	spin_lock_irqsave(&gpio->lock, flags);
	tmp = readb(clps711x_port(chip)) & ~(1 << offset);
	if (value)
		tmp |= 1 << offset;
	writeb(tmp, clps711x_port(chip));
	spin_unlock_irqrestore(&gpio->lock, flags);
}

static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset)
{
	int tmp;
	unsigned long flags;
	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
	if ((id < 0) || (id > 4))
		return -ENODEV;

	spin_lock_irqsave(&gpio->lock, flags);
	tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
	writeb(tmp, clps711x_pdir(chip));
	spin_unlock_irqrestore(&gpio->lock, flags);
	bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
	if (!bgc)
		return -ENOMEM;

	return 0;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	dat = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(dat))
		return PTR_ERR(dat);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	dir = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(dir))
		return PTR_ERR(dir);

	switch (id) {
	case 3:
		/* PORTD is inverted logic for direction register */
		err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
				 NULL, dir, 0);
		break;
	default:
		err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
				 dir, NULL, 0);
		break;
	}

static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset,
				 int value)
{
	int tmp;
	unsigned long flags;
	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);

	spin_lock_irqsave(&gpio->lock, flags);
	tmp = readb(clps711x_pdir(chip)) | (1 << offset);
	writeb(tmp, clps711x_pdir(chip));
	tmp = readb(clps711x_port(chip)) & ~(1 << offset);
	if (value)
		tmp |= 1 << offset;
	writeb(tmp, clps711x_port(chip));
	spin_unlock_irqrestore(&gpio->lock, flags);
	if (err)
		return err;

	return 0;
	switch (id) {
	case 4:
		/* PORTE is 3 lines only */
		bgc->gc.ngpio = 3;
		break;
	default:
		break;
	}

static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset)
{
	int tmp;
	unsigned long flags;
	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);

	spin_lock_irqsave(&gpio->lock, flags);
	tmp = readb(clps711x_pdir(chip)) | (1 << offset);
	writeb(tmp, clps711x_pdir(chip));
	spin_unlock_irqrestore(&gpio->lock, flags);
	bgc->gc.base = id * 8;
	platform_set_drvdata(pdev, bgc);

	return 0;
	return gpiochip_add(&bgc->gc);
}

static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset,
				     int value)
static int clps711x_gpio_remove(struct platform_device *pdev)
{
	int tmp;
	unsigned long flags;
	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);

	spin_lock_irqsave(&gpio->lock, flags);
	tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
	writeb(tmp, clps711x_pdir(chip));
	tmp = readb(clps711x_port(chip)) & ~(1 << offset);
	if (value)
		tmp |= 1 << offset;
	writeb(tmp, clps711x_port(chip));
	spin_unlock_irqrestore(&gpio->lock, flags);
	struct bgpio_chip *bgc = platform_get_drvdata(pdev);

	return 0;
	return bgpio_remove(bgc);
}

static struct {
	char	*name;
	int	nr;
	int	inv_dir;
} clps711x_gpio_ports[] __initconst = {
	{ "PORTA", 8, 0, },
	{ "PORTB", 8, 0, },
	{ "PORTC", 8, 0, },
	{ "PORTD", 8, 1, },
	{ "PORTE", 3, 0, },
static struct platform_driver clps711x_gpio_driver = {
	.driver	= {
		.name	= "clps711x-gpio",
		.owner	= THIS_MODULE,
	},
	.probe	= clps711x_gpio_probe,
	.remove	= clps711x_gpio_remove,
};
module_platform_driver(clps711x_gpio_driver);

static int __init gpio_clps711x_init(void)
{
	int i;
	struct platform_device *pdev;
	struct clps711x_gpio *gpio;

	pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
	if (!pdev) {
		pr_err("Cannot create platform device: %s\n",
		       CLPS711X_GPIO_NAME);
		return -ENOMEM;
	}

	platform_device_add(pdev);

	gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
			    GFP_KERNEL);
	if (!gpio) {
		dev_err(&pdev->dev, "GPIO allocating memory error\n");
		platform_device_unregister(pdev);
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, gpio);

	spin_lock_init(&gpio->lock);

	for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
		gpio->chip[i].owner		= THIS_MODULE;
		gpio->chip[i].dev		= &pdev->dev;
		gpio->chip[i].label		= clps711x_gpio_ports[i].name;
		gpio->chip[i].base		= i * 8;
		gpio->chip[i].ngpio		= clps711x_gpio_ports[i].nr;
		gpio->chip[i].get		= gpio_clps711x_get;
		gpio->chip[i].set		= gpio_clps711x_set;
		if (!clps711x_gpio_ports[i].inv_dir) {
			gpio->chip[i].direction_input = gpio_clps711x_dir_in;
			gpio->chip[i].direction_output = gpio_clps711x_dir_out;
		} else {
			gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv;
			gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv;
		}
		WARN_ON(gpiochip_add(&gpio->chip[i]));
	}

	dev_info(&pdev->dev, "GPIO driver initialized\n");

	return 0;
}
arch_initcall(gpio_clps711x_init);

MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("CLPS711X GPIO driver");