mirror of https://github.com/torvalds/linux.git
1071 lines
32 KiB
C
1071 lines
32 KiB
C
// 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 unsigned int upboard_up_pin_header[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(I2C0_SDA),
|
|
UPBOARD_UP_BIT_TO_PIN(I2C0_SCL),
|
|
UPBOARD_UP_BIT_TO_PIN(I2C1_SDA),
|
|
UPBOARD_UP_BIT_TO_PIN(I2C1_SCL),
|
|
UPBOARD_UP_BIT_TO_PIN(ADC0),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO5),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO6),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_CS1),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_CS0),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_MISO),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_MOSI),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_CLK),
|
|
UPBOARD_UP_BIT_TO_PIN(PWM0),
|
|
UPBOARD_UP_BIT_TO_PIN(PWM1),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_TX),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_RX),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_CTS),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_RTS),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_CLK),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_FRM),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_DIN),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_DOUT),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO22),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO23),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO24),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO25),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO26),
|
|
UPBOARD_UP_BIT_TO_PIN(GPIO27),
|
|
};
|
|
|
|
static const unsigned int upboard_up_uart1_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_TX),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_RX),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_RTS),
|
|
UPBOARD_UP_BIT_TO_PIN(UART1_CTS),
|
|
};
|
|
|
|
static const enum upboard_pin_mode upboard_up_uart1_modes[] = {
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up_uart1_modes) == ARRAY_SIZE(upboard_up_uart1_pins));
|
|
|
|
static const unsigned int upboard_up_i2c0_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(I2C0_SCL),
|
|
UPBOARD_UP_BIT_TO_PIN(I2C0_SDA),
|
|
};
|
|
|
|
static const unsigned int upboard_up_i2c1_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(I2C1_SCL),
|
|
UPBOARD_UP_BIT_TO_PIN(I2C1_SDA),
|
|
};
|
|
|
|
static const unsigned int upboard_up_spi2_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_MOSI),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_MISO),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_CLK),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_CS0),
|
|
UPBOARD_UP_BIT_TO_PIN(SPI_CS1),
|
|
};
|
|
|
|
static const enum upboard_pin_mode upboard_up_spi2_modes[] = {
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up_spi2_modes) == ARRAY_SIZE(upboard_up_spi2_pins));
|
|
|
|
static const unsigned int upboard_up_i2s0_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_FRM),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_CLK),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_DIN),
|
|
UPBOARD_UP_BIT_TO_PIN(I2S_DOUT),
|
|
};
|
|
|
|
static const enum upboard_pin_mode upboard_up_i2s0_modes[] = {
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up_i2s0_pins) == ARRAY_SIZE(upboard_up_i2s0_modes));
|
|
|
|
static const unsigned int upboard_up_pwm0_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(PWM0),
|
|
};
|
|
|
|
static const unsigned int upboard_up_pwm1_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(PWM1),
|
|
};
|
|
|
|
static const unsigned int upboard_up_adc0_pins[] = {
|
|
UPBOARD_UP_BIT_TO_PIN(ADC0),
|
|
};
|
|
|
|
#define UPBOARD_PINGROUP(n, p, m) \
|
|
{ \
|
|
.grp = PINCTRL_PINGROUP(n, p, ARRAY_SIZE(p)), \
|
|
.mode = __builtin_choose_expr( \
|
|
__builtin_types_compatible_p(typeof(m), const enum upboard_pin_mode *), \
|
|
0, m), \
|
|
.modes = __builtin_choose_expr( \
|
|
__builtin_types_compatible_p(typeof(m), const enum upboard_pin_mode *), \
|
|
m, NULL), \
|
|
}
|
|
|
|
static const struct upboard_pingroup upboard_up_pin_groups[] = {
|
|
UPBOARD_PINGROUP("uart1_grp", upboard_up_uart1_pins, &upboard_up_uart1_modes[0]),
|
|
UPBOARD_PINGROUP("i2c0_grp", upboard_up_i2c0_pins, UPBOARD_PIN_MODE_GPIO_OUT),
|
|
UPBOARD_PINGROUP("i2c1_grp", upboard_up_i2c1_pins, UPBOARD_PIN_MODE_GPIO_OUT),
|
|
UPBOARD_PINGROUP("spi2_grp", upboard_up_spi2_pins, &upboard_up_spi2_modes[0]),
|
|
UPBOARD_PINGROUP("i2s0_grp", upboard_up_i2s0_pins, &upboard_up_i2s0_modes[0]),
|
|
UPBOARD_PINGROUP("pwm0_grp", upboard_up_pwm0_pins, UPBOARD_PIN_MODE_GPIO_OUT),
|
|
UPBOARD_PINGROUP("pwm1_grp", upboard_up_pwm1_pins, UPBOARD_PIN_MODE_GPIO_OUT),
|
|
UPBOARD_PINGROUP("adc0_grp", upboard_up_adc0_pins, UPBOARD_PIN_MODE_GPIO_IN),
|
|
};
|
|
|
|
static const char * const upboard_up_uart1_groups[] = { "uart1_grp" };
|
|
static const char * const upboard_up_i2c0_groups[] = { "i2c0_grp" };
|
|
static const char * const upboard_up_i2c1_groups[] = { "i2c1_grp" };
|
|
static const char * const upboard_up_spi2_groups[] = { "spi2_grp" };
|
|
static const char * const upboard_up_i2s0_groups[] = { "i2s0_grp" };
|
|
static const char * const upboard_up_pwm0_groups[] = { "pwm0_grp" };
|
|
static const char * const upboard_up_pwm1_groups[] = { "pwm1_grp" };
|
|
static const char * const upboard_up_adc0_groups[] = { "adc0_grp" };
|
|
|
|
#define UPBOARD_FUNCTION(func, groups) PINCTRL_PINFUNCTION(func, groups, ARRAY_SIZE(groups))
|
|
|
|
static const struct pinfunction upboard_up_pin_functions[] = {
|
|
UPBOARD_FUNCTION("uart1", upboard_up_uart1_groups),
|
|
UPBOARD_FUNCTION("i2c0", upboard_up_i2c0_groups),
|
|
UPBOARD_FUNCTION("i2c1", upboard_up_i2c1_groups),
|
|
UPBOARD_FUNCTION("spi2", upboard_up_spi2_groups),
|
|
UPBOARD_FUNCTION("i2s0", upboard_up_i2s0_groups),
|
|
UPBOARD_FUNCTION("pwm0", upboard_up_pwm0_groups),
|
|
UPBOARD_FUNCTION("pwm1", upboard_up_pwm1_groups),
|
|
UPBOARD_FUNCTION("adc0", upboard_up_adc0_groups),
|
|
};
|
|
|
|
static const struct upboard_pinctrl_data upboard_up_pinctrl_data = {
|
|
.groups = &upboard_up_pin_groups[0],
|
|
.ngroups = ARRAY_SIZE(upboard_up_pin_groups),
|
|
.funcs = &upboard_up_pin_functions[0],
|
|
.nfuncs = ARRAY_SIZE(upboard_up_pin_functions),
|
|
.pin_header = &upboard_up_pin_header[0],
|
|
.ngpio = ARRAY_SIZE(upboard_up_pin_header),
|
|
};
|
|
|
|
#define UPBOARD_UP2_BIT_TO_PIN(bit) UPBOARD_UP2_BIT_##bit
|
|
|
|
#define UPBOARD_UP2_PIN_NAME(id) \
|
|
{ \
|
|
.number = UPBOARD_UP2_BIT_##id, \
|
|
.name = #id, \
|
|
}
|
|
|
|
#define UPBOARD_UP2_PIN_MUX(bit, data) \
|
|
{ \
|
|
.number = UPBOARD_UP2_BIT_##bit, \
|
|
.name = "PINMUX_"#bit, \
|
|
.drv_data = (void *)(data), \
|
|
}
|
|
|
|
#define UPBOARD_UP2_PIN_FUNC(id, data) \
|
|
{ \
|
|
.number = UPBOARD_UP2_BIT_##id, \
|
|
.name = #id, \
|
|
.drv_data = (void *)(data), \
|
|
}
|
|
|
|
enum upboard_up2_fpgabit {
|
|
UPBOARD_UP2_BIT_UART1_TXD,
|
|
UPBOARD_UP2_BIT_UART1_RXD,
|
|
UPBOARD_UP2_BIT_UART1_RTS,
|
|
UPBOARD_UP2_BIT_UART1_CTS,
|
|
UPBOARD_UP2_BIT_GPIO3_ADC0,
|
|
UPBOARD_UP2_BIT_GPIO5_ADC2,
|
|
UPBOARD_UP2_BIT_GPIO6_ADC3,
|
|
UPBOARD_UP2_BIT_GPIO11,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS1n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS1p,
|
|
UPBOARD_UP2_BIT_SPI2_TXD,
|
|
UPBOARD_UP2_BIT_SPI2_RXD,
|
|
UPBOARD_UP2_BIT_SPI2_FS1,
|
|
UPBOARD_UP2_BIT_SPI2_FS0,
|
|
UPBOARD_UP2_BIT_SPI2_CLK,
|
|
UPBOARD_UP2_BIT_SPI1_TXD,
|
|
UPBOARD_UP2_BIT_SPI1_RXD,
|
|
UPBOARD_UP2_BIT_SPI1_FS1,
|
|
UPBOARD_UP2_BIT_SPI1_FS0,
|
|
UPBOARD_UP2_BIT_SPI1_CLK,
|
|
UPBOARD_UP2_BIT_I2C0_SCL,
|
|
UPBOARD_UP2_BIT_I2C0_SDA,
|
|
UPBOARD_UP2_BIT_I2C1_SCL,
|
|
UPBOARD_UP2_BIT_I2C1_SDA,
|
|
UPBOARD_UP2_BIT_PWM1,
|
|
UPBOARD_UP2_BIT_PWM0,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS0n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS0p,
|
|
UPBOARD_UP2_BIT_GPIO24,
|
|
UPBOARD_UP2_BIT_GPIO10,
|
|
UPBOARD_UP2_BIT_GPIO2,
|
|
UPBOARD_UP2_BIT_GPIO1,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS3n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS3p,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS4n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS4p,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS5n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS5p,
|
|
UPBOARD_UP2_BIT_I2S_SDO,
|
|
UPBOARD_UP2_BIT_I2S_SDI,
|
|
UPBOARD_UP2_BIT_I2S_WS_SYNC,
|
|
UPBOARD_UP2_BIT_I2S_BCLK,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS6n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS6p,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS7n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS7p,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS2n,
|
|
UPBOARD_UP2_BIT_EXHAT_LVDS2p,
|
|
};
|
|
|
|
static const struct pinctrl_pin_desc upboard_up2_pins[] = {
|
|
UPBOARD_UP2_PIN_NAME(UART1_TXD),
|
|
UPBOARD_UP2_PIN_NAME(UART1_RXD),
|
|
UPBOARD_UP2_PIN_NAME(UART1_RTS),
|
|
UPBOARD_UP2_PIN_NAME(UART1_CTS),
|
|
UPBOARD_UP2_PIN_NAME(GPIO3_ADC0),
|
|
UPBOARD_UP2_PIN_NAME(GPIO5_ADC2),
|
|
UPBOARD_UP2_PIN_NAME(GPIO6_ADC3),
|
|
UPBOARD_UP2_PIN_NAME(GPIO11),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS1n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS1p),
|
|
UPBOARD_UP2_PIN_NAME(SPI2_TXD),
|
|
UPBOARD_UP2_PIN_NAME(SPI2_RXD),
|
|
UPBOARD_UP2_PIN_NAME(SPI2_FS1),
|
|
UPBOARD_UP2_PIN_NAME(SPI2_FS0),
|
|
UPBOARD_UP2_PIN_NAME(SPI2_CLK),
|
|
UPBOARD_UP2_PIN_NAME(SPI1_TXD),
|
|
UPBOARD_UP2_PIN_NAME(SPI1_RXD),
|
|
UPBOARD_UP2_PIN_NAME(SPI1_FS1),
|
|
UPBOARD_UP2_PIN_NAME(SPI1_FS0),
|
|
UPBOARD_UP2_PIN_NAME(SPI1_CLK),
|
|
UPBOARD_UP2_PIN_MUX(I2C0_SCL, &upboard_i2c0_reg),
|
|
UPBOARD_UP2_PIN_MUX(I2C0_SDA, &upboard_i2c0_reg),
|
|
UPBOARD_UP2_PIN_MUX(I2C1_SCL, &upboard_i2c1_reg),
|
|
UPBOARD_UP2_PIN_MUX(I2C1_SDA, &upboard_i2c1_reg),
|
|
UPBOARD_UP2_PIN_NAME(PWM1),
|
|
UPBOARD_UP2_PIN_NAME(PWM0),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS0n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS0p),
|
|
UPBOARD_UP2_PIN_MUX(GPIO24, &upboard_i2c0_reg),
|
|
UPBOARD_UP2_PIN_MUX(GPIO10, &upboard_i2c0_reg),
|
|
UPBOARD_UP2_PIN_MUX(GPIO2, &upboard_i2c1_reg),
|
|
UPBOARD_UP2_PIN_MUX(GPIO1, &upboard_i2c1_reg),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS3n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS3p),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS4n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS4p),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS5n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS5p),
|
|
UPBOARD_UP2_PIN_NAME(I2S_SDO),
|
|
UPBOARD_UP2_PIN_NAME(I2S_SDI),
|
|
UPBOARD_UP2_PIN_NAME(I2S_WS_SYNC),
|
|
UPBOARD_UP2_PIN_NAME(I2S_BCLK),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS6n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS6p),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS7n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS7p),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS2n),
|
|
UPBOARD_UP2_PIN_NAME(EXHAT_LVDS2p),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_pin_header[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO10),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO24),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO1),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO2),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO3_ADC0),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO11),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_CLK),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_FS1),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_FS0),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_RXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_TXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_CLK),
|
|
UPBOARD_UP2_BIT_TO_PIN(PWM0),
|
|
UPBOARD_UP2_BIT_TO_PIN(PWM1),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_TXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_RXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_CTS),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_RTS),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_BCLK),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_WS_SYNC),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_SDI),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_SDO),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO6_ADC3),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_FS1),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_RXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_TXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_FS0),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO5_ADC2),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_uart1_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_TXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_RXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_RTS),
|
|
UPBOARD_UP2_BIT_TO_PIN(UART1_CTS),
|
|
};
|
|
|
|
static const enum upboard_pin_mode upboard_up2_uart1_modes[] = {
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up2_uart1_modes) == ARRAY_SIZE(upboard_up2_uart1_pins));
|
|
|
|
static const unsigned int upboard_up2_i2c0_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(I2C0_SCL),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2C0_SDA),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO24),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO10),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_i2c1_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(I2C1_SCL),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2C1_SDA),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO2),
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO1),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_spi1_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_TXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_RXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_FS1),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_FS0),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI1_CLK),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_spi2_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_TXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_RXD),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_FS1),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_FS0),
|
|
UPBOARD_UP2_BIT_TO_PIN(SPI2_CLK),
|
|
};
|
|
|
|
static const enum upboard_pin_mode upboard_up2_spi_modes[] = {
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up2_spi_modes) == ARRAY_SIZE(upboard_up2_spi1_pins));
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up2_spi_modes) == ARRAY_SIZE(upboard_up2_spi2_pins));
|
|
|
|
static const unsigned int upboard_up2_i2s0_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_BCLK),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_WS_SYNC),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_SDI),
|
|
UPBOARD_UP2_BIT_TO_PIN(I2S_SDO),
|
|
};
|
|
|
|
static const enum upboard_pin_mode upboard_up2_i2s0_modes[] = {
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
UPBOARD_PIN_MODE_GPIO_IN,
|
|
UPBOARD_PIN_MODE_GPIO_OUT,
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(upboard_up2_i2s0_modes) == ARRAY_SIZE(upboard_up2_i2s0_pins));
|
|
|
|
static const unsigned int upboard_up2_pwm0_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(PWM0),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_pwm1_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(PWM1),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_adc0_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO3_ADC0),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_adc2_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO5_ADC2),
|
|
};
|
|
|
|
static const unsigned int upboard_up2_adc3_pins[] = {
|
|
UPBOARD_UP2_BIT_TO_PIN(GPIO6_ADC3),
|
|
};
|
|
|
|
static const struct upboard_pingroup upboard_up2_pin_groups[] = {
|
|
UPBOARD_PINGROUP("uart1_grp", upboard_up2_uart1_pins, &upboard_up2_uart1_modes[0]),
|
|
UPBOARD_PINGROUP("i2c0_grp", upboard_up2_i2c0_pins, UPBOARD_PIN_MODE_FUNCTION),
|
|
UPBOARD_PINGROUP("i2c1_grp", upboard_up2_i2c1_pins, UPBOARD_PIN_MODE_FUNCTION),
|
|
UPBOARD_PINGROUP("spi1_grp", upboard_up2_spi1_pins, &upboard_up2_spi_modes[0]),
|
|
UPBOARD_PINGROUP("spi2_grp", upboard_up2_spi2_pins, &upboard_up2_spi_modes[0]),
|
|
UPBOARD_PINGROUP("i2s0_grp", upboard_up2_i2s0_pins, &upboard_up2_i2s0_modes[0]),
|
|
UPBOARD_PINGROUP("pwm0_grp", upboard_up2_pwm0_pins, UPBOARD_PIN_MODE_GPIO_OUT),
|
|
UPBOARD_PINGROUP("pwm1_grp", upboard_up2_pwm1_pins, UPBOARD_PIN_MODE_GPIO_OUT),
|
|
UPBOARD_PINGROUP("adc0_grp", upboard_up2_adc0_pins, UPBOARD_PIN_MODE_GPIO_IN),
|
|
UPBOARD_PINGROUP("adc2_grp", upboard_up2_adc2_pins, UPBOARD_PIN_MODE_GPIO_IN),
|
|
UPBOARD_PINGROUP("adc3_grp", upboard_up2_adc3_pins, UPBOARD_PIN_MODE_GPIO_IN),
|
|
};
|
|
|
|
static const char * const upboard_up2_uart1_groups[] = { "uart1_grp" };
|
|
static const char * const upboard_up2_i2c0_groups[] = { "i2c0_grp" };
|
|
static const char * const upboard_up2_i2c1_groups[] = { "i2c1_grp" };
|
|
static const char * const upboard_up2_spi1_groups[] = { "spi1_grp" };
|
|
static const char * const upboard_up2_spi2_groups[] = { "spi2_grp" };
|
|
static const char * const upboard_up2_i2s0_groups[] = { "i2s0_grp" };
|
|
static const char * const upboard_up2_pwm0_groups[] = { "pwm0_grp" };
|
|
static const char * const upboard_up2_pwm1_groups[] = { "pwm1_grp" };
|
|
static const char * const upboard_up2_adc0_groups[] = { "adc0_grp" };
|
|
static const char * const upboard_up2_adc2_groups[] = { "adc2_grp" };
|
|
static const char * const upboard_up2_adc3_groups[] = { "adc3_grp" };
|
|
|
|
static const struct pinfunction upboard_up2_pin_functions[] = {
|
|
UPBOARD_FUNCTION("uart1", upboard_up2_uart1_groups),
|
|
UPBOARD_FUNCTION("i2c0", upboard_up2_i2c0_groups),
|
|
UPBOARD_FUNCTION("i2c1", upboard_up2_i2c1_groups),
|
|
UPBOARD_FUNCTION("spi1", upboard_up2_spi1_groups),
|
|
UPBOARD_FUNCTION("spi2", upboard_up2_spi2_groups),
|
|
UPBOARD_FUNCTION("i2s0", upboard_up2_i2s0_groups),
|
|
UPBOARD_FUNCTION("pwm0", upboard_up2_pwm0_groups),
|
|
UPBOARD_FUNCTION("pwm1", upboard_up2_pwm1_groups),
|
|
UPBOARD_FUNCTION("adc0", upboard_up2_adc0_groups),
|
|
UPBOARD_FUNCTION("adc2", upboard_up2_adc2_groups),
|
|
UPBOARD_FUNCTION("adc3", upboard_up2_adc3_groups),
|
|
};
|
|
|
|
static const struct upboard_pinctrl_data upboard_up2_pinctrl_data = {
|
|
.groups = &upboard_up2_pin_groups[0],
|
|
.ngroups = ARRAY_SIZE(upboard_up2_pin_groups),
|
|
.funcs = &upboard_up2_pin_functions[0],
|
|
.nfuncs = ARRAY_SIZE(upboard_up2_pin_functions),
|
|
.pin_header = &upboard_up2_pin_header[0],
|
|
.ngpio = ARRAY_SIZE(upboard_up2_pin_header),
|
|
};
|
|
|
|
static int upboard_pinctrl_set_function(struct pinctrl_dev *pctldev, unsigned int offset)
|
|
{
|
|
struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
struct upboard_pin *p = &pctrl->pins[offset];
|
|
int ret;
|
|
|
|
if (!p->funcbit)
|
|
return -EPERM;
|
|
|
|
ret = regmap_field_write(p->enbit, 0);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return regmap_field_write(p->funcbit, 1);
|
|
}
|
|
|
|
static int upboard_pinctrl_gpio_commit_enable(struct pinctrl_dev *pctldev, unsigned int offset)
|
|
{
|
|
struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
struct upboard_pin *p = &pctrl->pins[offset];
|
|
int ret;
|
|
|
|
if (p->funcbit) {
|
|
ret = regmap_field_write(p->funcbit, 0);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return regmap_field_write(p->enbit, 1);
|
|
}
|
|
|
|
static int upboard_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
|
|
struct pinctrl_gpio_range *range,
|
|
unsigned int offset)
|
|
{
|
|
return upboard_pinctrl_gpio_commit_enable(pctldev, offset);
|
|
}
|
|
|
|
static void upboard_pinctrl_gpio_commit_disable(struct pinctrl_dev *pctldev, unsigned int offset)
|
|
{
|
|
struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
struct upboard_pin *p = &pctrl->pins[offset];
|
|
|
|
regmap_field_write(p->enbit, 0);
|
|
};
|
|
|
|
static void upboard_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
|
|
struct pinctrl_gpio_range *range, unsigned int offset)
|
|
{
|
|
return upboard_pinctrl_gpio_commit_disable(pctldev, offset);
|
|
}
|
|
|
|
static int upboard_pinctrl_gpio_commit_direction(struct pinctrl_dev *pctldev, unsigned int offset,
|
|
bool input)
|
|
{
|
|
struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
struct upboard_pin *p = &pctrl->pins[offset];
|
|
|
|
return regmap_field_write(p->dirbit, input);
|
|
}
|
|
|
|
static int upboard_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|
struct pinctrl_gpio_range *range,
|
|
unsigned int offset, bool input)
|
|
{
|
|
return upboard_pinctrl_gpio_commit_direction(pctldev, offset, input);
|
|
}
|
|
|
|
static int upboard_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
|
|
unsigned int group_selector)
|
|
{
|
|
struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
const struct upboard_pinctrl_data *pctrl_data = pctrl->pctrl_data;
|
|
const struct upboard_pingroup *upgroups = pctrl_data->groups;
|
|
struct group_desc *grp;
|
|
unsigned int mode, i;
|
|
int ret;
|
|
|
|
grp = pinctrl_generic_get_group(pctldev, group_selector);
|
|
if (!grp)
|
|
return -EINVAL;
|
|
|
|
for (i = 0; i < grp->grp.npins; i++) {
|
|
mode = upgroups[group_selector].mode ?: upgroups[group_selector].modes[i];
|
|
if (mode == UPBOARD_PIN_MODE_FUNCTION) {
|
|
ret = upboard_pinctrl_set_function(pctldev, grp->grp.pins[i]);
|
|
if (ret)
|
|
return ret;
|
|
|
|
continue;
|
|
}
|
|
|
|
ret = upboard_pinctrl_gpio_commit_enable(pctldev, grp->grp.pins[i]);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = upboard_pinctrl_gpio_commit_direction(pctldev, grp->grp.pins[i],
|
|
mode == UPBOARD_PIN_MODE_GPIO_IN);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct pinmux_ops upboard_pinmux_ops = {
|
|
.get_functions_count = pinmux_generic_get_function_count,
|
|
.get_function_name = pinmux_generic_get_function_name,
|
|
.get_function_groups = pinmux_generic_get_function_groups,
|
|
.set_mux = upboard_pinctrl_set_mux,
|
|
.gpio_request_enable = upboard_pinctrl_gpio_request_enable,
|
|
.gpio_disable_free = upboard_pinctrl_gpio_disable_free,
|
|
.gpio_set_direction = upboard_pinctrl_gpio_set_direction,
|
|
};
|
|
|
|
static int upboard_pinctrl_pin_get_mode(struct pinctrl_dev *pctldev, unsigned int pin)
|
|
{
|
|
struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
struct upboard_pin *p = &pctrl->pins[pin];
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
if (p->funcbit) {
|
|
ret = regmap_field_read(p->funcbit, &val);
|
|
if (ret)
|
|
return ret;
|
|
if (val)
|
|
return UPBOARD_PIN_MODE_FUNCTION;
|
|
}
|
|
|
|
ret = regmap_field_read(p->enbit, &val);
|
|
if (ret)
|
|
return ret;
|
|
if (!val)
|
|
return UPBOARD_PIN_MODE_DISABLED;
|
|
|
|
ret = regmap_field_read(p->dirbit, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return val ? UPBOARD_PIN_MODE_GPIO_IN : UPBOARD_PIN_MODE_GPIO_OUT;
|
|
}
|
|
|
|
static void upboard_pinctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
|
|
unsigned int offset)
|
|
{
|
|
int ret;
|
|
|
|
ret = upboard_pinctrl_pin_get_mode(pctldev, offset);
|
|
if (ret == UPBOARD_PIN_MODE_FUNCTION)
|
|
seq_puts(s, "mode function ");
|
|
else if (ret == UPBOARD_PIN_MODE_DISABLED)
|
|
seq_puts(s, "HIGH-Z ");
|
|
else if (ret < 0)
|
|
seq_puts(s, "N/A ");
|
|
else
|
|
seq_printf(s, "GPIO (%s) ", str_input_output(ret == UPBOARD_PIN_MODE_GPIO_IN));
|
|
}
|
|
|
|
static const struct pinctrl_ops upboard_pinctrl_ops = {
|
|
.get_groups_count = pinctrl_generic_get_group_count,
|
|
.get_group_name = pinctrl_generic_get_group_name,
|
|
.get_group_pins = pinctrl_generic_get_group_pins,
|
|
.pin_dbg_show = upboard_pinctrl_dbg_show,
|
|
};
|
|
|
|
static int upboard_gpio_request(struct gpio_chip *gc, unsigned int offset)
|
|
{
|
|
struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
|
|
struct upboard_pinctrl *pctrl = gpiochip_fwd_get_data(fwd);
|
|
unsigned int pin = pctrl->pctrl_data->pin_header[offset];
|
|
struct gpio_desc *desc;
|
|
int ret;
|
|
|
|
ret = pinctrl_gpio_request(gc, offset);
|
|
if (ret)
|
|
return ret;
|
|
|
|
desc = gpiod_get_index(pctrl->dev, "external", pin, 0);
|
|
if (IS_ERR(desc)) {
|
|
pinctrl_gpio_free(gc, offset);
|
|
return PTR_ERR(desc);
|
|
}
|
|
|
|
return gpiochip_fwd_desc_add(fwd, desc, offset);
|
|
}
|
|
|
|
static void upboard_gpio_free(struct gpio_chip *gc, unsigned int offset)
|
|
{
|
|
struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
|
|
|
|
gpiochip_fwd_desc_free(fwd, offset);
|
|
pinctrl_gpio_free(gc, offset);
|
|
}
|
|
|
|
static int upboard_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
|
{
|
|
struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
|
|
struct upboard_pinctrl *pctrl = gpiochip_fwd_get_data(fwd);
|
|
unsigned int pin = pctrl->pctrl_data->pin_header[offset];
|
|
int mode;
|
|
|
|
/* If the pin is in function mode or high-z, input direction is returned */
|
|
mode = upboard_pinctrl_pin_get_mode(pctrl->pctldev, pin);
|
|
if (mode < 0)
|
|
return mode;
|
|
|
|
if (mode == UPBOARD_PIN_MODE_GPIO_OUT)
|
|
return GPIO_LINE_DIRECTION_OUT;
|
|
|
|
return GPIO_LINE_DIRECTION_IN;
|
|
}
|
|
|
|
static int upboard_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
|
|
{
|
|
struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
|
|
int ret;
|
|
|
|
ret = pinctrl_gpio_direction_input(gc, offset);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return gpiochip_fwd_gpio_direction_input(fwd, offset);
|
|
}
|
|
|
|
static int upboard_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
|
|
{
|
|
struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
|
|
int ret;
|
|
|
|
ret = pinctrl_gpio_direction_output(gc, offset);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return gpiochip_fwd_gpio_direction_output(fwd, offset, value);
|
|
}
|
|
|
|
static int upboard_pinctrl_register_groups(struct upboard_pinctrl *pctrl)
|
|
{
|
|
const struct upboard_pingroup *groups = pctrl->pctrl_data->groups;
|
|
size_t ngroups = pctrl->pctrl_data->ngroups;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < ngroups; i++) {
|
|
ret = pinctrl_generic_add_group(pctrl->pctldev, groups[i].grp.name,
|
|
groups[i].grp.pins, groups[i].grp.npins, pctrl);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int upboard_pinctrl_register_functions(struct upboard_pinctrl *pctrl)
|
|
{
|
|
const struct pinfunction *funcs = pctrl->pctrl_data->funcs;
|
|
size_t nfuncs = pctrl->pctrl_data->nfuncs;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < nfuncs ; i++) {
|
|
ret = pinmux_generic_add_function(pctrl->pctldev, funcs[i].name,
|
|
funcs[i].groups, funcs[i].ngroups, NULL);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct pinctrl_map pinctrl_map_apl01[] = {
|
|
PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "pwm0_grp", "pwm0"),
|
|
PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "pwm1_grp", "pwm1"),
|
|
PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "uart1_grp", "uart1"),
|
|
PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:02", "i2c0_grp", "i2c0"),
|
|
PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:02", "i2c1_grp", "i2c1"),
|
|
PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:01", "ssp0_grp", "ssp0"),
|
|
};
|
|
|
|
static const struct upboard_pinctrl_map upboard_pinctrl_map_apl01 = {
|
|
.maps = &pinctrl_map_apl01[0],
|
|
.nmaps = ARRAY_SIZE(pinctrl_map_apl01),
|
|
};
|
|
|
|
static const struct dmi_system_id dmi_platform_info[] = {
|
|
{
|
|
/* UP Squared */
|
|
.matches = {
|
|
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AAEON"),
|
|
DMI_EXACT_MATCH(DMI_BOARD_NAME, "UP-APL01"),
|
|
},
|
|
.driver_data = (void *)&upboard_pinctrl_map_apl01,
|
|
},
|
|
{ }
|
|
};
|
|
|
|
static int upboard_pinctrl_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct upboard_fpga *fpga = dev_get_drvdata(dev->parent);
|
|
const struct upboard_pinctrl_map *board_map;
|
|
const struct dmi_system_id *dmi_id;
|
|
struct pinctrl_desc *pctldesc;
|
|
struct upboard_pinctrl *pctrl;
|
|
struct upboard_pin *pins;
|
|
struct gpiochip_fwd *fwd;
|
|
struct pinctrl *pinctrl;
|
|
struct gpio_chip *chip;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
pctldesc = devm_kzalloc(dev, sizeof(*pctldesc), GFP_KERNEL);
|
|
if (!pctldesc)
|
|
return -ENOMEM;
|
|
|
|
pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
|
|
if (!pctrl)
|
|
return -ENOMEM;
|
|
|
|
switch (fpga->fpga_data->type) {
|
|
case UPBOARD_UP_FPGA:
|
|
pctldesc->pins = upboard_up_pins;
|
|
pctldesc->npins = ARRAY_SIZE(upboard_up_pins);
|
|
pctrl->pctrl_data = &upboard_up_pinctrl_data;
|
|
break;
|
|
case UPBOARD_UP2_FPGA:
|
|
pctldesc->pins = upboard_up2_pins;
|
|
pctldesc->npins = ARRAY_SIZE(upboard_up2_pins);
|
|
pctrl->pctrl_data = &upboard_up2_pinctrl_data;
|
|
break;
|
|
default:
|
|
return dev_err_probe(dev, -ENODEV, "Unsupported device type %d\n",
|
|
fpga->fpga_data->type);
|
|
}
|
|
|
|
dmi_id = dmi_first_match(dmi_platform_info);
|
|
if (!dmi_id)
|
|
return dev_err_probe(dev, -ENODEV, "Unsupported board\n");
|
|
|
|
board_map = (const struct upboard_pinctrl_map *)dmi_id->driver_data;
|
|
|
|
pctldesc->name = dev_name(dev);
|
|
pctldesc->owner = THIS_MODULE;
|
|
pctldesc->pctlops = &upboard_pinctrl_ops;
|
|
pctldesc->pmxops = &upboard_pinmux_ops;
|
|
|
|
pctrl->dev = dev;
|
|
|
|
pins = devm_kcalloc(dev, pctldesc->npins, sizeof(*pins), GFP_KERNEL);
|
|
if (!pins)
|
|
return -ENOMEM;
|
|
|
|
/* Initialize pins */
|
|
for (i = 0; i < pctldesc->npins; i++) {
|
|
const struct pinctrl_pin_desc *pin_desc = &pctldesc->pins[i];
|
|
unsigned int regoff = pin_desc->number / UPBOARD_REGISTER_SIZE;
|
|
unsigned int lsb = pin_desc->number % UPBOARD_REGISTER_SIZE;
|
|
struct reg_field * const fld_func = pin_desc->drv_data;
|
|
struct upboard_pin *pin = &pins[i];
|
|
struct reg_field fldconf = {};
|
|
|
|
if (fld_func) {
|
|
pin->funcbit = devm_regmap_field_alloc(dev, fpga->regmap, *fld_func);
|
|
if (IS_ERR(pin->funcbit))
|
|
return PTR_ERR(pin->funcbit);
|
|
}
|
|
|
|
fldconf.reg = UPBOARD_REG_GPIO_EN0 + regoff;
|
|
fldconf.lsb = lsb;
|
|
fldconf.msb = lsb;
|
|
pin->enbit = devm_regmap_field_alloc(dev, fpga->regmap, fldconf);
|
|
if (IS_ERR(pin->enbit))
|
|
return PTR_ERR(pin->enbit);
|
|
|
|
fldconf.reg = UPBOARD_REG_GPIO_DIR0 + regoff;
|
|
fldconf.lsb = lsb;
|
|
fldconf.msb = lsb;
|
|
pin->dirbit = devm_regmap_field_alloc(dev, fpga->regmap, fldconf);
|
|
if (IS_ERR(pin->dirbit))
|
|
return PTR_ERR(pin->dirbit);
|
|
}
|
|
|
|
pctrl->pins = pins;
|
|
|
|
ret = devm_pinctrl_register_and_init(dev, pctldesc, pctrl, &pctrl->pctldev);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "Failed to register pinctrl\n");
|
|
|
|
ret = upboard_pinctrl_register_groups(pctrl);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "Failed to register groups\n");
|
|
|
|
ret = upboard_pinctrl_register_functions(pctrl);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "Failed to register functions\n");
|
|
|
|
ret = devm_pinctrl_register_mappings(dev, board_map->maps, board_map->nmaps);
|
|
if (ret)
|
|
return ret;
|
|
|
|
pinctrl = devm_pinctrl_get_select_default(dev);
|
|
if (IS_ERR(pinctrl))
|
|
return dev_err_probe(dev, PTR_ERR(pinctrl), "Failed to select pinctrl\n");
|
|
|
|
ret = pinctrl_enable(pctrl->pctldev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
fwd = devm_gpiochip_fwd_alloc(dev, pctrl->pctrl_data->ngpio);
|
|
if (IS_ERR(fwd))
|
|
return dev_err_probe(dev, PTR_ERR(fwd), "Failed to allocate the gpiochip forwarder\n");
|
|
|
|
chip = gpiochip_fwd_get_gpiochip(fwd);
|
|
chip->request = upboard_gpio_request;
|
|
chip->free = upboard_gpio_free;
|
|
chip->get_direction = upboard_gpio_get_direction;
|
|
chip->direction_output = upboard_gpio_direction_output;
|
|
chip->direction_input = upboard_gpio_direction_input;
|
|
|
|
ret = gpiochip_fwd_register(fwd, pctrl);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "Failed to register the gpiochip forwarder\n");
|
|
|
|
return gpiochip_add_sparse_pin_range(chip, dev_name(dev), 0, pctrl->pctrl_data->pin_header,
|
|
pctrl->pctrl_data->ngpio);
|
|
}
|
|
|
|
static struct platform_driver upboard_pinctrl_driver = {
|
|
.driver = {
|
|
.name = "upboard-pinctrl",
|
|
},
|
|
.probe = upboard_pinctrl_probe,
|
|
};
|
|
module_platform_driver(upboard_pinctrl_driver);
|
|
|
|
MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com");
|
|
MODULE_DESCRIPTION("UP Board HAT pin controller driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS("platform:upboard-pinctrl");
|
|
MODULE_IMPORT_NS("GPIO_FORWARDER");
|