// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2015 IBM Corp.
*
* Joel Stanley <joel@jms.id.au>
*/
#include <linux/clk.h>
#include <linux/gpio/aspeed.h>
#include <linux/gpio/driver.h>
#include <linux/hashtable.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <asm/div64.h>
/*
* These two headers aren't meant to be used by GPIO drivers. We need
* them in order to access gpio_chip_hwgpio() which we need to implement
* the aspeed specific API which allows the coprocessor to request
* access to some GPIOs and to arbitrate between coprocessor and ARM.
*/
#include <linux/gpio/consumer.h>
#include "gpiolib.h"
struct aspeed_bank_props {
unsigned int bank;
u32 input;
u32 output;
};
struct aspeed_gpio_config {
unsigned int nr_gpios;
const struct aspeed_bank_props *props;
};
/*
* @offset_timer: Maps an offset to an @timer_users index, or zero if disabled
* @timer_users: Tracks the number of users for each timer
*
* The @timer_users has four elements but the first element is unused. This is
* to simplify accounting and indexing, as a zero value in @offset_timer
* represents disabled debouncing for the GPIO. Any other value for an element
* of @offset_timer is used as an index into @timer_users. This behaviour of
* the zero value aligns with the behaviour of zero built from the timer
* configuration registers (i.e. debouncing is disabled).
*/
struct aspeed_gpio {
struct gpio_chip chip;
struct device *dev;
raw_spinlock_t lock;
void __iomem *base;
int irq;
const struct aspeed_gpio_config *config;
u8 *offset_timer;
unsigned int timer_users[4];
struct clk *clk;
u32 *dcache;
u8 *cf_copro_bankmap;
};
struct aspeed_gpio_bank {
uint16_t val_regs; /* +0: Rd: read input value, Wr: set write latch
* +4: Rd/Wr: Direction (0=in, 1=out)
*/
uint16_t rdata_reg; /* Rd: read write latch, Wr: <none> */
uint16_t irq_regs;
uint16_t debounce_regs;
uint16_t tolerance_regs;
uint16_t cmdsrc_regs;
const char names[4][3];
};
/*
* Note: The "value" register returns the input value sampled on the
* line even when the GPIO is configured as an output. Since
* that input goes through synchronizers, writing, then reading
* back may not return the written value right away.
*
* The "rdata" register returns the content of the write latch
* and thus can be used to read back what was last written
* reliably.
*/
static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };
static const struct aspeed_gpio_copro_ops *copro_ops;
static void *copro_data;
static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
{
.val_regs = 0x0000,
.rdata_reg = 0x00c0,
.irq_regs = 0x0008,
.debounce_regs = 0x0040,
.tolerance_regs = 0x001c,
.cmdsrc_regs = 0x0060,
.names = { "A", "B", "C", "D" },
},
{
.val_regs = 0x0020,
.rdata_reg = 0x00c4,
.irq_regs = 0x0028,
.debounce_regs = 0x0048,
.tolerance_regs = 0x003c,
.cmdsrc_regs = 0x0068,
.names = { "E", "F", "G", "H" },
},
{
.val_regs = 0x0070,
.rdata_reg = 0x00c8,
.irq_regs = 0x0098,
.debounce_regs = 0x00b0,
.tolerance_regs = 0x00ac,
.cmdsrc_regs = 0x0090,
.names = { "I", "J", "K", "L" },
},
{
.