The UP Squared board <http://www.upboard.com> implements certain features (pin control) through an on-board FPGA. Signed-off-by: Javier Arteaga <javier@xxxxxxxxxx> [merge various fixes] Signed-off-by: Nicola Lunghi <nicola.lunghi@xxxxxxxxxx> Signed-off-by: chengwei <larry.lai@xxxxxxxxxxxxxxx> --- drivers/pinctrl/Kconfig | 15 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-upboard.c | 1003 +++++++++++++++++++++++++++++ 3 files changed, 1019 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-upboard.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 1cf74b0c42e5..5d719eadecdb 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -483,6 +483,21 @@ config PINCTRL_THUNDERBAY rate control and direction control. This module will be called as pinctrl-thunderbay. +config PINCTRL_UPBOARD + tristate "UP board FPGA pin controller" + depends on ACPI + depends on MFD_UPBOARD_FPGA + depends on X86 + select GENERIC_PINCONF + select PINMUX + select PINCONF + help + Pin controller for the FPGA GPIO lines on UP boards. Due to the + hardware layout, these are meant to be controlled in tandem with their + corresponding Intel SoC GPIOs. + To compile this driver as a module, choose M here: the module + will be called pinctrl-upboard. + config PINCTRL_ZYNQ bool "Pinctrl driver for Xilinx Zynq" depends on ARCH_ZYNQ diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index e76f5cdc64b0..c366706d36e7 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_THUNDERBAY) += pinctrl-thunderbay.o +obj-$(CONFIG_PINCTRL_UPBOARD) += pinctrl-upboard.o obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o diff --git a/drivers/pinctrl/pinctrl-upboard.c b/drivers/pinctrl/pinctrl-upboard.c new file mode 100644 index 000000000000..39cd45357f6b --- /dev/null +++ b/drivers/pinctrl/pinctrl-upboard.c @@ -0,0 +1,1003 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UP Board FPGA-based pin controller driver + * + * Copyright (c) 2017, Emutex Ltd. All rights reserved. + * + * Authors: Javier Arteaga <javier@xxxxxxxxxx> + * Dan O'Donovan <dan@xxxxxxxxxx> + * Nicola Lunghi <nicolal@xxxxxxxxxx> + */ + +#include <linux/acpi.h> +#include <linux/dmi.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/mfd/upboard-fpga.h> +#include <linux/module.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/string.h> + +#include "core.h" + +struct upboard_pin { + struct regmap_field *funcbit; + struct regmap_field *enbit; + struct regmap_field *dirbit; +}; + +struct upboard_bios { + const struct reg_sequence *patches; + size_t npatches; +}; + +struct upboard_pinctrl { + struct device *dev; + struct pinctrl_dev *pctldev; + struct regmap *regmap; + struct gpio_chip chip; + const unsigned int *rpi_mapping; +}; + +enum upboard_func0_fpgabit { + UPFPGA_I2C0_EN = 8, + UPFPGA_I2C1_EN = 9, + UPFPGA_CEC0_EN = 12, + UPFPGA_ADC0_EN = 14, +}; + +static const struct reg_field upboard_i2c0_reg = + REG_FIELD(UPFPGA_REG_FUNC_EN0, UPFPGA_I2C0_EN, UPFPGA_I2C0_EN); + +static const struct reg_field upboard_i2c1_reg = + REG_FIELD(UPFPGA_REG_FUNC_EN0, UPFPGA_I2C1_EN, UPFPGA_I2C1_EN); + +static const struct reg_field upboard_adc0_reg = + REG_FIELD(UPFPGA_REG_FUNC_EN0, UPFPGA_ADC0_EN, UPFPGA_ADC0_EN); + +#define UPBOARD_BIT_TO_PIN(r, bit) \ + ((r) * UPFPGA_REGISTER_SIZE + (bit)) + +/* + * UP board data + */ + +#define UPBOARD_UP_BIT_TO_PIN(r, id) (UPBOARD_BIT_TO_PIN(r, UPFPGA_UP_##id)) + +#define UPBOARD_UP_PIN_ANON(r, bit) \ + { \ + .number = UPBOARD_BIT_TO_PIN(r, bit), \ + } + +#define UPBOARD_UP_PIN_NAME(r, id) \ + { \ + .number = UPBOARD_UP_BIT_TO_PIN(r, id), \ + .name = #id, \ + } + +#define UPBOARD_UP_PIN_FUNC(r, id, data) \ + { \ + .number = UPBOARD_UP_BIT_TO_PIN(r, id), \ + .name = #id, \ + .drv_data = (void *)(data), \ + } + +enum upboard_up_reg1_fpgabit { + UPFPGA_UP_I2C1_SDA, + UPFPGA_UP_I2C1_SCL, + UPFPGA_UP_ADC0, + UPFPGA_UP_GPIO17, + UPFPGA_UP_GPIO27, + UPFPGA_UP_GPIO22, + UPFPGA_UP_SPI_MOSI, + UPFPGA_UP_SPI_MISO, + UPFPGA_UP_SPI_CLK, + UPFPGA_UP_I2C0_SDA, + UPFPGA_UP_GPIO5, + UPFPGA_UP_GPIO6, + UPFPGA_UP_PWM1, + UPFPGA_UP_I2S_FRM, + UPFPGA_UP_GPIO26, + UPFPGA_UP_UART1_TX, +}; + +enum upboard_up_reg2_fpgabit { + UPFPGA_UP_UART1_RX, + UPFPGA_UP_I2S_CLK, + UPFPGA_UP_GPIO23, + UPFPGA_UP_GPIO24, + UPFPGA_UP_GPIO25, + UPFPGA_UP_SPI_CS0, + UPFPGA_UP_SPI_CS1, + UPFPGA_UP_I2C0_SCL, + UPFPGA_UP_PWM0, + UPFPGA_UP_GPIO16, + UPFPGA_UP_I2S_DIN, + UPFPGA_UP_I2S_DOUT, +}; + +static struct pinctrl_pin_desc upboard_up_pins[] = { + UPBOARD_UP_PIN_FUNC(0, I2C1_SDA, &upboard_i2c1_reg), + UPBOARD_UP_PIN_FUNC(0, I2C1_SCL, &upboard_i2c1_reg), + UPBOARD_UP_PIN_FUNC(0, ADC0, &upboard_adc0_reg), + UPBOARD_UP_PIN_NAME(0, GPIO17), + UPBOARD_UP_PIN_NAME(0, GPIO27), + UPBOARD_UP_PIN_NAME(0, GPIO22), + UPBOARD_UP_PIN_NAME(0, SPI_MOSI), + UPBOARD_UP_PIN_NAME(0, SPI_MISO), + UPBOARD_UP_PIN_NAME(0, SPI_CLK), + UPBOARD_UP_PIN_FUNC(0, I2C0_SDA, &upboard_i2c0_reg), + UPBOARD_UP_PIN_NAME(0, GPIO5), + UPBOARD_UP_PIN_NAME(0, GPIO6), + UPBOARD_UP_PIN_NAME(0, PWM1), + UPBOARD_UP_PIN_NAME(0, I2S_FRM), + UPBOARD_UP_PIN_NAME(0, GPIO26), + UPBOARD_UP_PIN_NAME(0, UART1_TX), + /* register 1 */ + UPBOARD_UP_PIN_NAME(1, UART1_RX), + UPBOARD_UP_PIN_NAME(1, I2S_CLK), + UPBOARD_UP_PIN_NAME(1, GPIO23), + UPBOARD_UP_PIN_NAME(1, GPIO24), + UPBOARD_UP_PIN_NAME(1, GPIO25), + UPBOARD_UP_PIN_NAME(1, SPI_CS0), + UPBOARD_UP_PIN_NAME(1, SPI_CS1), + UPBOARD_UP_PIN_FUNC(1, I2C0_SCL, &upboard_i2c0_reg), + UPBOARD_UP_PIN_NAME(1, PWM0), + UPBOARD_UP_PIN_NAME(1, GPIO16), + UPBOARD_UP_PIN_NAME(1, I2S_DIN), + UPBOARD_UP_PIN_NAME(1, I2S_DOUT), +}; + +static const unsigned int upboard_up_rpi_mapping[] = { + UPBOARD_UP_BIT_TO_PIN(0, I2C0_SDA), + UPBOARD_UP_BIT_TO_PIN(1, I2C0_SCL), + UPBOARD_UP_BIT_TO_PIN(0, I2C1_SDA), + UPBOARD_UP_BIT_TO_PIN(0, I2C1_SCL), + UPBOARD_UP_BIT_TO_PIN(0, ADC0), + UPBOARD_UP_BIT_TO_PIN(0, GPIO5), + UPBOARD_UP_BIT_TO_PIN(0, GPIO6), + UPBOARD_UP_BIT_TO_PIN(1, SPI_CS1), + UPBOARD_UP_BIT_TO_PIN(1, SPI_CS0), + UPBOARD_UP_BIT_TO_PIN(0, SPI_MISO), + UPBOARD_UP_BIT_TO_PIN(0, SPI_MOSI), + UPBOARD_UP_BIT_TO_PIN(0, SPI_CLK), + UPBOARD_UP_BIT_TO_PIN(1, PWM0), + UPBOARD_UP_BIT_TO_PIN(0, PWM1), + UPBOARD_UP_BIT_TO_PIN(0, UART1_TX), + UPBOARD_UP_BIT_TO_PIN(1, UART1_RX), + UPBOARD_UP_BIT_TO_PIN(1, GPIO16), + UPBOARD_UP_BIT_TO_PIN(0, GPIO17), + UPBOARD_UP_BIT_TO_PIN(1, I2S_CLK), + UPBOARD_UP_BIT_TO_PIN(0, I2S_FRM), + UPBOARD_UP_BIT_TO_PIN(1, I2S_DIN), + UPBOARD_UP_BIT_TO_PIN(1, I2S_DOUT), + UPBOARD_UP_BIT_TO_PIN(0, GPIO22), + UPBOARD_UP_BIT_TO_PIN(1, GPIO23), + UPBOARD_UP_BIT_TO_PIN(1, GPIO24), + UPBOARD_UP_BIT_TO_PIN(1, GPIO25), + UPBOARD_UP_BIT_TO_PIN(0, GPIO26), + UPBOARD_UP_BIT_TO_PIN(0, GPIO27), +}; + +/* + * Init patches applied to the registers until the BIOS sets proper defaults + */ +static const struct reg_sequence upboard_up_reg_patches[] __initconst = { + { UPFPGA_REG_FUNC_EN0, + // enable I2C voltage-level shifters + BIT(UPFPGA_I2C0_EN) | + BIT(UPFPGA_I2C1_EN) | + // enable adc + BIT(UPFPGA_ADC0_EN) + }, + /* HAT function pins initially set as inputs */ + { UPFPGA_REG_GPIO_DIR0, + BIT(UPFPGA_UP_I2C1_SDA) | + BIT(UPFPGA_UP_I2C1_SCL) | + BIT(UPFPGA_UP_ADC0) | + BIT(UPFPGA_UP_GPIO27) | + BIT(UPFPGA_UP_GPIO22) | + BIT(UPFPGA_UP_SPI_MISO) | + BIT(UPFPGA_UP_I2C0_SDA) | + BIT(UPFPGA_UP_GPIO5) | + BIT(UPFPGA_UP_GPIO6) | + BIT(UPFPGA_UP_GPIO26) + }, + { UPFPGA_REG_GPIO_DIR1, + BIT(UPFPGA_UP_UART1_RX) | + BIT(UPFPGA_UP_GPIO23) | + BIT(UPFPGA_UP_GPIO24) | + BIT(UPFPGA_UP_GPIO25) | + BIT(UPFPGA_UP_I2C0_SCL) | + BIT(UPFPGA_UP_GPIO16) | + BIT(UPFPGA_UP_I2S_DIN) + }, +}; + +static const struct upboard_bios upboard_up_bios_info_dvt __initconst = { + .patches = upboard_up_reg_patches, + .npatches = ARRAY_SIZE(upboard_up_reg_patches), +}; + +/* + * UP^2 board data + */ + +#define UPBOARD_UP2_BIT_TO_PIN(r, id) (UPBOARD_BIT_TO_PIN(r, UPFPGA_UP2_##id)) + +#define UPBOARD_UP2_PIN_ANON(r, bit) \ + { \ + .number = UPBOARD_BIT_TO_PIN(r, bit), \ + } + +#define UPBOARD_UP2_PIN_NAME(r, id) \ + { \ + .number = UPBOARD_UP2_BIT_TO_PIN(r, id), \ + .name = #id, \ + } + +#define UPBOARD_UP2_PIN_FUNC(r, id, data) \ + { \ + .number = UPBOARD_UP2_BIT_TO_PIN(r, id), \ + .name = #id, \ + .drv_data = (void *)(data), \ + } + +enum upboard_up2_reg0_fpgabit { + UPFPGA_UP2_UART1_TXD, + UPFPGA_UP2_UART1_RXD, + UPFPGA_UP2_UART1_RTS, + UPFPGA_UP2_UART1_CTS, + UPFPGA_UP2_GPIO3, + UPFPGA_UP2_GPIO5, + UPFPGA_UP2_GPIO6, + UPFPGA_UP2_GPIO11, + UPFPGA_UP2_EXHAT_LVDS1n, + UPFPGA_UP2_EXHAT_LVDS1p, + UPFPGA_UP2_SPI2_TXD, + UPFPGA_UP2_SPI2_RXD, + UPFPGA_UP2_SPI2_FS1, + UPFPGA_UP2_SPI2_FS0, + UPFPGA_UP2_SPI2_CLK, + UPFPGA_UP2_SPI1_TXD, +}; + +enum upboard_up2_reg1_fpgabit { + UPFPGA_UP2_SPI1_RXD, + UPFPGA_UP2_SPI1_FS1, + UPFPGA_UP2_SPI1_FS0, + UPFPGA_UP2_SPI1_CLK, + UPFPGA_UP2_BIT20, + UPFPGA_UP2_BIT21, + UPFPGA_UP2_BIT22, + UPFPGA_UP2_BIT23, + UPFPGA_UP2_PWM1, + UPFPGA_UP2_PWM0, + UPFPGA_UP2_EXHAT_LVDS0n, + UPFPGA_UP2_EXHAT_LVDS0p, + UPFPGA_UP2_I2C0_SCL, + UPFPGA_UP2_I2C0_SDA, + UPFPGA_UP2_I2C1_SCL, + UPFPGA_UP2_I2C1_SDA, +}; + +enum upboard_up2_reg2_fpgabit { + UPFPGA_UP2_EXHAT_LVDS3n, + UPFPGA_UP2_EXHAT_LVDS3p, + UPFPGA_UP2_EXHAT_LVDS4n, + UPFPGA_UP2_EXHAT_LVDS4p, + UPFPGA_UP2_EXHAT_LVDS5n, + UPFPGA_UP2_EXHAT_LVDS5p, + UPFPGA_UP2_I2S_SDO, + UPFPGA_UP2_I2S_SDI, + UPFPGA_UP2_I2S_WS_SYNC, + UPFPGA_UP2_I2S_BCLK, + UPFPGA_UP2_EXHAT_LVDS6n, + UPFPGA_UP2_EXHAT_LVDS6p, + UPFPGA_UP2_EXHAT_LVDS7n, + UPFPGA_UP2_EXHAT_LVDS7p, + UPFPGA_UP2_EXHAT_LVDS2n, + UPFPGA_UP2_EXHAT_LVDS2p, +}; + +static struct pinctrl_pin_desc upboard_up2_pins[] = { + UPBOARD_UP2_PIN_NAME(0, UART1_TXD), + UPBOARD_UP2_PIN_NAME(0, UART1_RXD), + UPBOARD_UP2_PIN_NAME(0, UART1_RTS), + UPBOARD_UP2_PIN_NAME(0, UART1_CTS), + UPBOARD_UP2_PIN_NAME(0, GPIO3), + UPBOARD_UP2_PIN_NAME(0, GPIO5), + UPBOARD_UP2_PIN_NAME(0, GPIO6), + UPBOARD_UP2_PIN_NAME(0, GPIO11), + UPBOARD_UP2_PIN_NAME(0, EXHAT_LVDS1n), + UPBOARD_UP2_PIN_NAME(0, EXHAT_LVDS1p), + UPBOARD_UP2_PIN_NAME(0, SPI2_TXD), + UPBOARD_UP2_PIN_NAME(0, SPI2_RXD), + UPBOARD_UP2_PIN_NAME(0, SPI2_FS1), + UPBOARD_UP2_PIN_NAME(0, SPI2_FS0), + UPBOARD_UP2_PIN_NAME(0, SPI2_CLK), + UPBOARD_UP2_PIN_NAME(0, SPI1_TXD), + UPBOARD_UP2_PIN_NAME(1, SPI1_RXD), + UPBOARD_UP2_PIN_NAME(1, SPI1_FS1), + UPBOARD_UP2_PIN_NAME(1, SPI1_FS0), + UPBOARD_UP2_PIN_NAME(1, SPI1_CLK), + UPBOARD_UP2_PIN_ANON(1, 4), + UPBOARD_UP2_PIN_ANON(1, 5), + UPBOARD_UP2_PIN_ANON(1, 6), + UPBOARD_UP2_PIN_ANON(1, 7), + UPBOARD_UP2_PIN_NAME(1, PWM1), + UPBOARD_UP2_PIN_NAME(1, PWM0), + UPBOARD_UP2_PIN_NAME(1, EXHAT_LVDS0n), + UPBOARD_UP2_PIN_NAME(1, EXHAT_LVDS0p), + UPBOARD_UP2_PIN_FUNC(1, I2C0_SCL, &upboard_i2c0_reg), + UPBOARD_UP2_PIN_FUNC(1, I2C0_SDA, &upboard_i2c0_reg), + UPBOARD_UP2_PIN_FUNC(1, I2C1_SCL, &upboard_i2c1_reg), + UPBOARD_UP2_PIN_FUNC(1, I2C1_SDA, &upboard_i2c1_reg), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS3n), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS3p), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS4n), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS4p), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS5n), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS5p), + UPBOARD_UP2_PIN_NAME(2, I2S_SDO), + UPBOARD_UP2_PIN_NAME(2, I2S_SDI), + UPBOARD_UP2_PIN_NAME(2, I2S_WS_SYNC), + UPBOARD_UP2_PIN_NAME(2, I2S_BCLK), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS6n), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS6p), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS7n), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS7p), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS2n), + UPBOARD_UP2_PIN_NAME(2, EXHAT_LVDS2p), +}; + +static const unsigned int upboard_up2_rpi_mapping[] = { + UPBOARD_UP2_BIT_TO_PIN(1, I2C0_SDA), + UPBOARD_UP2_BIT_TO_PIN(1, I2C0_SCL), + UPBOARD_UP2_BIT_TO_PIN(1, I2C1_SDA), + UPBOARD_UP2_BIT_TO_PIN(1, I2C1_SCL), + UPBOARD_UP2_BIT_TO_PIN(0, GPIO3), + UPBOARD_UP2_BIT_TO_PIN(0, GPIO11), + UPBOARD_UP2_BIT_TO_PIN(0, SPI2_CLK), + UPBOARD_UP2_BIT_TO_PIN(1, SPI1_FS1), + UPBOARD_UP2_BIT_TO_PIN(1, SPI1_FS0), + UPBOARD_UP2_BIT_TO_PIN(1, SPI1_RXD), + UPBOARD_UP2_BIT_TO_PIN(0, SPI1_TXD), + UPBOARD_UP2_BIT_TO_PIN(1, SPI1_CLK), + UPBOARD_UP2_BIT_TO_PIN(1, PWM0), + UPBOARD_UP2_BIT_TO_PIN(1, PWM1), + UPBOARD_UP2_BIT_TO_PIN(0, UART1_TXD), + UPBOARD_UP2_BIT_TO_PIN(0, UART1_RXD), + UPBOARD_UP2_BIT_TO_PIN(0, UART1_CTS), + UPBOARD_UP2_BIT_TO_PIN(0, UART1_RTS), + UPBOARD_UP2_BIT_TO_PIN(2, I2S_BCLK), + UPBOARD_UP2_BIT_TO_PIN(2, I2S_WS_SYNC), + UPBOARD_UP2_BIT_TO_PIN(2, I2S_SDI), + UPBOARD_UP2_BIT_TO_PIN(2, I2S_SDO), + UPBOARD_UP2_BIT_TO_PIN(0, GPIO6), + UPBOARD_UP2_BIT_TO_PIN(0, SPI2_FS1), + UPBOARD_UP2_BIT_TO_PIN(0, SPI2_RXD), + UPBOARD_UP2_BIT_TO_PIN(0, SPI2_TXD), + UPBOARD_UP2_BIT_TO_PIN(0, SPI2_FS0), + UPBOARD_UP2_BIT_TO_PIN(0, GPIO5), +}; + +/* + * Init patches applied to the registers until the BIOS sets proper defaults + */ +static const struct reg_sequence upboard_up2_reg_patches[] __initconst = { + // enable I2C voltage-level shifters + { UPFPGA_REG_FUNC_EN0, + BIT(UPFPGA_I2C0_EN) | + BIT(UPFPGA_I2C1_EN) + }, + // HAT function pins initially set as inputs + { UPFPGA_REG_GPIO_DIR0, + BIT(UPFPGA_UP2_UART1_RXD) | + BIT(UPFPGA_UP2_UART1_CTS) + }, + { UPFPGA_REG_GPIO_DIR1, + BIT(UPFPGA_UP2_SPI1_RXD) + }, + // HAT function pins initially enabled (i.e. not hi-Z) + { UPFPGA_REG_GPIO_EN0, + BIT(UPFPGA_UP2_UART1_TXD) | + BIT(UPFPGA_UP2_UART1_RXD) | + BIT(UPFPGA_UP2_UART1_RTS) | + BIT(UPFPGA_UP2_UART1_CTS) | + BIT(UPFPGA_UP2_SPI1_TXD) + }, + { UPFPGA_REG_GPIO_EN1, + BIT(UPFPGA_UP2_SPI1_RXD) | + BIT(UPFPGA_UP2_SPI1_FS1) | + BIT(UPFPGA_UP2_SPI1_FS0) | + BIT(UPFPGA_UP2_SPI1_CLK) | + BIT(UPFPGA_UP2_PWM1) | + BIT(UPFPGA_UP2_PWM0) + }, +}; + +static const struct upboard_bios upboard_up2_bios_info_v0_3 __initconst = { + .patches = upboard_up2_reg_patches, + .npatches = ARRAY_SIZE(upboard_up2_reg_patches), +}; + +/* + * UP Core board + CREX carrier board data + */ + +#define UPBOARD_UPCORE_CREX_BIT_TO_PIN(r, id) \ + (UPBOARD_BIT_TO_PIN(r, UPFPGA_UPCORE_CREX_##id)) + +#define UPBOARD_UPCORE_CREX_PIN_ANON(r, bit) \ + { \ + .number = UPBOARD_BIT_TO_PIN(r, bit), \ + } + +#define UPBOARD_UPCORE_CREX_PIN_NAME(r, id) \ + { \ + .number = UPBOARD_UPCORE_CREX_BIT_TO_PIN(r, id), \ + .name = #id, \ + } + +#define UPBOARD_UPCORE_CREX_PIN_FUNC(r, id, data) \ + { \ + .number = UPBOARD_UPCORE_CREX_BIT_TO_PIN(r, id), \ + .name = #id, \ + .drv_data = (void *)(data), \ + } + +enum upboard_upcore_crex_reg1_fpgabit { + UPFPGA_UPCORE_CREX_I2C0_SDA, + UPFPGA_UPCORE_CREX_I2C0_SCL, + UPFPGA_UPCORE_CREX_I2C1_SDA, + UPFPGA_UPCORE_CREX_I2C1_SCL, + UPFPGA_UPCORE_CREX_SPI2_CS0, + UPFPGA_UPCORE_CREX_SPI2_CS1, + UPFPGA_UPCORE_CREX_SPI2_MOSI, + UPFPGA_UPCORE_CREX_SPI2_MISO, + UPFPGA_UPCORE_CREX_SPI2_CLK, + UPFPGA_UPCORE_CREX_UART1_TXD, + UPFPGA_UPCORE_CREX_UART1_RXD, + UPFPGA_UPCORE_CREX_PWM0, + UPFPGA_UPCORE_CREX_PWM1, + UPFPGA_UPCORE_CREX_I2S2_FRM, + UPFPGA_UPCORE_CREX_I2S2_CLK, + UPFPGA_UPCORE_CREX_I2S2_RX, +}; + +enum upboard_upcore_crex_reg2_fpgabit { + UPFPGA_UPCORE_CREX_I2S2_TX, + UPFPGA_UPCORE_CREX_GPIO0, + UPFPGA_UPCORE_CREX_GPIO2, + UPFPGA_UPCORE_CREX_GPIO3, + UPFPGA_UPCORE_CREX_GPIO4, + UPFPGA_UPCORE_CREX_GPIO9, +}; + +static struct pinctrl_pin_desc upboard_upcore_crex_pins[] = { + UPBOARD_UPCORE_CREX_PIN_FUNC(0, I2C0_SDA, &upboard_i2c0_reg), + UPBOARD_UPCORE_CREX_PIN_FUNC(0, I2C0_SCL, &upboard_i2c0_reg), + UPBOARD_UPCORE_CREX_PIN_FUNC(0, I2C1_SDA, &upboard_i2c1_reg), + UPBOARD_UPCORE_CREX_PIN_FUNC(0, I2C1_SCL, &upboard_i2c1_reg), + UPBOARD_UPCORE_CREX_PIN_NAME(0, SPI2_CS0), + UPBOARD_UPCORE_CREX_PIN_NAME(0, SPI2_CS1), + UPBOARD_UPCORE_CREX_PIN_NAME(0, SPI2_MOSI), + UPBOARD_UPCORE_CREX_PIN_NAME(0, SPI2_MISO), + UPBOARD_UPCORE_CREX_PIN_NAME(0, SPI2_CLK), + UPBOARD_UPCORE_CREX_PIN_NAME(0, UART1_TXD), + UPBOARD_UPCORE_CREX_PIN_NAME(0, UART1_RXD), + UPBOARD_UPCORE_CREX_PIN_NAME(0, PWM0), + UPBOARD_UPCORE_CREX_PIN_NAME(0, PWM1), + UPBOARD_UPCORE_CREX_PIN_NAME(0, I2S2_FRM), + UPBOARD_UPCORE_CREX_PIN_NAME(0, I2S2_CLK), + UPBOARD_UPCORE_CREX_PIN_NAME(0, I2S2_RX), + /* register 1 */ + UPBOARD_UPCORE_CREX_PIN_NAME(1, I2S2_TX), + UPBOARD_UPCORE_CREX_PIN_NAME(1, GPIO0), + UPBOARD_UPCORE_CREX_PIN_FUNC(1, GPIO2, &upboard_adc0_reg), + UPBOARD_UPCORE_CREX_PIN_NAME(1, GPIO3), + UPBOARD_UPCORE_CREX_PIN_NAME(1, GPIO4), + UPBOARD_UPCORE_CREX_PIN_NAME(1, GPIO9), +}; + +static unsigned int upboard_upcore_crex_rpi_mapping[] = { + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2C0_SDA), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2C0_SCL), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2C1_SDA), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2C1_SCL), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(1, GPIO0), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(1, GPIO2), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(1, GPIO3), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, SPI2_CS1), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, SPI2_CS0), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, SPI2_MISO), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, SPI2_MOSI), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, SPI2_CLK), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, PWM0), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, PWM1), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, UART1_TXD), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, UART1_RXD), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(1, GPIO9), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(1, GPIO4), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2S2_CLK), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2S2_FRM), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(0, I2S2_RX), + UPBOARD_UPCORE_CREX_BIT_TO_PIN(1, I2S2_TX), +}; + +/* + * Init patches applied to the registers until the BIOS sets proper defaults + */ +static const struct reg_sequence upboard_upcore_crex_reg_patches[] __initconst = { + // enable I2C voltage-level shifters + { UPFPGA_REG_FUNC_EN0, + BIT(UPFPGA_I2C0_EN) | + BIT(UPFPGA_I2C1_EN) + }, + // HAT function pins initially set as inputs + { UPFPGA_REG_GPIO_DIR0, + BIT(UPFPGA_UPCORE_CREX_SPI2_MISO) | + BIT(UPFPGA_UPCORE_CREX_UART1_RXD) | + BIT(UPFPGA_UPCORE_CREX_I2S2_FRM) | + BIT(UPFPGA_UPCORE_CREX_I2S2_CLK) | + BIT(UPFPGA_UPCORE_CREX_I2S2_RX) + }, +}; + +static const struct upboard_bios upboard_upcore_crex_bios_info __initconst = { + .patches = upboard_upcore_crex_reg_patches, + .npatches = ARRAY_SIZE(upboard_upcore_crex_reg_patches), +}; + +/* + * UP Core board + CRST02 carrier board data + */ + +#define upboard_upcore_crst02_pins upboard_upcore_crex_pins +#define upboard_upcore_crst02_rpi_mapping upboard_upcore_crex_rpi_mapping + +/* + * Init patches applied to the registers until the BIOS sets proper defaults + */ +static const struct reg_sequence upboard_upcore_crst02_reg_patches[] __initconst = { + // enable I2C voltage-level shifters + { UPFPGA_REG_FUNC_EN0, + BIT(UPFPGA_I2C0_EN) | + BIT(UPFPGA_I2C1_EN) + }, + // HAT function pins initially set as inputs + { UPFPGA_REG_GPIO_DIR0, + BIT(UPFPGA_UPCORE_CREX_SPI2_MISO) | + BIT(UPFPGA_UPCORE_CREX_UART1_RXD) | + BIT(UPFPGA_UPCORE_CREX_I2S2_FRM) | + BIT(UPFPGA_UPCORE_CREX_I2S2_CLK) | + BIT(UPFPGA_UPCORE_CREX_I2S2_RX) + }, + // HAT function pins initially enabled (i.e. not hi-Z) + { UPFPGA_REG_GPIO_EN0, + BIT(UPFPGA_UPCORE_CREX_SPI2_CS0) | + BIT(UPFPGA_UPCORE_CREX_SPI2_MOSI) | + BIT(UPFPGA_UPCORE_CREX_SPI2_MISO) | + BIT(UPFPGA_UPCORE_CREX_SPI2_CLK) | + BIT(UPFPGA_UPCORE_CREX_UART1_TXD) | + BIT(UPFPGA_UPCORE_CREX_UART1_RXD) | + BIT(UPFPGA_UPCORE_CREX_PWM0) | + BIT(UPFPGA_UPCORE_CREX_PWM1) | + BIT(UPFPGA_UPCORE_CREX_I2S2_FRM) | + BIT(UPFPGA_UPCORE_CREX_I2S2_CLK) | + BIT(UPFPGA_UPCORE_CREX_I2S2_RX) + }, + { UPFPGA_REG_GPIO_EN1, + BIT(UPFPGA_UPCORE_CREX_I2S2_TX) + }, +}; + +static const struct upboard_bios upboard_upcore_crst02_bios_info __initconst = { + .patches = upboard_upcore_crst02_reg_patches, + .npatches = ARRAY_SIZE(upboard_upcore_crst02_reg_patches), +}; + +static int upboard_set_mux(struct pinctrl_dev *pctldev, unsigned int function, + unsigned int group) +{ + return 0; +}; + +static int upboard_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + const struct pin_desc * const pd = pin_desc_get(pctldev, pin); + const struct upboard_pin *p; + int ret; + + if (!pd) + return -EINVAL; + p = pd->drv_data; + + if (p->funcbit) { + ret = regmap_field_write(p->funcbit, 0); + if (ret) + return ret; + } + + if (p->enbit) { + ret = regmap_field_write(p->enbit, 1); + if (ret) + return ret; + } + + return 0; +}; + +static int upboard_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + const struct pin_desc * const pd = pin_desc_get(pctldev, pin); + const struct upboard_pin *p; + + if (!pd) + return -EINVAL; + p = pd->drv_data; + + return regmap_field_write(p->dirbit, input); +}; + +static int upboard_get_functions_count(struct pinctrl_dev *pctldev) +{ + return 0; +} + +static const char *upboard_get_function_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return NULL; +} + +static int upboard_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int *num_groups) +{ + *groups = NULL; + *num_groups = 0; + return 0; +} + +static const struct pinmux_ops upboard_pinmux_ops = { + .get_functions_count = upboard_get_functions_count, + .get_function_groups = upboard_get_function_groups, + .get_function_name = upboard_get_function_name, + .set_mux = upboard_set_mux, + .gpio_request_enable = upboard_gpio_request_enable, + .gpio_set_direction = upboard_gpio_set_direction, +}; + +static int upboard_get_groups_count(struct pinctrl_dev *pctldev) +{ + return 0; +} + +static const char *upboard_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return NULL; +} + +static const struct pinctrl_ops upboard_pinctrl_ops = { + .get_groups_count = upboard_get_groups_count, + .get_group_name = upboard_get_group_name, +}; + +static struct pinctrl_desc upboard_up_pinctrl_desc = { + .pins = upboard_up_pins, + .npins = ARRAY_SIZE(upboard_up_pins), + .pctlops = &upboard_pinctrl_ops, + .pmxops = &upboard_pinmux_ops, + .owner = THIS_MODULE, +}; + +static struct pinctrl_desc upboard_up2_pinctrl_desc = { + .pins = upboard_up2_pins, + .npins = ARRAY_SIZE(upboard_up2_pins), + .pctlops = &upboard_pinctrl_ops, + .pmxops = &upboard_pinmux_ops, + .owner = THIS_MODULE, +}; + +static struct pinctrl_desc upboard_upcore_crex_pinctrl_desc = { + .pins = upboard_upcore_crex_pins, + .npins = ARRAY_SIZE(upboard_upcore_crex_pins), + .pctlops = &upboard_pinctrl_ops, + .pmxops = &upboard_pinmux_ops, + .owner = THIS_MODULE, +}; + +static struct pinctrl_desc upboard_upcore_crst02_pinctrl_desc = { + .pins = upboard_upcore_crst02_pins, + .npins = ARRAY_SIZE(upboard_upcore_crst02_pins), + .pctlops = &upboard_pinctrl_ops, + .pmxops = &upboard_pinmux_ops, + .owner = THIS_MODULE, +}; + + +static int upboard_rpi_to_native_gpio(struct gpio_chip *gc, unsigned int gpio) +{ + struct upboard_pinctrl *pctrl = + container_of(gc, struct upboard_pinctrl, chip); + unsigned int pin = pctrl->rpi_mapping[gpio]; + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(pctrl->pctldev, pin); + + if (!range) + return -ENODEV; + + return range->base; +} + +static int upboard_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + int gpio = upboard_rpi_to_native_gpio(gc, offset); + + if (gpio < 0) + return gpio; + + return gpio_request(gpio, module_name(THIS_MODULE)); +} + +static void upboard_gpio_free(struct gpio_chip *gc, unsigned int offset) +{ + int gpio = upboard_rpi_to_native_gpio(gc, offset); + + if (gpio < 0) + return; + + gpio_free(gpio); +} + +static int upboard_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + int gpio = upboard_rpi_to_native_gpio(gc, offset); + + if (gpio < 0) + return gpio; + + return gpio_get_value(gpio); +} + +static void upboard_gpio_set(struct gpio_chip *gc, unsigned int offset, int + value) +{ + int gpio = upboard_rpi_to_native_gpio(gc, offset); + + if (gpio < 0) + return; + + gpio_set_value(gpio, value); +} + +static int upboard_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + int gpio = upboard_rpi_to_native_gpio(gc, offset); + + if (gpio < 0) + return gpio; + + return gpio_direction_input(gpio); +} + +static int upboard_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int value) +{ + int gpio = upboard_rpi_to_native_gpio(gc, offset); + + if (gpio < 0) + return gpio; + + return gpio_direction_output(gpio, value); +} + +static struct gpio_chip upboard_gpio_chip = { + .label = "Raspberry Pi compatible UP GPIO", + .base = 0, + .request = upboard_gpio_request, + .free = upboard_gpio_free, + .get = upboard_gpio_get, + .set = upboard_gpio_set, + .direction_input = upboard_gpio_direction_input, + .direction_output = upboard_gpio_direction_output, + .owner = THIS_MODULE, +}; + +/* DMI Matches for older bios without fpga initialization */ +static const struct dmi_system_id upboard_dmi_table[] __initconst = { + { + .matches = { /* UP */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "UP-CHT01"), + DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V0.4"), + }, + .driver_data = (void *)&upboard_up_bios_info_dvt, + }, + { + .matches = { /* UP2 */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "UP-APL01"), + DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V0.3"), + }, + .driver_data = (void *)&upboard_up2_bios_info_v0_3, + }, + { }, +}; + +static int __init upboard_pinctrl_probe(struct platform_device *pdev) +{ + struct upboard_fpga * const fpga = dev_get_drvdata(pdev->dev.parent); + struct acpi_device * const adev = ACPI_COMPANION(&pdev->dev); + struct pinctrl_desc *pctldesc; + const struct upboard_bios *bios_info = NULL; + struct upboard_pinctrl *pctrl; + struct upboard_pin *pins; + const struct dmi_system_id *system_id; + const char *hid; + const unsigned int *rpi_mapping; + unsigned int ngpio; + int ret; + int i; + + if (!fpga) + return -EINVAL; + + if (!adev) + return -ENODEV; + + hid = acpi_device_hid(adev); + if (!strcmp(hid, "AANT0F00") || !strcmp(hid, "AANT0F04")) { + pctldesc = &upboard_up_pinctrl_desc; + rpi_mapping = upboard_up_rpi_mapping; + ngpio = ARRAY_SIZE(upboard_up_rpi_mapping); + } else if (!strcmp(hid, "AANT0F01")) { + pctldesc = &upboard_up2_pinctrl_desc; + rpi_mapping = upboard_up2_rpi_mapping; + ngpio = ARRAY_SIZE(upboard_up2_rpi_mapping); + } else if (!strcmp(hid, "AANT0F02")) { + pctldesc = &upboard_upcore_crex_pinctrl_desc; + rpi_mapping = upboard_upcore_crex_rpi_mapping; + ngpio = ARRAY_SIZE(upboard_upcore_crex_rpi_mapping); + bios_info = &upboard_upcore_crex_bios_info; + } else if (!strcmp(hid, "AANT0F03")) { + pctldesc = &upboard_upcore_crst02_pinctrl_desc; + rpi_mapping = upboard_upcore_crst02_rpi_mapping; + ngpio = ARRAY_SIZE(upboard_upcore_crst02_rpi_mapping); + bios_info = &upboard_upcore_crst02_bios_info; + } else + return -ENODEV; + + pctldesc->name = dev_name(&pdev->dev); + + pins = devm_kzalloc(&pdev->dev, + sizeof(*pins) * pctldesc->npins, + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + /* initialise pins */ + for (i = 0; i < pctldesc->npins; i++) { + struct upboard_pin *pin = &pins[i]; + struct pinctrl_pin_desc *pd = (struct pinctrl_pin_desc *) + &pctldesc->pins[i]; + struct reg_field fldconf = {0}; + unsigned int regoff = (pd->number / UPFPGA_REGISTER_SIZE); + unsigned int lsb = pd->number % UPFPGA_REGISTER_SIZE; + + pin->funcbit = NULL; + if (pd->drv_data) { + fldconf = *(struct reg_field *)pd->drv_data; + if (!regmap_writeable(fpga->regmap, fldconf.reg)) + return -EINVAL; + + pin->funcbit = devm_regmap_field_alloc(&pdev->dev, + fpga->regmap, + fldconf); + if (IS_ERR(pin->funcbit)) + return PTR_ERR(pin->funcbit); + } + + pin->enbit = NULL; + fldconf.reg = UPFPGA_REG_GPIO_EN0 + regoff; + fldconf.lsb = lsb; + fldconf.msb = lsb; + + /* some platform don't have enable bit, ignore if not present */ + if (regmap_writeable(fpga->regmap, fldconf.reg)) { + pin->enbit = devm_regmap_field_alloc(&pdev->dev, + fpga->regmap, + fldconf); + if (IS_ERR(pin->enbit)) + return PTR_ERR(pin->enbit); + } + + fldconf.reg = UPFPGA_REG_GPIO_DIR0 + regoff; + fldconf.lsb = lsb; + fldconf.msb = lsb; + + if (!regmap_writeable(fpga->regmap, fldconf.reg)) + return -EINVAL; + + pin->dirbit = devm_regmap_field_alloc(&pdev->dev, + fpga->regmap, + fldconf); + if (IS_ERR(pin->dirbit)) + return PTR_ERR(pin->dirbit); + + pd->drv_data = pin; + } + + /* create a new pinctrl device and register it */ + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->regmap = fpga->regmap; + pctrl->rpi_mapping = rpi_mapping; + pctrl->chip = upboard_gpio_chip; + pctrl->chip.parent = &pdev->dev; + pctrl->chip.ngpio = ngpio; + + ret = devm_gpiochip_add_data(&pdev->dev, &pctrl->chip, &pctrl->chip); + if (ret) + return ret; + + pctrl->pctldev = devm_pinctrl_register(&pdev->dev, pctldesc, pctrl); + if (IS_ERR(pctrl->pctldev)) + return PTR_ERR(pctrl->pctldev); + + /* add acpi pin mapping according to external-gpios key */ + ret = acpi_node_add_pin_mapping(acpi_fwnode_handle(adev), + "external-gpios", + dev_name(&pdev->dev), + 0, UINT_MAX); + if (ret) + return ret; + + if (!bios_info) { + /* check for special board versions that require register patches */ + system_id = dmi_first_match(upboard_dmi_table); + if (system_id) + bios_info = system_id->driver_data; + } + + if (bios_info && bios_info->patches) { + ret = regmap_register_patch(pctrl->regmap, + bios_info->patches, + bios_info->npatches); + if (ret) + return ret; + } + + return 0; +} + +static struct platform_driver upboard_pinctrl_driver = { + .driver = { + .name = "upboard-pinctrl", + }, +}; + +module_platform_driver_probe(upboard_pinctrl_driver, upboard_pinctrl_probe); + +MODULE_AUTHOR("Javier Arteaga <javier@xxxxxxxxxx>"); +MODULE_AUTHOR("Dan O'Donovan <dan@xxxxxxxxxx>"); +MODULE_AUTHOR("Nicola Lunghi <nicolal@xxxxxxxxxx>"); +MODULE_DESCRIPTION("UP Board HAT pin controller driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:upboard-pinctrl"); -- 2.17.1