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

Commit cab18d19 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge branch 'depends/gpio-devel' into next/soc



This is required for some of the clps711x series, so we're bringing in
the dependency explicitly.

By Linus Walleij (5) and others
via Linus Walleij
* depends/gpio-devel:
  GPIO: clps711x: use platform_device_unregister in gpio_clps711x_init()
  gpio/tc3589x: convert to use the simple irqdomain
  gpio/em: convert to linear IRQ domain
  gpio/mvebu: convert to use irq_domain_add_simple()
  gpio/tegra: convert to use linear irqdomain
  gpiolib: unlock on error in gpio_export()
  gpiolib: add gpio get direction callback support
  GPIO: clps711x: Fix direction logic for PORTD
  GPIO: clps711x: Fix return value for gpio_clps711x_get
  gpiolib: Refactor gpio_export
  GPIO: vt8500: Add extended gpio bank for WM8505/WM8650
  gpio: clps711x: delete local <mach/gpio.h> header
  GPIO: Add support for GPIO on CLPS711X-target platform
  DA9055 GPIO driver
  gpio/gpio-omap: Use existing pointer to struct device
  gpio/gpio-pl061: Covert to use devm_* functions

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents c3e5dba4 2cad6a8a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -367,6 +367,8 @@ config ARCH_CNS3XXX

config ARCH_CLPS711X
	bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
	select ARCH_REQUIRE_GPIOLIB
	select ARCH_USES_GETTIMEOFFSET
	select CLKDEV_LOOKUP
	select COMMON_CLK
	select CPU_ARM720T
+15 −0
Original line number Diff line number Diff line
@@ -86,11 +86,26 @@ config GPIO_DA9052
	help
	  Say yes here to enable the GPIO driver for the DA9052 chip.

config GPIO_DA9055
	tristate "Dialog Semiconductor DA9055 GPIO"
	depends on MFD_DA9055
	help
	  Say yes here to enable the GPIO driver for the DA9055 chip.

	  The Dialog DA9055 PMIC chip has 3 GPIO pins that can be
	  be controller by this driver.

	  If driver is built as a module it will be called gpio-da9055.

config GPIO_MAX730X
	tristate

comment "Memory mapped GPIO drivers:"

config GPIO_CLPS711X
	def_bool y
	depends on ARCH_CLPS711X

config GPIO_GENERIC_PLATFORM
	tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
	select GPIO_GENERIC
+2 −0
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
obj-$(CONFIG_GPIO_BT8XX)	+= gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X)	+= gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535)	+= gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052)	+= gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055)	+= gpio-da9055.o
obj-$(CONFIG_ARCH_DAVINCI)	+= gpio-davinci.o
obj-$(CONFIG_GPIO_EM)		+= gpio-em.o
obj-$(CONFIG_GPIO_EP93XX)	+= gpio-ep93xx.o
+199 −0
Original line number Diff line number Diff line
/*
 *  CLPS711X GPIO driver
 *
 *  Copyright (C) 2012 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/io.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/spinlock.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)
{
	return !!(readb(clps711x_port(chip)) & (1 << offset));
}

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);

	spin_lock_irqsave(&gpio->lock, flags);
	tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
	writeb(tmp, clps711x_pdir(chip));
	spin_unlock_irqrestore(&gpio->lock, flags);

	return 0;
}

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);

	return 0;
}

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);

	return 0;
}

static int gpio_clps711x_dir_out_inv(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);

	return 0;
}

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 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_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("CLPS711X GPIO driver");
+204 −0
Original line number Diff line number Diff line
/*
 * GPIO Driver for Dialog DA9055 PMICs.
 *
 * Copyright(c) 2012 Dialog Semiconductor Ltd.
 *
 * Author: David Dajun Chen <dchen@diasemi.com>
 *
 *  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 the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 */
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>

#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>
#include <linux/mfd/da9055/pdata.h>

#define DA9055_VDD_IO			0x0
#define DA9055_PUSH_PULL		0x3
#define DA9055_ACT_LOW			0x0
#define DA9055_GPI			0x1
#define DA9055_PORT_MASK		0x3
#define DA9055_PORT_SHIFT(offset)	(4 * (offset % 2))

#define DA9055_INPUT			DA9055_GPI
#define DA9055_OUTPUT			DA9055_PUSH_PULL
#define DA9055_IRQ_GPI0			3

