// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Microsemi/Microchip SoCs serial gpio driver
*
* Author: Lars Povlsen <lars.povlsen@microchip.com>
*
* Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/mfd/ocelot.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinmux.h>
#include "core.h"
#include "pinconf.h"
#define SGPIO_BITS_PER_WORD 32
#define SGPIO_MAX_BITS 4
#define SGPIO_SRC_BITS 3 /* 3 bit wide field per pin */
enum {
REG_INPUT_DATA,
REG_PORT_CONFIG,
REG_PORT_ENABLE,
REG_SIO_CONFIG,
REG_SIO_CLOCK,
REG_INT_POLARITY,
REG_INT_TRIGGER,
REG_INT_ACK,
REG_INT_ENABLE,
REG_INT_IDENT,
MAXREG
};
enum {
SGPIO_ARCH_LUTON,
SGPIO_ARCH_OCELOT,
SGPIO_ARCH_SPARX5,
};
enum {
SGPIO_FLAGS_HAS_IRQ = BIT(0),
};
struct sgpio_properties {
int arch;
int flags;
u8 regoff[MAXREG];
};
#define SGPIO_LUTON_AUTO_REPEAT BIT(5)
#define SGPIO_LUTON_PORT_WIDTH GENMASK(3, 2)
#define SGPIO_LUTON_CLK_FREQ GENMASK(11, 0)
#define SGPIO_LUTON_BIT_SOURCE GENMASK(11, 0)
#define SGPIO_OCELOT_AUTO_REPEAT BIT(10)
#define SGPIO_OCELOT_SINGLE_SHOT BIT(11)
#define SGPIO_OCELOT_PORT_WIDTH GENMASK(8, 7)
#define SGPIO_OCELOT_CLK_FREQ GENMASK(19, 8)
#define SGPIO_OCELOT_BIT_SOURCE GENMASK(23, 12)
#define SGPIO_SPARX5_AUTO_REPEAT BIT(6)
#define SGPIO_SPARX5_SINGLE_SHOT BIT(7)
#define SGPIO_SPARX5_PORT_WIDTH GENMASK(4, 3)
#define SGPIO_SPARX5_CLK_FREQ GENMASK(19, 8)
#define SGPIO_SPARX5_BIT_SOURCE GENMASK(23, 12)
#define SGPIO_MASTER_INTR_ENA BIT(0)
#define SGPIO_INT_TRG_LEVEL 0
#define SGPIO_INT_TRG_EDGE 1
#define SGPIO_INT_TRG_EDGE_FALL 2
#define SGPIO_INT_TRG_EDGE_RISE 3
#define SGPIO_TRG_LEVEL_HIGH 0
#define SGPIO_TRG_LEVEL_LOW 1
static const struct sgpio_properties properties_luton = {
.arch = SGPIO_ARCH_LUTON,
.regoff = { 0x00, 0x09, 0x29, 0x2a, 0x2b },
};
static const struct sgpio_properties properties_ocelot = {
.arch = SGPIO_ARCH_OCELOT,
.regoff = { 0x00, 0x06, 0x26, 0x04, 0x05 },
};
static const struct sgpio_properties properties_sparx5 = {
.arch = SGPIO_ARCH_SPARX5,
.flags = SGPIO_FLAGS_HAS_IRQ,
.regoff = { 0x00, 0x06, 0x26, 0x04, 0x05, 0x2a, 0x32, 0x3a, 0x3e, 0x42 },
};
static const char * const functions[] = { "gpio" };
struct sgpio_bank {
struct sgpio_priv *priv;
bool is_input;
struct gpio_chip gpio;
struct pinctrl_desc pctl_desc;
};
struct sgpio_priv {
struct device *dev;
struct sgpio_bank in;
struct sgpio_bank out;
u32 bitcount;
u32 ports;
u32 clock;
struct regmap *regs;
const struct sgpio_properties *properties;
spinlock_t lock;
/* protects the config register and single shot mode */
struct mutex poll_lock;
};
struct sgpio_port_addr {
u8 port;
u8 bit;
};
static inline void sgpio_pin_to_addr(struct sgpio_priv *priv, int pin,
struct sgpio_port_addr *addr)
{
addr->port = pin / priv->bitcount;
addr->bit = pin % priv->bitcount;
}
static inline int sgpio_addr_to_pin(struct sgpio_priv *priv, int port, int bit)
{
return bit + port * priv->bitcount;
}
static inline u32 sgpio_get_addr(struct sgpio_priv *priv, u32 rno, u32 off)
{
return (priv->properties->regoff[rno] + off) *
regmap_get_reg_stride(priv->regs);
}
static u32 sgpio_readl(struct sgpio_priv *priv, u32 rno, u32 off)
{
u32 addr = sgpio_get_addr(priv, rno, off);
u32 val = 0;
int ret;
ret = regmap_read(priv->regs, addr, &val);
WARN_ONCE(ret, "error reading sgpio reg %d\n", ret);
return val;
}
static void sgpio_writel(struct sgpio_priv *priv,
u32 val, u32 rno, u32 off)
{
u32 addr = sgpio_get_addr(priv, rno, off);
int ret;
ret = regmap_write(priv->regs, addr, val);
WARN_ONCE(ret, "error writing sgpio reg %d\n", ret);
}
static inline void sgpio_clrsetbits(struct sgpio_priv *priv,
u32 rno, u32 off, u32 clear, u32 set)
{
u32 addr = sgpio_get_addr(priv, rno, off);
int ret;
ret = regmap_update_bits(priv->regs, addr, clear | set, set);
WARN_ONCE(ret, "error updating sgpio reg %d\n", ret);
}
static inline void sgpio_configure_bitstream(struct sgpio_priv *priv)
{
int width = priv->bitcount - 1;
u32 clr, set;
switch (priv->properties->arch) {
case SGPIO_ARCH_LUTON:
clr = SGPIO_LUTON_PORT_WIDTH;
set = SGPIO_LUTON_AUTO_REPEAT |
FIELD_PREP(SGPIO_LUTON_PORT_WIDTH, width);
break;
case SGPIO_ARCH_OCELOT:
clr = SGPIO_OCELOT_PORT_WIDTH;
set = SGPIO_OCELOT_AUTO_REPEAT |
FIELD_PREP(SGPIO_OCELOT_PORT_WIDTH, width);
break;
case SGPIO_ARCH_SPARX5:
clr = SGPIO_SPARX5_PORT_WIDTH;
set = SGPIO_SPARX5_AUTO_REPEAT |
FIELD_PREP(SGPIO_SPARX5_PORT_WIDTH, width);
break;
default:
return;
}
sgpio_clrsetbits(priv, REG_SIO_CONFIG, 0, clr, set);
}<