![Thomas Gleixner](/assets/img/avatar_default.png)
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not write to the free software foundation inc 59 temple place suite 330 boston ma 02111 1307 usa extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 136 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190530000436.384967451@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
285 lines
6.3 KiB
C
285 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* arch/arm/mach-ks8695/gpio.c
|
|
*
|
|
* Copyright (C) 2006 Andrew Victor
|
|
* Updated to GPIOLIB, Copyright 2008 Simtec Electronics
|
|
* Daniel Silverstone <dsilvers@simtec.co.uk>
|
|
*/
|
|
#include <linux/gpio/driver.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/init.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/module.h>
|
|
#include <linux/io.h>
|
|
|
|
#include <mach/hardware.h>
|
|
#include <asm/mach/irq.h>
|
|
|
|
#include <mach/regs-gpio.h>
|
|
#include <mach/gpio-ks8695.h>
|
|
|
|
/*
|
|
* Configure a GPIO line for either GPIO function, or its internal
|
|
* function (Interrupt, Timer, etc).
|
|
*/
|
|
static void ks8695_gpio_mode(unsigned int pin, short gpio)
|
|
{
|
|
unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
|
|
unsigned long x, flags;
|
|
|
|
if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */
|
|
return;
|
|
|
|
local_irq_save(flags);
|
|
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
|
|
if (gpio) /* GPIO: set bit to 0 */
|
|
x &= ~enable[pin];
|
|
else /* Internal function: set bit to 1 */
|
|
x |= enable[pin];
|
|
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
|
|
static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
|
|
|
|
/*
|
|
* Configure GPIO pin as external interrupt source.
|
|
*/
|
|
int ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
|
|
{
|
|
unsigned long x, flags;
|
|
|
|
if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
|
|
return -EINVAL;
|
|
|
|
local_irq_save(flags);
|
|
|
|
/* set pin as input */
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
|
x &= ~IOPM(pin);
|
|
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
|
|
|
local_irq_restore(flags);
|
|
|
|
/* Set IRQ triggering type */
|
|
irq_set_irq_type(gpio_irq[pin], type);
|
|
|
|
/* enable interrupt mode */
|
|
ks8695_gpio_mode(pin, 0);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(ks8695_gpio_interrupt);
|
|
|
|
|
|
|
|
/* .... Generic GPIO interface .............................................. */
|
|
|
|
/*
|
|
* Configure the GPIO line as an input.
|
|
*/
|
|
static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin)
|
|
{
|
|
unsigned long x, flags;
|
|
|
|
if (pin > KS8695_GPIO_15)
|
|
return -EINVAL;
|
|
|
|
/* set pin to GPIO mode */
|
|
ks8695_gpio_mode(pin, 1);
|
|
|
|
local_irq_save(flags);
|
|
|
|
/* set pin as input */
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
|
x &= ~IOPM(pin);
|
|
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
|
|
|
local_irq_restore(flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Configure the GPIO line as an output, with default state.
|
|
*/
|
|
static int ks8695_gpio_direction_output(struct gpio_chip *gc,
|
|
unsigned int pin, int state)
|
|
{
|
|
unsigned long x, flags;
|
|
|
|
if (pin > KS8695_GPIO_15)
|
|
return -EINVAL;
|
|
|
|
/* set pin to GPIO mode */
|
|
ks8695_gpio_mode(pin, 1);
|
|
|
|
local_irq_save(flags);
|
|
|
|
/* set line state */
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
|
if (state)
|
|
x |= IOPD(pin);
|
|
else
|
|
x &= ~IOPD(pin);
|
|
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
|
|
|
|
/* set pin as output */
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
|
x |= IOPM(pin);
|
|
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
|
|
|
local_irq_restore(flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set the state of an output GPIO line.
|
|
*/
|
|
static void ks8695_gpio_set_value(struct gpio_chip *gc,
|
|
unsigned int pin, int state)
|
|
{
|
|
unsigned long x, flags;
|
|
|
|
if (pin > KS8695_GPIO_15)
|
|
return;
|
|
|
|
local_irq_save(flags);
|
|
|
|
/* set output line state */
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
|
if (state)
|
|
x |= IOPD(pin);
|
|
else
|
|
x &= ~IOPD(pin);
|
|
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
|
|
/*
|
|
* Read the state of a GPIO line.
|
|
*/
|
|
static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin)
|
|
{
|
|
unsigned long x;
|
|
|
|
if (pin > KS8695_GPIO_15)
|
|
return -EINVAL;
|
|
|
|
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
|
return (x & IOPD(pin)) != 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Map GPIO line to IRQ number.
|
|
*/
|
|
static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
|
|
{
|
|
if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
|
|
return -EINVAL;
|
|
|
|
return gpio_irq[pin];
|
|
}
|
|
|
|
/* GPIOLIB interface */
|
|
|
|
static struct gpio_chip ks8695_gpio_chip = {
|
|
.label = "KS8695",
|
|
.direction_input = ks8695_gpio_direction_input,
|
|
.direction_output = ks8695_gpio_direction_output,
|
|
.get = ks8695_gpio_get_value,
|
|
.set = ks8695_gpio_set_value,
|
|
.to_irq = ks8695_gpio_to_irq,
|
|
.base = 0,
|
|
.ngpio = 16,
|
|
.can_sleep = false,
|
|
};
|
|
|
|
/* Register the GPIOs */
|
|
void ks8695_register_gpios(void)
|
|
{
|
|
if (gpiochip_add_data(&ks8695_gpio_chip, NULL))
|
|
printk(KERN_ERR "Unable to register core GPIOs\n");
|
|
}
|
|
|
|
/* .... Debug interface ..................................................... */
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
static int ks8695_gpio_show(struct seq_file *s, void *unused)
|
|
{
|
|
unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
|
|
unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
|
|
unsigned long mode, ctrl, data;
|
|
int i;
|
|
|
|
mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
|
ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
|
|
data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
|
|
|
seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
|
|
|
|
for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
|
|
seq_printf(s, "%i:\t", i);
|
|
|
|
seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input");
|
|
|
|
if (i <= KS8695_GPIO_3) {
|
|
if (ctrl & enable[i]) {
|
|
seq_printf(s, "EXT%i ", i);
|
|
|
|
switch ((ctrl & intmask[i]) >> (4 * i)) {
|
|
case IOPC_TM_LOW:
|
|
seq_printf(s, "(Low)"); break;
|
|
case IOPC_TM_HIGH:
|
|
seq_printf(s, "(High)"); break;
|
|
case IOPC_TM_RISING:
|
|
seq_printf(s, "(Rising)"); break;
|
|
case IOPC_TM_FALLING:
|
|
seq_printf(s, "(Falling)"); break;
|
|
case IOPC_TM_EDGE:
|
|
seq_printf(s, "(Edges)"); break;
|
|
}
|
|
} else
|
|
seq_printf(s, "GPIO\t");
|
|
} else if (i <= KS8695_GPIO_5) {
|
|
if (ctrl & enable[i])
|
|
seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
|
|
else
|
|
seq_printf(s, "GPIO\t");
|
|
} else {
|
|
seq_printf(s, "GPIO\t");
|
|
}
|
|
|
|
seq_printf(s, "\t");
|
|
|
|
seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SHOW_ATTRIBUTE(ks8695_gpio);
|
|
|
|
static int __init ks8695_gpio_debugfs_init(void)
|
|
{
|
|
/* /sys/kernel/debug/ks8695_gpio */
|
|
debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL,
|
|
&ks8695_gpio_fops);
|
|
return 0;
|
|
}
|
|
postcore_initcall(ks8695_gpio_debugfs_init);
|
|
|
|
#endif
|