Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+228
View File
@@ -0,0 +1,228 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Broadcom pinctrl drivers
#
config PINCTRL_BCM281XX
bool "Broadcom BCM281xx pinctrl driver"
depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
select REGMAP_MMIO
default ARCH_BCM_MOBILE
help
Say Y here to support Broadcom BCM281xx pinctrl driver, which is used
for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351,
BCM28145, and BCM28155 SoCs. This driver requires the pinctrl
framework. GPIO is provided by a separate GPIO driver.
config PINCTRL_BCM2835
tristate "Broadcom BCM2835 GPIO (with PINCONF) driver"
depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
select GPIOLIB_IRQCHIP
default ARCH_BCM2835 || ARCH_BRCMSTB
help
Say Y here to enable the Broadcom BCM2835 GPIO driver.
config PINCTRL_BCM4908
tristate "Broadcom BCM4908 pinmux driver"
depends on OF && (ARCH_BCMBCA || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
default ARCH_BCMBCA
help
Driver for BCM4908 family SoCs with integrated pin controller.
If compiled as module it will be called pinctrl-bcm4908.
config PINCTRL_BCM63XX
bool
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
select REGMAP
select GPIO_REGMAP
config PINCTRL_BCM6318
bool "Broadcom BCM6318 GPIO driver"
depends on (BMIPS_GENERIC || COMPILE_TEST)
depends on OF
select PINCTRL_BCM63XX
default BMIPS_GENERIC
help
Say Y here to enable the Broadcom BCM6318 GPIO driver.
config PINCTRL_BCM6328
bool "Broadcom BCM6328 GPIO driver"
depends on (BMIPS_GENERIC || COMPILE_TEST)
depends on OF
select PINCTRL_BCM63XX
default BMIPS_GENERIC
help
Say Y here to enable the Broadcom BCM6328 GPIO driver.
config PINCTRL_BCM6358
bool "Broadcom BCM6358 GPIO driver"
depends on (BMIPS_GENERIC || COMPILE_TEST)
depends on OF
select PINCTRL_BCM63XX
default BMIPS_GENERIC
help
Say Y here to enable the Broadcom BCM6358 GPIO driver.
config PINCTRL_BCM6362
bool "Broadcom BCM6362 GPIO driver"
depends on (BMIPS_GENERIC || COMPILE_TEST)
depends on OF
select PINCTRL_BCM63XX
default BMIPS_GENERIC
help
Say Y here to enable the Broadcom BCM6362 GPIO driver.
config PINCTRL_BCM6368
bool "Broadcom BCM6368 GPIO driver"
depends on (BMIPS_GENERIC || COMPILE_TEST)
depends on OF
select PINCTRL_BCM63XX
default BMIPS_GENERIC
help
Say Y here to enable the Broadcom BCM6368 GPIO driver.
config PINCTRL_BCM63268
bool "Broadcom BCM63268 GPIO driver"
depends on (BMIPS_GENERIC || COMPILE_TEST)
depends on OF
select PINCTRL_BCM63XX
default BMIPS_GENERIC
help
Say Y here to enable the Broadcom BCM63268 GPIO driver.
config PINCTRL_BRCMSTB
tristate "Broadcom STB product line pin controller driver"
depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
help
Enable pin muxing and configuration functionality
for Broadcom STB product line chipsets.
source "drivers/pinctrl/bcm/Kconfig.stb"
config PINCTRL_IPROC_GPIO
bool "Broadcom iProc GPIO (with PINCONF) driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
select GPIOLIB_IRQCHIP
select PINCONF
select GENERIC_PINCONF
default ARCH_BCM_IPROC
help
Say yes here to enable the Broadcom iProc GPIO driver.
The Broadcom iProc based SoCs- Cygnus, NS2, NSP and Stingray, use
same GPIO Controller IP hence this driver could be used for all.
The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU
GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and
the always-ON GPIO controller (CRMU/AON). All 3 GPIO controllers are
supported by this driver.
The Broadcom NSP has two GPIO controllers including the ChipcommonA
GPIO, the ChipcommonB GPIO. Later controller is supported by this
driver.
The Broadcom NS2 has two GPIO controller including the CRMU GPIO,
the ChipcommonG GPIO. Both controllers are supported by this driver.
The Broadcom Stingray GPIO controllers are supported by this driver.
All above SoCs GPIO controllers support basic PINCONF functions such
as bias pull up, pull down, and drive strength configurations, when
these pins are muxed to GPIO.
It provides the framework where pins from the individual GPIO can be
individually muxed to GPIO function, through interaction with the
SoCs IOMUX controller. This features could be used only on SoCs which
support individual pin muxing.
config PINCTRL_CYGNUS_MUX
bool "Broadcom Cygnus IOMUX driver"
depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
depends on OF
select PINMUX
select GENERIC_PINCONF
default ARCH_BCM_CYGNUS
help
Say yes here to enable the Broadcom Cygnus IOMUX driver.
The Broadcom Cygnus IOMUX driver supports group based IOMUX
configuration, with the exception that certain individual pins
can be overridden to GPIO function
config PINCTRL_NS
bool "Broadcom Northstar pins driver"
depends on OF && (ARCH_BCM_5301X || COMPILE_TEST)
select PINMUX
select GENERIC_PINCONF
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
default ARCH_BCM_5301X
help
Say yes here to enable the Broadcom NS SoC pins driver.
The Broadcom Northstar pins driver supports muxing multi-purpose pins
that can be used for various functions (e.g. SPI, I2C, UART) as well
as GPIOs.
config PINCTRL_NSP_GPIO
bool "Broadcom NSP GPIO (with PINCONF) driver"
depends on ARCH_BCM_NSP || COMPILE_TEST
select GPIOLIB_IRQCHIP
select PINCONF
select GENERIC_PINCONF
default ARCH_BCM_NSP
help
Say yes here to enable the Broadcom NSP GPIO driver.
The Broadcom Northstar Plus SoC ChipcommonA GPIO controller is
supported by this driver.
The ChipcommonA GPIO controller support basic PINCONF functions such
as bias pull up, pull down, and drive strength configurations, when
these pins are muxed to GPIO.
config PINCTRL_NS2_MUX
bool "Broadcom Northstar2 pinmux driver"
depends on OF
depends on ARCH_BCM_IPROC || COMPILE_TEST
select PINMUX
select GENERIC_PINCONF
default ARM64 && ARCH_BCM_IPROC
help
Say yes here to enable the Broadcom NS2 MUX driver.
The Broadcom Northstar2 IOMUX driver supports group based IOMUX
configuration.
config PINCTRL_NSP_MUX
bool "Broadcom NSP IOMUX driver"
depends on (ARCH_BCM_NSP || COMPILE_TEST)
depends on OF
select PINMUX
select GENERIC_PINCONF
default ARCH_BCM_NSP
help
Say yes here to enable the Broadcom NSP SOC IOMUX driver.
The Broadcom Northstar Plus IOMUX driver supports pin based IOMUX
configuration, with certain individual pins can be overridden
to GPIO function.
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
if PINCTRL_BRCMSTB
config PINCTRL_BCM2712
tristate "BCM2712 SoC pin controller driver"
help
Driver for BCM2712 integrated pin controller,
commonly found on Raspberry Pi 5.
endif
+21
View File
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0
# Broadcom pinctrl support
obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_BCM4908) += pinctrl-bcm4908.o
obj-$(CONFIG_PINCTRL_BCM63XX) += pinctrl-bcm63xx.o
obj-$(CONFIG_PINCTRL_BCM6318) += pinctrl-bcm6318.o
obj-$(CONFIG_PINCTRL_BCM6328) += pinctrl-bcm6328.o
obj-$(CONFIG_PINCTRL_BCM6358) += pinctrl-bcm6358.o
obj-$(CONFIG_PINCTRL_BCM6362) += pinctrl-bcm6362.o
obj-$(CONFIG_PINCTRL_BCM6368) += pinctrl-bcm6368.o
obj-$(CONFIG_PINCTRL_BCM63268) += pinctrl-bcm63268.o
obj-$(CONFIG_PINCTRL_BRCMSTB) += pinctrl-brcmstb.o
obj-$(CONFIG_PINCTRL_BCM2712) += pinctrl-brcmstb-bcm2712.o
obj-$(CONFIG_PINCTRL_IPROC_GPIO) += pinctrl-iproc-gpio.o
obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o
obj-$(CONFIG_PINCTRL_NS) += pinctrl-ns.o
obj-$(CONFIG_PINCTRL_NSP_GPIO) += pinctrl-nsp-gpio.o
obj-$(CONFIG_PINCTRL_NS2_MUX) += pinctrl-ns2-mux.o
obj-$(CONFIG_PINCTRL_NSP_MUX) += pinctrl-nsp-mux.o
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,563 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> */
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include "../core.h"
#include "../pinmux.h"
#define BCM4908_NUM_PINS 86
#define BCM4908_TEST_PORT_BLOCK_EN_LSB 0x00
#define BCM4908_TEST_PORT_BLOCK_DATA_MSB 0x04
#define BCM4908_TEST_PORT_BLOCK_DATA_LSB 0x08
#define BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT 12
#define BCM4908_TEST_PORT_COMMAND 0x0c
#define BCM4908_TEST_PORT_CMD_LOAD_MUX_REG 0x00000021
struct bcm4908_pinctrl {
struct device *dev;
void __iomem *base;
struct mutex mutex;
struct pinctrl_dev *pctldev;
struct pinctrl_desc pctldesc;
};
/*
* Groups
*/
struct bcm4908_pinctrl_pin_setup {
unsigned int number;
unsigned int function;
};
static const struct bcm4908_pinctrl_pin_setup led_0_pins_a[] = {
{ 0, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_1_pins_a[] = {
{ 1, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_2_pins_a[] = {
{ 2, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_3_pins_a[] = {
{ 3, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_4_pins_a[] = {
{ 4, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_5_pins_a[] = {
{ 5, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_6_pins_a[] = {
{ 6, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_7_pins_a[] = {
{ 7, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_8_pins_a[] = {
{ 8, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_9_pins_a[] = {
{ 9, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_10_pins_a[] = {
{ 10, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_11_pins_a[] = {
{ 11, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_12_pins_a[] = {
{ 12, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_13_pins_a[] = {
{ 13, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_14_pins_a[] = {
{ 14, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_15_pins_a[] = {
{ 15, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_16_pins_a[] = {
{ 16, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_17_pins_a[] = {
{ 17, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_18_pins_a[] = {
{ 18, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_19_pins_a[] = {
{ 19, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_20_pins_a[] = {
{ 20, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_21_pins_a[] = {
{ 21, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_22_pins_a[] = {
{ 22, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_23_pins_a[] = {
{ 23, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_24_pins_a[] = {
{ 24, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_25_pins_a[] = {
{ 25, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_26_pins_a[] = {
{ 26, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_27_pins_a[] = {
{ 27, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_28_pins_a[] = {
{ 28, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_29_pins_a[] = {
{ 29, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_30_pins_a[] = {
{ 30, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_31_pins_a[] = {
{ 31, 3 },
};
static const struct bcm4908_pinctrl_pin_setup led_10_pins_b[] = {
{ 8, 2 },
};
static const struct bcm4908_pinctrl_pin_setup led_11_pins_b[] = {
{ 9, 2 },
};
static const struct bcm4908_pinctrl_pin_setup led_12_pins_b[] = {
{ 0, 2 },
};
static const struct bcm4908_pinctrl_pin_setup led_13_pins_b[] = {
{ 1, 2 },
};
static const struct bcm4908_pinctrl_pin_setup led_31_pins_b[] = {
{ 30, 2 },
};
static const struct bcm4908_pinctrl_pin_setup hs_uart_pins[] = {
{ 10, 0 }, /* CTS */
{ 11, 0 }, /* RTS */
{ 12, 0 }, /* RXD */
{ 13, 0 }, /* TXD */
};
static const struct bcm4908_pinctrl_pin_setup i2c_pins_a[] = {
{ 18, 0 }, /* SDA */
{ 19, 0 }, /* SCL */
};
static const struct bcm4908_pinctrl_pin_setup i2c_pins_b[] = {
{ 22, 0 }, /* SDA */
{ 23, 0 }, /* SCL */
};
static const struct bcm4908_pinctrl_pin_setup i2s_pins[] = {
{ 27, 0 }, /* MCLK */
{ 28, 0 }, /* LRCK */
{ 29, 0 }, /* SDATA */
{ 30, 0 }, /* SCLK */
};
static const struct bcm4908_pinctrl_pin_setup nand_ctrl_pins[] = {
{ 32, 0 },
{ 33, 0 },
{ 34, 0 },
{ 43, 0 },
{ 44, 0 },
{ 45, 0 },
{ 56, 1 },
};
static const struct bcm4908_pinctrl_pin_setup nand_data_pins[] = {
{ 35, 0 },
{ 36, 0 },
{ 37, 0 },
{ 38, 0 },
{ 39, 0 },
{ 40, 0 },
{ 41, 0 },
{ 42, 0 },
};
static const struct bcm4908_pinctrl_pin_setup emmc_ctrl_pins[] = {
{ 46, 0 },
{ 47, 0 },
};
static const struct bcm4908_pinctrl_pin_setup usb0_pwr_pins[] = {
{ 63, 0 },
{ 64, 0 },
};
static const struct bcm4908_pinctrl_pin_setup usb1_pwr_pins[] = {
{ 66, 0 },
{ 67, 0 },
};
struct bcm4908_pinctrl_grp {
const char *name;
const struct bcm4908_pinctrl_pin_setup *pins;
const unsigned int num_pins;
};
static const struct bcm4908_pinctrl_grp bcm4908_pinctrl_grps[] = {
{ "led_0_grp_a", led_0_pins_a, ARRAY_SIZE(led_0_pins_a) },
{ "led_1_grp_a", led_1_pins_a, ARRAY_SIZE(led_1_pins_a) },
{ "led_2_grp_a", led_2_pins_a, ARRAY_SIZE(led_2_pins_a) },
{ "led_3_grp_a", led_3_pins_a, ARRAY_SIZE(led_3_pins_a) },
{ "led_4_grp_a", led_4_pins_a, ARRAY_SIZE(led_4_pins_a) },
{ "led_5_grp_a", led_5_pins_a, ARRAY_SIZE(led_5_pins_a) },
{ "led_6_grp_a", led_6_pins_a, ARRAY_SIZE(led_6_pins_a) },
{ "led_7_grp_a", led_7_pins_a, ARRAY_SIZE(led_7_pins_a) },
{ "led_8_grp_a", led_8_pins_a, ARRAY_SIZE(led_8_pins_a) },
{ "led_9_grp_a", led_9_pins_a, ARRAY_SIZE(led_9_pins_a) },
{ "led_10_grp_a", led_10_pins_a, ARRAY_SIZE(led_10_pins_a) },
{ "led_11_grp_a", led_11_pins_a, ARRAY_SIZE(led_11_pins_a) },
{ "led_12_grp_a", led_12_pins_a, ARRAY_SIZE(led_12_pins_a) },
{ "led_13_grp_a", led_13_pins_a, ARRAY_SIZE(led_13_pins_a) },
{ "led_14_grp_a", led_14_pins_a, ARRAY_SIZE(led_14_pins_a) },
{ "led_15_grp_a", led_15_pins_a, ARRAY_SIZE(led_15_pins_a) },
{ "led_16_grp_a", led_16_pins_a, ARRAY_SIZE(led_16_pins_a) },
{ "led_17_grp_a", led_17_pins_a, ARRAY_SIZE(led_17_pins_a) },
{ "led_18_grp_a", led_18_pins_a, ARRAY_SIZE(led_18_pins_a) },
{ "led_19_grp_a", led_19_pins_a, ARRAY_SIZE(led_19_pins_a) },
{ "led_20_grp_a", led_20_pins_a, ARRAY_SIZE(led_20_pins_a) },
{ "led_21_grp_a", led_21_pins_a, ARRAY_SIZE(led_21_pins_a) },
{ "led_22_grp_a", led_22_pins_a, ARRAY_SIZE(led_22_pins_a) },
{ "led_23_grp_a", led_23_pins_a, ARRAY_SIZE(led_23_pins_a) },
{ "led_24_grp_a", led_24_pins_a, ARRAY_SIZE(led_24_pins_a) },
{ "led_25_grp_a", led_25_pins_a, ARRAY_SIZE(led_25_pins_a) },
{ "led_26_grp_a", led_26_pins_a, ARRAY_SIZE(led_26_pins_a) },
{ "led_27_grp_a", led_27_pins_a, ARRAY_SIZE(led_27_pins_a) },
{ "led_28_grp_a", led_28_pins_a, ARRAY_SIZE(led_28_pins_a) },
{ "led_29_grp_a", led_29_pins_a, ARRAY_SIZE(led_29_pins_a) },
{ "led_30_grp_a", led_30_pins_a, ARRAY_SIZE(led_30_pins_a) },
{ "led_31_grp_a", led_31_pins_a, ARRAY_SIZE(led_31_pins_a) },
{ "led_10_grp_b", led_10_pins_b, ARRAY_SIZE(led_10_pins_b) },
{ "led_11_grp_b", led_11_pins_b, ARRAY_SIZE(led_11_pins_b) },
{ "led_12_grp_b", led_12_pins_b, ARRAY_SIZE(led_12_pins_b) },
{ "led_13_grp_b", led_13_pins_b, ARRAY_SIZE(led_13_pins_b) },
{ "led_31_grp_b", led_31_pins_b, ARRAY_SIZE(led_31_pins_b) },
{ "hs_uart_grp", hs_uart_pins, ARRAY_SIZE(hs_uart_pins) },
{ "i2c_grp_a", i2c_pins_a, ARRAY_SIZE(i2c_pins_a) },
{ "i2c_grp_b", i2c_pins_b, ARRAY_SIZE(i2c_pins_b) },
{ "i2s_grp", i2s_pins, ARRAY_SIZE(i2s_pins) },
{ "nand_ctrl_grp", nand_ctrl_pins, ARRAY_SIZE(nand_ctrl_pins) },
{ "nand_data_grp", nand_data_pins, ARRAY_SIZE(nand_data_pins) },
{ "emmc_ctrl_grp", emmc_ctrl_pins, ARRAY_SIZE(emmc_ctrl_pins) },
{ "usb0_pwr_grp", usb0_pwr_pins, ARRAY_SIZE(usb0_pwr_pins) },
{ "usb1_pwr_grp", usb1_pwr_pins, ARRAY_SIZE(usb1_pwr_pins) },
};
/*
* Functions
*/
struct bcm4908_pinctrl_function {
const char *name;
const char * const *groups;
const unsigned int num_groups;
};
static const char * const led_0_groups[] = { "led_0_grp_a" };
static const char * const led_1_groups[] = { "led_1_grp_a" };
static const char * const led_2_groups[] = { "led_2_grp_a" };
static const char * const led_3_groups[] = { "led_3_grp_a" };
static const char * const led_4_groups[] = { "led_4_grp_a" };
static const char * const led_5_groups[] = { "led_5_grp_a" };
static const char * const led_6_groups[] = { "led_6_grp_a" };
static const char * const led_7_groups[] = { "led_7_grp_a" };
static const char * const led_8_groups[] = { "led_8_grp_a" };
static const char * const led_9_groups[] = { "led_9_grp_a" };
static const char * const led_10_groups[] = { "led_10_grp_a", "led_10_grp_b" };
static const char * const led_11_groups[] = { "led_11_grp_a", "led_11_grp_b" };
static const char * const led_12_groups[] = { "led_12_grp_a", "led_12_grp_b" };
static const char * const led_13_groups[] = { "led_13_grp_a", "led_13_grp_b" };
static const char * const led_14_groups[] = { "led_14_grp_a" };
static const char * const led_15_groups[] = { "led_15_grp_a" };
static const char * const led_16_groups[] = { "led_16_grp_a" };
static const char * const led_17_groups[] = { "led_17_grp_a" };
static const char * const led_18_groups[] = { "led_18_grp_a" };
static const char * const led_19_groups[] = { "led_19_grp_a" };
static const char * const led_20_groups[] = { "led_20_grp_a" };
static const char * const led_21_groups[] = { "led_21_grp_a" };
static const char * const led_22_groups[] = { "led_22_grp_a" };
static const char * const led_23_groups[] = { "led_23_grp_a" };
static const char * const led_24_groups[] = { "led_24_grp_a" };
static const char * const led_25_groups[] = { "led_25_grp_a" };
static const char * const led_26_groups[] = { "led_26_grp_a" };
static const char * const led_27_groups[] = { "led_27_grp_a" };
static const char * const led_28_groups[] = { "led_28_grp_a" };
static const char * const led_29_groups[] = { "led_29_grp_a" };
static const char * const led_30_groups[] = { "led_30_grp_a" };
static const char * const led_31_groups[] = { "led_31_grp_a", "led_31_grp_b" };
static const char * const hs_uart_groups[] = { "hs_uart_grp" };
static const char * const i2c_groups[] = { "i2c_grp_a", "i2c_grp_b" };
static const char * const i2s_groups[] = { "i2s_grp" };
static const char * const nand_ctrl_groups[] = { "nand_ctrl_grp" };
static const char * const nand_data_groups[] = { "nand_data_grp" };
static const char * const emmc_ctrl_groups[] = { "emmc_ctrl_grp" };
static const char * const usb0_pwr_groups[] = { "usb0_pwr_grp" };
static const char * const usb1_pwr_groups[] = { "usb1_pwr_grp" };
static const struct bcm4908_pinctrl_function bcm4908_pinctrl_functions[] = {
{ "led_0", led_0_groups, ARRAY_SIZE(led_0_groups) },
{ "led_1", led_1_groups, ARRAY_SIZE(led_1_groups) },
{ "led_2", led_2_groups, ARRAY_SIZE(led_2_groups) },
{ "led_3", led_3_groups, ARRAY_SIZE(led_3_groups) },
{ "led_4", led_4_groups, ARRAY_SIZE(led_4_groups) },
{ "led_5", led_5_groups, ARRAY_SIZE(led_5_groups) },
{ "led_6", led_6_groups, ARRAY_SIZE(led_6_groups) },
{ "led_7", led_7_groups, ARRAY_SIZE(led_7_groups) },
{ "led_8", led_8_groups, ARRAY_SIZE(led_8_groups) },
{ "led_9", led_9_groups, ARRAY_SIZE(led_9_groups) },
{ "led_10", led_10_groups, ARRAY_SIZE(led_10_groups) },
{ "led_11", led_11_groups, ARRAY_SIZE(led_11_groups) },
{ "led_12", led_12_groups, ARRAY_SIZE(led_12_groups) },
{ "led_13", led_13_groups, ARRAY_SIZE(led_13_groups) },
{ "led_14", led_14_groups, ARRAY_SIZE(led_14_groups) },
{ "led_15", led_15_groups, ARRAY_SIZE(led_15_groups) },
{ "led_16", led_16_groups, ARRAY_SIZE(led_16_groups) },
{ "led_17", led_17_groups, ARRAY_SIZE(led_17_groups) },
{ "led_18", led_18_groups, ARRAY_SIZE(led_18_groups) },
{ "led_19", led_19_groups, ARRAY_SIZE(led_19_groups) },
{ "led_20", led_20_groups, ARRAY_SIZE(led_20_groups) },
{ "led_21", led_21_groups, ARRAY_SIZE(led_21_groups) },
{ "led_22", led_22_groups, ARRAY_SIZE(led_22_groups) },
{ "led_23", led_23_groups, ARRAY_SIZE(led_23_groups) },
{ "led_24", led_24_groups, ARRAY_SIZE(led_24_groups) },
{ "led_25", led_25_groups, ARRAY_SIZE(led_25_groups) },
{ "led_26", led_26_groups, ARRAY_SIZE(led_26_groups) },
{ "led_27", led_27_groups, ARRAY_SIZE(led_27_groups) },
{ "led_28", led_28_groups, ARRAY_SIZE(led_28_groups) },
{ "led_29", led_29_groups, ARRAY_SIZE(led_29_groups) },
{ "led_30", led_30_groups, ARRAY_SIZE(led_30_groups) },
{ "led_31", led_31_groups, ARRAY_SIZE(led_31_groups) },
{ "hs_uart", hs_uart_groups, ARRAY_SIZE(hs_uart_groups) },
{ "i2c", i2c_groups, ARRAY_SIZE(i2c_groups) },
{ "i2s", i2s_groups, ARRAY_SIZE(i2s_groups) },
{ "nand_ctrl", nand_ctrl_groups, ARRAY_SIZE(nand_ctrl_groups) },
{ "nand_data", nand_data_groups, ARRAY_SIZE(nand_data_groups) },
{ "emmc_ctrl", emmc_ctrl_groups, ARRAY_SIZE(emmc_ctrl_groups) },
{ "usb0_pwr", usb0_pwr_groups, ARRAY_SIZE(usb0_pwr_groups) },
{ "usb1_pwr", usb1_pwr_groups, ARRAY_SIZE(usb1_pwr_groups) },
};
/*
* Groups code
*/
static const struct pinctrl_ops bcm4908_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,
.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
.dt_free_map = pinconf_generic_dt_free_map,
};
/*
* Functions code
*/
static int bcm4908_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
unsigned int func_selector,
unsigned int group_selector)
{
struct bcm4908_pinctrl *bcm4908_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
const struct bcm4908_pinctrl_grp *group;
struct group_desc *group_desc;
int i;
group_desc = pinctrl_generic_get_group(pctrl_dev, group_selector);
if (!group_desc)
return -EINVAL;
group = group_desc->data;
mutex_lock(&bcm4908_pinctrl->mutex);
for (i = 0; i < group->num_pins; i++) {
u32 lsb = 0;
lsb |= group->pins[i].number;
lsb |= group->pins[i].function << BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT;
writel(0x0, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_MSB);
writel(lsb, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_LSB);
writel(BCM4908_TEST_PORT_CMD_LOAD_MUX_REG,
bcm4908_pinctrl->base + BCM4908_TEST_PORT_COMMAND);
}
mutex_unlock(&bcm4908_pinctrl->mutex);
return 0;
}
static const struct pinmux_ops bcm4908_pinctrl_pmxops = {
.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 = bcm4908_pinctrl_set_mux,
};
/*
* Controller code
*/
static const struct pinctrl_desc bcm4908_pinctrl_desc = {
.name = "bcm4908-pinctrl",
.pctlops = &bcm4908_pinctrl_ops,
.pmxops = &bcm4908_pinctrl_pmxops,
};
static const struct of_device_id bcm4908_pinctrl_of_match_table[] = {
{ .compatible = "brcm,bcm4908-pinctrl", },
{ }
};
MODULE_DEVICE_TABLE(of, bcm4908_pinctrl_of_match_table);
static int bcm4908_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bcm4908_pinctrl *bcm4908_pinctrl;
struct pinctrl_desc *pctldesc;
struct pinctrl_pin_desc *pins;
char **pin_names;
int i;
bcm4908_pinctrl = devm_kzalloc(dev, sizeof(*bcm4908_pinctrl), GFP_KERNEL);
if (!bcm4908_pinctrl)
return -ENOMEM;
pctldesc = &bcm4908_pinctrl->pctldesc;
platform_set_drvdata(pdev, bcm4908_pinctrl);
/* Set basic properties */
bcm4908_pinctrl->dev = dev;
bcm4908_pinctrl->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bcm4908_pinctrl->base))
return PTR_ERR(bcm4908_pinctrl->base);
mutex_init(&bcm4908_pinctrl->mutex);
memcpy(pctldesc, &bcm4908_pinctrl_desc, sizeof(*pctldesc));
/* Set pinctrl properties */
pin_names = devm_kasprintf_strarray(dev, "pin", BCM4908_NUM_PINS);
if (IS_ERR(pin_names))
return PTR_ERR(pin_names);
pins = devm_kcalloc(dev, BCM4908_NUM_PINS, sizeof(*pins), GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (i = 0; i < BCM4908_NUM_PINS; i++) {
pins[i].number = i;
pins[i].name = pin_names[i];
}
pctldesc->pins = pins;
pctldesc->npins = BCM4908_NUM_PINS;
/* Register */
bcm4908_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, bcm4908_pinctrl);
if (IS_ERR(bcm4908_pinctrl->pctldev))
return dev_err_probe(dev, PTR_ERR(bcm4908_pinctrl->pctldev),
"Failed to register pinctrl\n");
/* Groups */
for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_grps); i++) {
const struct bcm4908_pinctrl_grp *group = &bcm4908_pinctrl_grps[i];
int *pins;
int j;
pins = devm_kcalloc(dev, group->num_pins, sizeof(*pins), GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (j = 0; j < group->num_pins; j++)
pins[j] = group->pins[j].number;
pinctrl_generic_add_group(bcm4908_pinctrl->pctldev, group->name,
pins, group->num_pins, (void *)group);
}
/* Functions */
for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_functions); i++) {
const struct bcm4908_pinctrl_function *function = &bcm4908_pinctrl_functions[i];
pinmux_generic_add_function(bcm4908_pinctrl->pctldev,
function->name,
function->groups,
function->num_groups, NULL);
}
return 0;
}
static struct platform_driver bcm4908_pinctrl_driver = {
.probe = bcm4908_pinctrl_probe,
.driver = {
.name = "bcm4908-pinctrl",
.of_match_table = bcm4908_pinctrl_of_match_table,
},
};
module_platform_driver(bcm4908_pinctrl_driver);
MODULE_AUTHOR("Rafał Miłecki");
MODULE_DESCRIPTION("Broadcom BCM4908 pinmux driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,485 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM6318 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl-utils.h"
#include "pinctrl-bcm63xx.h"
#define BCM6318_NUM_GPIOS 50
#define BCM6318_NUM_MUX 48
#define BCM6318_MODE_REG 0x18
#define BCM6318_MUX_REG 0x1c
#define BCM6328_MUX_MASK GENMASK(1, 0)
#define BCM6318_PAD_REG 0x54
#define BCM6328_PAD_MASK GENMASK(3, 0)
struct bcm6318_function {
const char *name;
const char * const *groups;
const unsigned num_groups;
unsigned mode_val:1;
unsigned mux_val:2;
};
static const struct pinctrl_pin_desc bcm6318_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
PINCTRL_PIN(2, "gpio2"),
PINCTRL_PIN(3, "gpio3"),
PINCTRL_PIN(4, "gpio4"),
PINCTRL_PIN(5, "gpio5"),
PINCTRL_PIN(6, "gpio6"),
PINCTRL_PIN(7, "gpio7"),
PINCTRL_PIN(8, "gpio8"),
PINCTRL_PIN(9, "gpio9"),
PINCTRL_PIN(10, "gpio10"),
PINCTRL_PIN(11, "gpio11"),
PINCTRL_PIN(12, "gpio12"),
PINCTRL_PIN(13, "gpio13"),
PINCTRL_PIN(14, "gpio14"),
PINCTRL_PIN(15, "gpio15"),
PINCTRL_PIN(16, "gpio16"),
PINCTRL_PIN(17, "gpio17"),
PINCTRL_PIN(18, "gpio18"),
PINCTRL_PIN(19, "gpio19"),
PINCTRL_PIN(20, "gpio20"),
PINCTRL_PIN(21, "gpio21"),
PINCTRL_PIN(22, "gpio22"),
PINCTRL_PIN(23, "gpio23"),
PINCTRL_PIN(24, "gpio24"),
PINCTRL_PIN(25, "gpio25"),
PINCTRL_PIN(26, "gpio26"),
PINCTRL_PIN(27, "gpio27"),
PINCTRL_PIN(28, "gpio28"),
PINCTRL_PIN(29, "gpio29"),
PINCTRL_PIN(30, "gpio30"),
PINCTRL_PIN(31, "gpio31"),
PINCTRL_PIN(32, "gpio32"),
PINCTRL_PIN(33, "gpio33"),
PINCTRL_PIN(34, "gpio34"),
PINCTRL_PIN(35, "gpio35"),
PINCTRL_PIN(36, "gpio36"),
PINCTRL_PIN(37, "gpio37"),
PINCTRL_PIN(38, "gpio38"),
PINCTRL_PIN(39, "gpio39"),
PINCTRL_PIN(40, "gpio40"),
PINCTRL_PIN(41, "gpio41"),
PINCTRL_PIN(42, "gpio42"),
PINCTRL_PIN(43, "gpio43"),
PINCTRL_PIN(44, "gpio44"),
PINCTRL_PIN(45, "gpio45"),
PINCTRL_PIN(46, "gpio46"),
PINCTRL_PIN(47, "gpio47"),
PINCTRL_PIN(48, "gpio48"),
PINCTRL_PIN(49, "gpio49"),
};
static unsigned gpio0_pins[] = { 0 };
static unsigned gpio1_pins[] = { 1 };
static unsigned gpio2_pins[] = { 2 };
static unsigned gpio3_pins[] = { 3 };
static unsigned gpio4_pins[] = { 4 };
static unsigned gpio5_pins[] = { 5 };
static unsigned gpio6_pins[] = { 6 };
static unsigned gpio7_pins[] = { 7 };
static unsigned gpio8_pins[] = { 8 };
static unsigned gpio9_pins[] = { 9 };
static unsigned gpio10_pins[] = { 10 };
static unsigned gpio11_pins[] = { 11 };
static unsigned gpio12_pins[] = { 12 };
static unsigned gpio13_pins[] = { 13 };
static unsigned gpio14_pins[] = { 14 };
static unsigned gpio15_pins[] = { 15 };
static unsigned gpio16_pins[] = { 16 };
static unsigned gpio17_pins[] = { 17 };
static unsigned gpio18_pins[] = { 18 };
static unsigned gpio19_pins[] = { 19 };
static unsigned gpio20_pins[] = { 20 };
static unsigned gpio21_pins[] = { 21 };
static unsigned gpio22_pins[] = { 22 };
static unsigned gpio23_pins[] = { 23 };
static unsigned gpio24_pins[] = { 24 };
static unsigned gpio25_pins[] = { 25 };
static unsigned gpio26_pins[] = { 26 };
static unsigned gpio27_pins[] = { 27 };
static unsigned gpio28_pins[] = { 28 };
static unsigned gpio29_pins[] = { 29 };
static unsigned gpio30_pins[] = { 30 };
static unsigned gpio31_pins[] = { 31 };
static unsigned gpio32_pins[] = { 32 };
static unsigned gpio33_pins[] = { 33 };
static unsigned gpio34_pins[] = { 34 };
static unsigned gpio35_pins[] = { 35 };
static unsigned gpio36_pins[] = { 36 };
static unsigned gpio37_pins[] = { 37 };
static unsigned gpio38_pins[] = { 38 };
static unsigned gpio39_pins[] = { 39 };
static unsigned gpio40_pins[] = { 40 };
static unsigned gpio41_pins[] = { 41 };
static unsigned gpio42_pins[] = { 42 };
static unsigned gpio43_pins[] = { 43 };
static unsigned gpio44_pins[] = { 44 };
static unsigned gpio45_pins[] = { 45 };
static unsigned gpio46_pins[] = { 46 };
static unsigned gpio47_pins[] = { 47 };
static unsigned gpio48_pins[] = { 48 };
static unsigned gpio49_pins[] = { 49 };
static struct pingroup bcm6318_groups[] = {
BCM_PIN_GROUP(gpio0),
BCM_PIN_GROUP(gpio1),
BCM_PIN_GROUP(gpio2),
BCM_PIN_GROUP(gpio3),
BCM_PIN_GROUP(gpio4),
BCM_PIN_GROUP(gpio5),
BCM_PIN_GROUP(gpio6),
BCM_PIN_GROUP(gpio7),
BCM_PIN_GROUP(gpio8),
BCM_PIN_GROUP(gpio9),
BCM_PIN_GROUP(gpio10),
BCM_PIN_GROUP(gpio11),
BCM_PIN_GROUP(gpio12),
BCM_PIN_GROUP(gpio13),
BCM_PIN_GROUP(gpio14),
BCM_PIN_GROUP(gpio15),
BCM_PIN_GROUP(gpio16),
BCM_PIN_GROUP(gpio17),
BCM_PIN_GROUP(gpio18),
BCM_PIN_GROUP(gpio19),
BCM_PIN_GROUP(gpio20),
BCM_PIN_GROUP(gpio21),
BCM_PIN_GROUP(gpio22),
BCM_PIN_GROUP(gpio23),
BCM_PIN_GROUP(gpio24),
BCM_PIN_GROUP(gpio25),
BCM_PIN_GROUP(gpio26),
BCM_PIN_GROUP(gpio27),
BCM_PIN_GROUP(gpio28),
BCM_PIN_GROUP(gpio29),
BCM_PIN_GROUP(gpio30),
BCM_PIN_GROUP(gpio31),
BCM_PIN_GROUP(gpio32),
BCM_PIN_GROUP(gpio33),
BCM_PIN_GROUP(gpio34),
BCM_PIN_GROUP(gpio35),
BCM_PIN_GROUP(gpio36),
BCM_PIN_GROUP(gpio37),
BCM_PIN_GROUP(gpio38),
BCM_PIN_GROUP(gpio39),
BCM_PIN_GROUP(gpio40),
BCM_PIN_GROUP(gpio41),
BCM_PIN_GROUP(gpio42),
BCM_PIN_GROUP(gpio43),
BCM_PIN_GROUP(gpio44),
BCM_PIN_GROUP(gpio45),
BCM_PIN_GROUP(gpio46),
BCM_PIN_GROUP(gpio47),
BCM_PIN_GROUP(gpio48),
BCM_PIN_GROUP(gpio49),
};
/* GPIO_MODE */
static const char * const led_groups[] = {
"gpio0",
"gpio1",
"gpio2",
"gpio3",
"gpio4",
"gpio5",
"gpio6",
"gpio7",
"gpio8",
"gpio9",
"gpio10",
"gpio11",
"gpio12",
"gpio13",
"gpio14",
"gpio15",
"gpio16",
"gpio17",
"gpio18",
"gpio19",
"gpio20",
"gpio21",
"gpio22",
"gpio23",
};
/* PINMUX_SEL */
static const char * const ephy0_spd_led_groups[] = {
"gpio0",
};
static const char * const ephy1_spd_led_groups[] = {
"gpio1",
};
static const char * const ephy2_spd_led_groups[] = {
"gpio2",
};
static const char * const ephy3_spd_led_groups[] = {
"gpio3",
};
static const char * const ephy0_act_led_groups[] = {
"gpio4",
};
static const char * const ephy1_act_led_groups[] = {
"gpio5",
};
static const char * const ephy2_act_led_groups[] = {
"gpio6",
};
static const char * const ephy3_act_led_groups[] = {
"gpio7",
};
static const char * const serial_led_data_groups[] = {
"gpio6",
};
static const char * const serial_led_clk_groups[] = {
"gpio7",
};
static const char * const inet_act_led_groups[] = {
"gpio8",
};
static const char * const inet_fail_led_groups[] = {
"gpio9",
};
static const char * const dsl_led_groups[] = {
"gpio10",
};
static const char * const post_fail_led_groups[] = {
"gpio11",
};
static const char * const wlan_wps_led_groups[] = {
"gpio12",
};
static const char * const usb_pwron_groups[] = {
"gpio13",
};
static const char * const usb_device_led_groups[] = {
"gpio13",
};
static const char * const usb_active_groups[] = {
"gpio40",
};
#define BCM6318_MODE_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.mode_val = 1, \
}
#define BCM6318_MUX_FUN(n, mux) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.mux_val = mux, \
}
static const struct bcm6318_function bcm6318_funcs[] = {
BCM6318_MODE_FUN(led),
BCM6318_MUX_FUN(ephy0_spd_led, 1),
BCM6318_MUX_FUN(ephy1_spd_led, 1),
BCM6318_MUX_FUN(ephy2_spd_led, 1),
BCM6318_MUX_FUN(ephy3_spd_led, 1),
BCM6318_MUX_FUN(ephy0_act_led, 1),
BCM6318_MUX_FUN(ephy1_act_led, 1),
BCM6318_MUX_FUN(ephy2_act_led, 1),
BCM6318_MUX_FUN(ephy3_act_led, 1),
BCM6318_MUX_FUN(serial_led_data, 3),
BCM6318_MUX_FUN(serial_led_clk, 3),
BCM6318_MUX_FUN(inet_act_led, 1),
BCM6318_MUX_FUN(inet_fail_led, 1),
BCM6318_MUX_FUN(dsl_led, 1),
BCM6318_MUX_FUN(post_fail_led, 1),
BCM6318_MUX_FUN(wlan_wps_led, 1),
BCM6318_MUX_FUN(usb_pwron, 1),
BCM6318_MUX_FUN(usb_device_led, 2),
BCM6318_MUX_FUN(usb_active, 2),
};
static inline unsigned int bcm6318_mux_off(unsigned int pin)
{
return BCM6318_MUX_REG + (pin / 16) * 4;
}
static inline unsigned int bcm6318_pad_off(unsigned int pin)
{
return BCM6318_PAD_REG + (pin / 8) * 4;
}
static int bcm6318_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6318_groups);
}
static const char *bcm6318_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned group)
{
return bcm6318_groups[group].name;
}
static int bcm6318_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned group, const unsigned **pins,
unsigned *npins)
{
*pins = bcm6318_groups[group].pins;
*npins = bcm6318_groups[group].npins;
return 0;
}
static int bcm6318_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6318_funcs);
}
static const char *bcm6318_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return bcm6318_funcs[selector].name;
}
static int bcm6318_pinctrl_get_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = bcm6318_funcs[selector].groups;
*num_groups = bcm6318_funcs[selector].num_groups;
return 0;
}
static inline void bcm6318_rmw_mux(struct bcm63xx_pinctrl *pc, unsigned pin,
unsigned int mode, unsigned int mux)
{
if (pin < BCM63XX_BANK_GPIOS)
regmap_update_bits(pc->regs, BCM6318_MODE_REG, BIT(pin),
mode ? BIT(pin) : 0);
if (pin < BCM6318_NUM_MUX)
regmap_update_bits(pc->regs,
bcm6318_mux_off(pin),
BCM6328_MUX_MASK << ((pin % 16) * 2),
mux << ((pin % 16) * 2));
}
static inline void bcm6318_set_pad(struct bcm63xx_pinctrl *pc, unsigned pin,
uint8_t val)
{
regmap_update_bits(pc->regs, bcm6318_pad_off(pin),
BCM6328_PAD_MASK << ((pin % 8) * 4),
val << ((pin % 8) * 4));
}
static int bcm6318_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned group)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
const struct pingroup *pg = &bcm6318_groups[group];
const struct bcm6318_function *f = &bcm6318_funcs[selector];
bcm6318_rmw_mux(pc, pg->pins[0], f->mode_val, f->mux_val);
return 0;
}
static int bcm6318_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* disable all functions using this pin */
if (offset < 13) {
/* GPIOs 0-12 use mux 0 as GPIO function */
bcm6318_rmw_mux(pc, offset, 0, 0);
} else if (offset < 42) {
/* GPIOs 13-41 use mux 3 as GPIO function */
bcm6318_rmw_mux(pc, offset, 0, 3);
bcm6318_set_pad(pc, offset, 0);
}
return 0;
}
static const struct pinctrl_ops bcm6318_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6318_pinctrl_get_group_name,
.get_group_pins = bcm6318_pinctrl_get_group_pins,
.get_groups_count = bcm6318_pinctrl_get_group_count,
};
static const struct pinmux_ops bcm6318_pmx_ops = {
.get_function_groups = bcm6318_pinctrl_get_groups,
.get_function_name = bcm6318_pinctrl_get_func_name,
.get_functions_count = bcm6318_pinctrl_get_func_count,
.gpio_request_enable = bcm6318_gpio_request_enable,
.set_mux = bcm6318_pinctrl_set_mux,
.strict = true,
};
static const struct bcm63xx_pinctrl_soc bcm6318_soc = {
.ngpios = BCM6318_NUM_GPIOS,
.npins = ARRAY_SIZE(bcm6318_pins),
.pctl_ops = &bcm6318_pctl_ops,
.pins = bcm6318_pins,
.pmx_ops = &bcm6318_pmx_ops,
};
static int bcm6318_pinctrl_probe(struct platform_device *pdev)
{
return bcm63xx_pinctrl_probe(pdev, &bcm6318_soc, NULL);
}
static const struct of_device_id bcm6318_pinctrl_match[] = {
{ .compatible = "brcm,bcm6318-pinctrl", },
{ /* sentinel */ }
};
static struct platform_driver bcm6318_pinctrl_driver = {
.probe = bcm6318_pinctrl_probe,
.driver = {
.name = "bcm6318-pinctrl",
.of_match_table = bcm6318_pinctrl_match,
},
};
builtin_platform_driver(bcm6318_pinctrl_driver);
@@ -0,0 +1,630 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM63268 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl-utils.h"
#include "pinctrl-bcm63xx.h"
#define BCM63268_NUM_GPIOS 52
#define BCM63268_NUM_LEDS 24
#define BCM63268_LED_REG 0x10
#define BCM63268_MODE_REG 0x18
#define BCM63268_CTRL_REG 0x1c
#define BCM63268_BASEMODE_REG 0x38
#define BCM63268_BASEMODE_NAND BIT(2) /* GPIOs 2-7, 24-31 */
#define BCM63268_BASEMODE_GPIO35 BIT(4) /* GPIO 35 */
#define BCM63268_BASEMODE_DECTPD BIT(5) /* GPIOs 8/9 */
#define BCM63268_BASEMODE_VDSL_PHY_0 BIT(6) /* GPIOs 10/11 */
#define BCM63268_BASEMODE_VDSL_PHY_1 BIT(7) /* GPIOs 12/13 */
#define BCM63268_BASEMODE_VDSL_PHY_2 BIT(8) /* GPIOs 24/25 */
#define BCM63268_BASEMODE_VDSL_PHY_3 BIT(9) /* GPIOs 26/27 */
enum bcm63268_pinctrl_reg {
BCM63268_LEDCTRL,
BCM63268_MODE,
BCM63268_CTRL,
BCM63268_BASEMODE,
};
struct bcm63268_function {
const char *name;
const char * const *groups;
const unsigned num_groups;
enum bcm63268_pinctrl_reg reg;
uint32_t mask;
};
#define BCM63268_PIN(a, b, basemode) \
{ \
.number = a, \
.name = b, \
.drv_data = (void *)(basemode) \
}
static const struct pinctrl_pin_desc bcm63268_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
BCM63268_PIN(2, "gpio2", BCM63268_BASEMODE_NAND),
BCM63268_PIN(3, "gpio3", BCM63268_BASEMODE_NAND),
BCM63268_PIN(4, "gpio4", BCM63268_BASEMODE_NAND),
BCM63268_PIN(5, "gpio5", BCM63268_BASEMODE_NAND),
BCM63268_PIN(6, "gpio6", BCM63268_BASEMODE_NAND),
BCM63268_PIN(7, "gpio7", BCM63268_BASEMODE_NAND),
BCM63268_PIN(8, "gpio8", BCM63268_BASEMODE_DECTPD),
BCM63268_PIN(9, "gpio9", BCM63268_BASEMODE_DECTPD),
BCM63268_PIN(10, "gpio10", BCM63268_BASEMODE_VDSL_PHY_0),
BCM63268_PIN(11, "gpio11", BCM63268_BASEMODE_VDSL_PHY_0),
BCM63268_PIN(12, "gpio12", BCM63268_BASEMODE_VDSL_PHY_1),
BCM63268_PIN(13, "gpio13", BCM63268_BASEMODE_VDSL_PHY_1),
PINCTRL_PIN(14, "gpio14"),
PINCTRL_PIN(15, "gpio15"),
PINCTRL_PIN(16, "gpio16"),
PINCTRL_PIN(17, "gpio17"),
PINCTRL_PIN(18, "gpio18"),
PINCTRL_PIN(19, "gpio19"),
PINCTRL_PIN(20, "gpio20"),
PINCTRL_PIN(21, "gpio21"),
PINCTRL_PIN(22, "gpio22"),
PINCTRL_PIN(23, "gpio23"),
BCM63268_PIN(24, "gpio24",
BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_2),
BCM63268_PIN(25, "gpio25",
BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_2),
BCM63268_PIN(26, "gpio26",
BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_3),
BCM63268_PIN(27, "gpio27",
BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_3),
BCM63268_PIN(28, "gpio28", BCM63268_BASEMODE_NAND),
BCM63268_PIN(29, "gpio29", BCM63268_BASEMODE_NAND),
BCM63268_PIN(30, "gpio30", BCM63268_BASEMODE_NAND),
BCM63268_PIN(31, "gpio31", BCM63268_BASEMODE_NAND),
PINCTRL_PIN(32, "gpio32"),
PINCTRL_PIN(33, "gpio33"),
PINCTRL_PIN(34, "gpio34"),
PINCTRL_PIN(35, "gpio35"),
PINCTRL_PIN(36, "gpio36"),
PINCTRL_PIN(37, "gpio37"),
PINCTRL_PIN(38, "gpio38"),
PINCTRL_PIN(39, "gpio39"),
PINCTRL_PIN(40, "gpio40"),
PINCTRL_PIN(41, "gpio41"),
PINCTRL_PIN(42, "gpio42"),
PINCTRL_PIN(43, "gpio43"),
PINCTRL_PIN(44, "gpio44"),
PINCTRL_PIN(45, "gpio45"),
PINCTRL_PIN(46, "gpio46"),
PINCTRL_PIN(47, "gpio47"),
PINCTRL_PIN(48, "gpio48"),
PINCTRL_PIN(49, "gpio49"),
PINCTRL_PIN(50, "gpio50"),
PINCTRL_PIN(51, "gpio51"),
};
static unsigned gpio0_pins[] = { 0 };
static unsigned gpio1_pins[] = { 1 };
static unsigned gpio2_pins[] = { 2 };
static unsigned gpio3_pins[] = { 3 };
static unsigned gpio4_pins[] = { 4 };
static unsigned gpio5_pins[] = { 5 };
static unsigned gpio6_pins[] = { 6 };
static unsigned gpio7_pins[] = { 7 };
static unsigned gpio8_pins[] = { 8 };
static unsigned gpio9_pins[] = { 9 };
static unsigned gpio10_pins[] = { 10 };
static unsigned gpio11_pins[] = { 11 };
static unsigned gpio12_pins[] = { 12 };
static unsigned gpio13_pins[] = { 13 };
static unsigned gpio14_pins[] = { 14 };
static unsigned gpio15_pins[] = { 15 };
static unsigned gpio16_pins[] = { 16 };
static unsigned gpio17_pins[] = { 17 };
static unsigned gpio18_pins[] = { 18 };
static unsigned gpio19_pins[] = { 19 };
static unsigned gpio20_pins[] = { 20 };
static unsigned gpio21_pins[] = { 21 };
static unsigned gpio22_pins[] = { 22 };
static unsigned gpio23_pins[] = { 23 };
static unsigned gpio24_pins[] = { 24 };
static unsigned gpio25_pins[] = { 25 };
static unsigned gpio26_pins[] = { 26 };
static unsigned gpio27_pins[] = { 27 };
static unsigned gpio28_pins[] = { 28 };
static unsigned gpio29_pins[] = { 29 };
static unsigned gpio30_pins[] = { 30 };
static unsigned gpio31_pins[] = { 31 };
static unsigned gpio32_pins[] = { 32 };
static unsigned gpio33_pins[] = { 33 };
static unsigned gpio34_pins[] = { 34 };
static unsigned gpio35_pins[] = { 35 };
static unsigned gpio36_pins[] = { 36 };
static unsigned gpio37_pins[] = { 37 };
static unsigned gpio38_pins[] = { 38 };
static unsigned gpio39_pins[] = { 39 };
static unsigned gpio40_pins[] = { 40 };
static unsigned gpio41_pins[] = { 41 };
static unsigned gpio42_pins[] = { 42 };
static unsigned gpio43_pins[] = { 43 };
static unsigned gpio44_pins[] = { 44 };
static unsigned gpio45_pins[] = { 45 };
static unsigned gpio46_pins[] = { 46 };
static unsigned gpio47_pins[] = { 47 };
static unsigned gpio48_pins[] = { 48 };
static unsigned gpio49_pins[] = { 49 };
static unsigned gpio50_pins[] = { 50 };
static unsigned gpio51_pins[] = { 51 };
static unsigned nand_grp_pins[] = {
2, 3, 4, 5, 6, 7, 24,
25, 26, 27, 28, 29, 30, 31,
};
static unsigned dectpd_grp_pins[] = { 8, 9 };
static unsigned vdsl_phy0_grp_pins[] = { 10, 11 };
static unsigned vdsl_phy1_grp_pins[] = { 12, 13 };
static unsigned vdsl_phy2_grp_pins[] = { 24, 25 };
static unsigned vdsl_phy3_grp_pins[] = { 26, 27 };
static struct pingroup bcm63268_groups[] = {
BCM_PIN_GROUP(gpio0),
BCM_PIN_GROUP(gpio1),
BCM_PIN_GROUP(gpio2),
BCM_PIN_GROUP(gpio3),
BCM_PIN_GROUP(gpio4),
BCM_PIN_GROUP(gpio5),
BCM_PIN_GROUP(gpio6),
BCM_PIN_GROUP(gpio7),
BCM_PIN_GROUP(gpio8),
BCM_PIN_GROUP(gpio9),
BCM_PIN_GROUP(gpio10),
BCM_PIN_GROUP(gpio11),
BCM_PIN_GROUP(gpio12),
BCM_PIN_GROUP(gpio13),
BCM_PIN_GROUP(gpio14),
BCM_PIN_GROUP(gpio15),
BCM_PIN_GROUP(gpio16),
BCM_PIN_GROUP(gpio17),
BCM_PIN_GROUP(gpio18),
BCM_PIN_GROUP(gpio19),
BCM_PIN_GROUP(gpio20),
BCM_PIN_GROUP(gpio21),
BCM_PIN_GROUP(gpio22),
BCM_PIN_GROUP(gpio23),
BCM_PIN_GROUP(gpio24),
BCM_PIN_GROUP(gpio25),
BCM_PIN_GROUP(gpio26),
BCM_PIN_GROUP(gpio27),
BCM_PIN_GROUP(gpio28),
BCM_PIN_GROUP(gpio29),
BCM_PIN_GROUP(gpio30),
BCM_PIN_GROUP(gpio31),
BCM_PIN_GROUP(gpio32),
BCM_PIN_GROUP(gpio33),
BCM_PIN_GROUP(gpio34),
BCM_PIN_GROUP(gpio35),
BCM_PIN_GROUP(gpio36),
BCM_PIN_GROUP(gpio37),
BCM_PIN_GROUP(gpio38),
BCM_PIN_GROUP(gpio39),
BCM_PIN_GROUP(gpio40),
BCM_PIN_GROUP(gpio41),
BCM_PIN_GROUP(gpio42),
BCM_PIN_GROUP(gpio43),
BCM_PIN_GROUP(gpio44),
BCM_PIN_GROUP(gpio45),
BCM_PIN_GROUP(gpio46),
BCM_PIN_GROUP(gpio47),
BCM_PIN_GROUP(gpio48),
BCM_PIN_GROUP(gpio49),
BCM_PIN_GROUP(gpio50),
BCM_PIN_GROUP(gpio51),
/* multi pin groups */
BCM_PIN_GROUP(nand_grp),
BCM_PIN_GROUP(dectpd_grp),
BCM_PIN_GROUP(vdsl_phy0_grp),
BCM_PIN_GROUP(vdsl_phy1_grp),
BCM_PIN_GROUP(vdsl_phy2_grp),
BCM_PIN_GROUP(vdsl_phy3_grp),
};
static const char * const led_groups[] = {
"gpio0",
"gpio1",
"gpio2",
"gpio3",
"gpio4",
"gpio5",
"gpio6",
"gpio7",
"gpio8",
"gpio9",
"gpio10",
"gpio11",
"gpio12",
"gpio13",
"gpio14",
"gpio15",
"gpio16",
"gpio17",
"gpio18",
"gpio19",
"gpio20",
"gpio21",
"gpio22",
"gpio23",
};
static const char * const serial_led_clk_groups[] = {
"gpio0",
};
static const char * const serial_led_data_groups[] = {
"gpio1",
};
static const char * const hsspi_cs4_groups[] = {
"gpio16",
};
static const char * const hsspi_cs5_groups[] = {
"gpio17",
};
static const char * const hsspi_cs6_groups[] = {
"gpio8",
};
static const char * const hsspi_cs7_groups[] = {
"gpio9",
};
static const char * const uart1_scts_groups[] = {
"gpio10",
"gpio24",
};
static const char * const uart1_srts_groups[] = {
"gpio11",
"gpio25",
};
static const char * const uart1_sdin_groups[] = {
"gpio12",
"gpio26",
};
static const char * const uart1_sdout_groups[] = {
"gpio13",
"gpio27",
};
static const char * const ntr_pulse_in_groups[] = {
"gpio14",
"gpio28",
};
static const char * const dsl_ntr_pulse_out_groups[] = {
"gpio15",
"gpio29",
};
static const char * const adsl_spi_miso_groups[] = {
"gpio18",
};
static const char * const adsl_spi_mosi_groups[] = {
"gpio19",
};
static const char * const vreg_clk_groups[] = {
"gpio22",
};
static const char * const pcie_clkreq_b_groups[] = {
"gpio23",
};
static const char * const switch_led_clk_groups[] = {
"gpio30",
};
static const char * const switch_led_data_groups[] = {
"gpio31",
};
static const char * const wifi_groups[] = {
"gpio32",
"gpio33",
"gpio34",
"gpio35",
"gpio36",
"gpio37",
"gpio38",
"gpio39",
"gpio40",
"gpio41",
"gpio42",
"gpio43",
"gpio44",
"gpio45",
"gpio46",
"gpio47",
"gpio48",
"gpio49",
"gpio50",
"gpio51",
};
static const char * const nand_groups[] = {
"nand_grp",
};
static const char * const dectpd_groups[] = {
"dectpd_grp",
};
static const char * const vdsl_phy_override_0_groups[] = {
"vdsl_phy_override_0_grp",
};
static const char * const vdsl_phy_override_1_groups[] = {
"vdsl_phy_override_1_grp",
};
static const char * const vdsl_phy_override_2_groups[] = {
"vdsl_phy_override_2_grp",
};
static const char * const vdsl_phy_override_3_groups[] = {
"vdsl_phy_override_3_grp",
};
#define BCM63268_LED_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM63268_LEDCTRL, \
}
#define BCM63268_MODE_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM63268_MODE, \
}
#define BCM63268_CTRL_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM63268_CTRL, \
}
#define BCM63268_BASEMODE_FUN(n, val) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM63268_BASEMODE, \
.mask = val, \
}
static const struct bcm63268_function bcm63268_funcs[] = {
BCM63268_LED_FUN(led),
BCM63268_MODE_FUN(serial_led_clk),
BCM63268_MODE_FUN(serial_led_data),
BCM63268_MODE_FUN(hsspi_cs6),
BCM63268_MODE_FUN(hsspi_cs7),
BCM63268_MODE_FUN(uart1_scts),
BCM63268_MODE_FUN(uart1_srts),
BCM63268_MODE_FUN(uart1_sdin),
BCM63268_MODE_FUN(uart1_sdout),
BCM63268_MODE_FUN(ntr_pulse_in),
BCM63268_MODE_FUN(dsl_ntr_pulse_out),
BCM63268_MODE_FUN(hsspi_cs4),
BCM63268_MODE_FUN(hsspi_cs5),
BCM63268_MODE_FUN(adsl_spi_miso),
BCM63268_MODE_FUN(adsl_spi_mosi),
BCM63268_MODE_FUN(vreg_clk),
BCM63268_MODE_FUN(pcie_clkreq_b),
BCM63268_MODE_FUN(switch_led_clk),
BCM63268_MODE_FUN(switch_led_data),
BCM63268_CTRL_FUN(wifi),
BCM63268_BASEMODE_FUN(nand, BCM63268_BASEMODE_NAND),
BCM63268_BASEMODE_FUN(dectpd, BCM63268_BASEMODE_DECTPD),
BCM63268_BASEMODE_FUN(vdsl_phy_override_0,
BCM63268_BASEMODE_VDSL_PHY_0),
BCM63268_BASEMODE_FUN(vdsl_phy_override_1,
BCM63268_BASEMODE_VDSL_PHY_1),
BCM63268_BASEMODE_FUN(vdsl_phy_override_2,
BCM63268_BASEMODE_VDSL_PHY_2),
BCM63268_BASEMODE_FUN(vdsl_phy_override_3,
BCM63268_BASEMODE_VDSL_PHY_3),
};
static int bcm63268_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm63268_groups);
}
static const char *bcm63268_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned group)
{
return bcm63268_groups[group].name;
}
static int bcm63268_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned group,
const unsigned **pins,
unsigned *npins)
{
*pins = bcm63268_groups[group].pins;
*npins = bcm63268_groups[group].npins;
return 0;
}
static int bcm63268_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm63268_funcs);
}
static const char *bcm63268_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return bcm63268_funcs[selector].name;
}
static int bcm63268_pinctrl_get_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = bcm63268_funcs[selector].groups;
*num_groups = bcm63268_funcs[selector].num_groups;
return 0;
}
static void bcm63268_set_gpio(struct bcm63xx_pinctrl *pc, unsigned pin)
{
const struct pinctrl_pin_desc *desc = &bcm63268_pins[pin];
unsigned int basemode = (unsigned long) desc->drv_data;
unsigned int mask = BIT(bcm63xx_bank_pin(pin));
if (basemode)
regmap_update_bits(pc->regs, BCM63268_BASEMODE_REG, basemode,
0);
if (pin < BCM63XX_BANK_GPIOS) {
/* base mode: 0 => gpio, 1 => mux function */
regmap_update_bits(pc->regs, BCM63268_MODE_REG, mask, 0);
/* pins 0-23 might be muxed to led */
if (pin < BCM63268_NUM_LEDS)
regmap_update_bits(pc->regs, BCM63268_LED_REG, mask,
0);
} else if (pin < BCM63268_NUM_GPIOS) {
/* ctrl reg: 0 => wifi function, 1 => gpio */
regmap_update_bits(pc->regs, BCM63268_CTRL_REG, mask, mask);
}
}
static int bcm63268_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned group)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
const struct pingroup *pg = &bcm63268_groups[group];
const struct bcm63268_function *f = &bcm63268_funcs[selector];
unsigned i;
unsigned int reg;
unsigned int val, mask;
for (i = 0; i < pg->npins; i++)
bcm63268_set_gpio(pc, pg->pins[i]);
switch (f->reg) {
case BCM63268_LEDCTRL:
reg = BCM63268_LED_REG;
mask = BIT(pg->pins[0]);
val = BIT(pg->pins[0]);
break;
case BCM63268_MODE:
reg = BCM63268_MODE_REG;
mask = BIT(pg->pins[0]);
val = BIT(pg->pins[0]);
break;
case BCM63268_CTRL:
reg = BCM63268_CTRL_REG;
mask = BIT(pg->pins[0]);
val = 0;
break;
case BCM63268_BASEMODE:
reg = BCM63268_BASEMODE_REG;
mask = f->mask;
val = f->mask;
break;
default:
WARN_ON(1);
return -EINVAL;
}
regmap_update_bits(pc->regs, reg, mask, val);
return 0;
}
static int bcm63268_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* disable all functions using this pin */
bcm63268_set_gpio(pc, offset);
return 0;
}
static const struct pinctrl_ops bcm63268_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm63268_pinctrl_get_group_name,
.get_group_pins = bcm63268_pinctrl_get_group_pins,
.get_groups_count = bcm63268_pinctrl_get_group_count,
};
static const struct pinmux_ops bcm63268_pmx_ops = {
.get_function_groups = bcm63268_pinctrl_get_groups,
.get_function_name = bcm63268_pinctrl_get_func_name,
.get_functions_count = bcm63268_pinctrl_get_func_count,
.gpio_request_enable = bcm63268_gpio_request_enable,
.set_mux = bcm63268_pinctrl_set_mux,
.strict = true,
};
static const struct bcm63xx_pinctrl_soc bcm63268_soc = {
.ngpios = BCM63268_NUM_GPIOS,
.npins = ARRAY_SIZE(bcm63268_pins),
.pctl_ops = &bcm63268_pctl_ops,
.pins = bcm63268_pins,
.pmx_ops = &bcm63268_pmx_ops,
};
static int bcm63268_pinctrl_probe(struct platform_device *pdev)
{
return bcm63xx_pinctrl_probe(pdev, &bcm63268_soc, NULL);
}
static const struct of_device_id bcm63268_pinctrl_match[] = {
{ .compatible = "brcm,bcm63268-pinctrl", },
{ /* sentinel */ }
};
static struct platform_driver bcm63268_pinctrl_driver = {
.probe = bcm63268_pinctrl_probe,
.driver = {
.name = "bcm63268-pinctrl",
.of_match_table = bcm63268_pinctrl_match,
},
};
builtin_platform_driver(bcm63268_pinctrl_driver);
@@ -0,0 +1,391 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM6328 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl-utils.h"
#include "pinctrl-bcm63xx.h"
#define BCM6328_NUM_GPIOS 32
#define BCM6328_MODE_REG 0x18
#define BCM6328_MUX_HI_REG 0x1c
#define BCM6328_MUX_LO_REG 0x20
#define BCM6328_MUX_OTHER_REG 0x24
#define BCM6328_MUX_MASK GENMASK(1, 0)
struct bcm6328_function {
const char *name;
const char * const *groups;
const unsigned num_groups;
unsigned mode_val:1;
unsigned mux_val:2;
};
static const unsigned int bcm6328_mux[] = {
BCM6328_MUX_LO_REG,
BCM6328_MUX_HI_REG,
BCM6328_MUX_OTHER_REG
};
static const struct pinctrl_pin_desc bcm6328_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
PINCTRL_PIN(2, "gpio2"),
PINCTRL_PIN(3, "gpio3"),
PINCTRL_PIN(4, "gpio4"),
PINCTRL_PIN(5, "gpio5"),
PINCTRL_PIN(6, "gpio6"),
PINCTRL_PIN(7, "gpio7"),
PINCTRL_PIN(8, "gpio8"),
PINCTRL_PIN(9, "gpio9"),
PINCTRL_PIN(10, "gpio10"),
PINCTRL_PIN(11, "gpio11"),
PINCTRL_PIN(12, "gpio12"),
PINCTRL_PIN(13, "gpio13"),
PINCTRL_PIN(14, "gpio14"),
PINCTRL_PIN(15, "gpio15"),
PINCTRL_PIN(16, "gpio16"),
PINCTRL_PIN(17, "gpio17"),
PINCTRL_PIN(18, "gpio18"),
PINCTRL_PIN(19, "gpio19"),
PINCTRL_PIN(20, "gpio20"),
PINCTRL_PIN(21, "gpio21"),
PINCTRL_PIN(22, "gpio22"),
PINCTRL_PIN(23, "gpio23"),
PINCTRL_PIN(24, "gpio24"),
PINCTRL_PIN(25, "gpio25"),
PINCTRL_PIN(26, "gpio26"),
PINCTRL_PIN(27, "gpio27"),
PINCTRL_PIN(28, "gpio28"),
PINCTRL_PIN(29, "gpio29"),
PINCTRL_PIN(30, "gpio30"),
PINCTRL_PIN(31, "gpio31"),
/*
* No idea where they really are; so let's put them according
* to their mux offsets.
*/
PINCTRL_PIN(36, "hsspi_cs1"),
PINCTRL_PIN(38, "usb_p2"),
};
static unsigned gpio0_pins[] = { 0 };
static unsigned gpio1_pins[] = { 1 };
static unsigned gpio2_pins[] = { 2 };
static unsigned gpio3_pins[] = { 3 };
static unsigned gpio4_pins[] = { 4 };
static unsigned gpio5_pins[] = { 5 };
static unsigned gpio6_pins[] = { 6 };
static unsigned gpio7_pins[] = { 7 };
static unsigned gpio8_pins[] = { 8 };
static unsigned gpio9_pins[] = { 9 };
static unsigned gpio10_pins[] = { 10 };
static unsigned gpio11_pins[] = { 11 };
static unsigned gpio12_pins[] = { 12 };
static unsigned gpio13_pins[] = { 13 };
static unsigned gpio14_pins[] = { 14 };
static unsigned gpio15_pins[] = { 15 };
static unsigned gpio16_pins[] = { 16 };
static unsigned gpio17_pins[] = { 17 };
static unsigned gpio18_pins[] = { 18 };
static unsigned gpio19_pins[] = { 19 };
static unsigned gpio20_pins[] = { 20 };
static unsigned gpio21_pins[] = { 21 };
static unsigned gpio22_pins[] = { 22 };
static unsigned gpio23_pins[] = { 23 };
static unsigned gpio24_pins[] = { 24 };
static unsigned gpio25_pins[] = { 25 };
static unsigned gpio26_pins[] = { 26 };
static unsigned gpio27_pins[] = { 27 };
static unsigned gpio28_pins[] = { 28 };
static unsigned gpio29_pins[] = { 29 };
static unsigned gpio30_pins[] = { 30 };
static unsigned gpio31_pins[] = { 31 };
static unsigned hsspi_cs1_pins[] = { 36 };
static unsigned usb_port1_pins[] = { 38 };
static struct pingroup bcm6328_groups[] = {
BCM_PIN_GROUP(gpio0),
BCM_PIN_GROUP(gpio1),
BCM_PIN_GROUP(gpio2),
BCM_PIN_GROUP(gpio3),
BCM_PIN_GROUP(gpio4),
BCM_PIN_GROUP(gpio5),
BCM_PIN_GROUP(gpio6),
BCM_PIN_GROUP(gpio7),
BCM_PIN_GROUP(gpio8),
BCM_PIN_GROUP(gpio9),
BCM_PIN_GROUP(gpio10),
BCM_PIN_GROUP(gpio11),
BCM_PIN_GROUP(gpio12),
BCM_PIN_GROUP(gpio13),
BCM_PIN_GROUP(gpio14),
BCM_PIN_GROUP(gpio15),
BCM_PIN_GROUP(gpio16),
BCM_PIN_GROUP(gpio17),
BCM_PIN_GROUP(gpio18),
BCM_PIN_GROUP(gpio19),
BCM_PIN_GROUP(gpio20),
BCM_PIN_GROUP(gpio21),
BCM_PIN_GROUP(gpio22),
BCM_PIN_GROUP(gpio23),
BCM_PIN_GROUP(gpio24),
BCM_PIN_GROUP(gpio25),
BCM_PIN_GROUP(gpio26),
BCM_PIN_GROUP(gpio27),
BCM_PIN_GROUP(gpio28),
BCM_PIN_GROUP(gpio29),
BCM_PIN_GROUP(gpio30),
BCM_PIN_GROUP(gpio31),
BCM_PIN_GROUP(hsspi_cs1),
BCM_PIN_GROUP(usb_port1),
};
/* GPIO_MODE */
static const char * const led_groups[] = {
"gpio0",
"gpio1",
"gpio2",
"gpio3",
"gpio4",
"gpio5",
"gpio6",
"gpio7",
"gpio8",
"gpio9",
"gpio10",
"gpio11",
"gpio12",
"gpio13",
"gpio14",
"gpio15",
"gpio16",
"gpio17",
"gpio18",
"gpio19",
"gpio20",
"gpio21",
"gpio22",
"gpio23",
};
/* PINMUX_SEL */
static const char * const serial_led_data_groups[] = {
"gpio6",
};
static const char * const serial_led_clk_groups[] = {
"gpio7",
};
static const char * const inet_act_led_groups[] = {
"gpio11",
};
static const char * const pcie_clkreq_groups[] = {
"gpio16",
};
static const char * const ephy0_act_led_groups[] = {
"gpio25",
};
static const char * const ephy1_act_led_groups[] = {
"gpio26",
};
static const char * const ephy2_act_led_groups[] = {
"gpio27",
};
static const char * const ephy3_act_led_groups[] = {
"gpio28",
};
static const char * const hsspi_cs1_groups[] = {
"hsspi_cs1"
};
static const char * const usb_host_port_groups[] = {
"usb_port1",
};
static const char * const usb_device_port_groups[] = {
"usb_port1",
};
#define BCM6328_MODE_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.mode_val = 1, \
}
#define BCM6328_MUX_FUN(n, mux) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.mux_val = mux, \
}
static const struct bcm6328_function bcm6328_funcs[] = {
BCM6328_MODE_FUN(led),
BCM6328_MUX_FUN(serial_led_data, 2),
BCM6328_MUX_FUN(serial_led_clk, 2),
BCM6328_MUX_FUN(inet_act_led, 1),
BCM6328_MUX_FUN(pcie_clkreq, 2),
BCM6328_MUX_FUN(ephy0_act_led, 1),
BCM6328_MUX_FUN(ephy1_act_led, 1),
BCM6328_MUX_FUN(ephy2_act_led, 1),
BCM6328_MUX_FUN(ephy3_act_led, 1),
BCM6328_MUX_FUN(hsspi_cs1, 2),
BCM6328_MUX_FUN(usb_host_port, 1),
BCM6328_MUX_FUN(usb_device_port, 2),
};
static inline unsigned int bcm6328_mux_off(unsigned int pin)
{
return bcm6328_mux[pin / 16];
}
static int bcm6328_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6328_groups);
}
static const char *bcm6328_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned group)
{
return bcm6328_groups[group].name;
}
static int bcm6328_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned group, const unsigned **pins,
unsigned *npins)
{
*pins = bcm6328_groups[group].pins;
*npins = bcm6328_groups[group].npins;
return 0;
}
static int bcm6328_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6328_funcs);
}
static const char *bcm6328_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return bcm6328_funcs[selector].name;
}
static int bcm6328_pinctrl_get_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = bcm6328_funcs[selector].groups;
*num_groups = bcm6328_funcs[selector].num_groups;
return 0;
}
static void bcm6328_rmw_mux(struct bcm63xx_pinctrl *pc, unsigned pin,
unsigned int mode, unsigned int mux)
{
if (pin < BCM6328_NUM_GPIOS)
regmap_update_bits(pc->regs, BCM6328_MODE_REG, BIT(pin),
mode ? BIT(pin) : 0);
regmap_update_bits(pc->regs, bcm6328_mux_off(pin),
BCM6328_MUX_MASK << ((pin % 16) * 2),
mux << ((pin % 16) * 2));
}
static int bcm6328_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned group)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
const struct pingroup *pg = &bcm6328_groups[group];
const struct bcm6328_function *f = &bcm6328_funcs[selector];
bcm6328_rmw_mux(pc, pg->pins[0], f->mode_val, f->mux_val);
return 0;
}
static int bcm6328_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* disable all functions using this pin */
bcm6328_rmw_mux(pc, offset, 0, 0);
return 0;
}
static const struct pinctrl_ops bcm6328_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6328_pinctrl_get_group_name,
.get_group_pins = bcm6328_pinctrl_get_group_pins,
.get_groups_count = bcm6328_pinctrl_get_group_count,
};
static const struct pinmux_ops bcm6328_pmx_ops = {
.get_function_groups = bcm6328_pinctrl_get_groups,
.get_function_name = bcm6328_pinctrl_get_func_name,
.get_functions_count = bcm6328_pinctrl_get_func_count,
.gpio_request_enable = bcm6328_gpio_request_enable,
.set_mux = bcm6328_pinctrl_set_mux,
.strict = true,
};
static const struct bcm63xx_pinctrl_soc bcm6328_soc = {
.ngpios = BCM6328_NUM_GPIOS,
.npins = ARRAY_SIZE(bcm6328_pins),
.pctl_ops = &bcm6328_pctl_ops,
.pins = bcm6328_pins,
.pmx_ops = &bcm6328_pmx_ops,
};
static int bcm6328_pinctrl_probe(struct platform_device *pdev)
{
return bcm63xx_pinctrl_probe(pdev, &bcm6328_soc, NULL);
}
static const struct of_device_id bcm6328_pinctrl_match[] = {
{ .compatible = "brcm,bcm6328-pinctrl", },
{ /* sentinel */ }
};
static struct platform_driver bcm6328_pinctrl_driver = {
.probe = bcm6328_pinctrl_probe,
.driver = {
.name = "bcm6328-pinctrl",
.of_match_table = bcm6328_pinctrl_match,
},
};
builtin_platform_driver(bcm6328_pinctrl_driver);
@@ -0,0 +1,363 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM6358 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl-utils.h"
#include "pinctrl-bcm63xx.h"
#define BCM6358_NUM_GPIOS 40
#define BCM6358_MODE_REG 0x18
#define BCM6358_MODE_MUX_NONE 0
#define BCM6358_MODE_MUX_EBI_CS BIT(5)
#define BCM6358_MODE_MUX_UART1 BIT(6)
#define BCM6358_MODE_MUX_SPI_CS BIT(7)
#define BCM6358_MODE_MUX_ASYNC_MODEM BIT(8)
#define BCM6358_MODE_MUX_LEGACY_LED BIT(9)
#define BCM6358_MODE_MUX_SERIAL_LED BIT(10)
#define BCM6358_MODE_MUX_LED BIT(11)
#define BCM6358_MODE_MUX_UTOPIA BIT(12)
#define BCM6358_MODE_MUX_CLKRST BIT(13)
#define BCM6358_MODE_MUX_PWM_SYN_CLK BIT(14)
#define BCM6358_MODE_MUX_SYS_IRQ BIT(15)
struct bcm6358_pingroup {
struct pingroup grp;
const uint16_t mode_val;
/* non-GPIO function muxes require the gpio direction to be set */
const uint16_t direction;
};
struct bcm6358_function {
const char *name;
const char * const *groups;
const unsigned num_groups;
};
struct bcm6358_priv {
struct regmap_field *overlays;
};
#define BCM6358_GPIO_PIN(a, b, bit1, bit2, bit3) \
{ \
.number = a, \
.name = b, \
.drv_data = (void *)(BCM6358_MODE_MUX_##bit1 | \
BCM6358_MODE_MUX_##bit2 | \
BCM6358_MODE_MUX_##bit3), \
}
static const struct pinctrl_pin_desc bcm6358_pins[] = {
BCM6358_GPIO_PIN(0, "gpio0", LED, NONE, NONE),
BCM6358_GPIO_PIN(1, "gpio1", LED, NONE, NONE),
BCM6358_GPIO_PIN(2, "gpio2", LED, NONE, NONE),
BCM6358_GPIO_PIN(3, "gpio3", LED, NONE, NONE),
PINCTRL_PIN(4, "gpio4"),
BCM6358_GPIO_PIN(5, "gpio5", SYS_IRQ, NONE, NONE),
BCM6358_GPIO_PIN(6, "gpio6", SERIAL_LED, NONE, NONE),
BCM6358_GPIO_PIN(7, "gpio7", SERIAL_LED, NONE, NONE),
BCM6358_GPIO_PIN(8, "gpio8", PWM_SYN_CLK, NONE, NONE),
BCM6358_GPIO_PIN(9, "gpio09", LEGACY_LED, NONE, NONE),
BCM6358_GPIO_PIN(10, "gpio10", LEGACY_LED, NONE, NONE),
BCM6358_GPIO_PIN(11, "gpio11", LEGACY_LED, NONE, NONE),
BCM6358_GPIO_PIN(12, "gpio12", LEGACY_LED, ASYNC_MODEM, UTOPIA),
BCM6358_GPIO_PIN(13, "gpio13", LEGACY_LED, ASYNC_MODEM, UTOPIA),
BCM6358_GPIO_PIN(14, "gpio14", LEGACY_LED, ASYNC_MODEM, UTOPIA),
BCM6358_GPIO_PIN(15, "gpio15", LEGACY_LED, ASYNC_MODEM, UTOPIA),
PINCTRL_PIN(16, "gpio16"),
PINCTRL_PIN(17, "gpio17"),
PINCTRL_PIN(18, "gpio18"),
PINCTRL_PIN(19, "gpio19"),
PINCTRL_PIN(20, "gpio20"),
PINCTRL_PIN(21, "gpio21"),
BCM6358_GPIO_PIN(22, "gpio22", UTOPIA, NONE, NONE),
BCM6358_GPIO_PIN(23, "gpio23", UTOPIA, NONE, NONE),
BCM6358_GPIO_PIN(24, "gpio24", UTOPIA, NONE, NONE),
BCM6358_GPIO_PIN(25, "gpio25", UTOPIA, NONE, NONE),
BCM6358_GPIO_PIN(26, "gpio26", UTOPIA, NONE, NONE),
BCM6358_GPIO_PIN(27, "gpio27", UTOPIA, NONE, NONE),
BCM6358_GPIO_PIN(28, "gpio28", UTOPIA, UART1, NONE),
BCM6358_GPIO_PIN(29, "gpio29", UTOPIA, UART1, NONE),
BCM6358_GPIO_PIN(30, "gpio30", UTOPIA, UART1, EBI_CS),
BCM6358_GPIO_PIN(31, "gpio31", UTOPIA, UART1, EBI_CS),
BCM6358_GPIO_PIN(32, "gpio32", SPI_CS, NONE, NONE),
BCM6358_GPIO_PIN(33, "gpio33", SPI_CS, NONE, NONE),
PINCTRL_PIN(34, "gpio34"),
PINCTRL_PIN(35, "gpio35"),
PINCTRL_PIN(36, "gpio36"),
PINCTRL_PIN(37, "gpio37"),
PINCTRL_PIN(38, "gpio38"),
PINCTRL_PIN(39, "gpio39"),
};
static unsigned ebi_cs_grp_pins[] = { 30, 31 };
static unsigned uart1_grp_pins[] = { 28, 29, 30, 31 };
static unsigned spi_cs_grp_pins[] = { 32, 33 };
static unsigned async_modem_grp_pins[] = { 12, 13, 14, 15 };
static unsigned serial_led_grp_pins[] = { 6, 7 };
static unsigned legacy_led_grp_pins[] = { 9, 10, 11, 12, 13, 14, 15 };
static unsigned led_grp_pins[] = { 0, 1, 2, 3 };
static unsigned utopia_grp_pins[] = {
12, 13, 14, 15, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
};
static unsigned pwm_syn_clk_grp_pins[] = { 8 };
static unsigned sys_irq_grp_pins[] = { 5 };
#define BCM6358_GPIO_MUX_GROUP(n, bit, dir) \
{ \
.grp = BCM_PIN_GROUP(n), \
.mode_val = BCM6358_MODE_MUX_##bit, \
.direction = dir, \
}
static const struct bcm6358_pingroup bcm6358_groups[] = {
BCM6358_GPIO_MUX_GROUP(ebi_cs_grp, EBI_CS, 0x3),
BCM6358_GPIO_MUX_GROUP(uart1_grp, UART1, 0x2),
BCM6358_GPIO_MUX_GROUP(spi_cs_grp, SPI_CS, 0x6),
BCM6358_GPIO_MUX_GROUP(async_modem_grp, ASYNC_MODEM, 0x6),
BCM6358_GPIO_MUX_GROUP(legacy_led_grp, LEGACY_LED, 0x7f),
BCM6358_GPIO_MUX_GROUP(serial_led_grp, SERIAL_LED, 0x3),
BCM6358_GPIO_MUX_GROUP(led_grp, LED, 0xf),
BCM6358_GPIO_MUX_GROUP(utopia_grp, UTOPIA, 0x000f),
BCM6358_GPIO_MUX_GROUP(pwm_syn_clk_grp, PWM_SYN_CLK, 0x1),
BCM6358_GPIO_MUX_GROUP(sys_irq_grp, SYS_IRQ, 0x1),
};
static const char * const ebi_cs_groups[] = {
"ebi_cs_grp"
};
static const char * const uart1_groups[] = {
"uart1_grp"
};
static const char * const spi_cs_2_3_groups[] = {
"spi_cs_2_3_grp"
};
static const char * const async_modem_groups[] = {
"async_modem_grp"
};
static const char * const legacy_led_groups[] = {
"legacy_led_grp",
};
static const char * const serial_led_groups[] = {
"serial_led_grp",
};
static const char * const led_groups[] = {
"led_grp",
};
static const char * const clkrst_groups[] = {
"clkrst_grp",
};
static const char * const pwm_syn_clk_groups[] = {
"pwm_syn_clk_grp",
};
static const char * const sys_irq_groups[] = {
"sys_irq_grp",
};
#define BCM6358_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
}
static const struct bcm6358_function bcm6358_funcs[] = {
BCM6358_FUN(ebi_cs),
BCM6358_FUN(uart1),
BCM6358_FUN(spi_cs_2_3),
BCM6358_FUN(async_modem),
BCM6358_FUN(legacy_led),
BCM6358_FUN(serial_led),
BCM6358_FUN(led),
BCM6358_FUN(clkrst),
BCM6358_FUN(pwm_syn_clk),
BCM6358_FUN(sys_irq),
};
static int bcm6358_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6358_groups);
}
static const char *bcm6358_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned group)
{
return bcm6358_groups[group].grp.name;
}
static int bcm6358_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned group, const unsigned **pins,
unsigned *npins)
{
*pins = bcm6358_groups[group].grp.pins;
*npins = bcm6358_groups[group].grp.npins;
return 0;
}
static int bcm6358_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6358_funcs);
}
static const char *bcm6358_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return bcm6358_funcs[selector].name;
}
static int bcm6358_pinctrl_get_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = bcm6358_funcs[selector].groups;
*num_groups = bcm6358_funcs[selector].num_groups;
return 0;
}
static int bcm6358_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned group)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
struct bcm6358_priv *priv = pc->driver_data;
const struct bcm6358_pingroup *pg = &bcm6358_groups[group];
unsigned int val = pg->mode_val;
unsigned int mask = val;
unsigned pin;
for (pin = 0; pin < pg->grp.npins; pin++)
mask |= (unsigned long)bcm6358_pins[pin].drv_data;
regmap_field_update_bits(priv->overlays, mask, val);
for (pin = 0; pin < pg->grp.npins; pin++) {
struct pinctrl_gpio_range *range;
unsigned int hw_gpio = bcm6358_pins[pin].number;
range = pinctrl_find_gpio_range_from_pin(pctldev, hw_gpio);
if (range) {
struct gpio_chip *gc = range->gc;
if (pg->direction & BIT(pin))
gc->direction_output(gc, hw_gpio, 0);
else
gc->direction_input(gc, hw_gpio);
}
}
return 0;
}
static int bcm6358_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
struct bcm6358_priv *priv = pc->driver_data;
unsigned int mask;
mask = (unsigned long) bcm6358_pins[offset].drv_data;
if (!mask)
return 0;
/* disable all functions using this pin */
return regmap_field_update_bits(priv->overlays, mask, 0);
}
static const struct pinctrl_ops bcm6358_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6358_pinctrl_get_group_name,
.get_group_pins = bcm6358_pinctrl_get_group_pins,
.get_groups_count = bcm6358_pinctrl_get_group_count,
};
static const struct pinmux_ops bcm6358_pmx_ops = {
.get_function_groups = bcm6358_pinctrl_get_groups,
.get_function_name = bcm6358_pinctrl_get_func_name,
.get_functions_count = bcm6358_pinctrl_get_func_count,
.gpio_request_enable = bcm6358_gpio_request_enable,
.set_mux = bcm6358_pinctrl_set_mux,
.strict = true,
};
static const struct bcm63xx_pinctrl_soc bcm6358_soc = {
.ngpios = BCM6358_NUM_GPIOS,
.npins = ARRAY_SIZE(bcm6358_pins),
.pctl_ops = &bcm6358_pctl_ops,
.pins = bcm6358_pins,
.pmx_ops = &bcm6358_pmx_ops,
};
static int bcm6358_pinctrl_probe(struct platform_device *pdev)
{
struct reg_field overlays = REG_FIELD(BCM6358_MODE_REG, 0, 15);
struct device *dev = &pdev->dev;
struct bcm63xx_pinctrl *pc;
struct bcm6358_priv *priv;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
err = bcm63xx_pinctrl_probe(pdev, &bcm6358_soc, (void *) priv);
if (err)
return err;
pc = platform_get_drvdata(pdev);
priv->overlays = devm_regmap_field_alloc(dev, pc->regs, overlays);
return PTR_ERR_OR_ZERO(priv->overlays);
}
static const struct of_device_id bcm6358_pinctrl_match[] = {
{ .compatible = "brcm,bcm6358-pinctrl", },
{ /* sentinel */ }
};
static struct platform_driver bcm6358_pinctrl_driver = {
.probe = bcm6358_pinctrl_probe,
.driver = {
.name = "bcm6358-pinctrl",
.of_match_table = bcm6358_pinctrl_match,
},
};
builtin_platform_driver(bcm6358_pinctrl_driver);
@@ -0,0 +1,604 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM6362 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl-utils.h"
#include "pinctrl-bcm63xx.h"
#define BCM6362_BANK_GPIOS 32
#define BCM6362_NUM_GPIOS 48
#define BCM6362_NUM_LEDS 24
#define BCM6362_LED_REG 0x10
#define BCM6362_MODE_REG 0x18
#define BCM6362_CTRL_REG 0x1c
#define BCM6362_BASEMODE_REG 0x38
#define BASEMODE_NAND BIT(2)
enum bcm6362_pinctrl_reg {
BCM6362_LEDCTRL,
BCM6362_MODE,
BCM6362_CTRL,
BCM6362_BASEMODE,
};
struct bcm6362_function {
const char *name;
const char * const *groups;
const unsigned num_groups;
enum bcm6362_pinctrl_reg reg;
uint32_t basemode_mask;
};
#define BCM6362_PIN(a, b, mask) \
{ \
.number = a, \
.name = b, \
.drv_data = (void *)(mask), \
}
static const struct pinctrl_pin_desc bcm6362_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
PINCTRL_PIN(2, "gpio2"),
PINCTRL_PIN(3, "gpio3"),
PINCTRL_PIN(4, "gpio4"),
PINCTRL_PIN(5, "gpio5"),
PINCTRL_PIN(6, "gpio6"),
PINCTRL_PIN(7, "gpio7"),
BCM6362_PIN(8, "gpio8", BASEMODE_NAND),
PINCTRL_PIN(9, "gpio9"),
PINCTRL_PIN(10, "gpio10"),
PINCTRL_PIN(11, "gpio11"),
BCM6362_PIN(12, "gpio12", BASEMODE_NAND),
BCM6362_PIN(13, "gpio13", BASEMODE_NAND),
BCM6362_PIN(14, "gpio14", BASEMODE_NAND),
BCM6362_PIN(15, "gpio15", BASEMODE_NAND),
BCM6362_PIN(16, "gpio16", BASEMODE_NAND),
BCM6362_PIN(17, "gpio17", BASEMODE_NAND),
BCM6362_PIN(18, "gpio18", BASEMODE_NAND),
BCM6362_PIN(19, "gpio19", BASEMODE_NAND),
BCM6362_PIN(20, "gpio20", BASEMODE_NAND),
BCM6362_PIN(21, "gpio21", BASEMODE_NAND),
BCM6362_PIN(22, "gpio22", BASEMODE_NAND),
BCM6362_PIN(23, "gpio23", BASEMODE_NAND),
PINCTRL_PIN(24, "gpio24"),
PINCTRL_PIN(25, "gpio25"),
PINCTRL_PIN(26, "gpio26"),
BCM6362_PIN(27, "gpio27", BASEMODE_NAND),
PINCTRL_PIN(28, "gpio28"),
PINCTRL_PIN(29, "gpio29"),
PINCTRL_PIN(30, "gpio30"),
PINCTRL_PIN(31, "gpio31"),
PINCTRL_PIN(32, "gpio32"),
PINCTRL_PIN(33, "gpio33"),
PINCTRL_PIN(34, "gpio34"),
PINCTRL_PIN(35, "gpio35"),
PINCTRL_PIN(36, "gpio36"),
PINCTRL_PIN(37, "gpio37"),
PINCTRL_PIN(38, "gpio38"),
PINCTRL_PIN(39, "gpio39"),
PINCTRL_PIN(40, "gpio40"),
PINCTRL_PIN(41, "gpio41"),
PINCTRL_PIN(42, "gpio42"),
PINCTRL_PIN(43, "gpio43"),
PINCTRL_PIN(44, "gpio44"),
PINCTRL_PIN(45, "gpio45"),
PINCTRL_PIN(46, "gpio46"),
PINCTRL_PIN(47, "gpio47"),
};
static unsigned gpio0_pins[] = { 0 };
static unsigned gpio1_pins[] = { 1 };
static unsigned gpio2_pins[] = { 2 };
static unsigned gpio3_pins[] = { 3 };
static unsigned gpio4_pins[] = { 4 };
static unsigned gpio5_pins[] = { 5 };
static unsigned gpio6_pins[] = { 6 };
static unsigned gpio7_pins[] = { 7 };
static unsigned gpio8_pins[] = { 8 };
static unsigned gpio9_pins[] = { 9 };
static unsigned gpio10_pins[] = { 10 };
static unsigned gpio11_pins[] = { 11 };
static unsigned gpio12_pins[] = { 12 };
static unsigned gpio13_pins[] = { 13 };
static unsigned gpio14_pins[] = { 14 };
static unsigned gpio15_pins[] = { 15 };
static unsigned gpio16_pins[] = { 16 };
static unsigned gpio17_pins[] = { 17 };
static unsigned gpio18_pins[] = { 18 };
static unsigned gpio19_pins[] = { 19 };
static unsigned gpio20_pins[] = { 20 };
static unsigned gpio21_pins[] = { 21 };
static unsigned gpio22_pins[] = { 22 };
static unsigned gpio23_pins[] = { 23 };
static unsigned gpio24_pins[] = { 24 };
static unsigned gpio25_pins[] = { 25 };
static unsigned gpio26_pins[] = { 26 };
static unsigned gpio27_pins[] = { 27 };
static unsigned gpio28_pins[] = { 28 };
static unsigned gpio29_pins[] = { 29 };
static unsigned gpio30_pins[] = { 30 };
static unsigned gpio31_pins[] = { 31 };
static unsigned gpio32_pins[] = { 32 };
static unsigned gpio33_pins[] = { 33 };
static unsigned gpio34_pins[] = { 34 };
static unsigned gpio35_pins[] = { 35 };
static unsigned gpio36_pins[] = { 36 };
static unsigned gpio37_pins[] = { 37 };
static unsigned gpio38_pins[] = { 38 };
static unsigned gpio39_pins[] = { 39 };
static unsigned gpio40_pins[] = { 40 };
static unsigned gpio41_pins[] = { 41 };
static unsigned gpio42_pins[] = { 42 };
static unsigned gpio43_pins[] = { 43 };
static unsigned gpio44_pins[] = { 44 };
static unsigned gpio45_pins[] = { 45 };
static unsigned gpio46_pins[] = { 46 };
static unsigned gpio47_pins[] = { 47 };
static unsigned nand_grp_pins[] = {
8, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 27,
};
static struct pingroup bcm6362_groups[] = {
BCM_PIN_GROUP(gpio0),
BCM_PIN_GROUP(gpio1),
BCM_PIN_GROUP(gpio2),
BCM_PIN_GROUP(gpio3),
BCM_PIN_GROUP(gpio4),
BCM_PIN_GROUP(gpio5),
BCM_PIN_GROUP(gpio6),
BCM_PIN_GROUP(gpio7),
BCM_PIN_GROUP(gpio8),
BCM_PIN_GROUP(gpio9),
BCM_PIN_GROUP(gpio10),
BCM_PIN_GROUP(gpio11),
BCM_PIN_GROUP(gpio12),
BCM_PIN_GROUP(gpio13),
BCM_PIN_GROUP(gpio14),
BCM_PIN_GROUP(gpio15),
BCM_PIN_GROUP(gpio16),
BCM_PIN_GROUP(gpio17),
BCM_PIN_GROUP(gpio18),
BCM_PIN_GROUP(gpio19),
BCM_PIN_GROUP(gpio20),
BCM_PIN_GROUP(gpio21),
BCM_PIN_GROUP(gpio22),
BCM_PIN_GROUP(gpio23),
BCM_PIN_GROUP(gpio24),
BCM_PIN_GROUP(gpio25),
BCM_PIN_GROUP(gpio26),
BCM_PIN_GROUP(gpio27),
BCM_PIN_GROUP(gpio28),
BCM_PIN_GROUP(gpio29),
BCM_PIN_GROUP(gpio30),
BCM_PIN_GROUP(gpio31),
BCM_PIN_GROUP(gpio32),
BCM_PIN_GROUP(gpio33),
BCM_PIN_GROUP(gpio34),
BCM_PIN_GROUP(gpio35),
BCM_PIN_GROUP(gpio36),
BCM_PIN_GROUP(gpio37),
BCM_PIN_GROUP(gpio38),
BCM_PIN_GROUP(gpio39),
BCM_PIN_GROUP(gpio40),
BCM_PIN_GROUP(gpio41),
BCM_PIN_GROUP(gpio42),
BCM_PIN_GROUP(gpio43),
BCM_PIN_GROUP(gpio44),
BCM_PIN_GROUP(gpio45),
BCM_PIN_GROUP(gpio46),
BCM_PIN_GROUP(gpio47),
BCM_PIN_GROUP(nand_grp),
};
static const char * const led_groups[] = {
"gpio0",
"gpio1",
"gpio2",
"gpio3",
"gpio4",
"gpio5",
"gpio6",
"gpio7",
"gpio8",
"gpio9",
"gpio10",
"gpio11",
"gpio12",
"gpio13",
"gpio14",
"gpio15",
"gpio16",
"gpio17",
"gpio18",
"gpio19",
"gpio20",
"gpio21",
"gpio22",
"gpio23",
};
static const char * const usb_device_led_groups[] = {
"gpio0",
};
static const char * const sys_irq_groups[] = {
"gpio1",
};
static const char * const serial_led_clk_groups[] = {
"gpio2",
};
static const char * const serial_led_data_groups[] = {
"gpio3",
};
static const char * const robosw_led_data_groups[] = {
"gpio4",
};
static const char * const robosw_led_clk_groups[] = {
"gpio5",
};
static const char * const robosw_led0_groups[] = {
"gpio6",
};
static const char * const robosw_led1_groups[] = {
"gpio7",
};
static const char * const inet_led_groups[] = {
"gpio8",
};
static const char * const spi_cs2_groups[] = {
"gpio9",
};
static const char * const spi_cs3_groups[] = {
"gpio10",
};
static const char * const ntr_pulse_groups[] = {
"gpio11",
};
static const char * const uart1_scts_groups[] = {
"gpio12",
};
static const char * const uart1_srts_groups[] = {
"gpio13",
};
static const char * const uart1_sdin_groups[] = {
"gpio14",
};
static const char * const uart1_sdout_groups[] = {
"gpio15",
};
static const char * const adsl_spi_miso_groups[] = {
"gpio16",
};
static const char * const adsl_spi_mosi_groups[] = {
"gpio17",
};
static const char * const adsl_spi_clk_groups[] = {
"gpio18",
};
static const char * const adsl_spi_cs_groups[] = {
"gpio19",
};
static const char * const ephy0_led_groups[] = {
"gpio20",
};
static const char * const ephy1_led_groups[] = {
"gpio21",
};
static const char * const ephy2_led_groups[] = {
"gpio22",
};
static const char * const ephy3_led_groups[] = {
"gpio23",
};
static const char * const ext_irq0_groups[] = {
"gpio24",
};
static const char * const ext_irq1_groups[] = {
"gpio25",
};
static const char * const ext_irq2_groups[] = {
"gpio26",
};
static const char * const ext_irq3_groups[] = {
"gpio27",
};
static const char * const wifi_groups[] = {
"gpio32",
"gpio33",
"gpio34",
"gpio35",
"gpio36",
"gpio37",
"gpio38",
"gpio39",
"gpio40",
"gpio41",
"gpio42",
"gpio43",
"gpio44",
"gpio45",
"gpio46",
"gpio47",
};
static const char * const nand_groups[] = {
"nand_grp",
};
#define BCM6362_LED_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM6362_LEDCTRL, \
}
#define BCM6362_MODE_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM6362_MODE, \
}
#define BCM6362_CTRL_FUN(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM6362_CTRL, \
}
#define BCM6362_BASEMODE_FUN(n, mask) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.reg = BCM6362_BASEMODE, \
.basemode_mask = (mask), \
}
static const struct bcm6362_function bcm6362_funcs[] = {
BCM6362_LED_FUN(led),
BCM6362_MODE_FUN(usb_device_led),
BCM6362_MODE_FUN(sys_irq),
BCM6362_MODE_FUN(serial_led_clk),
BCM6362_MODE_FUN(serial_led_data),
BCM6362_MODE_FUN(robosw_led_data),
BCM6362_MODE_FUN(robosw_led_clk),
BCM6362_MODE_FUN(robosw_led0),
BCM6362_MODE_FUN(robosw_led1),
BCM6362_MODE_FUN(inet_led),
BCM6362_MODE_FUN(spi_cs2),
BCM6362_MODE_FUN(spi_cs3),
BCM6362_MODE_FUN(ntr_pulse),
BCM6362_MODE_FUN(uart1_scts),
BCM6362_MODE_FUN(uart1_srts),
BCM6362_MODE_FUN(uart1_sdin),
BCM6362_MODE_FUN(uart1_sdout),
BCM6362_MODE_FUN(adsl_spi_miso),
BCM6362_MODE_FUN(adsl_spi_mosi),
BCM6362_MODE_FUN(adsl_spi_clk),
BCM6362_MODE_FUN(adsl_spi_cs),
BCM6362_MODE_FUN(ephy0_led),
BCM6362_MODE_FUN(ephy1_led),
BCM6362_MODE_FUN(ephy2_led),
BCM6362_MODE_FUN(ephy3_led),
BCM6362_MODE_FUN(ext_irq0),
BCM6362_MODE_FUN(ext_irq1),
BCM6362_MODE_FUN(ext_irq2),
BCM6362_MODE_FUN(ext_irq3),
BCM6362_CTRL_FUN(wifi),
BCM6362_BASEMODE_FUN(nand, BASEMODE_NAND),
};
static int bcm6362_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6362_groups);
}
static const char *bcm6362_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned group)
{
return bcm6362_groups[group].name;
}
static int bcm6362_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned group, const unsigned **pins,
unsigned *npins)
{
*pins = bcm6362_groups[group].pins;
*npins = bcm6362_groups[group].npins;
return 0;
}
static int bcm6362_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6362_funcs);
}
static const char *bcm6362_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return bcm6362_funcs[selector].name;
}
static int bcm6362_pinctrl_get_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = bcm6362_funcs[selector].groups;
*num_groups = bcm6362_funcs[selector].num_groups;
return 0;
}
static void bcm6362_set_gpio(struct bcm63xx_pinctrl *pc, unsigned pin)
{
const struct pinctrl_pin_desc *desc = &bcm6362_pins[pin];
unsigned int basemode = (uintptr_t)desc->drv_data;
unsigned int mask = bcm63xx_bank_pin(pin);
if (basemode)
regmap_update_bits(pc->regs, BCM6362_BASEMODE_REG, basemode, 0);
if (pin < BCM63XX_BANK_GPIOS) {
/* base mode 0 => gpio 1 => mux function */
regmap_update_bits(pc->regs, BCM6362_MODE_REG, mask, 0);
/* pins 0-23 might be muxed to led */
if (pin < BCM6362_NUM_LEDS)
regmap_update_bits(pc->regs, BCM6362_LED_REG, mask, 0);
} else {
/* ctrl reg 0 => wifi function 1 => gpio */
regmap_update_bits(pc->regs, BCM6362_CTRL_REG, mask, mask);
}
}
static int bcm6362_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned group)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
const struct pingroup *pg = &bcm6362_groups[group];
const struct bcm6362_function *f = &bcm6362_funcs[selector];
unsigned i;
unsigned int reg;
unsigned int val, mask;
for (i = 0; i < pg->npins; i++)
bcm6362_set_gpio(pc, pg->pins[i]);
switch (f->reg) {
case BCM6362_LEDCTRL:
reg = BCM6362_LED_REG;
mask = BIT(pg->pins[0]);
val = BIT(pg->pins[0]);
break;
case BCM6362_MODE:
reg = BCM6362_MODE_REG;
mask = BIT(pg->pins[0]);
val = BIT(pg->pins[0]);
break;
case BCM6362_CTRL:
reg = BCM6362_CTRL_REG;
mask = BIT(pg->pins[0]);
val = 0;
break;
case BCM6362_BASEMODE:
reg = BCM6362_BASEMODE_REG;
mask = f->basemode_mask;
val = f->basemode_mask;
break;
default:
WARN_ON(1);
return -EINVAL;
}
regmap_update_bits(pc->regs, reg, mask, val);
return 0;
}
static int bcm6362_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* disable all functions using this pin */
bcm6362_set_gpio(pc, offset);
return 0;
}
static const struct pinctrl_ops bcm6362_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6362_pinctrl_get_group_name,
.get_group_pins = bcm6362_pinctrl_get_group_pins,
.get_groups_count = bcm6362_pinctrl_get_group_count,
};
static const struct pinmux_ops bcm6362_pmx_ops = {
.get_function_groups = bcm6362_pinctrl_get_groups,
.get_function_name = bcm6362_pinctrl_get_func_name,
.get_functions_count = bcm6362_pinctrl_get_func_count,
.gpio_request_enable = bcm6362_gpio_request_enable,
.set_mux = bcm6362_pinctrl_set_mux,
.strict = true,
};
static const struct bcm63xx_pinctrl_soc bcm6362_soc = {
.ngpios = BCM6362_NUM_GPIOS,
.npins = ARRAY_SIZE(bcm6362_pins),
.pctl_ops = &bcm6362_pctl_ops,
.pins = bcm6362_pins,
.pmx_ops = &bcm6362_pmx_ops,
};
static int bcm6362_pinctrl_probe(struct platform_device *pdev)
{
return bcm63xx_pinctrl_probe(pdev, &bcm6362_soc, NULL);
}
static const struct of_device_id bcm6362_pinctrl_match[] = {
{ .compatible = "brcm,bcm6362-pinctrl", },
{ /* sentinel */ }
};
static struct platform_driver bcm6362_pinctrl_driver = {
.probe = bcm6362_pinctrl_probe,
.driver = {
.name = "bcm6362-pinctrl",
.of_match_table = bcm6362_pinctrl_match,
},
};
builtin_platform_driver(bcm6362_pinctrl_driver);
@@ -0,0 +1,510 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM6368 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl-utils.h"
#include "pinctrl-bcm63xx.h"
#define BCM6368_NUM_GPIOS 38
#define BCM6368_MODE_REG 0x18
#define BCM6368_BASEMODE_REG 0x38
#define BCM6368_BASEMODE_MASK 0x7
#define BCM6368_BASEMODE_GPIO 0x0
#define BCM6368_BASEMODE_UART1 0x1
struct bcm6368_function {
const char *name;
const char * const *groups;
const unsigned num_groups;
unsigned dir_out:16;
unsigned basemode:3;
};
struct bcm6368_priv {
struct regmap_field *overlays;
};
#define BCM6368_BASEMODE_PIN(a, b) \
{ \
.number = a, \
.name = b, \
.drv_data = (void *)true \
}
static const struct pinctrl_pin_desc bcm6368_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
PINCTRL_PIN(2, "gpio2"),
PINCTRL_PIN(3, "gpio3"),
PINCTRL_PIN(4, "gpio4"),
PINCTRL_PIN(5, "gpio5"),
PINCTRL_PIN(6, "gpio6"),
PINCTRL_PIN(7, "gpio7"),
PINCTRL_PIN(8, "gpio8"),
PINCTRL_PIN(9, "gpio9"),
PINCTRL_PIN(10, "gpio10"),
PINCTRL_PIN(11, "gpio11"),
PINCTRL_PIN(12, "gpio12"),
PINCTRL_PIN(13, "gpio13"),
PINCTRL_PIN(14, "gpio14"),
PINCTRL_PIN(15, "gpio15"),
PINCTRL_PIN(16, "gpio16"),
PINCTRL_PIN(17, "gpio17"),
PINCTRL_PIN(18, "gpio18"),
PINCTRL_PIN(19, "gpio19"),
PINCTRL_PIN(20, "gpio20"),
PINCTRL_PIN(21, "gpio21"),
PINCTRL_PIN(22, "gpio22"),
PINCTRL_PIN(23, "gpio23"),
PINCTRL_PIN(24, "gpio24"),
PINCTRL_PIN(25, "gpio25"),
PINCTRL_PIN(26, "gpio26"),
PINCTRL_PIN(27, "gpio27"),
PINCTRL_PIN(28, "gpio28"),
PINCTRL_PIN(29, "gpio29"),
BCM6368_BASEMODE_PIN(30, "gpio30"),
BCM6368_BASEMODE_PIN(31, "gpio31"),
BCM6368_BASEMODE_PIN(32, "gpio32"),
BCM6368_BASEMODE_PIN(33, "gpio33"),
PINCTRL_PIN(34, "gpio34"),
PINCTRL_PIN(35, "gpio35"),
PINCTRL_PIN(36, "gpio36"),
PINCTRL_PIN(37, "gpio37"),
};
static unsigned gpio0_pins[] = { 0 };
static unsigned gpio1_pins[] = { 1 };
static unsigned gpio2_pins[] = { 2 };
static unsigned gpio3_pins[] = { 3 };
static unsigned gpio4_pins[] = { 4 };
static unsigned gpio5_pins[] = { 5 };
static unsigned gpio6_pins[] = { 6 };
static unsigned gpio7_pins[] = { 7 };
static unsigned gpio8_pins[] = { 8 };
static unsigned gpio9_pins[] = { 9 };
static unsigned gpio10_pins[] = { 10 };
static unsigned gpio11_pins[] = { 11 };
static unsigned gpio12_pins[] = { 12 };
static unsigned gpio13_pins[] = { 13 };
static unsigned gpio14_pins[] = { 14 };
static unsigned gpio15_pins[] = { 15 };
static unsigned gpio16_pins[] = { 16 };
static unsigned gpio17_pins[] = { 17 };
static unsigned gpio18_pins[] = { 18 };
static unsigned gpio19_pins[] = { 19 };
static unsigned gpio20_pins[] = { 20 };
static unsigned gpio21_pins[] = { 21 };
static unsigned gpio22_pins[] = { 22 };
static unsigned gpio23_pins[] = { 23 };
static unsigned gpio24_pins[] = { 24 };
static unsigned gpio25_pins[] = { 25 };
static unsigned gpio26_pins[] = { 26 };
static unsigned gpio27_pins[] = { 27 };
static unsigned gpio28_pins[] = { 28 };
static unsigned gpio29_pins[] = { 29 };
static unsigned gpio30_pins[] = { 30 };
static unsigned gpio31_pins[] = { 31 };
static unsigned uart1_grp_pins[] = { 30, 31, 32, 33 };
static struct pingroup bcm6368_groups[] = {
BCM_PIN_GROUP(gpio0),
BCM_PIN_GROUP(gpio1),
BCM_PIN_GROUP(gpio2),
BCM_PIN_GROUP(gpio3),
BCM_PIN_GROUP(gpio4),
BCM_PIN_GROUP(gpio5),
BCM_PIN_GROUP(gpio6),
BCM_PIN_GROUP(gpio7),
BCM_PIN_GROUP(gpio8),
BCM_PIN_GROUP(gpio9),
BCM_PIN_GROUP(gpio10),
BCM_PIN_GROUP(gpio11),
BCM_PIN_GROUP(gpio12),
BCM_PIN_GROUP(gpio13),
BCM_PIN_GROUP(gpio14),
BCM_PIN_GROUP(gpio15),
BCM_PIN_GROUP(gpio16),
BCM_PIN_GROUP(gpio17),
BCM_PIN_GROUP(gpio18),
BCM_PIN_GROUP(gpio19),
BCM_PIN_GROUP(gpio20),
BCM_PIN_GROUP(gpio21),
BCM_PIN_GROUP(gpio22),
BCM_PIN_GROUP(gpio23),
BCM_PIN_GROUP(gpio24),
BCM_PIN_GROUP(gpio25),
BCM_PIN_GROUP(gpio26),
BCM_PIN_GROUP(gpio27),
BCM_PIN_GROUP(gpio28),
BCM_PIN_GROUP(gpio29),
BCM_PIN_GROUP(gpio30),
BCM_PIN_GROUP(gpio31),
BCM_PIN_GROUP(uart1_grp),
};
static const char * const analog_afe_0_groups[] = {
"gpio0",
};
static const char * const analog_afe_1_groups[] = {
"gpio1",
};
static const char * const sys_irq_groups[] = {
"gpio2",
};
static const char * const serial_led_data_groups[] = {
"gpio3",
};
static const char * const serial_led_clk_groups[] = {
"gpio4",
};
static const char * const inet_led_groups[] = {
"gpio5",
};
static const char * const ephy0_led_groups[] = {
"gpio6",
};
static const char * const ephy1_led_groups[] = {
"gpio7",
};
static const char * const ephy2_led_groups[] = {
"gpio8",
};
static const char * const ephy3_led_groups[] = {
"gpio9",
};
static const char * const robosw_led_data_groups[] = {
"gpio10",
};
static const char * const robosw_led_clk_groups[] = {
"gpio11",
};
static const char * const robosw_led0_groups[] = {
"gpio12",
};
static const char * const robosw_led1_groups[] = {
"gpio13",
};
static const char * const usb_device_led_groups[] = {
"gpio14",
};
static const char * const pci_req1_groups[] = {
"gpio16",
};
static const char * const pci_gnt1_groups[] = {
"gpio17",
};
static const char * const pci_intb_groups[] = {
"gpio18",
};
static const char * const pci_req0_groups[] = {
"gpio19",
};
static const char * const pci_gnt0_groups[] = {
"gpio20",
};
static const char * const pcmcia_cd1_groups[] = {
"gpio22",
};
static const char * const pcmcia_cd2_groups[] = {
"gpio23",
};
static const char * const pcmcia_vs1_groups[] = {
"gpio24",
};
static const char * const pcmcia_vs2_groups[] = {
"gpio25",
};
static const char * const ebi_cs2_groups[] = {
"gpio26",
};
static const char * const ebi_cs3_groups[] = {
"gpio27",
};
static const char * const spi_cs2_groups[] = {
"gpio28",
};
static const char * const spi_cs3_groups[] = {
"gpio29",
};
static const char * const spi_cs4_groups[] = {
"gpio30",
};
static const char * const spi_cs5_groups[] = {
"gpio31",
};
static const char * const uart1_groups[] = {
"uart1_grp",
};
#define BCM6368_FUN(n, out) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.dir_out = out, \
}
#define BCM6368_BASEMODE_FUN(n, val, out) \
{ \
.name = #n, \
.groups = n##_groups, \
.num_groups = ARRAY_SIZE(n##_groups), \
.basemode = BCM6368_BASEMODE_##val, \
.dir_out = out, \
}
static const struct bcm6368_function bcm6368_funcs[] = {
BCM6368_FUN(analog_afe_0, 1),
BCM6368_FUN(analog_afe_1, 1),
BCM6368_FUN(sys_irq, 1),
BCM6368_FUN(serial_led_data, 1),
BCM6368_FUN(serial_led_clk, 1),
BCM6368_FUN(inet_led, 1),
BCM6368_FUN(ephy0_led, 1),
BCM6368_FUN(ephy1_led, 1),
BCM6368_FUN(ephy2_led, 1),
BCM6368_FUN(ephy3_led, 1),
BCM6368_FUN(robosw_led_data, 1),
BCM6368_FUN(robosw_led_clk, 1),
BCM6368_FUN(robosw_led0, 1),
BCM6368_FUN(robosw_led1, 1),
BCM6368_FUN(usb_device_led, 1),
BCM6368_FUN(pci_req1, 0),
BCM6368_FUN(pci_gnt1, 0),
BCM6368_FUN(pci_intb, 0),
BCM6368_FUN(pci_req0, 0),
BCM6368_FUN(pci_gnt0, 0),
BCM6368_FUN(pcmcia_cd1, 0),
BCM6368_FUN(pcmcia_cd2, 0),
BCM6368_FUN(pcmcia_vs1, 0),
BCM6368_FUN(pcmcia_vs2, 0),
BCM6368_FUN(ebi_cs2, 1),
BCM6368_FUN(ebi_cs3, 1),
BCM6368_FUN(spi_cs2, 1),
BCM6368_FUN(spi_cs3, 1),
BCM6368_FUN(spi_cs4, 1),
BCM6368_FUN(spi_cs5, 1),
BCM6368_BASEMODE_FUN(uart1, UART1, 0x6),
};
static int bcm6368_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6368_groups);
}
static const char *bcm6368_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned group)
{
return bcm6368_groups[group].name;
}
static int bcm6368_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned group, const unsigned **pins,
unsigned *npins)
{
*pins = bcm6368_groups[group].pins;
*npins = bcm6368_groups[group].npins;
return 0;
}
static int bcm6368_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(bcm6368_funcs);
}
static const char *bcm6368_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return bcm6368_funcs[selector].name;
}
static int bcm6368_pinctrl_get_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = bcm6368_funcs[selector].groups;
*num_groups = bcm6368_funcs[selector].num_groups;
return 0;
}
static int bcm6368_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned group)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
struct bcm6368_priv *priv = pc->driver_data;
const struct pingroup *pg = &bcm6368_groups[group];
const struct bcm6368_function *fun = &bcm6368_funcs[selector];
int i, pin;
if (fun->basemode) {
unsigned int mask = 0;
for (i = 0; i < pg->npins; i++) {
pin = pg->pins[i];
if (pin < BCM63XX_BANK_GPIOS)
mask |= BIT(pin);
}
regmap_update_bits(pc->regs, BCM6368_MODE_REG, mask, 0);
regmap_field_write(priv->overlays, fun->basemode);
} else {
pin = pg->pins[0];
if (bcm6368_pins[pin].drv_data)
regmap_field_write(priv->overlays,
BCM6368_BASEMODE_GPIO);
regmap_update_bits(pc->regs, BCM6368_MODE_REG, BIT(pin),
BIT(pin));
}
for (pin = 0; pin < pg->npins; pin++) {
struct pinctrl_gpio_range *range;
int hw_gpio = bcm6368_pins[pin].number;
range = pinctrl_find_gpio_range_from_pin(pctldev, hw_gpio);
if (range) {
struct gpio_chip *gc = range->gc;
if (fun->dir_out & BIT(pin))
gc->direction_output(gc, hw_gpio, 0);
else
gc->direction_input(gc, hw_gpio);
}
}
return 0;
}
static int bcm6368_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
struct bcm6368_priv *priv = pc->driver_data;
if (offset >= BCM63XX_BANK_GPIOS && !bcm6368_pins[offset].drv_data)
return 0;
/* disable all functions using this pin */
if (offset < BCM63XX_BANK_GPIOS)
regmap_update_bits(pc->regs, BCM6368_MODE_REG, BIT(offset), 0);
if (bcm6368_pins[offset].drv_data)
regmap_field_write(priv->overlays, BCM6368_BASEMODE_GPIO);
return 0;
}
static const struct pinctrl_ops bcm6368_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6368_pinctrl_get_group_name,
.get_group_pins = bcm6368_pinctrl_get_group_pins,
.get_groups_count = bcm6368_pinctrl_get_group_count,
};
static const struct pinmux_ops bcm6368_pmx_ops = {
.get_function_groups = bcm6368_pinctrl_get_groups,
.get_function_name = bcm6368_pinctrl_get_func_name,
.get_functions_count = bcm6368_pinctrl_get_func_count,
.gpio_request_enable = bcm6368_gpio_request_enable,
.set_mux = bcm6368_pinctrl_set_mux,
.strict = true,
};
static const struct bcm63xx_pinctrl_soc bcm6368_soc = {
.ngpios = BCM6368_NUM_GPIOS,
.npins = ARRAY_SIZE(bcm6368_pins),
.pctl_ops = &bcm6368_pctl_ops,
.pins = bcm6368_pins,
.pmx_ops = &bcm6368_pmx_ops,
};
static int bcm6368_pinctrl_probe(struct platform_device *pdev)
{
struct reg_field overlays = REG_FIELD(BCM6368_BASEMODE_REG, 0, 15);
struct device *dev = &pdev->dev;
struct bcm63xx_pinctrl *pc;
struct bcm6368_priv *priv;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
err = bcm63xx_pinctrl_probe(pdev, &bcm6368_soc, (void *) priv);
if (err)
return err;
pc = platform_get_drvdata(pdev);
priv->overlays = devm_regmap_field_alloc(dev, pc->regs, overlays);
if (IS_ERR(priv->overlays))
return PTR_ERR(priv->overlays);
return 0;
}
static const struct of_device_id bcm6368_pinctrl_match[] = {
{ .compatible = "brcm,bcm6368-pinctrl", },
{ /* sentinel */ }
};
static struct platform_driver bcm6368_pinctrl_driver = {
.probe = bcm6368_pinctrl_probe,
.driver = {
.name = "bcm6368-pinctrl",
.of_match_table = bcm6368_pinctrl_match,
},
};
builtin_platform_driver(bcm6368_pinctrl_driver);
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for BCM63xx GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#include <linux/gpio/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "pinctrl-bcm63xx.h"
#define BCM63XX_BANK_SIZE 4
#define BCM63XX_DIROUT_REG 0x04
#define BCM63XX_DATA_REG 0x0c
static int bcm63xx_reg_mask_xlate(struct gpio_regmap *gpio,
unsigned int base, unsigned int offset,
unsigned int *reg, unsigned int *mask)
{
unsigned int line = offset % BCM63XX_BANK_GPIOS;
unsigned int stride = offset / BCM63XX_BANK_GPIOS;
*reg = base - stride * BCM63XX_BANK_SIZE;
*mask = BIT(line);
return 0;
}
static const struct of_device_id bcm63xx_gpio_of_match[] = {
{ .compatible = "brcm,bcm6318-gpio", },
{ .compatible = "brcm,bcm6328-gpio", },
{ .compatible = "brcm,bcm6358-gpio", },
{ .compatible = "brcm,bcm6362-gpio", },
{ .compatible = "brcm,bcm6368-gpio", },
{ .compatible = "brcm,bcm63268-gpio", },
{ /* sentinel */ }
};
static int bcm63xx_gpio_probe(struct device *dev, struct device_node *node,
const struct bcm63xx_pinctrl_soc *soc,
struct bcm63xx_pinctrl *pc)
{
struct gpio_regmap_config grc = {0};
grc.parent = dev;
grc.fwnode = &node->fwnode;
grc.ngpio = soc->ngpios;
grc.ngpio_per_reg = BCM63XX_BANK_GPIOS;
grc.regmap = pc->regs;
grc.reg_dat_base = BCM63XX_DATA_REG;
grc.reg_dir_out_base = BCM63XX_DIROUT_REG;
grc.reg_set_base = BCM63XX_DATA_REG;
grc.reg_mask_xlate = bcm63xx_reg_mask_xlate;
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &grc));
}
int bcm63xx_pinctrl_probe(struct platform_device *pdev,
const struct bcm63xx_pinctrl_soc *soc,
void *driver_data)
{
struct device *dev = &pdev->dev;
struct bcm63xx_pinctrl *pc;
int err;
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
platform_set_drvdata(pdev, pc);
pc->dev = dev;
pc->driver_data = driver_data;
pc->regs = syscon_node_to_regmap(dev->parent->of_node);
if (IS_ERR(pc->regs))
return PTR_ERR(pc->regs);
pc->pctl_desc.name = dev_name(dev);
pc->pctl_desc.pins = soc->pins;
pc->pctl_desc.npins = soc->npins;
pc->pctl_desc.pctlops = soc->pctl_ops;
pc->pctl_desc.pmxops = soc->pmx_ops;
pc->pctl_desc.owner = THIS_MODULE;
pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
if (IS_ERR(pc->pctl_dev))
return PTR_ERR(pc->pctl_dev);
for_each_child_of_node_scoped(dev->parent->of_node, node) {
if (of_match_node(bcm63xx_gpio_of_match, node)) {
err = bcm63xx_gpio_probe(dev, node, soc, pc);
if (err) {
dev_err(dev, "could not add GPIO chip\n");
return err;
}
}
}
return 0;
}
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
* Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
*/
#ifndef __PINCTRL_BCM63XX_H__
#define __PINCTRL_BCM63XX_H__
#include <linux/pinctrl/pinctrl.h>
#define BCM63XX_BANK_GPIOS 32
struct bcm63xx_pinctrl_soc {
const struct pinctrl_ops *pctl_ops;
const struct pinmux_ops *pmx_ops;
const struct pinctrl_pin_desc *pins;
unsigned npins;
unsigned int ngpios;
};
#define BCM_PIN_GROUP(n) PINCTRL_PINGROUP(#n, n##_pins, ARRAY_SIZE(n##_pins))
struct bcm63xx_pinctrl {
struct device *dev;
struct regmap *regs;
struct pinctrl_desc pctl_desc;
struct pinctrl_dev *pctl_dev;
void *driver_data;
};
static inline unsigned int bcm63xx_bank_pin(unsigned int pin)
{
return pin % BCM63XX_BANK_GPIOS;
}
int bcm63xx_pinctrl_probe(struct platform_device *pdev,
const struct bcm63xx_pinctrl_soc *soc,
void *driver_data);
#endif /* __PINCTRL_BCM63XX_H__ */
@@ -0,0 +1,747 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Broadcom brcmstb GPIO units (pinctrl only)
*
* Copyright (C) 2024-2025 Ivan T. Ivanov, Andrea della Porta
* Copyright (C) 2021-3 Raspberry Pi Ltd.
* Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren
*
* Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by:
* pinctrl-nomadik.c, please see original file for copyright information
* pinctrl-tegra.c, please see original file for copyright information
*/
#include <linux/pinctrl/pinctrl.h>
#include <linux/of.h>
#include "pinctrl-brcmstb.h"
#define BRCMSTB_FSEL_COUNT 8
#define BRCMSTB_FSEL_MASK 0xf
#define BRCMSTB_PIN(i, f1, f2, f3, f4, f5, f6, f7, f8) \
[i] = { \
.funcs = (u8[]) { \
func_##f1, \
func_##f2, \
func_##f3, \
func_##f4, \
func_##f5, \
func_##f6, \
func_##f7, \
func_##f8, \
}, \
.n_funcs = BRCMSTB_FSEL_COUNT, \
.func_mask = BRCMSTB_FSEL_MASK, \
}
enum bcm2712_funcs {
func_gpio,
func_alt1,
func_alt2,
func_alt3,
func_alt4,
func_alt5,
func_alt6,
func_alt7,
func_alt8,
func_aon_cpu_standbyb,
func_aon_fp_4sec_resetb,
func_aon_gpclk,
func_aon_pwm,
func_arm_jtag,
func_aud_fs_clk0,
func_avs_pmu_bsc,
func_bsc_m0,
func_bsc_m1,
func_bsc_m2,
func_bsc_m3,
func_clk_observe,
func_ctl_hdmi_5v,
func_enet0,
func_enet0_mii,
func_enet0_rgmii,
func_ext_sc_clk,
func_fl0,
func_fl1,
func_gpclk0,
func_gpclk1,
func_gpclk2,
func_hdmi_tx0_auto_i2c,
func_hdmi_tx0_bsc,
func_hdmi_tx1_auto_i2c,
func_hdmi_tx1_bsc,
func_i2s_in,
func_i2s_out,
func_ir_in,
func_mtsif,
func_mtsif_alt,
func_mtsif_alt1,
func_pdm,
func_pkt,
func_pm_led_out,
func_sc0,
func_sd0,
func_sd2,
func_sd_card_a,
func_sd_card_b,
func_sd_card_c,
func_sd_card_d,
func_sd_card_e,
func_sd_card_f,
func_sd_card_g,
func_spdif_out,
func_spi_m,
func_spi_s,
func_sr_edm_sense,
func_te0,
func_te1,
func_tsio,
func_uart0,
func_uart1,
func_uart2,
func_usb_pwr,
func_usb_vbus,
func_uui,
func_vc_i2c0,
func_vc_i2c3,
func_vc_i2c4,
func_vc_i2c5,
func_vc_i2csl,
func_vc_pcm,
func_vc_pwm0,
func_vc_pwm1,
func_vc_spi0,
func_vc_spi3,
func_vc_spi4,
func_vc_spi5,
func_vc_uart0,
func_vc_uart2,
func_vc_uart3,
func_vc_uart4,
func__,
func_count = func__
};
static const struct pin_regs bcm2712_c0_gpio_pin_regs[] = {
GPIO_REGS(0, 0, 0, 7, 7),
GPIO_REGS(1, 0, 1, 7, 8),
GPIO_REGS(2, 0, 2, 7, 9),
GPIO_REGS(3, 0, 3, 7, 10),
GPIO_REGS(4, 0, 4, 7, 11),
GPIO_REGS(5, 0, 5, 7, 12),
GPIO_REGS(6, 0, 6, 7, 13),
GPIO_REGS(7, 0, 7, 7, 14),
GPIO_REGS(8, 1, 0, 8, 0),
GPIO_REGS(9, 1, 1, 8, 1),
GPIO_REGS(10, 1, 2, 8, 2),
GPIO_REGS(11, 1, 3, 8, 3),
GPIO_REGS(12, 1, 4, 8, 4),
GPIO_REGS(13, 1, 5, 8, 5),
GPIO_REGS(14, 1, 6, 8, 6),
GPIO_REGS(15, 1, 7, 8, 7),
GPIO_REGS(16, 2, 0, 8, 8),
GPIO_REGS(17, 2, 1, 8, 9),
GPIO_REGS(18, 2, 2, 8, 10),
GPIO_REGS(19, 2, 3, 8, 11),
GPIO_REGS(20, 2, 4, 8, 12),
GPIO_REGS(21, 2, 5, 8, 13),
GPIO_REGS(22, 2, 6, 8, 14),
GPIO_REGS(23, 2, 7, 9, 0),
GPIO_REGS(24, 3, 0, 9, 1),
GPIO_REGS(25, 3, 1, 9, 2),
GPIO_REGS(26, 3, 2, 9, 3),
GPIO_REGS(27, 3, 3, 9, 4),
GPIO_REGS(28, 3, 4, 9, 5),
GPIO_REGS(29, 3, 5, 9, 6),
GPIO_REGS(30, 3, 6, 9, 7),
GPIO_REGS(31, 3, 7, 9, 8),
GPIO_REGS(32, 4, 0, 9, 9),
GPIO_REGS(33, 4, 1, 9, 10),
GPIO_REGS(34, 4, 2, 9, 11),
GPIO_REGS(35, 4, 3, 9, 12),
GPIO_REGS(36, 4, 4, 9, 13),
GPIO_REGS(37, 4, 5, 9, 14),
GPIO_REGS(38, 4, 6, 10, 0),
GPIO_REGS(39, 4, 7, 10, 1),
GPIO_REGS(40, 5, 0, 10, 2),
GPIO_REGS(41, 5, 1, 10, 3),
GPIO_REGS(42, 5, 2, 10, 4),
GPIO_REGS(43, 5, 3, 10, 5),
GPIO_REGS(44, 5, 4, 10, 6),
GPIO_REGS(45, 5, 5, 10, 7),
GPIO_REGS(46, 5, 6, 10, 8),
GPIO_REGS(47, 5, 7, 10, 9),
GPIO_REGS(48, 6, 0, 10, 10),
GPIO_REGS(49, 6, 1, 10, 11),
GPIO_REGS(50, 6, 2, 10, 12),
GPIO_REGS(51, 6, 3, 10, 13),
GPIO_REGS(52, 6, 4, 10, 14),
GPIO_REGS(53, 6, 5, 11, 0),
EMMC_REGS(54, 11, 1), /* EMMC_CMD */
EMMC_REGS(55, 11, 2), /* EMMC_DS */
EMMC_REGS(56, 11, 3), /* EMMC_CLK */
EMMC_REGS(57, 11, 4), /* EMMC_DAT0 */
EMMC_REGS(58, 11, 5), /* EMMC_DAT1 */
EMMC_REGS(59, 11, 6), /* EMMC_DAT2 */
EMMC_REGS(60, 11, 7), /* EMMC_DAT3 */
EMMC_REGS(61, 11, 8), /* EMMC_DAT4 */
EMMC_REGS(62, 11, 9), /* EMMC_DAT5 */
EMMC_REGS(63, 11, 10), /* EMMC_DAT6 */
EMMC_REGS(64, 11, 11), /* EMMC_DAT7 */
};
static struct pin_regs bcm2712_c0_aon_gpio_pin_regs[] = {
AON_GPIO_REGS(0, 3, 0, 6, 10),
AON_GPIO_REGS(1, 3, 1, 6, 11),
AON_GPIO_REGS(2, 3, 2, 6, 12),
AON_GPIO_REGS(3, 3, 3, 6, 13),
AON_GPIO_REGS(4, 3, 4, 6, 14),
AON_GPIO_REGS(5, 3, 5, 7, 0),
AON_GPIO_REGS(6, 3, 6, 7, 1),
AON_GPIO_REGS(7, 3, 7, 7, 2),
AON_GPIO_REGS(8, 4, 0, 7, 3),
AON_GPIO_REGS(9, 4, 1, 7, 4),
AON_GPIO_REGS(10, 4, 2, 7, 5),
AON_GPIO_REGS(11, 4, 3, 7, 6),
AON_GPIO_REGS(12, 4, 4, 7, 7),
AON_GPIO_REGS(13, 4, 5, 7, 8),
AON_GPIO_REGS(14, 4, 6, 7, 9),
AON_GPIO_REGS(15, 4, 7, 7, 10),
AON_GPIO_REGS(16, 5, 0, 7, 11),
AON_SGPIO_REGS(0, 0, 0),
AON_SGPIO_REGS(1, 0, 1),
AON_SGPIO_REGS(2, 0, 2),
AON_SGPIO_REGS(3, 0, 3),
AON_SGPIO_REGS(4, 1, 0),
AON_SGPIO_REGS(5, 2, 0),
};
static const struct pinctrl_pin_desc bcm2712_c0_gpio_pins[] = {
GPIO_PIN(0),
GPIO_PIN(1),
GPIO_PIN(2),
GPIO_PIN(3),
GPIO_PIN(4),
GPIO_PIN(5),
GPIO_PIN(6),
GPIO_PIN(7),
GPIO_PIN(8),
GPIO_PIN(9),
GPIO_PIN(10),
GPIO_PIN(11),
GPIO_PIN(12),
GPIO_PIN(13),
GPIO_PIN(14),
GPIO_PIN(15),
GPIO_PIN(16),
GPIO_PIN(17),
GPIO_PIN(18),
GPIO_PIN(19),
GPIO_PIN(20),
GPIO_PIN(21),
GPIO_PIN(22),
GPIO_PIN(23),
GPIO_PIN(24),
GPIO_PIN(25),
GPIO_PIN(26),
GPIO_PIN(27),
GPIO_PIN(28),
GPIO_PIN(29),
GPIO_PIN(30),
GPIO_PIN(31),
GPIO_PIN(32),
GPIO_PIN(33),
GPIO_PIN(34),
GPIO_PIN(35),
GPIO_PIN(36),
GPIO_PIN(37),
GPIO_PIN(38),
GPIO_PIN(39),
GPIO_PIN(40),
GPIO_PIN(41),
GPIO_PIN(42),
GPIO_PIN(43),
GPIO_PIN(44),
GPIO_PIN(45),
GPIO_PIN(46),
GPIO_PIN(47),
GPIO_PIN(48),
GPIO_PIN(49),
GPIO_PIN(50),
GPIO_PIN(51),
GPIO_PIN(52),
GPIO_PIN(53),
PINCTRL_PIN(54, "emmc_cmd"),
PINCTRL_PIN(55, "emmc_ds"),
PINCTRL_PIN(56, "emmc_clk"),
PINCTRL_PIN(57, "emmc_dat0"),
PINCTRL_PIN(58, "emmc_dat1"),
PINCTRL_PIN(59, "emmc_dat2"),
PINCTRL_PIN(60, "emmc_dat3"),
PINCTRL_PIN(61, "emmc_dat4"),
PINCTRL_PIN(62, "emmc_dat5"),
PINCTRL_PIN(63, "emmc_dat6"),
PINCTRL_PIN(64, "emmc_dat7"),
};
static struct pinctrl_pin_desc bcm2712_c0_aon_gpio_pins[] = {
AON_GPIO_PIN(0), AON_GPIO_PIN(1), AON_GPIO_PIN(2), AON_GPIO_PIN(3),
AON_GPIO_PIN(4), AON_GPIO_PIN(5), AON_GPIO_PIN(6), AON_GPIO_PIN(7),
AON_GPIO_PIN(8), AON_GPIO_PIN(9), AON_GPIO_PIN(10), AON_GPIO_PIN(11),
AON_GPIO_PIN(12), AON_GPIO_PIN(13), AON_GPIO_PIN(14), AON_GPIO_PIN(15),
AON_GPIO_PIN(16), AON_SGPIO_PIN(0), AON_SGPIO_PIN(1), AON_SGPIO_PIN(2),
AON_SGPIO_PIN(3), AON_SGPIO_PIN(4), AON_SGPIO_PIN(5),
};
static const struct pin_regs bcm2712_d0_gpio_pin_regs[] = {
GPIO_REGS(1, 0, 0, 4, 5),
GPIO_REGS(2, 0, 1, 4, 6),
GPIO_REGS(3, 0, 2, 4, 7),
GPIO_REGS(4, 0, 3, 4, 8),
GPIO_REGS(10, 0, 4, 4, 9),
GPIO_REGS(11, 0, 5, 4, 10),
GPIO_REGS(12, 0, 6, 4, 11),
GPIO_REGS(13, 0, 7, 4, 12),
GPIO_REGS(14, 1, 0, 4, 13),
GPIO_REGS(15, 1, 1, 4, 14),
GPIO_REGS(18, 1, 2, 5, 0),
GPIO_REGS(19, 1, 3, 5, 1),
GPIO_REGS(20, 1, 4, 5, 2),
GPIO_REGS(21, 1, 5, 5, 3),
GPIO_REGS(22, 1, 6, 5, 4),
GPIO_REGS(23, 1, 7, 5, 5),
GPIO_REGS(24, 2, 0, 5, 6),
GPIO_REGS(25, 2, 1, 5, 7),
GPIO_REGS(26, 2, 2, 5, 8),
GPIO_REGS(27, 2, 3, 5, 9),
GPIO_REGS(28, 2, 4, 5, 10),
GPIO_REGS(29, 2, 5, 5, 11),
GPIO_REGS(30, 2, 6, 5, 12),
GPIO_REGS(31, 2, 7, 5, 13),
GPIO_REGS(32, 3, 0, 5, 14),
GPIO_REGS(33, 3, 1, 6, 0),
GPIO_REGS(34, 3, 2, 6, 1),
GPIO_REGS(35, 3, 3, 6, 2),
EMMC_REGS(36, 6, 3), /* EMMC_CMD */
EMMC_REGS(37, 6, 4), /* EMMC_DS */
EMMC_REGS(38, 6, 5), /* EMMC_CLK */
EMMC_REGS(39, 6, 6), /* EMMC_DAT0 */
EMMC_REGS(40, 6, 7), /* EMMC_DAT1 */
EMMC_REGS(41, 6, 8), /* EMMC_DAT2 */
EMMC_REGS(42, 6, 9), /* EMMC_DAT3 */
EMMC_REGS(43, 6, 10), /* EMMC_DAT4 */
EMMC_REGS(44, 6, 11), /* EMMC_DAT5 */
EMMC_REGS(45, 6, 12), /* EMMC_DAT6 */
EMMC_REGS(46, 6, 13), /* EMMC_DAT7 */
};
static struct pin_regs bcm2712_d0_aon_gpio_pin_regs[] = {
AON_GPIO_REGS(0, 3, 0, 5, 9),
AON_GPIO_REGS(1, 3, 1, 5, 10),
AON_GPIO_REGS(2, 3, 2, 5, 11),
AON_GPIO_REGS(3, 3, 3, 5, 12),
AON_GPIO_REGS(4, 3, 4, 5, 13),
AON_GPIO_REGS(5, 3, 5, 5, 14),
AON_GPIO_REGS(6, 3, 6, 6, 0),
AON_GPIO_REGS(8, 3, 7, 6, 1),
AON_GPIO_REGS(9, 4, 0, 6, 2),
AON_GPIO_REGS(12, 4, 1, 6, 3),
AON_GPIO_REGS(13, 4, 2, 6, 4),
AON_GPIO_REGS(14, 4, 3, 6, 5),
AON_SGPIO_REGS(0, 0, 0),
AON_SGPIO_REGS(1, 0, 1),
AON_SGPIO_REGS(2, 0, 2),
AON_SGPIO_REGS(3, 0, 3),
AON_SGPIO_REGS(4, 1, 0),
AON_SGPIO_REGS(5, 2, 0),
};
static const struct pinctrl_pin_desc bcm2712_d0_gpio_pins[] = {
GPIO_PIN(1),
GPIO_PIN(2),
GPIO_PIN(3),
GPIO_PIN(4),
GPIO_PIN(10),
GPIO_PIN(11),
GPIO_PIN(12),
GPIO_PIN(13),
GPIO_PIN(14),
GPIO_PIN(15),
GPIO_PIN(18),
GPIO_PIN(19),
GPIO_PIN(20),
GPIO_PIN(21),
GPIO_PIN(22),
GPIO_PIN(23),
GPIO_PIN(24),
GPIO_PIN(25),
GPIO_PIN(26),
GPIO_PIN(27),
GPIO_PIN(28),
GPIO_PIN(29),
GPIO_PIN(30),
GPIO_PIN(31),
GPIO_PIN(32),
GPIO_PIN(33),
GPIO_PIN(34),
GPIO_PIN(35),
PINCTRL_PIN(36, "emmc_cmd"),
PINCTRL_PIN(37, "emmc_ds"),
PINCTRL_PIN(38, "emmc_clk"),
PINCTRL_PIN(39, "emmc_dat0"),
PINCTRL_PIN(40, "emmc_dat1"),
PINCTRL_PIN(41, "emmc_dat2"),
PINCTRL_PIN(42, "emmc_dat3"),
PINCTRL_PIN(43, "emmc_dat4"),
PINCTRL_PIN(44, "emmc_dat5"),
PINCTRL_PIN(45, "emmc_dat6"),
PINCTRL_PIN(46, "emmc_dat7"),
};
static struct pinctrl_pin_desc bcm2712_d0_aon_gpio_pins[] = {
AON_GPIO_PIN(0), AON_GPIO_PIN(1), AON_GPIO_PIN(2), AON_GPIO_PIN(3),
AON_GPIO_PIN(4), AON_GPIO_PIN(5), AON_GPIO_PIN(6), AON_GPIO_PIN(8),
AON_GPIO_PIN(9), AON_GPIO_PIN(12), AON_GPIO_PIN(13), AON_GPIO_PIN(14),
AON_SGPIO_PIN(0), AON_SGPIO_PIN(1), AON_SGPIO_PIN(2),
AON_SGPIO_PIN(3), AON_SGPIO_PIN(4), AON_SGPIO_PIN(5),
};
static const char * const bcm2712_func_names[] = {
BRCMSTB_FUNC(gpio),
BRCMSTB_FUNC(alt1),
BRCMSTB_FUNC(alt2),
BRCMSTB_FUNC(alt3),
BRCMSTB_FUNC(alt4),
BRCMSTB_FUNC(alt5),
BRCMSTB_FUNC(alt6),
BRCMSTB_FUNC(alt7),
BRCMSTB_FUNC(alt8),
BRCMSTB_FUNC(aon_cpu_standbyb),
BRCMSTB_FUNC(aon_fp_4sec_resetb),
BRCMSTB_FUNC(aon_gpclk),
BRCMSTB_FUNC(aon_pwm),
BRCMSTB_FUNC(arm_jtag),
BRCMSTB_FUNC(aud_fs_clk0),
BRCMSTB_FUNC(avs_pmu_bsc),
BRCMSTB_FUNC(bsc_m0),
BRCMSTB_FUNC(bsc_m1),
BRCMSTB_FUNC(bsc_m2),
BRCMSTB_FUNC(bsc_m3),
BRCMSTB_FUNC(clk_observe),
BRCMSTB_FUNC(ctl_hdmi_5v),
BRCMSTB_FUNC(enet0),
BRCMSTB_FUNC(enet0_mii),
BRCMSTB_FUNC(enet0_rgmii),
BRCMSTB_FUNC(ext_sc_clk),
BRCMSTB_FUNC(fl0),
BRCMSTB_FUNC(fl1),
BRCMSTB_FUNC(gpclk0),
BRCMSTB_FUNC(gpclk1),
BRCMSTB_FUNC(gpclk2),
BRCMSTB_FUNC(hdmi_tx0_auto_i2c),
BRCMSTB_FUNC(hdmi_tx0_bsc),
BRCMSTB_FUNC(hdmi_tx1_auto_i2c),
BRCMSTB_FUNC(hdmi_tx1_bsc),
BRCMSTB_FUNC(i2s_in),
BRCMSTB_FUNC(i2s_out),
BRCMSTB_FUNC(ir_in),
BRCMSTB_FUNC(mtsif),
BRCMSTB_FUNC(mtsif_alt),
BRCMSTB_FUNC(mtsif_alt1),
BRCMSTB_FUNC(pdm),
BRCMSTB_FUNC(pkt),
BRCMSTB_FUNC(pm_led_out),
BRCMSTB_FUNC(sc0),
BRCMSTB_FUNC(sd0),
BRCMSTB_FUNC(sd2),
BRCMSTB_FUNC(sd_card_a),
BRCMSTB_FUNC(sd_card_b),
BRCMSTB_FUNC(sd_card_c),
BRCMSTB_FUNC(sd_card_d),
BRCMSTB_FUNC(sd_card_e),
BRCMSTB_FUNC(sd_card_f),
BRCMSTB_FUNC(sd_card_g),
BRCMSTB_FUNC(spdif_out),
BRCMSTB_FUNC(spi_m),
BRCMSTB_FUNC(spi_s),
BRCMSTB_FUNC(sr_edm_sense),
BRCMSTB_FUNC(te0),
BRCMSTB_FUNC(te1),
BRCMSTB_FUNC(tsio),
BRCMSTB_FUNC(uart0),
BRCMSTB_FUNC(uart1),
BRCMSTB_FUNC(uart2),
BRCMSTB_FUNC(usb_pwr),
BRCMSTB_FUNC(usb_vbus),
BRCMSTB_FUNC(uui),
BRCMSTB_FUNC(vc_i2c0),
BRCMSTB_FUNC(vc_i2c3),
BRCMSTB_FUNC(vc_i2c4),
BRCMSTB_FUNC(vc_i2c5),
BRCMSTB_FUNC(vc_i2csl),
BRCMSTB_FUNC(vc_pcm),
BRCMSTB_FUNC(vc_pwm0),
BRCMSTB_FUNC(vc_pwm1),
BRCMSTB_FUNC(vc_spi0),
BRCMSTB_FUNC(vc_spi3),
BRCMSTB_FUNC(vc_spi4),
BRCMSTB_FUNC(vc_spi5),
BRCMSTB_FUNC(vc_uart0),
BRCMSTB_FUNC(vc_uart2),
BRCMSTB_FUNC(vc_uart3),
BRCMSTB_FUNC(vc_uart4),
};
static const struct brcmstb_pin_funcs bcm2712_c0_aon_gpio_pin_funcs[] = {
BRCMSTB_PIN(0, ir_in, vc_spi0, vc_uart3, vc_i2c3, te0, vc_i2c0, _, _),
BRCMSTB_PIN(1, vc_pwm0, vc_spi0, vc_uart3, vc_i2c3, te1, aon_pwm, vc_i2c0, vc_pwm1),
BRCMSTB_PIN(2, vc_pwm0, vc_spi0, vc_uart3, ctl_hdmi_5v, fl0, aon_pwm, ir_in, vc_pwm1),
BRCMSTB_PIN(3, ir_in, vc_spi0, vc_uart3, aon_fp_4sec_resetb, fl1, sd_card_g, aon_gpclk, _),
BRCMSTB_PIN(4, gpclk0, vc_spi0, vc_i2csl, aon_gpclk, pm_led_out, aon_pwm, sd_card_g, vc_pwm0),
BRCMSTB_PIN(5, gpclk1, ir_in, vc_i2csl, clk_observe, aon_pwm, sd_card_g, vc_pwm0, _),
BRCMSTB_PIN(6, uart1, vc_uart4, gpclk2, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _),
BRCMSTB_PIN(7, uart1, vc_uart4, gpclk0, aon_pwm, vc_uart0, vc_spi3, _, _),
BRCMSTB_PIN(8, uart1, vc_uart4, vc_i2csl, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _),
BRCMSTB_PIN(9, uart1, vc_uart4, vc_i2csl, aon_pwm, vc_uart0, vc_spi3, _, _),
BRCMSTB_PIN(10, tsio, ctl_hdmi_5v, sc0, spdif_out, vc_spi5, usb_pwr, aon_gpclk, sd_card_f),
BRCMSTB_PIN(11, tsio, uart0, sc0, aud_fs_clk0, vc_spi5, usb_vbus, vc_uart2, sd_card_f),
BRCMSTB_PIN(12, tsio, uart0, vc_uart0, tsio, vc_spi5, usb_pwr, vc_uart2, sd_card_f),
BRCMSTB_PIN(13, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3),
BRCMSTB_PIN(14, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3),
BRCMSTB_PIN(15, ir_in, aon_fp_4sec_resetb, vc_uart0, pm_led_out, ctl_hdmi_5v, aon_pwm, aon_gpclk, _),
BRCMSTB_PIN(16, aon_cpu_standbyb, gpclk0, pm_led_out, ctl_hdmi_5v, vc_pwm0, usb_pwr, aud_fs_clk0, _),
};
static const struct brcmstb_pin_funcs bcm2712_c0_gpio_pin_funcs[] = {
BRCMSTB_PIN(0, bsc_m3, vc_i2c0, gpclk0, enet0, vc_pwm1, vc_spi0, ir_in, _),
BRCMSTB_PIN(1, bsc_m3, vc_i2c0, gpclk1, enet0, vc_pwm1, sr_edm_sense, vc_spi0, vc_uart3),
BRCMSTB_PIN(2, pdm, i2s_in, gpclk2, vc_spi4, pkt, vc_spi0, vc_uart3, _),
BRCMSTB_PIN(3, pdm, i2s_in, vc_spi4, pkt, vc_spi0, vc_uart3, _, _),
BRCMSTB_PIN(4, pdm, i2s_in, arm_jtag, vc_spi4, pkt, vc_spi0, vc_uart3, _),
BRCMSTB_PIN(5, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5),
BRCMSTB_PIN(6, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5),
BRCMSTB_PIN(7, i2s_out, spdif_out, arm_jtag, sd_card_e, vc_i2c3, enet0_rgmii, vc_pcm, vc_spi4),
BRCMSTB_PIN(8, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, vc_i2c3, enet0_mii, vc_pcm, vc_spi4),
BRCMSTB_PIN(9, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, enet0_mii, sd_card_c, vc_spi4, _),
BRCMSTB_PIN(10, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4),
BRCMSTB_PIN(11, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4),
BRCMSTB_PIN(12, spi_s, mtsif_alt1, i2s_in, i2s_out, vc_spi5, vc_i2csl, sd0, sd_card_d),
BRCMSTB_PIN(13, spi_s, mtsif_alt1, i2s_out, usb_vbus, vc_spi5, vc_i2csl, sd0, sd_card_d),
BRCMSTB_PIN(14, spi_s, vc_i2csl, enet0_rgmii, arm_jtag, vc_spi5, vc_pwm0, vc_i2c4, sd_card_d),
BRCMSTB_PIN(15, spi_s, vc_i2csl, vc_spi3, arm_jtag, vc_pwm0, vc_i2c4, gpclk0, _),
BRCMSTB_PIN(16, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, gpclk1, _),
BRCMSTB_PIN(17, sd_card_b, i2s_out, vc_spi3, i2s_in, ext_sc_clk, sd0, enet0_rgmii, gpclk2),
BRCMSTB_PIN(18, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, vc_pwm1, _),
BRCMSTB_PIN(19, sd_card_b, usb_pwr, vc_spi3, pkt, spdif_out, sd0, ir_in, vc_pwm1),
BRCMSTB_PIN(20, sd_card_b, uui, vc_uart0, arm_jtag, uart2, usb_pwr, vc_pcm, vc_uart4),
BRCMSTB_PIN(21, usb_pwr, uui, vc_uart0, arm_jtag, uart2, sd_card_b, vc_pcm, vc_uart4),
BRCMSTB_PIN(22, usb_pwr, enet0, vc_uart0, mtsif, uart2, usb_vbus, vc_pcm, vc_i2c5),
BRCMSTB_PIN(23, usb_vbus, enet0, vc_uart0, mtsif, uart2, i2s_out, vc_pcm, vc_i2c5),
BRCMSTB_PIN(24, mtsif, pkt, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3, _),
BRCMSTB_PIN(25, mtsif, pkt, sc0, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3),
BRCMSTB_PIN(26, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _),
BRCMSTB_PIN(27, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _),
BRCMSTB_PIN(28, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _),
BRCMSTB_PIN(29, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _),
BRCMSTB_PIN(30, mtsif, pkt, sc0, sd2, enet0_rgmii, gpclk0, vc_pwm0, _),
BRCMSTB_PIN(31, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_pwm0, _),
BRCMSTB_PIN(32, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_uart3, _),
BRCMSTB_PIN(33, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_uart3, _, _),
BRCMSTB_PIN(34, mtsif, pkt, ext_sc_clk, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _),
BRCMSTB_PIN(35, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _, _),
BRCMSTB_PIN(36, sd0, mtsif, sc0, i2s_in, vc_uart3, vc_uart2, _, _),
BRCMSTB_PIN(37, sd0, mtsif, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _),
BRCMSTB_PIN(38, sd0, mtsif_alt, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _),
BRCMSTB_PIN(39, sd0, mtsif_alt, sc0, vc_spi0, vc_uart3, vc_uart2, _, _),
BRCMSTB_PIN(40, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _),
BRCMSTB_PIN(41, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _),
BRCMSTB_PIN(42, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m),
BRCMSTB_PIN(43, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m),
BRCMSTB_PIN(44, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m),
BRCMSTB_PIN(45, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m),
BRCMSTB_PIN(46, vc_spi0, mtsif_alt, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m, _),
BRCMSTB_PIN(47, enet0, mtsif_alt, i2s_out, mtsif_alt1, arm_jtag, _, _, _),
BRCMSTB_PIN(48, sc0, usb_pwr, spdif_out, mtsif, _, _, _, _),
BRCMSTB_PIN(49, sc0, usb_pwr, aud_fs_clk0, mtsif, _, _, _, _),
BRCMSTB_PIN(50, sc0, usb_vbus, sc0, _, _, _, _, _),
BRCMSTB_PIN(51, sc0, enet0, sc0, sr_edm_sense, _, _, _, _),
BRCMSTB_PIN(52, sc0, enet0, vc_pwm1, _, _, _, _, _),
BRCMSTB_PIN(53, sc0, enet0_rgmii, ext_sc_clk, _, _, _, _, _),
};
static const struct brcmstb_pin_funcs bcm2712_d0_aon_gpio_pin_funcs[] = {
BRCMSTB_PIN(0, ir_in, vc_spi0, vc_uart0, vc_i2c3, uart0, vc_i2c0, _, _),
BRCMSTB_PIN(1, vc_pwm0, vc_spi0, vc_uart0, vc_i2c3, uart0, aon_pwm, vc_i2c0, vc_pwm1),
BRCMSTB_PIN(2, vc_pwm0, vc_spi0, vc_uart0, ctl_hdmi_5v, uart0, aon_pwm, ir_in, vc_pwm1),
BRCMSTB_PIN(3, ir_in, vc_spi0, vc_uart0, uart0, sd_card_g, aon_gpclk, _, _),
BRCMSTB_PIN(4, gpclk0, vc_spi0, pm_led_out, aon_pwm, sd_card_g, vc_pwm0, _, _),
BRCMSTB_PIN(5, gpclk1, ir_in, aon_pwm, sd_card_g, vc_pwm0, _, _, _),
BRCMSTB_PIN(6, uart1, vc_uart2, ctl_hdmi_5v, gpclk2, vc_spi3, _, _, _),
BRCMSTB_PIN(7, _, _, _, _, _, _, _, _), /* non-existent on D0 silicon */
BRCMSTB_PIN(8, uart1, vc_uart2, ctl_hdmi_5v, vc_spi0, vc_spi3, _, _, _),
BRCMSTB_PIN(9, uart1, vc_uart2, vc_uart0, aon_pwm, vc_spi0, vc_uart2, vc_spi3, _),
BRCMSTB_PIN(10, _, _, _, _, _, _, _, _), /* non-existent on D0 silicon */
BRCMSTB_PIN(11, _, _, _, _, _, _, _, _), /* non-existent on D0 silicon */
BRCMSTB_PIN(12, uart1, vc_uart2, vc_uart0, vc_spi0, usb_pwr, vc_uart2, vc_spi3, _),
BRCMSTB_PIN(13, bsc_m1, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3, _),
BRCMSTB_PIN(14, bsc_m1, aon_gpclk, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3),
};
static const struct brcmstb_pin_funcs bcm2712_d0_gpio_pin_funcs[] = {
BRCMSTB_PIN(1, vc_i2c0, usb_pwr, gpclk0, sd_card_e, vc_spi3, sr_edm_sense, vc_spi0, vc_uart0),
BRCMSTB_PIN(2, vc_i2c0, usb_pwr, gpclk1, sd_card_e, vc_spi3, clk_observe, vc_spi0, vc_uart0),
BRCMSTB_PIN(3, vc_i2c3, usb_vbus, gpclk2, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _),
BRCMSTB_PIN(4, vc_i2c3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _),
BRCMSTB_PIN(10, bsc_m3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, gpclk0, _, _),
BRCMSTB_PIN(11, bsc_m3, vc_spi3, clk_observe, sd_card_c, gpclk1, _, _, _),
BRCMSTB_PIN(12, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _),
BRCMSTB_PIN(13, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _),
BRCMSTB_PIN(14, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, sd_card_d, _, _),
BRCMSTB_PIN(15, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, gpclk0, _, _),
BRCMSTB_PIN(18, sd_card_f, vc_pwm1, _, _, _, _, _, _),
BRCMSTB_PIN(19, sd_card_f, usb_pwr, vc_pwm1, _, _, _, _, _),
BRCMSTB_PIN(20, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _),
BRCMSTB_PIN(21, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _),
BRCMSTB_PIN(22, sd_card_f, vc_uart0, vc_i2c3, _, _, _, _, _),
BRCMSTB_PIN(23, vc_uart0, vc_i2c3, _, _, _, _, _, _),
BRCMSTB_PIN(24, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _),
BRCMSTB_PIN(25, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _),
BRCMSTB_PIN(26, sd_card_b, vc_spi0, arm_jtag, uart0, usb_vbus, vc_uart2, vc_spi0, _),
BRCMSTB_PIN(27, sd_card_b, vc_spi0, arm_jtag, uart0, vc_uart2, vc_spi0, _, _),
BRCMSTB_PIN(28, sd_card_b, vc_spi0, arm_jtag, vc_i2c0, vc_spi0, _, _, _),
BRCMSTB_PIN(29, arm_jtag, vc_i2c0, vc_spi0, _, _, _, _, _),
BRCMSTB_PIN(30, sd2, gpclk0, vc_pwm0, _, _, _, _, _),
BRCMSTB_PIN(31, sd2, vc_spi3, vc_pwm0, _, _, _, _, _),
BRCMSTB_PIN(32, sd2, vc_spi3, vc_uart3, _, _, _, _, _),
BRCMSTB_PIN(33, sd2, vc_spi3, vc_uart3, _, _, _, _, _),
BRCMSTB_PIN(34, sd2, vc_spi3, vc_i2c5, _, _, _, _, _),
BRCMSTB_PIN(35, sd2, vc_spi3, vc_i2c5, _, _, _, _, _),
};
static const struct pinctrl_desc bcm2712_c0_pinctrl_desc = {
.name = "pinctrl-bcm2712",
.pins = bcm2712_c0_gpio_pins,
.npins = ARRAY_SIZE(bcm2712_c0_gpio_pins),
};
static const struct pinctrl_desc bcm2712_c0_aon_pinctrl_desc = {
.name = "aon-pinctrl-bcm2712",
.pins = bcm2712_c0_aon_gpio_pins,
.npins = ARRAY_SIZE(bcm2712_c0_aon_gpio_pins),
};
static const struct pinctrl_desc bcm2712_d0_pinctrl_desc = {
.name = "pinctrl-bcm2712",
.pins = bcm2712_d0_gpio_pins,
.npins = ARRAY_SIZE(bcm2712_d0_gpio_pins),
};
static const struct pinctrl_desc bcm2712_d0_aon_pinctrl_desc = {
.name = "aon-pinctrl-bcm2712",
.pins = bcm2712_d0_aon_gpio_pins,
.npins = ARRAY_SIZE(bcm2712_d0_aon_gpio_pins),
};
static const struct pinctrl_gpio_range bcm2712_c0_pinctrl_gpio_range = {
.name = "pinctrl-bcm2712",
.npins = ARRAY_SIZE(bcm2712_c0_gpio_pins),
};
static const struct pinctrl_gpio_range bcm2712_c0_aon_pinctrl_gpio_range = {
.name = "aon-pinctrl-bcm2712",
.npins = ARRAY_SIZE(bcm2712_c0_aon_gpio_pins),
};
static const struct pinctrl_gpio_range bcm2712_d0_pinctrl_gpio_range = {
.name = "pinctrl-bcm2712",
.npins = ARRAY_SIZE(bcm2712_d0_gpio_pins),
};
static const struct pinctrl_gpio_range bcm2712_d0_aon_pinctrl_gpio_range = {
.name = "aon-pinctrl-bcm2712",
.npins = ARRAY_SIZE(bcm2712_d0_aon_gpio_pins),
};
static const struct brcmstb_pdata bcm2712_c0_pdata = {
.pctl_desc = &bcm2712_c0_pinctrl_desc,
.gpio_range = &bcm2712_c0_pinctrl_gpio_range,
.pin_regs = bcm2712_c0_gpio_pin_regs,
.pin_funcs = bcm2712_c0_gpio_pin_funcs,
.func_count = func_count,
.func_gpio = func_gpio,
.func_names = bcm2712_func_names,
};
static const struct brcmstb_pdata bcm2712_c0_aon_pdata = {
.pctl_desc = &bcm2712_c0_aon_pinctrl_desc,
.gpio_range = &bcm2712_c0_aon_pinctrl_gpio_range,
.pin_regs = bcm2712_c0_aon_gpio_pin_regs,
.pin_funcs = bcm2712_c0_aon_gpio_pin_funcs,
.func_count = func_count,
.func_gpio = func_gpio,
.func_names = bcm2712_func_names,
};
static const struct brcmstb_pdata bcm2712_d0_pdata = {
.pctl_desc = &bcm2712_d0_pinctrl_desc,
.gpio_range = &bcm2712_d0_pinctrl_gpio_range,
.pin_regs = bcm2712_d0_gpio_pin_regs,
.pin_funcs = bcm2712_d0_gpio_pin_funcs,
.func_count = func_count,
.func_gpio = func_gpio,
.func_names = bcm2712_func_names,
};
static const struct brcmstb_pdata bcm2712_d0_aon_pdata = {
.pctl_desc = &bcm2712_d0_aon_pinctrl_desc,
.gpio_range = &bcm2712_d0_aon_pinctrl_gpio_range,
.pin_regs = bcm2712_d0_aon_gpio_pin_regs,
.pin_funcs = bcm2712_d0_aon_gpio_pin_funcs,
.func_count = func_count,
.func_gpio = func_gpio,
.func_names = bcm2712_func_names,
};
static int bcm2712_pinctrl_probe(struct platform_device *pdev)
{
return brcmstb_pinctrl_probe(pdev);
}
static const struct of_device_id bcm2712_pinctrl_match[] = {
{
.compatible = "brcm,bcm2712c0-pinctrl",
.data = &bcm2712_c0_pdata
},
{
.compatible = "brcm,bcm2712c0-aon-pinctrl",
.data = &bcm2712_c0_aon_pdata
},
{
.compatible = "brcm,bcm2712d0-pinctrl",
.data = &bcm2712_d0_pdata
},
{
.compatible = "brcm,bcm2712d0-aon-pinctrl",
.data = &bcm2712_d0_aon_pdata
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, bcm2712_pinctrl_match);
static struct platform_driver bcm2712_pinctrl_driver = {
.probe = bcm2712_pinctrl_probe,
.driver = {
.name = "pinctrl-bcm2712",
.of_match_table = bcm2712_pinctrl_match,
.suppress_bind_attrs = true,
},
};
module_platform_driver(bcm2712_pinctrl_driver);
MODULE_AUTHOR("Phil Elwell");
MODULE_AUTHOR("Jonathan Bell");
MODULE_AUTHOR("Ivan T. Ivanov");
MODULE_AUTHOR("Andrea della Porta");
MODULE_DESCRIPTION("Broadcom BCM2712 pinctrl driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,442 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Broadcom brcmstb GPIO units (pinctrl only)
*
* Copyright (C) 2024-2025 Ivan T. Ivanov, Andrea della Porta
* Copyright (C) 2021-3 Raspberry Pi Ltd.
* Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren
*
* Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by:
* pinctrl-nomadik.c, please see original file for copyright information
* pinctrl-tegra.c, please see original file for copyright information
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/cleanup.h>
#include "pinctrl-brcmstb.h"
#define BRCMSTB_PULL_NONE 0
#define BRCMSTB_PULL_DOWN 1
#define BRCMSTB_PULL_UP 2
#define BRCMSTB_PULL_MASK 0x3
#define BIT_TO_REG(b) (((b) >> 5) << 2)
#define BIT_TO_SHIFT(b) ((b) & 0x1f)
struct brcmstb_pinctrl {
struct device *dev;
void __iomem *base;
struct pinctrl_dev *pctl_dev;
struct pinctrl_desc pctl_desc;
const struct pin_regs *pin_regs;
const struct brcmstb_pin_funcs *pin_funcs;
const char * const *func_names;
unsigned int func_count;
unsigned int func_gpio;
const char *const *gpio_groups;
struct pinctrl_gpio_range gpio_range;
/* Protect FSEL registers */
spinlock_t fsel_lock;
};
static unsigned int brcmstb_pinctrl_fsel_get(struct brcmstb_pinctrl *pc,
unsigned int pin)
{
u32 bit = pc->pin_regs[pin].mux_bit;
unsigned int func;
int fsel;
u32 val;
if (!bit)
return pc->func_gpio;
bit &= ~MUX_BIT_VALID;
val = readl(pc->base + BIT_TO_REG(bit));
fsel = (val >> BIT_TO_SHIFT(bit)) & pc->pin_funcs[pin].func_mask;
func = pc->pin_funcs[pin].funcs[fsel];
if (func >= pc->func_count)
func = fsel;
dev_dbg(pc->dev, "get %04x: %08x (%u => %s)\n",
BIT_TO_REG(bit), val, pin,
pc->func_names[func]);
return func;
}
static int brcmstb_pinctrl_fsel_set(struct brcmstb_pinctrl *pc,
unsigned int pin, unsigned int func)
{
u32 bit = pc->pin_regs[pin].mux_bit, val, fsel_mask;
const u8 *pin_funcs;
int fsel;
int cur;
int i;
if (!bit || func >= pc->func_count)
return -EINVAL;
bit &= ~MUX_BIT_VALID;
fsel = pc->pin_funcs[pin].n_funcs + 1;
fsel_mask = pc->pin_funcs[pin].func_mask;
if (func >= fsel) {
/* Convert to an fsel number */
pin_funcs = pc->pin_funcs[pin].funcs;
for (i = 1; i < fsel; i++) {
if (pin_funcs[i - 1] == func) {
fsel = i;
break;
}
}
} else {
fsel = func;
}
if (fsel >= pc->pin_funcs[pin].n_funcs + 1)
return -EINVAL;
guard(spinlock_irqsave)(&pc->fsel_lock);
val = readl(pc->base + BIT_TO_REG(bit));
cur = (val >> BIT_TO_SHIFT(bit)) & fsel_mask;
dev_dbg(pc->dev, "read %04x: %08x (%u => %s)\n",
BIT_TO_REG(bit), val, pin,
pc->func_names[cur]);
if (cur != fsel) {
val &= ~(fsel_mask << BIT_TO_SHIFT(bit));
val |= fsel << BIT_TO_SHIFT(bit);
dev_dbg(pc->dev, "write %04x: %08x (%u <= %s)\n",
BIT_TO_REG(bit), val, pin,
pc->func_names[fsel]);
writel(val, pc->base + BIT_TO_REG(bit));
}
return 0;
}
static int brcmstb_pctl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
return pc->pctl_desc.npins;
}
static const char *brcmstb_pctl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
return pc->gpio_groups[selector];
}
static int brcmstb_pctl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int selector,
const unsigned int **pins,
unsigned int *num_pins)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
*pins = &pc->pctl_desc.pins[selector].number;
*num_pins = 1;
return 0;
}
static void brcmstb_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned int offset)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
unsigned int fsel = brcmstb_pinctrl_fsel_get(pc, offset);
const char *fname = pc->func_names[fsel];
seq_printf(s, "function %s", fname);
}
static void brcmstb_pctl_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *maps,
unsigned int num_maps)
{
int i;
for (i = 0; i < num_maps; i++)
if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
kfree(maps[i].data.configs.configs);
kfree(maps);
}
static const struct pinctrl_ops brcmstb_pctl_ops = {
.get_groups_count = brcmstb_pctl_get_groups_count,
.get_group_name = brcmstb_pctl_get_group_name,
.get_group_pins = brcmstb_pctl_get_group_pins,
.pin_dbg_show = brcmstb_pctl_pin_dbg_show,
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = brcmstb_pctl_dt_free_map,
};
static int brcmstb_pmx_free(struct pinctrl_dev *pctldev, unsigned int offset)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* disable by setting to GPIO */
return brcmstb_pinctrl_fsel_set(pc, offset, pc->func_gpio);
}
static int brcmstb_pmx_get_functions_count(struct pinctrl_dev *pctldev)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
return pc->func_count;
}
static const char *brcmstb_pmx_get_function_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
return (selector < pc->func_count) ? pc->func_names[selector] : NULL;
}
static int brcmstb_pmx_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const char *const **groups,
unsigned *const num_groups)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
*groups = pc->gpio_groups;
*num_groups = pc->pctl_desc.npins;
return 0;
}
static int brcmstb_pmx_set(struct pinctrl_dev *pctldev,
unsigned int func_selector,
unsigned int group_selector)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
const struct pinctrl_desc *pctldesc = &pc->pctl_desc;
const struct pinctrl_pin_desc *pindesc;
if (group_selector >= pctldesc->npins)
return -EINVAL;
pindesc = &pctldesc->pins[group_selector];
return brcmstb_pinctrl_fsel_set(pc, pindesc->number, func_selector);
}
static int brcmstb_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int pin)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
return brcmstb_pinctrl_fsel_set(pc, pin, pc->func_gpio);
}
static void brcmstb_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* disable by setting to GPIO */
(void)brcmstb_pinctrl_fsel_set(pc, offset, pc->func_gpio);
}
static bool brcmstb_pmx_function_is_gpio(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
return pc->func_gpio == selector;
}
static const struct pinmux_ops brcmstb_pmx_ops = {
.free = brcmstb_pmx_free,
.get_functions_count = brcmstb_pmx_get_functions_count,
.get_function_name = brcmstb_pmx_get_function_name,
.get_function_groups = brcmstb_pmx_get_function_groups,
.set_mux = brcmstb_pmx_set,
.gpio_request_enable = brcmstb_pmx_gpio_request_enable,
.gpio_disable_free = brcmstb_pmx_gpio_disable_free,
.function_is_gpio = brcmstb_pmx_function_is_gpio,
.strict = true,
};
static unsigned int brcmstb_pull_config_get(struct brcmstb_pinctrl *pc,
unsigned int pin)
{
u32 bit = pc->pin_regs[pin].pad_bit, val;
if (bit == PAD_BIT_INVALID)
return BRCMSTB_PULL_NONE;
val = readl(pc->base + BIT_TO_REG(bit));
return (val >> BIT_TO_SHIFT(bit)) & BRCMSTB_PULL_MASK;
}
static int brcmstb_pull_config_set(struct brcmstb_pinctrl *pc,
unsigned int pin, unsigned int arg)
{
u32 bit = pc->pin_regs[pin].pad_bit, val;
if (bit == PAD_BIT_INVALID) {
dev_warn(pc->dev, "Can't set pulls for %s\n",
pc->gpio_groups[pin]);
return -EINVAL;
}
guard(spinlock_irqsave)(&pc->fsel_lock);
val = readl(pc->base + BIT_TO_REG(bit));
val &= ~(BRCMSTB_PULL_MASK << BIT_TO_SHIFT(bit));
val |= (arg << BIT_TO_SHIFT(bit));
writel(val, pc->base + BIT_TO_REG(bit));
return 0;
}
static int brcmstb_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
u32 arg;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_NONE);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_DOWN);
break;
case PIN_CONFIG_BIAS_PULL_UP:
arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_UP);
break;
default:
return -ENOTSUPP;
}
*config = pinconf_to_config_packed(param, arg);
return 0;
}
static int brcmstb_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
int ret = 0;
u32 param;
int i;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_NONE);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_DOWN);
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_UP);
break;
default:
return -ENOTSUPP;
}
}
return ret;
}
static const struct pinconf_ops brcmstb_pinconf_ops = {
.is_generic = true,
.pin_config_get = brcmstb_pinconf_get,
.pin_config_set = brcmstb_pinconf_set,
};
int brcmstb_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const struct brcmstb_pdata *pdata;
struct brcmstb_pinctrl *pc;
const char **names;
int num_pins, i;
pdata = of_device_get_match_data(dev);
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
platform_set_drvdata(pdev, pc);
pc->dev = dev;
spin_lock_init(&pc->fsel_lock);
pc->base = devm_of_iomap(dev, np, 0, NULL);
if (IS_ERR(pc->base))
return dev_err_probe(&pdev->dev, PTR_ERR(pc->base),
"Could not get IO memory\n");
pc->pctl_desc = *pdata->pctl_desc;
pc->pctl_desc.pctlops = &brcmstb_pctl_ops;
pc->pctl_desc.pmxops = &brcmstb_pmx_ops;
pc->pctl_desc.confops = &brcmstb_pinconf_ops;
pc->pctl_desc.owner = THIS_MODULE;
num_pins = pc->pctl_desc.npins;
names = devm_kmalloc_array(dev, num_pins, sizeof(const char *),
GFP_KERNEL);
if (!names)
return -ENOMEM;
for (i = 0; i < num_pins; i++)
names[i] = pc->pctl_desc.pins[i].name;
pc->gpio_groups = names;
pc->pin_regs = pdata->pin_regs;
pc->pin_funcs = pdata->pin_funcs;
pc->func_count = pdata->func_count;
pc->func_names = pdata->func_names;
pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
if (IS_ERR(pc->pctl_dev))
return dev_err_probe(&pdev->dev, PTR_ERR(pc->pctl_dev),
"Failed to register pinctrl device\n");
pc->gpio_range = *pdata->gpio_range;
pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
return 0;
}
EXPORT_SYMBOL(brcmstb_pinctrl_probe);
MODULE_AUTHOR("Phil Elwell");
MODULE_AUTHOR("Jonathan Bell");
MODULE_AUTHOR("Ivan T. Ivanov");
MODULE_AUTHOR("Andrea della Porta");
MODULE_DESCRIPTION("Broadcom brcmstb pinctrl driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,93 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Header for Broadcom brcmstb GPIO based drivers
*
* Copyright (C) 2024-2025 Ivan T. Ivanov, Andrea della Porta
* Copyright (C) 2021-3 Raspberry Pi Ltd.
* Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren
*
* Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by:
* pinctrl-nomadik.c, please see original file for copyright information
* pinctrl-tegra.c, please see original file for copyright information
*/
#ifndef __PINCTRL_BRCMSTB_H__
#define __PINCTRL_BRCMSTB_H__
#include <linux/types.h>
#include <linux/platform_device.h>
#define BRCMSTB_FUNC(f) \
[func_##f] = #f
#define MUX_BIT_VALID 0x8000
#define PAD_BIT_INVALID 0xffff
#define MUX_BIT(muxreg, muxshift) \
(MUX_BIT_VALID + ((muxreg) << 5) + ((muxshift) << 2))
#define PAD_BIT(padreg, padshift) \
(((padreg) << 5) + ((padshift) << 1))
#define GPIO_REGS(n, muxreg, muxshift, padreg, padshift) \
[n] = { MUX_BIT(muxreg, muxshift), PAD_BIT(padreg, padshift) }
#define EMMC_REGS(n, padreg, padshift) \
[n] = { 0, PAD_BIT(padreg, padshift) }
#define AON_GPIO_REGS(n, muxreg, muxshift, padreg, padshift) \
GPIO_REGS(n, muxreg, muxshift, padreg, padshift)
#define AON_SGPIO_REGS(n, muxreg, muxshift) \
[(n) + 32] = { MUX_BIT(muxreg, muxshift), PAD_BIT_INVALID }
#define GPIO_PIN(n) PINCTRL_PIN(n, "gpio" #n)
/**
* AON pins are in the Always-On power domain. SGPIOs are also 'Safe'
* being 5V tolerant (necessary for the HDMI I2C pins), and can be driven
* while the power is off.
*/
#define AON_GPIO_PIN(n) PINCTRL_PIN(n, "aon_gpio" #n)
#define AON_SGPIO_PIN(n) PINCTRL_PIN((n) + 32, "aon_sgpio" #n)
struct pin_regs {
u16 mux_bit;
u16 pad_bit;
};
/**
* struct brcmstb_pin_funcs - pins provide their primary/alternate
* functions in this struct
* @func_mask: mask representing valid bits of the function selector
* in the registers
* @funcs: array of function identifiers
* @n_funcs: number of identifiers of the @funcs array above
*/
struct brcmstb_pin_funcs {
const u32 func_mask;
const u8 *funcs;
const unsigned int n_funcs;
};
/**
* struct brcmstb_pdata - specific data for a pinctrl chip implementation
* @pctl_desc: pin controller descriptor for this implementation
* @gpio_range: range of GPIOs served by this controller
* @pin_regs: array of register descriptors for each pin
* @pin_funcs: array of all possible assignable function for each pin
* @func_count: total number of functions
* @func_gpio: which function number is GPIO (usually 0)
* @func_names: an array listing all function names
*/
struct brcmstb_pdata {
const struct pinctrl_desc *pctl_desc;
const struct pinctrl_gpio_range *gpio_range;
const struct pin_regs *pin_regs;
const struct brcmstb_pin_funcs *pin_funcs;
const unsigned int func_count;
const unsigned int func_gpio;
const char * const *func_names;
};
int brcmstb_pinctrl_probe(struct platform_device *pdev);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,935 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2017 Broadcom
*/
/*
* This file contains the Broadcom Iproc GPIO driver that supports 3
* GPIO controllers on Iproc including the ASIU GPIO controller, the
* chipCommonG GPIO controller, and the always-on GPIO controller. Basic
* PINCONF such as bias pull up/down, and drive strength are also supported
* in this driver.
*
* It provides the functionality where pins from the GPIO can be
* individually muxed to GPIO function, if individual pad
* configuration is supported, through the interaction with respective
* SoCs IOMUX controller.
*/
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include "../pinctrl-utils.h"
#define IPROC_GPIO_DATA_IN_OFFSET 0x00
#define IPROC_GPIO_DATA_OUT_OFFSET 0x04
#define IPROC_GPIO_OUT_EN_OFFSET 0x08
#define IPROC_GPIO_INT_TYPE_OFFSET 0x0c
#define IPROC_GPIO_INT_DE_OFFSET 0x10
#define IPROC_GPIO_INT_EDGE_OFFSET 0x14
#define IPROC_GPIO_INT_MSK_OFFSET 0x18
#define IPROC_GPIO_INT_STAT_OFFSET 0x1c
#define IPROC_GPIO_INT_MSTAT_OFFSET 0x20
#define IPROC_GPIO_INT_CLR_OFFSET 0x24
#define IPROC_GPIO_PAD_RES_OFFSET 0x34
#define IPROC_GPIO_RES_EN_OFFSET 0x38
/* drive strength control for ASIU GPIO */
#define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
/* pinconf for CCM GPIO */
#define IPROC_GPIO_PULL_DN_OFFSET 0x10
#define IPROC_GPIO_PULL_UP_OFFSET 0x14
/* pinconf for CRMU(aon) GPIO and CCM GPIO*/
#define IPROC_GPIO_DRV_CTRL_OFFSET 0x00
#define GPIO_BANK_SIZE 0x200
#define NGPIOS_PER_BANK 32
#define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
#define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
#define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
#define GPIO_DRV_STRENGTH_BIT_SHIFT 20
#define GPIO_DRV_STRENGTH_BITS 3
#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
enum iproc_pinconf_param {
IPROC_PINCONF_DRIVE_STRENGTH = 0,
IPROC_PINCONF_BIAS_DISABLE,
IPROC_PINCONF_BIAS_PULL_UP,
IPROC_PINCONF_BIAS_PULL_DOWN,
IPROC_PINCON_MAX,
};
enum iproc_pinconf_ctrl_type {
IOCTRL_TYPE_AON = 1,
IOCTRL_TYPE_CDRU,
IOCTRL_TYPE_INVALID,
};
/*
* Iproc GPIO core
*
* @dev: pointer to device
* @base: I/O register base for Iproc GPIO controller
* @io_ctrl: I/O register base for certain type of Iproc GPIO controller that
* has the PINCONF support implemented outside of the GPIO block
* @lock: lock to protect access to I/O registers
* @gc: GPIO chip
* @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
* @pinmux_is_supported: flag to indicate this GPIO controller contains pins
* that can be individually muxed to GPIO
* @pinconf_disable: contains a list of PINCONF parameters that need to be
* disabled
* @nr_pinconf_disable: total number of PINCONF parameters that need to be
* disabled
* @pctl: pointer to pinctrl_dev
* @pctldesc: pinctrl descriptor
*/
struct iproc_gpio {
struct device *dev;
void __iomem *base;
void __iomem *io_ctrl;
enum iproc_pinconf_ctrl_type io_ctrl_type;
raw_spinlock_t lock;
struct gpio_chip gc;
unsigned num_banks;
bool pinmux_is_supported;
enum pin_config_param *pinconf_disable;
unsigned int nr_pinconf_disable;
struct pinctrl_dev *pctl;
struct pinctrl_desc pctldesc;
};
/*
* Mapping from PINCONF pins to GPIO pins is 1-to-1
*/
static inline unsigned iproc_pin_to_gpio(unsigned pin)
{
return pin;
}
/**
* iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
* Iproc GPIO register
*
* @chip: Iproc GPIO device
* @reg: register offset
* @gpio: GPIO pin
* @set: set or clear
*/
static inline void iproc_set_bit(struct iproc_gpio *chip, unsigned int reg,
unsigned gpio, bool set)
{
unsigned int offset = IPROC_GPIO_REG(gpio, reg);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
u32 val;
val = readl(chip->base + offset);
if (set)
val |= BIT(shift);
else
val &= ~BIT(shift);
writel(val, chip->base + offset);
}
static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg,
unsigned gpio)
{
unsigned int offset = IPROC_GPIO_REG(gpio, reg);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
return !!(readl(chip->base + offset) & BIT(shift));
}
static void iproc_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct iproc_gpio *chip = gpiochip_get_data(gc);
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
int i, bit;
chained_irq_enter(irq_chip, desc);
/* go through the entire GPIO banks and handle all interrupts */
for (i = 0; i < chip->num_banks; i++) {
unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) +
IPROC_GPIO_INT_MSTAT_OFFSET);
for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
unsigned pin = NGPIOS_PER_BANK * i + bit;
/*
* Clear the interrupt before invoking the
* handler, so we do not leave any window
*/
writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) +
IPROC_GPIO_INT_CLR_OFFSET);
generic_handle_domain_irq(gc->irq.domain, pin);
}
}
chained_irq_exit(irq_chip, desc);
}
static void iproc_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq;
unsigned int offset = IPROC_GPIO_REG(gpio,
IPROC_GPIO_INT_CLR_OFFSET);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
u32 val = BIT(shift);
writel(val, chip->base + offset);
}
/**
* iproc_gpio_irq_set_mask - mask/unmask a GPIO interrupt
*
* @d: IRQ chip data
* @unmask: mask/unmask GPIO interrupt
*/
static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = irqd_to_hwirq(d);
iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask);
}
static void iproc_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
iproc_gpio_irq_set_mask(d, false);
raw_spin_unlock_irqrestore(&chip->lock, flags);
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void iproc_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
raw_spin_lock_irqsave(&chip->lock, flags);
iproc_gpio_irq_set_mask(d, true);
raw_spin_unlock_irqrestore(&chip->lock, flags);
}
static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq;
bool level_triggered = false;
bool dual_edge = false;
bool rising_or_high = false;
unsigned long flags;
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
rising_or_high = true;
break;
case IRQ_TYPE_EDGE_FALLING:
break;
case IRQ_TYPE_EDGE_BOTH:
dual_edge = true;
break;
case IRQ_TYPE_LEVEL_HIGH:
level_triggered = true;
rising_or_high = true;
break;
case IRQ_TYPE_LEVEL_LOW:
level_triggered = true;
break;
default:
dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
type);
return -EINVAL;
}
raw_spin_lock_irqsave(&chip->lock, flags);
iproc_set_bit(chip, IPROC_GPIO_INT_TYPE_OFFSET, gpio,
level_triggered);
iproc_set_bit(chip, IPROC_GPIO_INT_DE_OFFSET, gpio, dual_edge);
iproc_set_bit(chip, IPROC_GPIO_INT_EDGE_OFFSET, gpio,
rising_or_high);
if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
else
irq_set_handler_locked(d, handle_level_irq);
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev,
"gpio:%u level_triggered:%d dual_edge:%d rising_or_high:%d\n",
gpio, level_triggered, dual_edge, rising_or_high);
return 0;
}
static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = gpiochip_get_data(gc);
seq_puts(p, dev_name(chip->dev));
}
static const struct irq_chip iproc_gpio_irq_chip = {
.irq_ack = iproc_gpio_irq_ack,
.irq_mask = iproc_gpio_irq_mask,
.irq_unmask = iproc_gpio_irq_unmask,
.irq_set_type = iproc_gpio_irq_set_type,
.irq_enable = iproc_gpio_irq_unmask,
.irq_disable = iproc_gpio_irq_mask,
.irq_print_chip = iproc_gpio_irq_print_chip,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
/*
* Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO
*/
static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
/* not all Iproc GPIO pins can be muxed individually */
if (!chip->pinmux_is_supported)
return 0;
return pinctrl_gpio_request(gc, offset);
}
static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
if (!chip->pinmux_is_supported)
return;
pinctrl_gpio_free(gc, offset);
}
static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, false);
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
return 0;
}
static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
int val)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
return 0;
}
static int iproc_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
if (readl(chip->base + offset) & BIT(shift))
return GPIO_LINE_DIRECTION_OUT;
return GPIO_LINE_DIRECTION_IN;
}
static int iproc_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
return 0;
}
static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned int offset = IPROC_GPIO_REG(gpio,
IPROC_GPIO_DATA_IN_OFFSET);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
return !!(readl(chip->base + offset) & BIT(shift));
}
/*
* Mapping of the iProc PINCONF parameters to the generic pin configuration
* parameters
*/
static const enum pin_config_param iproc_pinconf_disable_map[] = {
[IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH,
[IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE,
[IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP,
[IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN,
};
static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip,
enum pin_config_param param)
{
unsigned int i;
if (!chip->nr_pinconf_disable)
return false;
for (i = 0; i < chip->nr_pinconf_disable; i++)
if (chip->pinconf_disable[i] == param)
return true;
return false;
}
static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip,
unsigned long disable_mask)
{
unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map);
unsigned int bit, nbits = 0;
/* figure out total number of PINCONF parameters to disable */
for_each_set_bit(bit, &disable_mask, map_size)
nbits++;
if (!nbits)
return 0;
/*
* Allocate an array to store PINCONF parameters that need to be
* disabled
*/
chip->pinconf_disable = devm_kcalloc(chip->dev, nbits,
sizeof(*chip->pinconf_disable),
GFP_KERNEL);
if (!chip->pinconf_disable)
return -ENOMEM;
chip->nr_pinconf_disable = nbits;
/* now store these parameters */
nbits = 0;
for_each_set_bit(bit, &disable_mask, map_size)
chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit];
return 0;
}
static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
{
return 1;
}
/*
* Only one group: "gpio_grp", since this local pinctrl device only performs
* GPIO specific PINCONF configurations
*/
static const char *iproc_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return "gpio_grp";
}
static const struct pinctrl_ops iproc_pctrl_ops = {
.get_groups_count = iproc_get_groups_count,
.get_group_name = iproc_get_group_name,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinctrl_utils_free_map,
};
static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
bool disable, bool pull_up)
{
void __iomem *base;
unsigned long flags;
unsigned int shift;
u32 val_1, val_2;
raw_spin_lock_irqsave(&chip->lock, flags);
if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
base = chip->io_ctrl;
shift = IPROC_GPIO_SHIFT(gpio);
val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET);
val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET);
if (disable) {
/* no pull-up or pull-down */
val_1 &= ~BIT(shift);
val_2 &= ~BIT(shift);
} else if (pull_up) {
val_1 |= BIT(shift);
val_2 &= ~BIT(shift);
} else {
val_1 &= ~BIT(shift);
val_2 |= BIT(shift);
}
writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET);
writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET);
} else {
if (disable) {
iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
false);
} else {
iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
pull_up);
iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
true);
}
}
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up);
return 0;
}
static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio,
bool *disable, bool *pull_up)
{
void __iomem *base;
unsigned long flags;
unsigned int shift;
u32 val_1, val_2;
raw_spin_lock_irqsave(&chip->lock, flags);
if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
base = chip->io_ctrl;
shift = IPROC_GPIO_SHIFT(gpio);
val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift);
val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift);
*pull_up = val_1 ? true : false;
*disable = (val_1 | val_2) ? false : true;
} else {
*disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
*pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
}
raw_spin_unlock_irqrestore(&chip->lock, flags);
}
#define DRV_STRENGTH_OFFSET(gpio, bit, type) ((type) == IOCTRL_TYPE_AON ? \
((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
((type) == IOCTRL_TYPE_CDRU) ? \
((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET)))
static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
unsigned strength)
{
void __iomem *base;
unsigned int i, offset, shift;
u32 val;
unsigned long flags;
/* make sure drive strength is supported */
if (strength < 2 || strength > 16 || (strength % 2))
return -ENOTSUPP;
if (chip->io_ctrl) {
base = chip->io_ctrl;
} else {
base = chip->base;
}
shift = IPROC_GPIO_SHIFT(gpio);
dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
strength);
raw_spin_lock_irqsave(&chip->lock, flags);
strength = (strength / 2) - 1;
for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
val = readl(base + offset);
val &= ~BIT(shift);
val |= ((strength >> i) & 0x1) << shift;
writel(val, base + offset);
}
raw_spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
u16 *strength)
{
void __iomem *base;
unsigned int i, offset, shift;
u32 val;
unsigned long flags;
if (chip->io_ctrl) {
base = chip->io_ctrl;
} else {
base = chip->base;
}
shift = IPROC_GPIO_SHIFT(gpio);
raw_spin_lock_irqsave(&chip->lock, flags);
*strength = 0;
for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
val = readl(base + offset) & BIT(shift);
val >>= shift;
*strength += (val << i);
}
/* convert to mA */
*strength = (*strength + 1) * 2;
raw_spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *config)
{
struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
unsigned gpio = iproc_pin_to_gpio(pin);
u16 arg;
bool disable, pull_up;
int ret;
if (iproc_pinconf_param_is_disabled(chip, param))
return -ENOTSUPP;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
if (disable)
return 0;
else
return -EINVAL;
case PIN_CONFIG_BIAS_PULL_UP:
iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
if (!disable && pull_up)
return 0;
else
return -EINVAL;
case PIN_CONFIG_BIAS_PULL_DOWN:
iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
if (!disable && !pull_up)
return 0;
else
return -EINVAL;
case PIN_CONFIG_DRIVE_STRENGTH:
ret = iproc_gpio_get_strength(chip, gpio, &arg);
if (ret)
return ret;
*config = pinconf_to_config_packed(param, arg);
return 0;
default:
return -ENOTSUPP;
}
return -ENOTSUPP;
}
static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *configs, unsigned num_configs)
{
struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
u32 arg;
unsigned i, gpio = iproc_pin_to_gpio(pin);
int ret = -ENOTSUPP;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
if (iproc_pinconf_param_is_disabled(chip, param))
return -ENOTSUPP;
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
ret = iproc_gpio_set_pull(chip, gpio, true, false);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = iproc_gpio_set_pull(chip, gpio, false, true);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = iproc_gpio_set_pull(chip, gpio, false, false);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
ret = iproc_gpio_set_strength(chip, gpio, arg);
if (ret < 0)
goto out;
break;
default:
dev_err(chip->dev, "invalid configuration\n");
return -ENOTSUPP;
}
} /* for each config */
out:
return ret;
}
static const struct pinconf_ops iproc_pconf_ops = {
.is_generic = true,
.pin_config_get = iproc_pin_config_get,
.pin_config_set = iproc_pin_config_set,
};
/*
* Iproc GPIO controller supports some PINCONF related configurations such as
* pull up, pull down, and drive strength, when the pin is configured to GPIO
*
* Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
* local GPIO pins
*/
static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
{
struct pinctrl_desc *pctldesc = &chip->pctldesc;
struct pinctrl_pin_desc *pins;
struct gpio_chip *gc = &chip->gc;
int i;
pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (i = 0; i < gc->ngpio; i++) {
pins[i].number = i;
pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
"gpio-%d", i);
if (!pins[i].name)
return -ENOMEM;
}
pctldesc->name = dev_name(chip->dev);
pctldesc->pctlops = &iproc_pctrl_ops;
pctldesc->pins = pins;
pctldesc->npins = gc->ngpio;
pctldesc->confops = &iproc_pconf_ops;
chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip);
if (IS_ERR(chip->pctl)) {
dev_err(chip->dev, "unable to register pinctrl device\n");
return PTR_ERR(chip->pctl);
}
return 0;
}
static const struct of_device_id iproc_gpio_of_match[] = {
{ .compatible = "brcm,iproc-gpio" },
{ .compatible = "brcm,cygnus-ccm-gpio" },
{ .compatible = "brcm,cygnus-asiu-gpio" },
{ .compatible = "brcm,cygnus-crmu-gpio" },
{ .compatible = "brcm,iproc-nsp-gpio" },
{ .compatible = "brcm,iproc-stingray-gpio" },
{ /* sentinel */ }
};
static int iproc_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct iproc_gpio *chip;
struct gpio_chip *gc;
u32 ngpios, pinconf_disable_mask = 0;
int irq, ret;
bool no_pinconf = false;
enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID;
/* NSP does not support drive strength config */
if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
/* Stingray does not support pinconf in this controller */
else if (of_device_is_compatible(dev->of_node,
"brcm,iproc-stingray-gpio"))
no_pinconf = true;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = dev;
platform_set_drvdata(pdev, chip);
chip->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->base)) {
dev_err(dev, "unable to map I/O memory\n");
return PTR_ERR(chip->base);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
chip->io_ctrl = devm_ioremap_resource(dev, res);
if (IS_ERR(chip->io_ctrl))
return PTR_ERR(chip->io_ctrl);
if (of_device_is_compatible(dev->of_node,
"brcm,cygnus-ccm-gpio"))
io_ctrl_type = IOCTRL_TYPE_CDRU;
else
io_ctrl_type = IOCTRL_TYPE_AON;
}
chip->io_ctrl_type = io_ctrl_type;
if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "missing ngpios DT property\n");
return -ENODEV;
}
raw_spin_lock_init(&chip->lock);
gc = &chip->gc;
gc->base = -1;
gc->ngpio = ngpios;
chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
gc->label = dev_name(dev);
gc->parent = dev;
gc->request = iproc_gpio_request;
gc->free = iproc_gpio_free;
gc->direction_input = iproc_gpio_direction_input;
gc->direction_output = iproc_gpio_direction_output;
gc->get_direction = iproc_gpio_get_direction;
gc->set = iproc_gpio_set;
gc->get = iproc_gpio_get;
chip->pinmux_is_supported = of_property_present(dev->of_node,
"gpio-ranges");
/* optional GPIO interrupt support */
irq = platform_get_irq_optional(pdev, 0);
if (irq > 0) {
struct gpio_irq_chip *girq;
girq = &gc->irq;
gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip);
girq->parent_handler = iproc_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1,
sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->parents[0] = irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
}
ret = gpiochip_add_data(gc, chip);
if (ret < 0)
return dev_err_probe(dev, ret, "unable to add GPIO chip\n");
if (!no_pinconf) {
ret = iproc_gpio_register_pinconf(chip);
if (ret) {
dev_err(dev, "unable to register pinconf\n");
goto err_rm_gpiochip;
}
if (pinconf_disable_mask) {
ret = iproc_pinconf_disable_map_create(chip,
pinconf_disable_mask);
if (ret) {
dev_err(dev,
"unable to create pinconf disable map\n");
goto err_rm_gpiochip;
}
}
}
return 0;
err_rm_gpiochip:
gpiochip_remove(gc);
return ret;
}
static struct platform_driver iproc_gpio_driver = {
.driver = {
.name = "iproc-gpio",
.of_match_table = iproc_gpio_of_match,
},
.probe = iproc_gpio_probe,
};
static int __init iproc_gpio_init(void)
{
return platform_driver_register(&iproc_gpio_driver);
}
arch_initcall_sync(iproc_gpio_init);
@@ -0,0 +1,298 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Rafał Miłecki <rafal@milecki.pl>
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include "../core.h"
#include "../pinmux.h"
#define FLAG_BCM4708 BIT(1)
#define FLAG_BCM4709 BIT(2)
#define FLAG_BCM53012 BIT(3)
struct ns_pinctrl {
struct device *dev;
unsigned int chipset_flag;
struct pinctrl_dev *pctldev;
void __iomem *base;
struct pinctrl_desc pctldesc;
};
/*
* Pins
*/
static const struct pinctrl_pin_desc ns_pinctrl_pins[] = {
{ 0, "spi_clk", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 1, "spi_ss", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 2, "spi_mosi", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 3, "spi_miso", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 4, "i2c_scl", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 5, "i2c_sda", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 6, "mdc", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
{ 7, "mdio", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
{ 8, "pwm0", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 9, "pwm1", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 10, "pwm2", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 11, "pwm3", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 12, "uart1_rx", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 13, "uart1_tx", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 14, "uart1_cts", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 15, "uart1_rts", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
{ 16, "uart2_rx", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
{ 17, "uart2_tx", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
/* TODO { ??, "xtal_out", (void *)(FLAG_BCM4709) }, */
{ 22, "sdio_pwr", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
{ 23, "sdio_en_1p8v", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
};
/*
* Groups
*/
struct ns_pinctrl_group {
const char *name;
unsigned int *pins;
const unsigned int num_pins;
unsigned int chipsets;
};
static unsigned int spi_pins[] = { 0, 1, 2, 3 };
static unsigned int i2c_pins[] = { 4, 5 };
static unsigned int mdio_pins[] = { 6, 7 };
static unsigned int pwm0_pins[] = { 8 };
static unsigned int pwm1_pins[] = { 9 };
static unsigned int pwm2_pins[] = { 10 };
static unsigned int pwm3_pins[] = { 11 };
static unsigned int uart1_pins[] = { 12, 13, 14, 15 };
static unsigned int uart2_pins[] = { 16, 17 };
static unsigned int sdio_pwr_pins[] = { 22 };
static unsigned int sdio_1p8v_pins[] = { 23 };
#define NS_GROUP(_name, _pins, _chipsets) \
{ \
.name = _name, \
.pins = _pins, \
.num_pins = ARRAY_SIZE(_pins), \
.chipsets = _chipsets, \
}
static const struct ns_pinctrl_group ns_pinctrl_groups[] = {
NS_GROUP("spi_grp", spi_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("i2c_grp", i2c_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("mdio_grp", mdio_pins, FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("pwm0_grp", pwm0_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("pwm1_grp", pwm1_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("pwm2_grp", pwm2_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("pwm3_grp", pwm3_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("uart1_grp", uart1_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("uart2_grp", uart2_pins, FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("sdio_pwr_grp", sdio_pwr_pins, FLAG_BCM4709 | FLAG_BCM53012),
NS_GROUP("sdio_1p8v_grp", sdio_1p8v_pins, FLAG_BCM4709 | FLAG_BCM53012),
};
/*
* Functions
*/
struct ns_pinctrl_function {
const char *name;
const char * const *groups;
const unsigned int num_groups;
unsigned int chipsets;
};
static const char * const spi_groups[] = { "spi_grp" };
static const char * const i2c_groups[] = { "i2c_grp" };
static const char * const mdio_groups[] = { "mdio_grp" };
static const char * const pwm_groups[] = { "pwm0_grp", "pwm1_grp", "pwm2_grp",
"pwm3_grp" };
static const char * const uart1_groups[] = { "uart1_grp" };
static const char * const uart2_groups[] = { "uart2_grp" };
static const char * const sdio_groups[] = { "sdio_pwr_grp", "sdio_1p8v_grp" };
#define NS_FUNCTION(_name, _groups, _chipsets) \
{ \
.name = _name, \
.groups = _groups, \
.num_groups = ARRAY_SIZE(_groups), \
.chipsets = _chipsets, \
}
static const struct ns_pinctrl_function ns_pinctrl_functions[] = {
NS_FUNCTION("spi", spi_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_FUNCTION("i2c", i2c_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_FUNCTION("mdio", mdio_groups, FLAG_BCM4709 | FLAG_BCM53012),
NS_FUNCTION("pwm", pwm_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_FUNCTION("uart1", uart1_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
NS_FUNCTION("uart2", uart2_groups, FLAG_BCM4709 | FLAG_BCM53012),
NS_FUNCTION("sdio", sdio_groups, FLAG_BCM4709 | FLAG_BCM53012),
};
/*
* Groups code
*/
static const struct pinctrl_ops ns_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,
.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
.dt_free_map = pinconf_generic_dt_free_map,
};
/*
* Functions code
*/
static int ns_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
unsigned int func_select,
unsigned int group_selector)
{
struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
struct group_desc *group;
u32 unset = 0;
u32 tmp;
int i;
group = pinctrl_generic_get_group(pctrl_dev, group_selector);
if (!group)
return -EINVAL;
for (i = 0; i < group->grp.npins; i++)
unset |= BIT(group->grp.pins[i]);
tmp = readl(ns_pinctrl->base);
tmp &= ~unset;
writel(tmp, ns_pinctrl->base);
return 0;
}
static const struct pinmux_ops ns_pinctrl_pmxops = {
.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 = ns_pinctrl_set_mux,
};
/*
* Controller code
*/
static const struct pinctrl_desc ns_pinctrl_desc = {
.name = "pinctrl-ns",
.pctlops = &ns_pinctrl_ops,
.pmxops = &ns_pinctrl_pmxops,
};
static const struct of_device_id ns_pinctrl_of_match_table[] = {
{ .compatible = "brcm,bcm4708-pinmux", .data = (void *)FLAG_BCM4708, },
{ .compatible = "brcm,bcm4709-pinmux", .data = (void *)FLAG_BCM4709, },
{ .compatible = "brcm,bcm53012-pinmux", .data = (void *)FLAG_BCM53012, },
{ }
};
MODULE_DEVICE_TABLE(of, ns_pinctrl_of_match_table);
static int ns_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ns_pinctrl *ns_pinctrl;
struct pinctrl_desc *pctldesc;
struct pinctrl_pin_desc *pin;
struct resource *res;
int i;
ns_pinctrl = devm_kzalloc(dev, sizeof(*ns_pinctrl), GFP_KERNEL);
if (!ns_pinctrl)
return -ENOMEM;
pctldesc = &ns_pinctrl->pctldesc;
platform_set_drvdata(pdev, ns_pinctrl);
/* Set basic properties */
ns_pinctrl->dev = dev;
ns_pinctrl->chipset_flag = (uintptr_t)device_get_match_data(dev);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"cru_gpio_control");
ns_pinctrl->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ns_pinctrl->base))
return PTR_ERR(ns_pinctrl->base);
memcpy(pctldesc, &ns_pinctrl_desc, sizeof(*pctldesc));
/* Set pinctrl properties */
pctldesc->pins = devm_kcalloc(dev, ARRAY_SIZE(ns_pinctrl_pins),
sizeof(struct pinctrl_pin_desc),
GFP_KERNEL);
if (!pctldesc->pins)
return -ENOMEM;
for (i = 0, pin = (struct pinctrl_pin_desc *)&pctldesc->pins[0];
i < ARRAY_SIZE(ns_pinctrl_pins); i++) {
const struct pinctrl_pin_desc *src = &ns_pinctrl_pins[i];
unsigned int chipsets = (uintptr_t)src->drv_data;
if (chipsets & ns_pinctrl->chipset_flag) {
memcpy(pin++, src, sizeof(*src));
pctldesc->npins++;
}
}
/* Register */
ns_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, ns_pinctrl);
if (IS_ERR(ns_pinctrl->pctldev)) {
dev_err(dev, "Failed to register pinctrl\n");
return PTR_ERR(ns_pinctrl->pctldev);
}
for (i = 0; i < ARRAY_SIZE(ns_pinctrl_groups); i++) {
const struct ns_pinctrl_group *group = &ns_pinctrl_groups[i];
if (!(group->chipsets & ns_pinctrl->chipset_flag))
continue;
pinctrl_generic_add_group(ns_pinctrl->pctldev, group->name,
group->pins, group->num_pins, NULL);
}
for (i = 0; i < ARRAY_SIZE(ns_pinctrl_functions); i++) {
const struct ns_pinctrl_function *function = &ns_pinctrl_functions[i];
if (!(function->chipsets & ns_pinctrl->chipset_flag))
continue;
pinmux_generic_add_function(ns_pinctrl->pctldev, function->name,
function->groups,
function->num_groups, NULL);
}
return 0;
}
static struct platform_driver ns_pinctrl_driver = {
.probe = ns_pinctrl_probe,
.driver = {
.name = "ns-pinmux",
.of_match_table = ns_pinctrl_of_match_table,
},
};
module_platform_driver(ns_pinctrl_driver);
MODULE_AUTHOR("Rafał Miłecki");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,715 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2014-2017 Broadcom
/*
* This file contains the Broadcom Northstar Plus (NSP) GPIO driver that
* supports the chipCommonA GPIO controller. Basic PINCONF such as bias,
* pull up/down, slew and drive strength are also supported in this driver.
*
* Pins from the chipCommonA GPIO can be individually muxed to GPIO function,
* through the interaction with the NSP IOMUX controller.
*/
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
#include "../pinctrl-utils.h"
#define NSP_CHIP_A_INT_STATUS 0x00
#define NSP_CHIP_A_INT_MASK 0x04
#define NSP_GPIO_DATA_IN 0x40
#define NSP_GPIO_DATA_OUT 0x44
#define NSP_GPIO_OUT_EN 0x48
#define NSP_GPIO_INT_POLARITY 0x50
#define NSP_GPIO_INT_MASK 0x54
#define NSP_GPIO_EVENT 0x58
#define NSP_GPIO_EVENT_INT_MASK 0x5c
#define NSP_GPIO_EVENT_INT_POLARITY 0x64
#define NSP_CHIP_A_GPIO_INT_BIT 0x01
/* I/O parameters offset for chipcommon A GPIO */
#define NSP_GPIO_DRV_CTRL 0x00
#define NSP_GPIO_HYSTERESIS_EN 0x10
#define NSP_GPIO_SLEW_RATE_EN 0x14
#define NSP_PULL_UP_EN 0x18
#define NSP_PULL_DOWN_EN 0x1c
#define GPIO_DRV_STRENGTH_BITS 0x03
/*
* nsp GPIO core
*
* @dev: pointer to device
* @base: I/O register base for nsp GPIO controller
* @io_ctrl: I/O register base for PINCONF support outside the GPIO block
* @gc: GPIO chip
* @pctl: pointer to pinctrl_dev
* @pctldesc: pinctrl descriptor
* @lock: lock to protect access to I/O registers
*/
struct nsp_gpio {
struct device *dev;
void __iomem *base;
void __iomem *io_ctrl;
struct gpio_chip gc;
struct pinctrl_dev *pctl;
struct pinctrl_desc pctldesc;
raw_spinlock_t lock;
};
enum base_type {
REG,
IO_CTRL
};
/*
* Mapping from PINCONF pins to GPIO pins is 1-to-1
*/
static inline unsigned nsp_pin_to_gpio(unsigned pin)
{
return pin;
}
/*
* nsp_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
* nsp GPIO register
*
* @nsp_gpio: nsp GPIO device
* @base_type: reg base to modify
* @reg: register offset
* @gpio: GPIO pin
* @set: set or clear
*/
static inline void nsp_set_bit(struct nsp_gpio *chip, enum base_type address,
unsigned int reg, unsigned gpio, bool set)
{
u32 val;
void __iomem *base_address;
if (address == IO_CTRL)
base_address = chip->io_ctrl;
else
base_address = chip->base;
val = readl(base_address + reg);
if (set)
val |= BIT(gpio);
else
val &= ~BIT(gpio);
writel(val, base_address + reg);
}
/*
* nsp_get_bit - get one bit (corresponding to the GPIO pin) in a
* nsp GPIO register
*/
static inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address,
unsigned int reg, unsigned gpio)
{
if (address == IO_CTRL)
return !!(readl(chip->io_ctrl + reg) & BIT(gpio));
else
return !!(readl(chip->base + reg) & BIT(gpio));
}
static irqreturn_t nsp_gpio_irq_handler(int irq, void *data)
{
struct gpio_chip *gc = (struct gpio_chip *)data;
struct nsp_gpio *chip = gpiochip_get_data(gc);
int bit;
unsigned long int_bits = 0;
u32 int_status;
/* go through the entire GPIOs and handle all interrupts */
int_status = readl(chip->base + NSP_CHIP_A_INT_STATUS);
if (int_status & NSP_CHIP_A_GPIO_INT_BIT) {
unsigned int event, level;
/* Get level and edge interrupts */
event = readl(chip->base + NSP_GPIO_EVENT_INT_MASK) &
readl(chip->base + NSP_GPIO_EVENT);
level = readl(chip->base + NSP_GPIO_DATA_IN) ^
readl(chip->base + NSP_GPIO_INT_POLARITY);
level &= readl(chip->base + NSP_GPIO_INT_MASK);
int_bits = level | event;
for_each_set_bit(bit, &int_bits, gc->ngpio)
generic_handle_domain_irq(gc->irq.domain, bit);
}
return int_bits ? IRQ_HANDLED : IRQ_NONE;
}
static void nsp_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq;
u32 val = BIT(gpio);
u32 trigger_type;
trigger_type = irq_get_trigger_type(d->irq);
if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
writel(val, chip->base + NSP_GPIO_EVENT);
}
/*
* nsp_gpio_irq_set_mask - mask/unmask a GPIO interrupt
*
* @d: IRQ chip data
* @unmask: mask/unmask GPIO interrupt
*/
static void nsp_gpio_irq_set_mask(struct irq_data *d, bool unmask)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq;
u32 trigger_type;
trigger_type = irq_get_trigger_type(d->irq);
if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_MASK, gpio, unmask);
else
nsp_set_bit(chip, REG, NSP_GPIO_INT_MASK, gpio, unmask);
}
static void nsp_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
nsp_gpio_irq_set_mask(d, false);
raw_spin_unlock_irqrestore(&chip->lock, flags);
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void nsp_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
raw_spin_lock_irqsave(&chip->lock, flags);
nsp_gpio_irq_set_mask(d, true);
raw_spin_unlock_irqrestore(&chip->lock, flags);
}
static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq;
bool level_low;
bool falling;
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
falling = nsp_get_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio);
level_low = nsp_get_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio);
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
falling = false;
break;
case IRQ_TYPE_EDGE_FALLING:
falling = true;
break;
case IRQ_TYPE_LEVEL_HIGH:
level_low = false;
break;
case IRQ_TYPE_LEVEL_LOW:
level_low = true;
break;
default:
dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
type);
raw_spin_unlock_irqrestore(&chip->lock, flags);
return -EINVAL;
}
nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling);
nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low);
if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
else
irq_set_handler_locked(d, handle_level_irq);
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio,
str_true_false(level_low), str_true_false(falling));
return 0;
}
static const struct irq_chip nsp_gpio_irq_chip = {
.name = "gpio-a",
.irq_ack = nsp_gpio_irq_ack,
.irq_mask = nsp_gpio_irq_mask,
.irq_unmask = nsp_gpio_irq_unmask,
.irq_set_type = nsp_gpio_irq_set_type,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
{
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, false);
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
return 0;
}
static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
int val)
{
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, true);
nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val));
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
return 0;
}
static int nsp_gpio_get_direction(struct gpio_chip *gc, unsigned gpio)
{
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
int val;
raw_spin_lock_irqsave(&chip->lock, flags);
val = nsp_get_bit(chip, REG, NSP_GPIO_OUT_EN, gpio);
raw_spin_unlock_irqrestore(&chip->lock, flags);
return !val;
}
static int nsp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val));
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
return 0;
}
static int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
struct nsp_gpio *chip = gpiochip_get_data(gc);
return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio));
}
static int nsp_get_groups_count(struct pinctrl_dev *pctldev)
{
return 1;
}
/*
* Only one group: "gpio_grp", since this local pinctrl device only performs
* GPIO specific PINCONF configurations
*/
static const char *nsp_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return "gpio_grp";
}
static const struct pinctrl_ops nsp_pctrl_ops = {
.get_groups_count = nsp_get_groups_count,
.get_group_name = nsp_get_group_name,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinctrl_utils_free_map,
};
static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u32 slew)
{
if (slew)
nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true);
else
nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, false);
return 0;
}
static int nsp_gpio_set_pull(struct nsp_gpio *chip, unsigned gpio,
bool pull_up, bool pull_down)
{
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
nsp_set_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio, pull_down);
nsp_set_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio, pull_up);
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set pullup:%d pulldown: %d\n",
gpio, pull_up, pull_down);
return 0;
}
static void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio,
bool *pull_up, bool *pull_down)
{
unsigned long flags;
raw_spin_lock_irqsave(&chip->lock, flags);
*pull_up = nsp_get_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio);
*pull_down = nsp_get_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio);
raw_spin_unlock_irqrestore(&chip->lock, flags);
}
static int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio,
u32 strength)
{
u32 offset, shift, i;
u32 val;
unsigned long flags;
/* make sure drive strength is supported */
if (strength < 2 || strength > 16 || (strength % 2))
return -ENOTSUPP;
shift = gpio;
offset = NSP_GPIO_DRV_CTRL;
dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
strength);
raw_spin_lock_irqsave(&chip->lock, flags);
strength = (strength / 2) - 1;
for (i = GPIO_DRV_STRENGTH_BITS; i > 0; i--) {
val = readl(chip->io_ctrl + offset);
val &= ~BIT(shift);
val |= ((strength >> (i-1)) & 0x1) << shift;
writel(val, chip->io_ctrl + offset);
offset += 4;
}
raw_spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio,
u16 *strength)
{
unsigned int offset, shift;
u32 val;
unsigned long flags;
int i;
offset = NSP_GPIO_DRV_CTRL;
shift = gpio;
raw_spin_lock_irqsave(&chip->lock, flags);
*strength = 0;
for (i = (GPIO_DRV_STRENGTH_BITS - 1); i >= 0; i--) {
val = readl(chip->io_ctrl + offset) & BIT(shift);
val >>= shift;
*strength += (val << i);
offset += 4;
}
/* convert to mA */
*strength = (*strength + 1) * 2;
raw_spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int nsp_pin_config_group_get(struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long *config)
{
return 0;
}
static int nsp_pin_config_group_set(struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long *configs, unsigned num_configs)
{
return 0;
}
static int nsp_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *config)
{
struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
unsigned int gpio;
u16 arg = 0;
bool pull_up, pull_down;
int ret;
gpio = nsp_pin_to_gpio(pin);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
if ((pull_up == false) && (pull_down == false))
return 0;
else
return -EINVAL;
case PIN_CONFIG_BIAS_PULL_UP:
nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
if (pull_up)
return 0;
else
return -EINVAL;
case PIN_CONFIG_BIAS_PULL_DOWN:
nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
if (pull_down)
return 0;
else
return -EINVAL;
case PIN_CONFIG_DRIVE_STRENGTH:
ret = nsp_gpio_get_strength(chip, gpio, &arg);
if (ret)
return ret;
*config = pinconf_to_config_packed(param, arg);
return 0;
default:
return -ENOTSUPP;
}
}
static int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *configs, unsigned num_configs)
{
struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
u32 arg;
unsigned int i, gpio;
int ret = -ENOTSUPP;
gpio = nsp_pin_to_gpio(pin);
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
ret = nsp_gpio_set_pull(chip, gpio, false, false);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = nsp_gpio_set_pull(chip, gpio, true, false);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = nsp_gpio_set_pull(chip, gpio, false, true);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
ret = nsp_gpio_set_strength(chip, gpio, arg);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_SLEW_RATE:
ret = nsp_gpio_set_slew(chip, gpio, arg);
if (ret < 0)
goto out;
break;
default:
dev_err(chip->dev, "invalid configuration\n");
return -ENOTSUPP;
}
}
out:
return ret;
}
static const struct pinconf_ops nsp_pconf_ops = {
.is_generic = true,
.pin_config_get = nsp_pin_config_get,
.pin_config_set = nsp_pin_config_set,
.pin_config_group_get = nsp_pin_config_group_get,
.pin_config_group_set = nsp_pin_config_group_set,
};
/*
* NSP GPIO controller supports some PINCONF related configurations such as
* pull up, pull down, slew and drive strength, when the pin is configured
* to GPIO.
*
* Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
* local GPIO pins
*/
static int nsp_gpio_register_pinconf(struct nsp_gpio *chip)
{
struct pinctrl_desc *pctldesc = &chip->pctldesc;
struct pinctrl_pin_desc *pins;
struct gpio_chip *gc = &chip->gc;
int i;
pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (i = 0; i < gc->ngpio; i++) {
pins[i].number = i;
pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
"gpio-%d", i);
if (!pins[i].name)
return -ENOMEM;
}
pctldesc->name = dev_name(chip->dev);
pctldesc->pctlops = &nsp_pctrl_ops;
pctldesc->pins = pins;
pctldesc->npins = gc->ngpio;
pctldesc->confops = &nsp_pconf_ops;
chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip);
if (IS_ERR(chip->pctl)) {
dev_err(chip->dev, "unable to register pinctrl device\n");
return PTR_ERR(chip->pctl);
}
return 0;
}
static const struct of_device_id nsp_gpio_of_match[] = {
{.compatible = "brcm,nsp-gpio-a",},
{}
};
static int nsp_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct nsp_gpio *chip;
struct gpio_chip *gc;
u32 val;
int irq, ret;
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &val)) {
dev_err(&pdev->dev, "Missing ngpios OF property\n");
return -ENODEV;
}
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = dev;
platform_set_drvdata(pdev, chip);
chip->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->base)) {
dev_err(dev, "unable to map I/O memory\n");
return PTR_ERR(chip->base);
}
chip->io_ctrl = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(chip->io_ctrl)) {
dev_err(dev, "unable to map I/O memory\n");
return PTR_ERR(chip->io_ctrl);
}
raw_spin_lock_init(&chip->lock);
gc = &chip->gc;
gc->base = -1;
gc->can_sleep = false;
gc->ngpio = val;
gc->label = dev_name(dev);
gc->parent = dev;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
gc->direction_input = nsp_gpio_direction_input;
gc->direction_output = nsp_gpio_direction_output;
gc->get_direction = nsp_gpio_get_direction;
gc->set = nsp_gpio_set;
gc->get = nsp_gpio_get;
/* optional GPIO interrupt support */
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
struct gpio_irq_chip *girq;
val = readl(chip->base + NSP_CHIP_A_INT_MASK);
val = val | NSP_CHIP_A_GPIO_INT_BIT;
writel(val, (chip->base + NSP_CHIP_A_INT_MASK));
/* Install ISR for this GPIO controller. */
ret = devm_request_irq(dev, irq, nsp_gpio_irq_handler,
IRQF_SHARED, "gpio-a", &chip->gc);
if (ret) {
dev_err(&pdev->dev, "Unable to request IRQ%d: %d\n",
irq, ret);
return ret;
}
girq = &chip->gc.irq;
gpio_irq_chip_set_chip(girq, &nsp_gpio_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
}
ret = devm_gpiochip_add_data(dev, gc, chip);
if (ret < 0)
return dev_err_probe(dev, ret, "unable to add GPIO chip\n");
ret = nsp_gpio_register_pinconf(chip);
if (ret) {
dev_err(dev, "unable to register pinconf\n");
return ret;
}
return 0;
}
static struct platform_driver nsp_gpio_driver = {
.driver = {
.name = "nsp-gpio-a",
.of_match_table = nsp_gpio_of_match,
},
.probe = nsp_gpio_probe,
};
static int __init nsp_gpio_init(void)
{
return platform_driver_register(&nsp_gpio_driver);
}
arch_initcall_sync(nsp_gpio_init);
@@ -0,0 +1,636 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2015 Broadcom Corporation
*
* This file contains the Northstar plus (NSP) IOMUX driver that supports
* group based PINMUX configuration. The Northstar plus IOMUX controller
* allows pins to be individually muxed to GPIO function. The NAND and MMC is
* a group based selection. The gpio_a 8 - 11 are muxed with gpio_b and pwm.
* To select PWM, one need to enable the corresponding gpio_b as well.
*
* gpio_a (8 - 11)
* +----------
* |
* gpio_a (8-11) | gpio_b (0 - 3)
* ------------------------+-------+----------
* |
* | pwm (0 - 3)
* +----------
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include "../core.h"
#include "../pinctrl-utils.h"
#define NSP_MUX_BASE0 0x00
#define NSP_MUX_BASE1 0x01
#define NSP_MUX_BASE2 0x02
/*
* nsp IOMUX register description
*
* @base: base 0 or base 1
* @shift: bit shift for mux configuration of a group
* @mask: bit mask of the function
* @alt: alternate function to set to
*/
struct nsp_mux {
unsigned int base;
unsigned int shift;
unsigned int mask;
unsigned int alt;
};
/*
* Keep track of nsp IOMUX configuration and prevent double configuration
*
* @nsp_mux: nsp IOMUX register description
* @is_configured: flag to indicate whether a mux setting has already been
* configured
*/
struct nsp_mux_log {
struct nsp_mux mux;
bool is_configured;
};
/*
* Group based IOMUX configuration
*
* @name: name of the group
* @pins: array of pins used by this group
* @num_pins: total number of pins used by this group
* @mux: nsp group based IOMUX configuration
*/
struct nsp_pin_group {
const char *name;
const unsigned int *pins;
const unsigned int num_pins;
const struct nsp_mux mux;
};
/*
* nsp mux function and supported pin groups
*
* @name: name of the function
* @groups: array of groups that can be supported by this function
* @num_groups: total number of groups that can be supported by this function
*/
struct nsp_pin_function {
const char *name;
const char * const *groups;
const unsigned int num_groups;
};
/*
* nsp IOMUX pinctrl core
*
* @pctl: pointer to pinctrl_dev
* @dev: pointer to device
* @base0: first mux register
* @base1: second mux register
* @base2: third mux register
* @groups: pointer to array of groups
* @num_groups: total number of groups
* @functions: pointer to array of functions
* @num_functions: total number of functions
* @mux_log: pointer to the array of mux logs
* @lock: lock to protect register access
*/
struct nsp_pinctrl {
struct pinctrl_dev *pctl;
struct device *dev;
void __iomem *base0;
void __iomem *base1;
void __iomem *base2;
const struct nsp_pin_group *groups;
unsigned int num_groups;
const struct nsp_pin_function *functions;
unsigned int num_functions;
struct nsp_mux_log *mux_log;
spinlock_t lock;
};
/*
* Description of a pin in nsp
*
* @pin: pin number
* @name: pin name
* @gpio_select: reg data to select GPIO
*/
struct nsp_pin {
unsigned int pin;
char *name;
unsigned int gpio_select;
};
#define NSP_PIN_DESC(p, n, g) \
{ \
.pin = p, \
.name = n, \
.gpio_select = g, \
}
/*
* List of muxable pins in nsp
*/
static struct nsp_pin nsp_pins[] = {
NSP_PIN_DESC(0, "spi_clk", 1),
NSP_PIN_DESC(1, "spi_ss", 1),
NSP_PIN_DESC(2, "spi_mosi", 1),
NSP_PIN_DESC(3, "spi_miso", 1),
NSP_PIN_DESC(4, "scl", 1),
NSP_PIN_DESC(5, "sda", 1),
NSP_PIN_DESC(6, "mdc", 1),
NSP_PIN_DESC(7, "mdio", 1),
NSP_PIN_DESC(8, "pwm0", 1),
NSP_PIN_DESC(9, "pwm1", 1),
NSP_PIN_DESC(10, "pwm2", 1),
NSP_PIN_DESC(11, "pwm3", 1),
NSP_PIN_DESC(12, "uart1_rx", 1),
NSP_PIN_DESC(13, "uart1_tx", 1),
NSP_PIN_DESC(14, "uart1_cts", 1),
NSP_PIN_DESC(15, "uart1_rts", 1),
NSP_PIN_DESC(16, "uart2_rx", 1),
NSP_PIN_DESC(17, "uart2_tx", 1),
NSP_PIN_DESC(18, "synce", 0),
NSP_PIN_DESC(19, "sata0_led", 0),
NSP_PIN_DESC(20, "sata1_led", 0),
NSP_PIN_DESC(21, "xtal_out", 1),
NSP_PIN_DESC(22, "sdio_pwr", 1),
NSP_PIN_DESC(23, "sdio_en_1p8v", 1),
NSP_PIN_DESC(24, "gpio_24", 1),
NSP_PIN_DESC(25, "gpio_25", 1),
NSP_PIN_DESC(26, "p5_led0", 0),
NSP_PIN_DESC(27, "p5_led1", 0),
NSP_PIN_DESC(28, "gpio_28", 1),
NSP_PIN_DESC(29, "gpio_29", 1),
NSP_PIN_DESC(30, "gpio_30", 1),
NSP_PIN_DESC(31, "gpio_31", 1),
NSP_PIN_DESC(32, "nand_ale", 0),
NSP_PIN_DESC(33, "nand_ce0", 0),
NSP_PIN_DESC(34, "nand_r/b", 0),
NSP_PIN_DESC(35, "nand_dq0", 0),
NSP_PIN_DESC(36, "nand_dq1", 0),
NSP_PIN_DESC(37, "nand_dq2", 0),
NSP_PIN_DESC(38, "nand_dq3", 0),
NSP_PIN_DESC(39, "nand_dq4", 0),
NSP_PIN_DESC(40, "nand_dq5", 0),
NSP_PIN_DESC(41, "nand_dq6", 0),
NSP_PIN_DESC(42, "nand_dq7", 0),
};
/*
* List of groups of pins
*/
static const unsigned int spi_pins[] = {0, 1, 2, 3};
static const unsigned int i2c_pins[] = {4, 5};
static const unsigned int mdio_pins[] = {6, 7};
static const unsigned int pwm0_pins[] = {8};
static const unsigned int gpio_b_0_pins[] = {8};
static const unsigned int pwm1_pins[] = {9};
static const unsigned int gpio_b_1_pins[] = {9};
static const unsigned int pwm2_pins[] = {10};
static const unsigned int gpio_b_2_pins[] = {10};
static const unsigned int pwm3_pins[] = {11};
static const unsigned int gpio_b_3_pins[] = {11};
static const unsigned int uart1_pins[] = {12, 13, 14, 15};
static const unsigned int uart2_pins[] = {16, 17};
static const unsigned int synce_pins[] = {18};
static const unsigned int sata0_led_pins[] = {19};
static const unsigned int sata1_led_pins[] = {20};
static const unsigned int xtal_out_pins[] = {21};
static const unsigned int sdio_pwr_pins[] = {22};
static const unsigned int sdio_1p8v_pins[] = {23};
static const unsigned int switch_p05_led0_pins[] = {26};
static const unsigned int switch_p05_led1_pins[] = {27};
static const unsigned int nand_pins[] = {32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42};
static const unsigned int emmc_pins[] = {32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42};
#define NSP_PIN_GROUP(group_name, ba, sh, ma, al) \
{ \
.name = __stringify(group_name) "_grp", \
.pins = group_name ## _pins, \
.num_pins = ARRAY_SIZE(group_name ## _pins), \
.mux = { \
.base = ba, \
.shift = sh, \
.mask = ma, \
.alt = al, \
} \
}
/*
* List of nsp pin groups
*/
static const struct nsp_pin_group nsp_pin_groups[] = {
NSP_PIN_GROUP(spi, NSP_MUX_BASE0, 0, 0x0f, 0x00),
NSP_PIN_GROUP(i2c, NSP_MUX_BASE0, 3, 0x03, 0x00),
NSP_PIN_GROUP(mdio, NSP_MUX_BASE0, 5, 0x03, 0x00),
NSP_PIN_GROUP(gpio_b_0, NSP_MUX_BASE0, 7, 0x01, 0x00),
NSP_PIN_GROUP(pwm0, NSP_MUX_BASE1, 0, 0x01, 0x01),
NSP_PIN_GROUP(gpio_b_1, NSP_MUX_BASE0, 8, 0x01, 0x00),
NSP_PIN_GROUP(pwm1, NSP_MUX_BASE1, 1, 0x01, 0x01),
NSP_PIN_GROUP(gpio_b_2, NSP_MUX_BASE0, 9, 0x01, 0x00),
NSP_PIN_GROUP(pwm2, NSP_MUX_BASE1, 2, 0x01, 0x01),
NSP_PIN_GROUP(gpio_b_3, NSP_MUX_BASE0, 10, 0x01, 0x00),
NSP_PIN_GROUP(pwm3, NSP_MUX_BASE1, 3, 0x01, 0x01),
NSP_PIN_GROUP(uart1, NSP_MUX_BASE0, 11, 0x0f, 0x00),
NSP_PIN_GROUP(uart2, NSP_MUX_BASE0, 15, 0x03, 0x00),
NSP_PIN_GROUP(synce, NSP_MUX_BASE0, 17, 0x01, 0x01),
NSP_PIN_GROUP(sata0_led, NSP_MUX_BASE0, 18, 0x01, 0x01),
NSP_PIN_GROUP(sata1_led, NSP_MUX_BASE0, 19, 0x01, 0x01),
NSP_PIN_GROUP(xtal_out, NSP_MUX_BASE0, 20, 0x01, 0x00),
NSP_PIN_GROUP(sdio_pwr, NSP_MUX_BASE0, 21, 0x01, 0x00),
NSP_PIN_GROUP(sdio_1p8v, NSP_MUX_BASE0, 22, 0x01, 0x00),
NSP_PIN_GROUP(switch_p05_led0, NSP_MUX_BASE0, 26, 0x01, 0x01),
NSP_PIN_GROUP(switch_p05_led1, NSP_MUX_BASE0, 27, 0x01, 0x01),
NSP_PIN_GROUP(nand, NSP_MUX_BASE2, 0, 0x01, 0x00),
NSP_PIN_GROUP(emmc, NSP_MUX_BASE2, 0, 0x01, 0x01)
};
/*
* List of groups supported by functions
*/
static const char * const spi_grps[] = {"spi_grp"};
static const char * const i2c_grps[] = {"i2c_grp"};
static const char * const mdio_grps[] = {"mdio_grp"};
static const char * const pwm_grps[] = {"pwm0_grp", "pwm1_grp", "pwm2_grp"
, "pwm3_grp"};
static const char * const gpio_b_grps[] = {"gpio_b_0_grp", "gpio_b_1_grp",
"gpio_b_2_grp", "gpio_b_3_grp"};
static const char * const uart1_grps[] = {"uart1_grp"};
static const char * const uart2_grps[] = {"uart2_grp"};
static const char * const synce_grps[] = {"synce_grp"};
static const char * const sata_led_grps[] = {"sata0_led_grp", "sata1_led_grp"};
static const char * const xtal_out_grps[] = {"xtal_out_grp"};
static const char * const sdio_grps[] = {"sdio_pwr_grp", "sdio_1p8v_grp"};
static const char * const switch_led_grps[] = {"switch_p05_led0_grp",
"switch_p05_led1_grp"};
static const char * const nand_grps[] = {"nand_grp"};
static const char * const emmc_grps[] = {"emmc_grp"};
#define NSP_PIN_FUNCTION(func) \
{ \
.name = #func, \
.groups = func ## _grps, \
.num_groups = ARRAY_SIZE(func ## _grps), \
}
/*
* List of supported functions in nsp
*/
static const struct nsp_pin_function nsp_pin_functions[] = {
NSP_PIN_FUNCTION(spi),
NSP_PIN_FUNCTION(i2c),
NSP_PIN_FUNCTION(mdio),
NSP_PIN_FUNCTION(pwm),
NSP_PIN_FUNCTION(gpio_b),
NSP_PIN_FUNCTION(uart1),
NSP_PIN_FUNCTION(uart2),
NSP_PIN_FUNCTION(synce),
NSP_PIN_FUNCTION(sata_led),
NSP_PIN_FUNCTION(xtal_out),
NSP_PIN_FUNCTION(sdio),
NSP_PIN_FUNCTION(switch_led),
NSP_PIN_FUNCTION(nand),
NSP_PIN_FUNCTION(emmc)
};
static int nsp_get_groups_count(struct pinctrl_dev *pctrl_dev)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
return pinctrl->num_groups;
}
static const char *nsp_get_group_name(struct pinctrl_dev *pctrl_dev,
unsigned int selector)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
return pinctrl->groups[selector].name;
}
static int nsp_get_group_pins(struct pinctrl_dev *pctrl_dev,
unsigned int selector, const unsigned int **pins,
unsigned int *num_pins)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
*pins = pinctrl->groups[selector].pins;
*num_pins = pinctrl->groups[selector].num_pins;
return 0;
}
static void nsp_pin_dbg_show(struct pinctrl_dev *pctrl_dev,
struct seq_file *s, unsigned int offset)
{
seq_printf(s, " %s", dev_name(pctrl_dev->dev));
}
static const struct pinctrl_ops nsp_pinctrl_ops = {
.get_groups_count = nsp_get_groups_count,
.get_group_name = nsp_get_group_name,
.get_group_pins = nsp_get_group_pins,
.pin_dbg_show = nsp_pin_dbg_show,
.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
.dt_free_map = pinctrl_utils_free_map,
};
static int nsp_get_functions_count(struct pinctrl_dev *pctrl_dev)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
return pinctrl->num_functions;
}
static const char *nsp_get_function_name(struct pinctrl_dev *pctrl_dev,
unsigned int selector)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
return pinctrl->functions[selector].name;
}
static int nsp_get_function_groups(struct pinctrl_dev *pctrl_dev,
unsigned int selector,
const char * const **groups,
unsigned * const num_groups)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
*groups = pinctrl->functions[selector].groups;
*num_groups = pinctrl->functions[selector].num_groups;
return 0;
}
static int nsp_pinmux_set(struct nsp_pinctrl *pinctrl,
const struct nsp_pin_function *func,
const struct nsp_pin_group *grp,
struct nsp_mux_log *mux_log)
{
const struct nsp_mux *mux = &grp->mux;
int i;
u32 val, mask;
unsigned long flags;
void __iomem *base_address;
for (i = 0; i < pinctrl->num_groups; i++) {
if ((mux->shift != mux_log[i].mux.shift) ||
(mux->base != mux_log[i].mux.base))
continue;
/* if this is a new configuration, just do it! */
if (!mux_log[i].is_configured)
break;
/*
* IOMUX has been configured previously and one is trying to
* configure it to a different function
*/
if (mux_log[i].mux.alt != mux->alt) {
dev_err(pinctrl->dev,
"double configuration error detected!\n");
dev_err(pinctrl->dev, "func:%s grp:%s\n",
func->name, grp->name);
return -EINVAL;
}
return 0;
}
if (i == pinctrl->num_groups)
return -EINVAL;
mask = mux->mask;
mux_log[i].mux.alt = mux->alt;
mux_log[i].is_configured = true;
switch (mux->base) {
case NSP_MUX_BASE0:
base_address = pinctrl->base0;
break;
case NSP_MUX_BASE1:
base_address = pinctrl->base1;
break;
case NSP_MUX_BASE2:
base_address = pinctrl->base2;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&pinctrl->lock, flags);
val = readl(base_address);
val &= ~(mask << grp->mux.shift);
val |= grp->mux.alt << grp->mux.shift;
writel(val, base_address);
spin_unlock_irqrestore(&pinctrl->lock, flags);
return 0;
}
static int nsp_pinmux_enable(struct pinctrl_dev *pctrl_dev,
unsigned int func_select, unsigned int grp_select)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
const struct nsp_pin_function *func;
const struct nsp_pin_group *grp;
if (grp_select >= pinctrl->num_groups ||
func_select >= pinctrl->num_functions)
return -EINVAL;
func = &pinctrl->functions[func_select];
grp = &pinctrl->groups[grp_select];
dev_dbg(pctrl_dev->dev, "func:%u name:%s grp:%u name:%s\n",
func_select, func->name, grp_select, grp->name);
dev_dbg(pctrl_dev->dev, "shift:%u alt:%u\n", grp->mux.shift,
grp->mux.alt);
return nsp_pinmux_set(pinctrl, func, grp, pinctrl->mux_log);
}
static int nsp_gpio_request_enable(struct pinctrl_dev *pctrl_dev,
struct pinctrl_gpio_range *range,
unsigned int pin)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
u32 *gpio_select = pctrl_dev->desc->pins[pin].drv_data;
u32 val;
unsigned long flags;
spin_lock_irqsave(&pinctrl->lock, flags);
val = readl(pinctrl->base0);
if ((val & BIT(pin)) != (*gpio_select << pin)) {
val &= ~BIT(pin);
val |= *gpio_select << pin;
writel(val, pinctrl->base0);
}
spin_unlock_irqrestore(&pinctrl->lock, flags);
return 0;
}
static void nsp_gpio_disable_free(struct pinctrl_dev *pctrl_dev,
struct pinctrl_gpio_range *range,
unsigned int pin)
{
struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
u32 *gpio_select = pctrl_dev->desc->pins[pin].drv_data;
u32 val;
unsigned long flags;
spin_lock_irqsave(&pinctrl->lock, flags);
val = readl(pinctrl->base0);
if ((val & (1 << pin)) == (*gpio_select << pin)) {
val &= ~(1 << pin);
if (!(*gpio_select))
val |= (1 << pin);
writel(val, pinctrl->base0);
}
spin_unlock_irqrestore(&pinctrl->lock, flags);
}
static const struct pinmux_ops nsp_pinmux_ops = {
.get_functions_count = nsp_get_functions_count,
.get_function_name = nsp_get_function_name,
.get_function_groups = nsp_get_function_groups,
.set_mux = nsp_pinmux_enable,
.gpio_request_enable = nsp_gpio_request_enable,
.gpio_disable_free = nsp_gpio_disable_free,
};
static struct pinctrl_desc nsp_pinctrl_desc = {
.name = "nsp-pinmux",
.pctlops = &nsp_pinctrl_ops,
.pmxops = &nsp_pinmux_ops,
.npins = ARRAY_SIZE(nsp_pins),
};
static int nsp_mux_log_init(struct nsp_pinctrl *pinctrl)
{
struct nsp_mux_log *log;
unsigned int i;
u32 no_of_groups = ARRAY_SIZE(nsp_pin_groups);
pinctrl->mux_log = devm_kcalloc(pinctrl->dev, no_of_groups,
sizeof(struct nsp_mux_log),
GFP_KERNEL);
if (!pinctrl->mux_log)
return -ENOMEM;
for (i = 0; i < no_of_groups; i++) {
log = &pinctrl->mux_log[i];
log->mux.base = nsp_pin_groups[i].mux.base;
log->mux.shift = nsp_pin_groups[i].mux.shift;
log->mux.alt = 0;
log->is_configured = false;
}
return 0;
}
static int nsp_pinmux_probe(struct platform_device *pdev)
{
struct nsp_pinctrl *pinctrl;
struct resource *res;
int i, ret;
struct pinctrl_pin_desc *pins;
pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
if (!pinctrl)
return -ENOMEM;
pinctrl->dev = &pdev->dev;
platform_set_drvdata(pdev, pinctrl);
spin_lock_init(&pinctrl->lock);
pinctrl->base0 = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pinctrl->base0))
return PTR_ERR(pinctrl->base0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res)
return -EINVAL;
pinctrl->base1 = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!pinctrl->base1) {
dev_err(&pdev->dev, "unable to map I/O space\n");
return -ENOMEM;
}
pinctrl->base2 = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(pinctrl->base2))
return PTR_ERR(pinctrl->base2);
ret = nsp_mux_log_init(pinctrl);
if (ret) {
dev_err(&pdev->dev, "unable to initialize IOMUX log\n");
return ret;
}
pins = devm_kcalloc(&pdev->dev, ARRAY_SIZE(nsp_pins), sizeof(*pins),
GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(nsp_pins); i++) {
pins[i].number = nsp_pins[i].pin;
pins[i].name = nsp_pins[i].name;
pins[i].drv_data = &nsp_pins[i].gpio_select;
}
pinctrl->groups = nsp_pin_groups;
pinctrl->num_groups = ARRAY_SIZE(nsp_pin_groups);
pinctrl->functions = nsp_pin_functions;
pinctrl->num_functions = ARRAY_SIZE(nsp_pin_functions);
nsp_pinctrl_desc.pins = pins;
pinctrl->pctl = devm_pinctrl_register(&pdev->dev, &nsp_pinctrl_desc,
pinctrl);
if (IS_ERR(pinctrl->pctl)) {
dev_err(&pdev->dev, "unable to register nsp IOMUX pinctrl\n");
return PTR_ERR(pinctrl->pctl);
}
return 0;
}
static const struct of_device_id nsp_pinmux_of_match[] = {
{ .compatible = "brcm,nsp-pinmux" },
{ }
};
static struct platform_driver nsp_pinmux_driver = {
.driver = {
.name = "nsp-pinmux",
.of_match_table = nsp_pinmux_of_match,
},
.probe = nsp_pinmux_probe,
};
static int __init nsp_pinmux_init(void)
{
return platform_driver_register(&nsp_pinmux_driver);
}
arch_initcall(nsp_pinmux_init);