// SPDX-License-Identifier: GPL-2.0
/*
* SP7021 Pin Controller Driver.
* Copyright (C) Sunplus Tech / Tibbo Tech.
*/
#include <linux/cleanup.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinmux.h>
#include <dt-bindings/pinctrl/sppctl-sp7021.h>
#include "../core.h"
#include "../pinctrl-utils.h"
#include "sppctl.h"
struct sppctl_gpio_chip {
void __iomem *gpioxt_base; /* MASTER, OE, OUT, IN, I_INV, O_INV, OD */
void __iomem *first_base; /* GPIO_FIRST */
struct gpio_chip chip;
spinlock_t lock; /* lock for accessing OE register */
};
static inline u32 sppctl_first_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->first_base + SPPCTL_GPIO_OFF_FIRST + off);
}
static inline void sppctl_first_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off)
{
writel(val, spp_gchip->first_base + SPPCTL_GPIO_OFF_FIRST + off);
}
static inline u32 sppctl_gpio_master_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_MASTER + off);
}
static inline void sppctl_gpio_master_writel(struct sppctl_gpio_chip *spp_gchip, u32 val,
u32 off)
{
writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_MASTER + off);
}
static inline u32 sppctl_gpio_oe_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OE + off);
}
static inline void sppctl_gpio_oe_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off)
{
writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OE + off);
}
static inline void sppctl_gpio_out_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off)
{
writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OUT + off);
}
static inline u32 sppctl_gpio_in_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_IN + off);
}
static inline u32 sppctl_gpio_iinv_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_IINV + off);
}
static inline void sppctl_gpio_iinv_writel(struct sppctl_gpio_chip *spp_gchip, u32 val,
u32 off)
{
writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_IINV + off);
}
static inline u32 sppctl_gpio_oinv_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OINV + off);
}
static inline void sppctl_gpio_oinv_writel(struct sppctl_gpio_chip *spp_gchip, u32 val,
u32 off)
{
writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OINV + off);
}
static inline u32 sppctl_gpio_od_readl(struct sppctl_gpio_chip *spp_gchip, u32 off)
{
return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OD + off);
}
static inline void sppctl_gpio_od_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off)
{
writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OD + off);
}
static inline u32 sppctl_get_reg_and_bit_offset(unsigned int offset, u32 *reg_off)
{
u32 bit_off;
/* Each register has 32 bits. */
*reg_off = (offset / 32) * 4;
bit_off = offset % 32;
return bit_off;
}
static inline u32 sppctl_get_moon_reg_and_bit_offset(unsigned int offset, u32 *reg_off)
{
u32 bit_off;
/*
* Each MOON register has 32 bits. Upper 16-bit word are mask-fields.
* The lower 16-bit word are the control-fields. The corresponding
* bits in mask-field should be set then you can write something to
* control-field.
*/
*reg_off = (offset / 16) * 4;
bit_off = offset % 16;
return bit_off;
}
static inline u32 sppctl_prep_moon_reg_and_offset(unsigned int offset, u32 *reg_off, int val)
{
u32 bit_off;
bit_off = sppctl_get_moon_reg_and_bit_offset(offset, reg_off);
if (val)
return SPPCTL_SET_MOON_REG_BIT(bit_off);
else
return SPPCTL_CLR_MOON_REG_BIT(bit_off);