gpio: xilinx: convert from OF GPIO to standard devm APIs
This driver was using the OF GPIO helper API, but barely used any of its features and it cost more code than it saved. Also, the OF GPIO code is now deprecated. Convert it to use a more standard setup and use devm APIs for initialization to avoid the need for a remove function. Our rationale for this change is that we are using the Xilinx GPIO with resources injected using the MFD core rather than on the device tree itself. Using platform rather than OF-specific resources allows this to work for free. Signed-off-by: Robert Hancock <hancock@sedsystems.ca> Acked-by: Michal Simek <michal.simek@xilinx.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Родитель
7fae8a9ced
Коммит
1ebd06871b
|
@ -598,7 +598,6 @@ config GPIO_XGENE_SB
|
|||
|
||||
config GPIO_XILINX
|
||||
tristate "Xilinx GPIO support"
|
||||
depends on OF_GPIO
|
||||
help
|
||||
Say yes here to support the Xilinx FPGA GPIO device
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -40,14 +39,16 @@
|
|||
|
||||
/**
|
||||
* struct xgpio_instance - Stores information about GPIO device
|
||||
* @mmchip: OF GPIO chip for memory mapped banks
|
||||
* @gc: GPIO chip
|
||||
* @regs: register block
|
||||
* @gpio_width: GPIO width for every channel
|
||||
* @gpio_state: GPIO state shadow register
|
||||
* @gpio_dir: GPIO direction shadow register
|
||||
* @gpio_lock: Lock used for synchronization
|
||||
*/
|
||||
struct xgpio_instance {
|
||||
struct of_mm_gpio_chip mmchip;
|
||||
struct gpio_chip gc;
|
||||
void __iomem *regs;
|
||||
unsigned int gpio_width[2];
|
||||
u32 gpio_state[2];
|
||||
u32 gpio_dir[2];
|
||||
|
@ -91,11 +92,10 @@ static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
|
|||
*/
|
||||
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct xgpio_instance *chip = gpiochip_get_data(gc);
|
||||
u32 val;
|
||||
|
||||
val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
|
||||
val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_regoffset(chip, gpio));
|
||||
|
||||
return !!(val & BIT(xgpio_offset(chip, gpio)));
|
||||
|
@ -113,7 +113,6 @@ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
|
|||
static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct xgpio_instance *chip = gpiochip_get_data(gc);
|
||||
int index = xgpio_index(chip, gpio);
|
||||
int offset = xgpio_offset(chip, gpio);
|
||||
|
@ -126,7 +125,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
|||
else
|
||||
chip->gpio_state[index] &= ~BIT(offset);
|
||||
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
|
||||
|
||||
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
|
||||
|
@ -145,7 +144,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
|||
unsigned long *bits)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct xgpio_instance *chip = gpiochip_get_data(gc);
|
||||
int index = xgpio_index(chip, 0);
|
||||
int offset, i;
|
||||
|
@ -157,7 +155,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
|||
if (*mask == 0)
|
||||
break;
|
||||
if (index != xgpio_index(chip, i)) {
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_regoffset(chip, i),
|
||||
chip->gpio_state[index]);
|
||||
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
|
||||
|
@ -173,7 +171,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
|||
}
|
||||
}
|
||||
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_regoffset(chip, i), chip->gpio_state[index]);
|
||||
|
||||
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
|
||||
|
@ -191,7 +189,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
|||
static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct xgpio_instance *chip = gpiochip_get_data(gc);
|
||||
int index = xgpio_index(chip, gpio);
|
||||
int offset = xgpio_offset(chip, gpio);
|
||||
|
@ -200,7 +197,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
|||
|
||||
/* Set the GPIO bit in shadow register and set direction as input */
|
||||
chip->gpio_dir[index] |= BIT(offset);
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
|
||||
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
|
||||
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
|
||||
|
||||
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
|
||||
|
@ -223,7 +220,6 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
|||
static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct xgpio_instance *chip = gpiochip_get_data(gc);
|
||||
int index = xgpio_index(chip, gpio);
|
||||
int offset = xgpio_offset(chip, gpio);
|
||||
|
@ -235,12 +231,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
|||
chip->gpio_state[index] |= BIT(offset);
|
||||
else
|
||||
chip->gpio_state[index] &= ~BIT(offset);
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
|
||||
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
|
||||
|
||||
/* Clear the GPIO bit in shadow register and set direction as output */
|
||||
chip->gpio_dir[index] &= ~BIT(offset);
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
|
||||
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
|
||||
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
|
||||
|
||||
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
|
||||
|
@ -250,42 +246,22 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
|||
|
||||
/**
|
||||
* xgpio_save_regs - Set initial values of GPIO pins
|
||||
* @mm_gc: Pointer to memory mapped GPIO chip structure
|
||||
* @chip: Pointer to GPIO instance
|
||||
*/
|
||||
static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
static void xgpio_save_regs(struct xgpio_instance *chip)
|
||||
{
|
||||
struct xgpio_instance *chip =
|
||||
container_of(mm_gc, struct xgpio_instance, mmchip);
|
||||
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
|
||||
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
|
||||
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
|
||||
|
||||
if (!chip->gpio_width[1])
|
||||
return;
|
||||
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
|
||||
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
|
||||
chip->gpio_state[1]);
|
||||
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
|
||||
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
|
||||
chip->gpio_dir[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* xgpio_remove - Remove method for the GPIO device.
|
||||
* @pdev: pointer to the platform device
|
||||
*
|
||||
* This function remove gpiochips and frees all the allocated resources.
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int xgpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xgpio_instance *chip = platform_get_drvdata(pdev);
|
||||
|
||||
of_mm_gpiochip_remove(&chip->mmchip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xgpio_of_probe - Probe method for the GPIO device.
|
||||
* @pdev: pointer to the platform device
|
||||
|
@ -347,21 +323,28 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&chip->gpio_lock[1]);
|
||||
}
|
||||
|
||||
chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
|
||||
chip->mmchip.gc.parent = &pdev->dev;
|
||||
chip->mmchip.gc.direction_input = xgpio_dir_in;
|
||||
chip->mmchip.gc.direction_output = xgpio_dir_out;
|
||||
chip->mmchip.gc.get = xgpio_get;
|
||||
chip->mmchip.gc.set = xgpio_set;
|
||||
chip->mmchip.gc.set_multiple = xgpio_set_multiple;
|
||||
chip->gc.base = -1;
|
||||
chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
|
||||
chip->gc.parent = &pdev->dev;
|
||||
chip->gc.direction_input = xgpio_dir_in;
|
||||
chip->gc.direction_output = xgpio_dir_out;
|
||||
chip->gc.get = xgpio_get;
|
||||
chip->gc.set = xgpio_set;
|
||||
chip->gc.set_multiple = xgpio_set_multiple;
|
||||
|
||||
chip->mmchip.save_regs = xgpio_save_regs;
|
||||
chip->gc.label = dev_name(&pdev->dev);
|
||||
|
||||
/* Call the OF gpio helper to setup and register the GPIO device */
|
||||
status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
|
||||
chip->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(chip->regs)) {
|
||||
dev_err(&pdev->dev, "failed to ioremap memory resource\n");
|
||||
return PTR_ERR(chip->regs);
|
||||
}
|
||||
|
||||
xgpio_save_regs(chip);
|
||||
|
||||
status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
|
||||
if (status) {
|
||||
pr_err("%pOF: error in probe function with status %d\n",
|
||||
np, status);
|
||||
dev_err(&pdev->dev, "failed to add GPIO chip\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -377,7 +360,6 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match);
|
|||
|
||||
static struct platform_driver xgpio_plat_driver = {
|
||||
.probe = xgpio_probe,
|
||||
.remove = xgpio_remove,
|
||||
.driver = {
|
||||
.name = "gpio-xilinx",
|
||||
.of_match_table = xgpio_of_match,
|
||||
|
|
Загрузка…
Ссылка в новой задаче