mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
4.4 KiB
195 lines
4.4 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* PPC4xx gpio driver |
|
* |
|
* Copyright (c) 2008 Harris Corporation |
|
* Copyright (c) 2008 Sascha Hauer <[email protected]>, Pengutronix |
|
* Copyright (c) MontaVista Software, Inc. 2008. |
|
* |
|
* Author: Steve Falco <[email protected]> |
|
*/ |
|
|
|
#include <linux/kernel.h> |
|
#include <linux/init.h> |
|
#include <linux/spinlock.h> |
|
#include <linux/io.h> |
|
#include <linux/of.h> |
|
#include <linux/of_gpio.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 void |
|
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); |
|
} |
|
|
|
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);
|
|
|