mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 18:10:32 +00:00

The conversion of all GPIO drivers to using the .set_rv() and .set_multiple_rv() callbacks from struct gpio_chip (which - unlike their predecessors - return an integer and allow the controller drivers to indicate failures to users) is now complete and the legacy ones have been removed. Rename the new callbacks back to their original names in one sweeping change. Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
197 lines
4.4 KiB
C
197 lines
4.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* PPC4xx gpio driver
|
|
*
|
|
* Copyright (c) 2008 Harris Corporation
|
|
* Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
|
* Copyright (c) MontaVista Software, Inc. 2008.
|
|
*
|
|
* Author: Steve Falco <sfalco@harris.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
|
#include <linux/gpio/driver.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
|
|
#define GPIO_MASK(gpio) (0x80000000 >> (gpio))
|
|
#define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2))
|
|
|
|
/* Physical GPIO register layout */
|
|
struct ppc4xx_gpio {
|
|
__be32 or;
|
|
__be32 tcr;
|
|
__be32 osrl;
|
|
__be32 osrh;
|
|
__be32 tsrl;
|
|
__be32 tsrh;
|
|
__be32 odr;
|
|
__be32 ir;
|
|
__be32 rr1;
|
|
__be32 rr2;
|
|
__be32 rr3;
|
|
__be32 reserved1;
|
|
__be32 isr1l;
|
|
__be32 isr1h;
|
|
__be32 isr2l;
|
|
__be32 isr2h;
|
|
__be32 isr3l;
|
|
__be32 isr3h;
|
|
};
|
|
|
|
struct ppc4xx_gpio_chip {
|
|
struct of_mm_gpio_chip mm_gc;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
/*
|
|
* GPIO LIB API implementation for GPIOs
|
|
*
|
|
* There are a maximum of 32 gpios in each gpio controller.
|
|
*/
|
|
|
|
static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
|
{
|
|
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
|
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
|
|
|
|
return !!(in_be32(®s->ir) & GPIO_MASK(gpio));
|
|
}
|
|
|
|
static inline void
|
|
__ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
|
{
|
|
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
|
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
|
|
|
|
if (val)
|
|
setbits32(®s->or, GPIO_MASK(gpio));
|
|
else
|
|
clrbits32(®s->or, GPIO_MASK(gpio));
|
|
}
|
|
|
|
static int ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
|
{
|
|
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&chip->lock, flags);
|
|
|
|
__ppc4xx_gpio_set(gc, gpio, val);
|
|
|
|
spin_unlock_irqrestore(&chip->lock, flags);
|
|
|
|
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
|
{
|
|
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
|
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
|
|
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&chip->lock, flags);
|
|
|
|
/* Disable open-drain function */
|
|
clrbits32(®s->odr, GPIO_MASK(gpio));
|
|
|
|
/* Float the pin */
|
|
clrbits32(®s->tcr, GPIO_MASK(gpio));
|
|
|
|
/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
|
|
if (gpio < 16) {
|
|
clrbits32(®s->osrl, GPIO_MASK2(gpio));
|
|
clrbits32(®s->tsrl, GPIO_MASK2(gpio));
|
|
} else {
|
|
clrbits32(®s->osrh, GPIO_MASK2(gpio));
|
|
clrbits32(®s->tsrh, GPIO_MASK2(gpio));
|
|
}
|
|
|
|
spin_unlock_irqrestore(&chip->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
|
{
|
|
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
|
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
|
|
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&chip->lock, flags);
|
|
|
|
/* First set initial value */
|
|
__ppc4xx_gpio_set(gc, gpio, val);
|
|
|
|
/* Disable open-drain function */
|
|
clrbits32(®s->odr, GPIO_MASK(gpio));
|
|
|
|
/* Drive the pin */
|
|
setbits32(®s->tcr, GPIO_MASK(gpio));
|
|
|
|
/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
|
|
if (gpio < 16) {
|
|
clrbits32(®s->osrl, GPIO_MASK2(gpio));
|
|
clrbits32(®s->tsrl, GPIO_MASK2(gpio));
|
|
} else {
|
|
clrbits32(®s->osrh, GPIO_MASK2(gpio));
|
|
clrbits32(®s->tsrh, GPIO_MASK2(gpio));
|
|
}
|
|
|
|
spin_unlock_irqrestore(&chip->lock, flags);
|
|
|
|
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __init ppc4xx_add_gpiochips(void)
|
|
{
|
|
struct device_node *np;
|
|
|
|
for_each_compatible_node(np, NULL, "ibm,ppc4xx-gpio") {
|
|
int ret;
|
|
struct ppc4xx_gpio_chip *ppc4xx_gc;
|
|
struct of_mm_gpio_chip *mm_gc;
|
|
struct gpio_chip *gc;
|
|
|
|
ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL);
|
|
if (!ppc4xx_gc) {
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
spin_lock_init(&ppc4xx_gc->lock);
|
|
|
|
mm_gc = &ppc4xx_gc->mm_gc;
|
|
gc = &mm_gc->gc;
|
|
|
|
gc->ngpio = 32;
|
|
gc->direction_input = ppc4xx_gpio_dir_in;
|
|
gc->direction_output = ppc4xx_gpio_dir_out;
|
|
gc->get = ppc4xx_gpio_get;
|
|
gc->set = ppc4xx_gpio_set;
|
|
|
|
ret = of_mm_gpiochip_add_data(np, mm_gc, ppc4xx_gc);
|
|
if (ret)
|
|
goto err;
|
|
continue;
|
|
err:
|
|
pr_err("%pOF: registration failed with status %d\n", np, ret);
|
|
kfree(ppc4xx_gc);
|
|
/* try others anyway */
|
|
}
|
|
return 0;
|
|
}
|
|
arch_initcall(ppc4xx_add_gpiochips);
|