Files
android_kernel_xiaomi_sm8450/drivers/gpio/gpio-arizona.c
Linus Torvalds 510965dd4a Merge tag 'gpio-v4.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.1 development cycle:

   - A new GPIO hogging mechanism has been added.  This can be used on
     boards that want to drive some GPIO line high, low, or set it as
     input on boot and then never touch it again.  For some embedded
     systems this is bliss and simplifies things to a great extent.

   - Some API cleanup and closure: gpiod_get_array() and
     gpiod_put_array() has been added to get and put GPIOs in bulk as
     was possible with the non-descriptor API.

   - Encapsulate cross-calls to the pin control subsystem in
     <linux/gpio/driver.h>.  Now this should be the only header any GPIO
     driver needs to include or something is wrong.  Cleanups
     restricting drivers to this include are welcomed if tested.

   - Sort the GPIO Kconfig and split it into submenus, as it was
     becoming and unstructured, illogical and unnavigatable mess.  I
     hope this is easier to follow.  Menus that require a certain
     subsystem like I2C can now be hidden nicely for example, still
     working on others.

   - New drivers:

       - New driver for the Altera Soft GPIO.

       - The F7188x driver now handles the F71869 and F71869A variants.

       - The MIPS Loongson driver has been moved to drivers/gpio for
         consolidation and cleanup.

   - Cleanups:

       - The MAX732x is converted to use the GPIOLIB_IRQCHIP
         infrastructure.

       - The PCF857x is converted to use the GPIOLIB_IRQCHIP
         infrastructure.

       - Radical cleanup of the OMAP driver.

   - Misc:

       - Enable the DWAPB GPIO for all architectures.  This is a "hard
         IP" block from Synopsys which has started to turn up in so
         diverse architectures as X86 Quark, ARC and a slew of ARM
         systems.  So even though it's not an expander, it's generic
         enough to be available for all.

       - We add a mock GPIO on Crystalcove PMIC after a long discussion
         with Daniel Vetter et al, tracing back to the shootout at the
         kernel summit where DRM drivers and sub-componentization was
         discussed.  In this case a mock GPIO is assumed to be the best
         compromise gaining some reuse of infrastructure without making
         DRM drivers overly complex at the same time.  Let's see"

* tag 'gpio-v4.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (62 commits)
  Revert "gpio: sch: use uapi/linux/pci_ids.h directly"
  gpio: dwapb: remove dependencies
  gpio: dwapb: enable for ARC
  gpio: removing kfree remove functionality
  gpio: mvebu: Fix mask/unmask managment per irq chip type
  gpio: split GPIO drivers in submenus
  gpio: move MFD GPIO drivers under their own comment
  gpio: move BCM Kona Kconfig option
  gpio: arrange SPI Kconfig symbols alphabetically
  gpio: arrange PCI GPIO controllers alphabetically
  gpio: arrange I2C Kconfig symbols alphabetically
  gpio: arrange Kconfig symbols alphabetically
  gpio: ich: Implement get_direction function
  gpio: use (!foo) instead of (foo == NULL)
  gpio: arizona: drop owner assignment from platform_drivers
  gpio: max7300: remove 'ret' variable
  gpio: use devm_kzalloc
  gpio: sch: use uapi/linux/pci_ids.h directly
  gpio: x-gene: fix devm_ioremap_resource() check
  gpio: loongson: Add Loongson-3A/3B GPIO driver support
  ...
2015-04-18 08:22:10 -04:00

169 lines
4.2 KiB
C

/*
* gpiolib support for Wolfson Arizona class devices
*
* Copyright 2012 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.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/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
struct arizona_gpio {
struct arizona *arizona;
struct gpio_chip gpio_chip;
};
static inline struct arizona_gpio *to_arizona_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct arizona_gpio, gpio_chip);
}
static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
struct arizona *arizona = arizona_gpio->arizona;
return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
ARIZONA_GPN_DIR, ARIZONA_GPN_DIR);
}
static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
struct arizona *arizona = arizona_gpio->arizona;
unsigned int val;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val);
if (ret < 0)
return ret;
if (val & ARIZONA_GPN_LVL)
return 1;
else
return 0;
}
static int arizona_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
struct arizona *arizona = arizona_gpio->arizona;
if (value)
value = ARIZONA_GPN_LVL;
return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
}
static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
struct arizona *arizona = arizona_gpio->arizona;
if (value)
value = ARIZONA_GPN_LVL;
regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
ARIZONA_GPN_LVL, value);
}
static struct gpio_chip template_chip = {
.label = "arizona",
.owner = THIS_MODULE,
.direction_input = arizona_gpio_direction_in,
.get = arizona_gpio_get,
.direction_output = arizona_gpio_direction_out,
.set = arizona_gpio_set,
.can_sleep = true,
};
static int arizona_gpio_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
struct arizona_gpio *arizona_gpio;
int ret;
arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio),
GFP_KERNEL);
if (!arizona_gpio)
return -ENOMEM;
arizona_gpio->arizona = arizona;
arizona_gpio->gpio_chip = template_chip;
arizona_gpio->gpio_chip.dev = &pdev->dev;
#ifdef CONFIG_OF_GPIO
arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
#endif
switch (arizona->type) {
case WM5102:
case WM5110:
case WM8280:
case WM8997:
arizona_gpio->gpio_chip.ngpio = 5;
break;
default:
dev_err(&pdev->dev, "Unknown chip variant %d\n",
arizona->type);
return -EINVAL;
}
if (pdata && pdata->gpio_base)
arizona_gpio->gpio_chip.base = pdata->gpio_base;
else
arizona_gpio->gpio_chip.base = -1;
ret = gpiochip_add(&arizona_gpio->gpio_chip);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
ret);
goto err;
}
platform_set_drvdata(pdev, arizona_gpio);
return ret;
err:
return ret;
}
static int arizona_gpio_remove(struct platform_device *pdev)
{
struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev);
gpiochip_remove(&arizona_gpio->gpio_chip);
return 0;
}
static struct platform_driver arizona_gpio_driver = {
.driver.name = "arizona-gpio",
.probe = arizona_gpio_probe,
.remove = arizona_gpio_remove,
};
module_platform_driver(arizona_gpio_driver);
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("GPIO interface for Arizona devices");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-gpio");