// SPDX-License-Identifier: GPL-2.0-or-later
/*
* UP board pin control driver.
*
* Copyright (C) 2025 Bootlin
*
* Author: Thomas Richard <thomas.richard@bootlin.com>
*/
#include <linux/array_size.h>
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/gpio/forwarder.h>
#include <linux/mfd/upboard-fpga.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
#include <linux/stddef.h>
#include <linux/string_choices.h>
#include <linux/types.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include "core.h"
#include "pinmux.h"
enum upboard_pin_mode {
UPBOARD_PIN_MODE_FUNCTION,
UPBOARD_PIN_MODE_GPIO_IN,
UPBOARD_PIN_MODE_GPIO_OUT,
UPBOARD_PIN_MODE_DISABLED,
};
struct upboard_pin {
struct regmap_field *funcbit;
struct regmap_field *enbit;
struct regmap_field *dirbit;
};
struct upboard_pingroup {
struct pingroup grp;
enum upboard_pin_mode mode;
const enum upboard_pin_mode *modes;
};
struct upboard_pinctrl_data {
const struct upboard_pingroup *groups;
size_t ngroups;
const struct pinfunction *funcs;
size_t nfuncs;
const unsigned int *pin_header;
size_t ngpio;
};
struct upboard_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
const struct upboard_pinctrl_data *pctrl_data;
struct gpio_pin_range pin_range;
struct upboard_pin *pins;
};
struct upboard_pinctrl_map {
const struct pinctrl_map *maps;
size_t nmaps;
};
enum upboard_func0_fpgabit {
UPBOARD_FUNC_I2C0_EN = 8,
UPBOARD_FUNC_I2C1_EN = 9,
UPBOARD_FUNC_CEC0_EN = 12,
UPBOARD_FUNC_ADC0_EN = 14,
};
static const struct reg_field upboard_i2c0_reg =
REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_I2C0_EN, UPBOARD_FUNC_I2C0_EN);
static const struct reg_field upboard_i2c1_reg =
REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_I2C1_EN, UPBOARD_FUNC_I2C1_EN);
static const struct reg_field upboard_adc0_reg =
REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_ADC0_EN, UPBOARD_FUNC_ADC0_EN);
#define UPBOARD_UP_BIT_TO_PIN(bit) UPBOARD_UP_BIT_##bit
#define UPBOARD_UP_PIN_NAME(id) \
{ \
.number = UPBOARD_UP_BIT_##id, \
.name = #id, \
}
#define UPBOARD_UP_PIN_MUX(bit, data) \
{ \
.number = UPBOARD_UP_BIT_##bit, \
.name = "PINMUX_"#bit, \
.drv_data = (void *)(data), \
}
#define UPBOARD_UP_PIN_FUNC(id, data) \
{ \
.number = UPBOARD_UP_BIT_##id, \
.name = #id, \
.drv_data = (void *)(data), \
}
enum upboard_up_fpgabit {
UPBOARD_UP_BIT_I2C1_SDA,
UPBOARD_UP_BIT_I2C1_SCL,
UPBOARD_UP_BIT_ADC0,
UPBOARD_UP_BIT_UART1_RTS,
UPBOARD_UP_BIT_GPIO27,
UPBOARD_UP_BIT_GPIO22,
UPBOARD_UP_BIT_SPI_MOSI,
UPBOARD_UP_BIT_SPI_MISO,
UPBOARD_UP_BIT_SPI_CLK,
UPBOARD_UP_BIT_I2C0_SDA,
UPBOARD_UP_BIT_GPIO5,
UPBOARD_UP_BIT_GPIO6,
UPBOARD_UP_BIT_PWM1,
UPBOARD_UP_BIT_I2S_FRM,
UPBOARD_UP_BIT_GPIO26,
UPBOARD_UP_BIT_UART1_TX,
UPBOARD_UP_BIT_UART1_RX,
UPBOARD_UP_BIT_I2S_CLK,
UPBOARD_UP_BIT_GPIO23,
UPBOARD_UP_BIT_GPIO24,
UPBOARD_UP_BIT_GPIO25,
UPBOARD_UP_BIT_SPI_CS0,
UPBOARD_UP_BIT_SPI_CS1,
UPBOARD_UP_BIT_I2C0_SCL,
UPBOARD_UP_BIT_PWM0,
UPBOARD_UP_BIT_UART1_CTS,
UPBOARD_UP_BIT_I2S_DIN,
UPBOARD_UP_BIT_I2S_DOUT,
};
static const struct pinctrl_pin_desc upboard_up_pins[] = {
UPBOARD_UP_PIN_FUNC(I2C1_SDA, &upboard_i2c1_reg),
UPBOARD_UP_PIN_FUNC(I2C1_SCL, &upboard_i2c1_reg),
UPBOARD_UP_PIN_FUNC(ADC0, &upboard_adc0_reg),
UPBOARD_UP_PIN_NAME(UART1_RTS),
UPBOARD_UP_PIN_NAME(GPIO27),
UPBOARD_UP_PIN_NAME(GPIO22),
UPBOARD_UP_PIN_NAME(SPI_MOSI),
UPBOARD_UP_PIN_NAME(SPI_MISO),
UPBOARD_UP_PIN_NAME(SPI_CLK),
UPBOARD_UP_PIN_FUNC(I2C0_SDA, &upboard_i2c0_reg),
UPBOARD_UP_PIN_NAME(GPIO5),
UPBOARD_UP_PIN_NAME(GPIO6),
UPBOARD_UP_PIN_NAME(PWM1),
UPBOARD_UP_PIN_NAME(I2S_FRM),
UPBOARD_UP_PIN_NAME(GPIO26),
UPBOARD_UP_PIN_NAME(UART1_TX),
UPBOARD_UP_PIN_NAME(UART1_RX),
UPBOARD_UP_PIN_NAME(I2S_CLK),
UPBOARD_UP_PIN_NAME(GPIO23),
UPBOARD_UP_PIN_NAME(GPIO24),
UPBOARD_UP_PIN_NAME(GPIO25),
UPBOARD_UP_PIN_NAME(SPI_CS0),
UPBOARD_UP_PIN_NAME(SPI_CS1),
UPBOARD_UP_PIN_FUNC(I2C0_SCL, &upboard_i2c0_reg),
UPBOARD_UP_PIN_NAME(PWM0),
UPBOARD_UP_PIN_NAME(UART1_CTS),
UPBOARD_UP_PIN_NAME(I2S_DIN),
UPBOARD_UP_PIN_NAME(I2S_DOUT),
};
static const