struct da9055_gpio {
	struct da9055 *da9055;
	struct gpio_chip gp;
};

static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
{
	return container_of(chip, struct da9055_gpio, gp);
}

static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
{
	struct da9055_gpio *gpio = to_da9055_gpio(gc);
	int gpio_direction = 0;
	int ret;

	/* Get GPIO direction */
	ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1);
	if (ret < 0)
		return ret;

	gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset);
	gpio_direction >>= DA9055_PORT_SHIFT(offset);
	switch (gpio_direction) {
	case DA9055_INPUT:
		ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B);
		if (ret < 0)
			return ret;
		break;
	case DA9055_OUTPUT:
		ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2);
		if (ret < 0)
			return ret;
	}

	return ret & (1 << offset);

}

static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
	struct da9055_gpio *gpio = to_da9055_gpio(gc);

	da9055_reg_update(gpio->da9055,
			DA9055_REG_GPIO_MODE0_2,
			1 << offset,
			value << offset);
}

static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
	struct da9055_gpio *gpio = to_da9055_gpio(gc);
	unsigned char reg_byte;

	reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
				<< DA9055_PORT_SHIFT(offset);

	return da9055_reg_update(gpio->da9055, (offset >> 1) +
				DA9055_REG_GPIO0_1,
				DA9055_PORT_MASK <<
				DA9055_PORT_SHIFT(offset),
				reg_byte);
}

static int da9055_gpio_direction_output(struct gpio_chip *gc,
					unsigned offset, int value)
{
	struct da9055_gpio *gpio = to_da9055_gpio(gc);
	unsigned char reg_byte;
	int ret;

	reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL)
					<< DA9055_PORT_SHIFT(offset);

	ret = da9055_reg_update(gpio->da9055, (offset >> 1) +
				DA9055_REG_GPIO0_1,
				DA9055_PORT_MASK <<
				DA9055_PORT_SHIFT(offset),
				reg_byte);
	if (ret < 0)
		return ret;

	da9055_gpio_set(gc, offset, value);

	return 0;
}

static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
{
	struct da9055_gpio *gpio = to_da9055_gpio(gc);
	struct da9055 *da9055 = gpio->da9055;

	return regmap_irq_get_virq(da9055->irq_data,
				  DA9055_IRQ_GPI0 + offset);
}

static struct gpio_chip reference_gp __devinitdata = {
	.label = "da9055-gpio",
	.owner = THIS_MODULE,
	.get = da9055_gpio_get,
	.set = da9055_gpio_set,
	.direction_input = da9055_gpio_direction_input,
	.direction_output = da9055_gpio_direction_output,
	.to_irq = da9055_gpio_to_irq,
	.can_sleep = 1,
	.ngpio = 3,
	.base = -1,
};

static int __devinit da9055_gpio_probe(struct platform_device *pdev)
{
	struct da9055_gpio *gpio;
	struct da9055_pdata *pdata;
	int ret;

	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
	if (gpio == NULL)
		return -ENOMEM;

	gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
	pdata = gpio->da9055->dev->platform_data;

	gpio->gp = reference_gp;
	if (pdata && pdata->gpio_base)
		gpio->gp.base = pdata->gpio_base;

	ret = gpiochip_add(&gpio->gp);
	if (ret < 0) {
		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
		goto err_mem;
	}

	platform_set_drvdata(pdev, gpio);

	return 0;

err_mem:
	return ret;
}

static int __devexit da9055_gpio_remove(struct platform_device *pdev)
{
	struct da9055_gpio *gpio = platform_get_drvdata(pdev);

	return gpiochip_remove(&gpio->gp);
}

static struct platform_driver da9055_gpio_driver = {
	.probe = da9055_gpio_probe,
	.remove = __devexit_p(da9055_gpio_remove),
	.driver = {
		.name	= "da9055-gpio",
		.owner	= THIS_MODULE,
	},
};

static int __init da9055_gpio_init(void)
{
	return platform_driver_register(&da9055_gpio_driver);
}
subsys_initcall(da9055_gpio_init);

static void __exit da9055_gpio_exit(void)
{
	platform_driver_unregister(&da9055_gpio_driver);
}
module_exit(da9055_gpio_exit);

MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
MODULE_DESCRIPTION("DA9055 GPIO Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9055-gpio");
Loading