// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019 Intel Corporation */
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include "core.h"
#include "pinconf.h"
#include "pinmux.h"
#include "pinctrl-equilibrium.h"
#define PIN_NAME_FMT "io-%d"
#define PIN_NAME_LEN 10
#define PAD_REG_OFF 0x100
static void eqbr_gpio_disable_irq(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
unsigned int offset = irqd_to_hwirq(d);
unsigned long flags;
raw_spin_lock_irqsave(&gctrl->lock, flags);
writel(BIT(offset), gctrl->membase + GPIO_IRNENCLR);
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
static void eqbr_gpio_enable_irq(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
unsigned int offset = irqd_to_hwirq(d);
unsigned long flags;
gc->direction_input(gc, offset);
raw_spin_lock_irqsave(&gctrl->lock, flags);
writel(BIT(offset), gctrl->membase + GPIO_IRNRNSET);
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
static void eqbr_gpio_ack_irq(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
unsigned int offset = irqd_to_hwirq(d);
unsigned long flags;
raw_spin_lock_irqsave(&gctrl->lock, flags);
writel(BIT(offset), gctrl->membase + GPIO_IRNCR);
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
static void eqbr_gpio_mask_ack_irq(struct irq_data *d)
{
eqbr_gpio_disable_irq(d);
eqbr_gpio_ack_irq(d);
}
static inline void eqbr_cfg_bit(void __iomem *addr,
unsigned int offset, unsigned int set)
{
if (set)
writel(readl(addr) | BIT(offset), addr);
else
writel(readl(addr) & ~BIT(offset), addr);
}
static int eqbr_irq_type_cfg(struct gpio_irq_type *type,
struct eqbr_gpio_ctrl *gctrl,
unsigned int offset)
{
unsigned long flags;
raw_spin_lock_irqsave(&gctrl->lock, flags);
eqbr_cfg_bit(gctrl->membase + GPIO_IRNCFG, offset, type->trig_type);
eqbr_cfg_bit(gctrl->membase + GPIO_EXINTCR1, offset, type->trig_type);
eqbr_cfg_bit(gctrl->membase + GPIO_EXINTCR0, offset, type->logic_type);
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
return 0;
}
static int eqbr_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
unsigned int offset = irqd_to_hwirq(d);
struct gpio_irq_type it;
memset(&it, 0, sizeof(it));
if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE)
return 0;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
it.trig_type = GPIO_EDGE_TRIG;
it.edge_type = GPIO_SINGLE_EDGE;
it.logic_type = GPIO_POSITIVE_TRIG;
break;
case IRQ_TYPE_EDGE_FALLING:
it.trig_type = GPIO_EDGE_TRIG;
it.edge_type = GPIO_SINGLE_EDGE;
it.logic_type = GPIO_NEGATIVE_TRIG;
break;
case IRQ_TYPE_EDGE_BOTH:
it.trig_type = GPIO_EDGE_TRIG;
it.edge_type = GPIO_BOTH_EDGE;
it.logic_type = GPIO_POSITIVE_TRIG;
break;
case IRQ_TYPE_LEVEL_HIGH:
it.trig_type = GPIO_LEVEL_TRIG;
it.edge_type = GPIO_SINGLE_EDGE;
it.logic_type = GPIO_POSITIVE_TRIG;
break;
case IRQ_TYPE_LEVEL_LOW:
it.trig_type = GPIO_LEVEL_TRIG;
it.edge_type = GPIO_SINGLE_EDGE;
it.logic_type = GPIO_NEGATIVE_TRIG;
break;
default:
return -EINVAL;
}
eqbr_irq_type_cfg(&it, gctrl, offset);
if (it.trig_type == GPIO_EDGE_TRIG)