diff options
Diffstat (limited to 'drivers')
81 files changed, 7663 insertions, 1183 deletions
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index cfbfcaefec0f..e1f8740ae688 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1245,8 +1245,8 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, int irq) channel_templates = xadc_us_channels; max_channels = ARRAY_SIZE(xadc_us_channels); } - channels = devm_kmemdup(dev, channel_templates, - sizeof(channels[0]) * max_channels, GFP_KERNEL); + channels = devm_kmemdup_array(dev, channel_templates, max_channels, + sizeof(*channel_templates), GFP_KERNEL); if (!channels) return -ENOMEM; diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index 58631bf7ce55..ca7ec054b1ce 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -102,9 +102,8 @@ static int micro_key_probe(struct platform_device *pdev) keys->input->keycodesize = sizeof(micro_keycodes[0]); keys->input->keycodemax = ARRAY_SIZE(micro_keycodes); - keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes, - keys->input->keycodesize * keys->input->keycodemax, - GFP_KERNEL); + keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax, + keys->input->keycodesize, GFP_KERNEL); if (!keys->codes) return -ENOMEM; diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 25bf8be6e711..96f23ae57d5a 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -176,8 +176,7 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), - GFP_KERNEL); + map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL); if (!map) return -ENOMEM; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 95a8e2b9a614..464cc9aca157 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -49,6 +49,20 @@ config PINCTRL_AMD Requires ACPI/FDT device enumeration code to set up a platform device. +config PINCTRL_AMDISP + tristate "AMDISP GPIO pin control" + depends on DRM_AMD_ISP || COMPILE_TEST + depends on HAS_IOMEM + select GPIOLIB + select PINCONF + select GENERIC_PINCONF + help + The driver for memory mapped GPIO functionality on AMD platforms + with ISP support. All the pins are output controlled only + + Requires AMDGPU to MFD add device for enumeration to set up as + platform device. + config PINCTRL_APPLE_GPIO tristate "Apple SoC GPIO pin controller driver" depends on ARCH_APPLE diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index fba1c56624c0..ac27e88677d1 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o +obj-$(CONFIG_PINCTRL_AMDISP) += pinctrl-amdisp.o obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index cf6efa9c0364..9ea20fde3a24 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -52,6 +52,12 @@ #define BCM281XX_HDMI_PIN_REG_MODE_MASK 0x0010 #define BCM281XX_HDMI_PIN_REG_MODE_SHIFT 4 +/* BCM21664 access lock registers */ +#define BCM21664_WR_ACCESS_OFFSET 0x07F0 +#define BCM21664_WR_ACCESS_PASSWORD 0xA5A501 +#define BCM21664_ACCESS_LOCK_OFFSET(lock) (0x0780 + (lock * 4)) +#define BCM21664_ACCESS_LOCK_COUNT 5 + /* * bcm281xx_pin_type - types of pin register */ @@ -72,24 +78,45 @@ static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI; struct bcm281xx_pin_function { const char *name; const char * const *groups; - const unsigned ngroups; + const unsigned int ngroups; }; /* - * bcm281xx_pinctrl_data - Broadcom-specific pinctrl data - * @reg_base - base of pinctrl registers + * Device types (used in bcm281xx_pinctrl_desc to differentiate + * the two device types from each other) */ -struct bcm281xx_pinctrl_data { - void __iomem *reg_base; +enum bcm281xx_pinctrl_type { + BCM281XX_PINCTRL_TYPE, + BCM21664_PINCTRL_TYPE, +}; + +/* + * bcm281xx_pinctrl_info - description of a pinctrl device supported + * by this driver, intended to be used as a provider of OF match data. + */ +struct bcm281xx_pinctrl_info { + enum bcm281xx_pinctrl_type device_type; /* List of all pins */ const struct pinctrl_pin_desc *pins; - const unsigned npins; + unsigned int npins; const struct bcm281xx_pin_function *functions; - const unsigned nfunctions; + unsigned int nfunctions; + + const struct regmap_config *regmap_config; +}; + +/* + * bcm281xx_pinctrl_data - Broadcom-specific pinctrl data + * @reg_base - base of pinctrl registers + */ +struct bcm281xx_pinctrl_data { + struct device *dev; + void __iomem *reg_base; struct regmap *regmap; + const struct bcm281xx_pinctrl_info *info; }; /* @@ -933,22 +960,598 @@ static const struct bcm281xx_pin_function bcm281xx_functions[] = { BCM281XX_PIN_FUNCTION(alt4), }; -static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = { +static const struct regmap_config bcm281xx_pinctrl_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM281XX_PIN_VC_CAM3_SDA * 4, +}; + +static const struct bcm281xx_pinctrl_info bcm281xx_pinctrl = { + .device_type = BCM281XX_PINCTRL_TYPE, + .pins = bcm281xx_pinctrl_pins, .npins = ARRAY_SIZE(bcm281xx_pinctrl_pins), .functions = bcm281xx_functions, .nfunctions = ARRAY_SIZE(bcm281xx_functions), + + .regmap_config = &bcm281xx_pinctrl_regmap_config, +}; + +/* BCM21664 data */ +#define BCM21664_PIN_ADCSYN 0 +#define BCM21664_PIN_BATRM 1 +#define BCM21664_PIN_BSC1CLK 2 +#define BCM21664_PIN_BSC1DAT 3 +#define BCM21664_PIN_CAMCS0 4 +#define BCM21664_PIN_CAMCS1 5 +#define BCM21664_PIN_CLK32K 6 +#define BCM21664_PIN_CLK_CX8 7 +#define BCM21664_PIN_DCLK1 8 +#define BCM21664_PIN_DCLK4 9 +#define BCM21664_PIN_DCLKREQ1 10 +#define BCM21664_PIN_DCLKREQ4 11 +#define BCM21664_PIN_DMIC0CLK 12 +#define BCM21664_PIN_DMIC0DQ 13 +#define BCM21664_PIN_DSI0TE 14 +#define BCM21664_PIN_GPIO00 15 +#define BCM21664_PIN_GPIO01 16 +#define BCM21664_PIN_GPIO02 17 +#define BCM21664_PIN_GPIO03 18 +#define BCM21664_PIN_GPIO04 19 +#define BCM21664_PIN_GPIO05 20 +#define BCM21664_PIN_GPIO06 21 +#define BCM21664_PIN_GPIO07 22 +#define BCM21664_PIN_GPIO08 23 +#define BCM21664_PIN_GPIO09 24 +#define BCM21664_PIN_GPIO10 25 +#define BCM21664_PIN_GPIO11 26 +#define BCM21664_PIN_GPIO12 27 +#define BCM21664_PIN_GPIO13 28 +#define BCM21664_PIN_GPIO14 29 +#define BCM21664_PIN_GPIO15 30 +#define BCM21664_PIN_GPIO16 31 +#define BCM21664_PIN_GPIO17 32 +#define BCM21664_PIN_GPIO18 33 +#define BCM21664_PIN_GPIO19 34 +#define BCM21664_PIN_GPIO20 35 +#define BCM21664_PIN_GPIO21 36 +#define BCM21664_PIN_GPIO22 37 +#define BCM21664_PIN_GPIO23 38 +#define BCM21664_PIN_GPIO24 39 +#define BCM21664_PIN_GPIO25 40 +#define BCM21664_PIN_GPIO26 41 +#define BCM21664_PIN_GPIO27 42 +#define BCM21664_PIN_GPIO28 43 +#define BCM21664_PIN_GPIO32 44 +#define BCM21664_PIN_GPIO33 45 +#define BCM21664_PIN_GPIO34 46 +#define BCM21664_PIN_GPS_CALREQ 47 +#define BCM21664_PIN_GPS_HOSTREQ 48 +#define BCM21664_PIN_GPS_PABLANK 49 +#define BCM21664_PIN_GPS_TMARK 50 +#define BCM21664_PIN_ICUSBDM 51 +#define BCM21664_PIN_ICUSBDP 52 +#define BCM21664_PIN_LCDCS0 53 +#define BCM21664_PIN_LCDRES 54 +#define BCM21664_PIN_LCDSCL 55 +#define BCM21664_PIN_LCDSDA 56 +#define BCM21664_PIN_LCDTE 57 +#define BCM21664_PIN_MDMGPIO00 58 +#define BCM21664_PIN_MDMGPIO01 59 +#define BCM21664_PIN_MDMGPIO02 60 +#define BCM21664_PIN_MDMGPIO03 61 +#define BCM21664_PIN_MDMGPIO04 62 +#define BCM21664_PIN_MDMGPIO05 63 +#define BCM21664_PIN_MDMGPIO06 64 +#define BCM21664_PIN_MDMGPIO07 65 +#define BCM21664_PIN_MDMGPIO08 66 +#define BCM21664_PIN_MMC0CK 67 +#define BCM21664_PIN_MMC0CMD 68 +#define BCM21664_PIN_MMC0DAT0 69 +#define BCM21664_PIN_MMC0DAT1 70 +#define BCM21664_PIN_MMC0DAT2 71 +#define BCM21664_PIN_MMC0DAT3 72 +#define BCM21664_PIN_MMC0DAT4 73 +#define BCM21664_PIN_MMC0DAT5 74 +#define BCM21664_PIN_MMC0DAT6 75 +#define BCM21664_PIN_MMC0DAT7 76 +#define BCM21664_PIN_MMC0RST 77 +#define BCM21664_PIN_MMC1CK 78 +#define BCM21664_PIN_MMC1CMD 79 +#define BCM21664_PIN_MMC1DAT0 80 +#define BCM21664_PIN_MMC1DAT1 81 +#define BCM21664_PIN_MMC1DAT2 82 +#define BCM21664_PIN_MMC1DAT3 83 +#define BCM21664_PIN_MMC1DAT4 84 +#define BCM21664_PIN_MMC1DAT5 85 +#define BCM21664_PIN_MMC1DAT6 86 +#define BCM21664_PIN_MMC1DAT7 87 +#define BCM21664_PIN_MMC1RST 88 +#define BCM21664_PIN_PC1 89 +#define BCM21664_PIN_PC2 90 +#define BCM21664_PIN_PMBSCCLK 91 +#define BCM21664_PIN_PMBSCDAT 92 +#define BCM21664_PIN_PMUINT 93 +#define BCM21664_PIN_RESETN 94 +#define BCM21664_PIN_RFST2G_MTSLOTEN3G 95 +#define BCM21664_PIN_RTXDATA2G_TXDATA3G1 96 +#define BCM21664_PIN_RTXEN2G_TXDATA3G2 97 +#define BCM21664_PIN_RXDATA3G0 98 +#define BCM21664_PIN_RXDATA3G1 99 +#define BCM21664_PIN_RXDATA3G2 100 +#define BCM21664_PIN_SDCK 101 +#define BCM21664_PIN_SDCMD 102 +#define BCM21664_PIN_SDDAT0 103 +#define BCM21664_PIN_SDDAT1 104 +#define BCM21664_PIN_SDDAT2 105 +#define BCM21664_PIN_SDDAT3 106 +#define BCM21664_PIN_SIMCLK 107 +#define BCM21664_PIN_SIMDAT 108 +#define BCM21664_PIN_SIMDET 109 +#define BCM21664_PIN_SIMRST 110 +#define BCM21664_PIN_GPIO93 111 +#define BCM21664_PIN_GPIO94 112 +#define BCM21664_PIN_SPI0CLK 113 +#define BCM21664_PIN_SPI0FSS 114 +#define BCM21664_PIN_SPI0RXD 115 +#define BCM21664_PIN_SPI0TXD 116 +#define BCM21664_PIN_SRI_C 117 +#define BCM21664_PIN_SRI_D 118 +#define BCM21664_PIN_SRI_E 119 +#define BCM21664_PIN_SSPCK 120 +#define BCM21664_PIN_SSPDI 121 +#define BCM21664_PIN_SSPDO 122 +#define BCM21664_PIN_SSPSYN 123 +#define BCM21664_PIN_STAT1 124 +#define BCM21664_PIN_STAT2 125 +#define BCM21664_PIN_SWCLKTCK 126 +#define BCM21664_PIN_SWDIOTMS 127 +#define BCM21664_PIN_SYSCLKEN 128 +#define BCM21664_PIN_TDI 129 +#define BCM21664_PIN_TDO 130 +#define BCM21664_PIN_TESTMODE 131 +#define BCM21664_PIN_TRACECLK 132 +#define BCM21664_PIN_TRACEDT00 133 +#define BCM21664_PIN_TRACEDT01 134 +#define BCM21664_PIN_TRACEDT02 135 +#define BCM21664_PIN_TRACEDT03 136 +#define BCM21664_PIN_TRACEDT04 137 +#define BCM21664_PIN_TRACEDT05 138 +#define BCM21664_PIN_TRACEDT06 139 +#define BCM21664_PIN_TRACEDT07 140 +#define BCM21664_PIN_TRSTB 141 +#define BCM21664_PIN_TXDATA3G0 142 +#define BCM21664_PIN_UBCTSN 143 +#define BCM21664_PIN_UBRTSN 144 +#define BCM21664_PIN_UBRX 145 +#define BCM21664_PIN_UBTX 146 +#define BCM21664_PIN_TRACEDT08 147 +#define BCM21664_PIN_TRACEDT09 148 +#define BCM21664_PIN_TRACEDT10 149 +#define BCM21664_PIN_TRACEDT11 150 +#define BCM21664_PIN_TRACEDT12 151 +#define BCM21664_PIN_TRACEDT13 152 +#define BCM21664_PIN_TRACEDT14 153 +#define BCM21664_PIN_TRACEDT15 154 + +static const struct pinctrl_pin_desc bcm21664_pinctrl_pins[] = { + BCM281XX_PIN_DESC(BCM21664_PIN_ADCSYN, "adcsyn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_BATRM, "batrm", std), + BCM281XX_PIN_DESC(BCM21664_PIN_BSC1CLK, "bsc1clk", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_BSC1DAT, "bsc1dat", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_CAMCS0, "camcs0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_CAMCS1, "camcs1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_CLK32K, "clk32k", std), + BCM281XX_PIN_DESC(BCM21664_PIN_CLK_CX8, "clk_cx8", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLK1, "dclk1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLK4, "dclk4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLKREQ1, "dclkreq1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLKREQ4, "dclkreq4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DMIC0CLK, "dmic0clk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DMIC0DQ, "dmic0dq", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DSI0TE, "dsi0te", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO00, "gpio00", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO01, "gpio01", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO02, "gpio02", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO03, "gpio03", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO04, "gpio04", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO05, "gpio05", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO06, "gpio06", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO07, "gpio07", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO08, "gpio08", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO09, "gpio09", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO10, "gpio10", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO11, "gpio11", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO12, "gpio12", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO13, "gpio13", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO14, "gpio14", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO15, "gpio15", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO16, "gpio16", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO17, "gpio17", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO18, "gpio18", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO19, "gpio19", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO20, "gpio20", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO21, "gpio21", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO22, "gpio22", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO23, "gpio23", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO24, "gpio24", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO25, "gpio25", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO26, "gpio26", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO27, "gpio27", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO28, "gpio28", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO32, "gpio32", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO33, "gpio33", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO34, "gpio34", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_CALREQ, "gps_calreq", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_HOSTREQ, "gps_hostreq", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_PABLANK, "gps_pablank", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_TMARK, "gps_tmark", std), + BCM281XX_PIN_DESC(BCM21664_PIN_ICUSBDM, "icusbdm", std), + BCM281XX_PIN_DESC(BCM21664_PIN_ICUSBDP, "icusbdp", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDCS0, "lcdcs0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDRES, "lcdres", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDSCL, "lcdscl", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDSDA, "lcdsda", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDTE, "lcdte", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO00, "mdmgpio00", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO01, "mdmgpio01", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO02, "mdmgpio02", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO03, "mdmgpio03", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO04, "mdmgpio04", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO05, "mdmgpio05", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO06, "mdmgpio06", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO07, "mdmgpio07", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO08, "mdmgpio08", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0CK, "mmc0ck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0CMD, "mmc0cmd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT0, "mmc0dat0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT1, "mmc0dat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT2, "mmc0dat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT3, "mmc0dat3", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT4, "mmc0dat4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT5, "mmc0dat5", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT6, "mmc0dat6", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT7, "mmc0dat7", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0RST, "mmc0rst", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1CK, "mmc1ck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1CMD, "mmc1cmd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT0, "mmc1dat0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT1, "mmc1dat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT2, "mmc1dat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT3, "mmc1dat3", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT4, "mmc1dat4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT5, "mmc1dat5", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT6, "mmc1dat6", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT7, "mmc1dat7", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1RST, "mmc1rst", std), + BCM281XX_PIN_DESC(BCM21664_PIN_PC1, "pc1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_PC2, "pc2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_PMBSCCLK, "pmbscclk", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_PMBSCDAT, "pmbscdat", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_PMUINT, "pmuint", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RESETN, "resetn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RFST2G_MTSLOTEN3G, "rfst2g_mtsloten3g", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RTXDATA2G_TXDATA3G1, "rtxdata2g_txdata3g1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RTXEN2G_TXDATA3G2, "rtxen2g_txdata3g2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RXDATA3G0, "rxdata3g0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RXDATA3G1, "rxdata3g1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RXDATA3G2, "rxdata3g2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDCK, "sdck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDCMD, "sdcmd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT0, "sddat0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT1, "sddat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT2, "sddat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT3, "sddat3", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMCLK, "simclk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMDAT, "simdat", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMDET, "simdet", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMRST, "simrst", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO93, "gpio93", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO94, "gpio94", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0CLK, "spi0clk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0FSS, "spi0fss", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0RXD, "spi0rxd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0TXD, "spi0txd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SRI_C, "sri_c", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SRI_D, "sri_d", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SRI_E, "sri_e", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPCK, "sspck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPDI, "sspdi", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPDO, "sspdo", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPSYN, "sspsyn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_STAT1, "stat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_STAT2, "stat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SWCLKTCK, "swclktck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SWDIOTMS, "swdiotms", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SYSCLKEN, "sysclken", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TDI, "tdi", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TDO, "tdo", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TESTMODE, "testmode", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACECLK, "traceclk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT00, "tracedt00", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT01, "tracedt01", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT02, "tracedt02", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT03, "tracedt03", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT04, "tracedt04", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT05, "tracedt05", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT06, "tracedt06", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT07, "tracedt07", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRSTB, "trstb", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TXDATA3G0, "txdata3g0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBCTSN, "ubctsn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBRTSN, "ubrtsn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBRX, "ubrx", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBTX, "ubtx", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT08, "tracedt08", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT09, "tracedt09", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT10, "tracedt10", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT11, "tracedt11", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT12, "tracedt12", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT13, "tracedt13", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT14, "tracedt14", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT15, "tracedt15", std), +}; + +static const char * const bcm21664_alt_groups[] = { + "adcsyn", + "batrm", + "bsc1clk", + "bsc1dat", + "camcs0", + "camcs1", + "clk32k", + "clk_cx8", + "dclk1", + "dclk4", + "dclkreq1", + "dclkreq4", + "dmic0clk", + "dmic0dq", + "dsi0te", + "gpio00", + "gpio01", + "gpio02", + "gpio03", + "gpio04", + "gpio05", + "gpio06", + "gpio07", + "gpio08", + "gpio09", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gpio15", + "gpio16", + "gpio17", + "gpio18", + "gpio19", + "gpio20", + "gpio21", + "gpio22", + "gpio23", + "gpio24", + "gpio25", + "gpio26", + "gpio27", + "gpio28", + "gpio32", + "gpio33", + "gpio34", + "gps_calreq", + "gps_hostreq", + "gps_pablank", + "gps_tmark", + "icusbdm", + "icusbdp", + "lcdcs0", + "lcdres", + "lcdscl", + "lcdsda", + "lcdte", + "mdmgpio00", + "mdmgpio01", + "mdmgpio02", + "mdmgpio03", + "mdmgpio04", + "mdmgpio05", + "mdmgpio06", + "mdmgpio07", + "mdmgpio08", + "mmc0ck", + "mmc0cmd", + "mmc0dat0", + "mmc0dat1", + "mmc0dat2", + "mmc0dat3", + "mmc0dat4", + "mmc0dat5", + "mmc0dat6", + "mmc0dat7", + "mmc0rst", + "mmc1ck", + "mmc1cmd", + "mmc1dat0", + "mmc1dat1", + "mmc1dat2", + "mmc1dat3", + "mmc1dat4", + "mmc1dat5", + "mmc1dat6", + "mmc1dat7", + "mmc1rst", + "pc1", + "pc2", + "pmbscclk", + "pmbscdat", + "pmuint", + "resetn", + "rfst2g_mtsloten3g", + "rtxdata2g_txdata3g1", + "rtxen2g_txdata3g2", + "rxdata3g0", + "rxdata3g1", + "rxdata3g2", + "sdck", + "sdcmd", + "sddat0", + "sddat1", + "sddat2", + "sddat3", + "simclk", + "simdat", + "simdet", + "simrst", + "gpio93", + "gpio94", + "spi0clk", + "spi0fss", + "spi0rxd", + "spi0txd", + "sri_c", + "sri_d", + "sri_e", + "sspck", + "sspdi", + "sspdo", + "sspsyn", + "stat1", + "stat2", + "swclktck", + "swdiotms", + "sysclken", + "tdi", + "tdo", + "testmode", + "traceclk", + "tracedt00", + "tracedt01", + "tracedt02", + "tracedt03", + "tracedt04", + "tracedt05", + "tracedt06", + "tracedt07", + "trstb", + "txdata3g0", + "ubctsn", + "ubrtsn", + "ubrx", + "ubtx", + "tracedt08", + "tracedt09", + "tracedt10", + "tracedt11", + "tracedt12", + "tracedt13", + "tracedt14", + "tracedt15", +}; + +#define BCM21664_PIN_FUNCTION(fcn_name) \ +{ \ + .name = #fcn_name, \ + .groups = bcm21664_alt_groups, \ + .ngroups = ARRAY_SIZE(bcm21664_alt_groups), \ +} + +static const struct bcm281xx_pin_function bcm21664_functions[] = { + BCM21664_PIN_FUNCTION(alt1), + BCM21664_PIN_FUNCTION(alt2), + BCM21664_PIN_FUNCTION(alt3), + BCM21664_PIN_FUNCTION(alt4), + BCM21664_PIN_FUNCTION(alt5), + BCM21664_PIN_FUNCTION(alt6), +}; + +static const struct regmap_config bcm21664_pinctrl_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM21664_WR_ACCESS_OFFSET, }; +static const struct bcm281xx_pinctrl_info bcm21664_pinctrl = { + .device_type = BCM21664_PINCTRL_TYPE, + + .pins = bcm21664_pinctrl_pins, + .npins = ARRAY_SIZE(bcm21664_pinctrl_pins), + .functions = bcm21664_functions, + .nfunctions = ARRAY_SIZE(bcm21664_functions), + + .regmap_config = &bcm21664_pinctrl_regmap_config, +}; + +/* BCM21664 pinctrl access lock handlers */ +static int bcm21664_pinctrl_lock_all(struct bcm281xx_pinctrl_data *pdata) +{ + int i, rc; + + for (i = 0; i < BCM21664_ACCESS_LOCK_COUNT; i++) { + rc = regmap_write(pdata->regmap, BCM21664_WR_ACCESS_OFFSET, + BCM21664_WR_ACCESS_PASSWORD); + if (rc) { + dev_err(pdata->dev, "Failed to enable write access: %d\n", + rc); + return rc; + } + rc = regmap_write(pdata->regmap, BCM21664_ACCESS_LOCK_OFFSET(i), + 0xffffffff); + if (rc) { + dev_err(pdata->dev, "Failed to write access lock: %d\n", + rc); + return rc; + } + } + + return 0; +} + +static int bcm21664_pinctrl_set_pin_lock(struct bcm281xx_pinctrl_data *pdata, + unsigned int pin, bool lock) +{ + unsigned int access_lock = pin / 32; + int rc; + + dev_dbg(pdata->dev, + "%s(): %s pin %s (%d)\n", + __func__, lock ? "Lock" : "Unlock", pdata->info->pins[pin].name, + pin); + + rc = regmap_write(pdata->regmap, BCM21664_WR_ACCESS_OFFSET, + BCM21664_WR_ACCESS_PASSWORD); + if (rc) { + dev_err(pdata->dev, "Failed to enable write access: %d\n", + rc); + return rc; + } + + rc = regmap_update_bits(pdata->regmap, + BCM21664_ACCESS_LOCK_OFFSET(access_lock), + BIT(pin % 32), + (int)lock << (pin % 32)); + + if (rc) { + dev_err(pdata->dev, "Failed to %s pin: %d\n", + lock ? "lock" : "unlock", rc); + return rc; + } + + return 0; +} + static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, - unsigned pin) + unsigned int pin) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - if (pin >= pdata->npins) + if (pin >= pdata->info->npins) return BCM281XX_PIN_TYPE_UNKNOWN; - return *(enum bcm281xx_pin_type *)(pdata->pins[pin].drv_data); + return *(enum bcm281xx_pin_type *)(pdata->info->pins[pin].drv_data); } #define BCM281XX_PIN_SHIFT(type, param) \ @@ -970,36 +1573,29 @@ static inline void bcm281xx_pin_update(u32 *reg_val, u32 *reg_mask, *reg_mask |= param_mask; } -static const struct regmap_config bcm281xx_pinctrl_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = BCM281XX_PIN_VC_CAM3_SDA * 4, -}; - static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->npins; + return pdata->info->npins; } static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, - unsigned group) + unsigned int group) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->pins[group].name; + return pdata->info->pins[group].name; } static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, - unsigned group, + unsigned int group, const unsigned **pins, - unsigned *num_pins) + unsigned int *num_pins) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - *pins = &pdata->pins[group].number; + *pins = &pdata->info->pins[group].number; *num_pins = 1; return 0; @@ -1007,7 +1603,7 @@ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) + unsigned int offset) { seq_printf(s, " %s", dev_name(pctldev->dev)); } @@ -1025,43 +1621,53 @@ static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->nfunctions; + return pdata->info->nfunctions; } static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, - unsigned function) + unsigned int function) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->functions[function].name; + return pdata->info->functions[function].name; } static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, - unsigned function, + unsigned int function, const char * const **groups, - unsigned * const num_groups) + unsigned int * const num_groups) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - *groups = pdata->functions[function].groups; - *num_groups = pdata->functions[function].ngroups; + *groups = pdata->info->functions[function].groups; + *num_groups = pdata->info->functions[function].ngroups; return 0; } static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) + unsigned int function, + unsigned int group) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - const struct bcm281xx_pin_function *f = &pdata->functions[function]; - u32 offset = 4 * pdata->pins[group].number; + const struct bcm281xx_pin_function *f = &pdata->info->functions[function]; + enum bcm281xx_pinctrl_type device_type = pdata->info->device_type; + unsigned int pin = pdata->info->pins[group].number; + u32 offset = 4 * pin; int rc = 0; dev_dbg(pctldev->dev, "%s(): Enable function %s (%d) of pin %s (%d) @offset 0x%x.\n", - __func__, f->name, function, pdata->pins[group].name, - pdata->pins[group].number, offset); + __func__, f->name, function, pdata->info->pins[group].name, + pin, offset); + + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, false); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } rc = regmap_update_bits(pdata->regmap, offset, BCM281XX_PIN_REG_F_SEL_MASK, @@ -1069,7 +1675,15 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, if (rc) dev_err(pctldev->dev, "Error updating register for pin %s (%d).\n", - pdata->pins[group].name, pdata->pins[group].number); + pdata->info->pins[group].name, pin); + + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, true); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } return rc; } @@ -1082,7 +1696,7 @@ static const struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = { }; static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *config) { return -ENOTSUPP; @@ -1091,9 +1705,9 @@ static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, /* Goes through the configs and update register val/mask */ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs, + unsigned int num_configs, u32 *val, u32 *mask) { @@ -1168,7 +1782,7 @@ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, "Invalid Drive Strength value (%d) for " "pin %s (%d). Valid values are " "(2..16) mA, even numbers only.\n", - arg, pdata->pins[pin].name, pin); + arg, pdata->info->pins[pin].name, pin); return -EINVAL; } bcm281xx_pin_update(val, mask, (arg/2)-1, @@ -1179,7 +1793,7 @@ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); + param, pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch config */ @@ -1207,9 +1821,9 @@ static const u16 bcm281xx_pullup_map[] = { /* Goes through the configs and update register val/mask */ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs, + unsigned int num_configs, u32 *val, u32 *mask) { @@ -1233,7 +1847,7 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, "Invalid pull-up value (%d) for pin %s " "(%d). Valid values are 568, 720, 831, " "1080, 1200, 1800, 2700 Ohms.\n", - arg, pdata->pins[pin].name, pin); + arg, pdata->info->pins[pin].name, pin); return -EINVAL; } @@ -1266,7 +1880,69 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); + param, pdata->info->pins[pin].name, pin); + return -EINVAL; + + } /* switch config */ + } /* for each config */ + + return 0; +} + +/* Goes through the configs and update register val/mask */ +static int bcm21664_i2c_pin_update(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *configs, + unsigned int num_configs, + u32 *val, + u32 *mask) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + int i; + enum pin_config_param param; + u32 arg; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + /* + * BCM21664 I2C pins use the same config bits as standard pins, + * but only pull up/none, slew rate and input enable/disable + * options are supported. + */ + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + bcm281xx_pin_update(val, mask, 1, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + break; + + case PIN_CONFIG_BIAS_DISABLE: + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + break; + + case PIN_CONFIG_SLEW_RATE: + arg = (arg >= 1 ? 1 : 0); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, SLEW), + BCM281XX_PIN_MASK(STD, SLEW)); + break; + + case PIN_CONFIG_INPUT_ENABLE: + /* inversed since register is for input _disable_ */ + arg = (arg >= 1 ? 0 : 1); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, INPUT_DIS), + BCM281XX_PIN_MASK(STD, INPUT_DIS)); + break; + + default: + dev_err(pctldev->dev, + "Unrecognized pin config %d for pin %s (%d).\n", + param, pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch config */ @@ -1277,9 +1953,9 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, /* Goes through the configs and update register val/mask */ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs, + unsigned int num_configs, u32 *val, u32 *mask) { @@ -1311,7 +1987,7 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); + param, pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch config */ @@ -1321,11 +1997,12 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, } static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs) + unsigned int num_configs) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + enum bcm281xx_pinctrl_type device_type = pdata->info->device_type; enum bcm281xx_pin_type pin_type; u32 offset = 4 * pin; u32 cfg_val, cfg_mask; @@ -1343,8 +2020,12 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, break; case BCM281XX_PIN_TYPE_I2C: - rc = bcm281xx_i2c_pin_update(pctldev, pin, configs, - num_configs, &cfg_val, &cfg_mask); + if (device_type == BCM21664_PINCTRL_TYPE) + rc = bcm21664_i2c_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); + else + rc = bcm281xx_i2c_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); break; case BCM281XX_PIN_TYPE_HDMI: @@ -1354,7 +2035,7 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unknown pin type for pin %s (%d).\n", - pdata->pins[pin].name, pin); + pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch pin type */ @@ -1364,16 +2045,32 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, dev_dbg(pctldev->dev, "%s(): Set pin %s (%d) with config 0x%x, mask 0x%x\n", - __func__, pdata->pins[pin].name, pin, cfg_val, cfg_mask); + __func__, pdata->info->pins[pin].name, pin, cfg_val, cfg_mask); + + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, false); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } rc = regmap_update_bits(pdata->regmap, offset, cfg_mask, cfg_val); if (rc) { dev_err(pctldev->dev, "Error updating register for pin %s (%d).\n", - pdata->pins[pin].name, pin); + pdata->info->pins[pin].name, pin); return rc; } + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, true); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } + return 0; } @@ -1390,10 +2087,23 @@ static struct pinctrl_desc bcm281xx_pinctrl_desc = { .owner = THIS_MODULE, }; +static struct bcm281xx_pinctrl_data bcm281xx_pinctrl_pdata; + static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) { - struct bcm281xx_pinctrl_data *pdata = &bcm281xx_pinctrl; + struct bcm281xx_pinctrl_data *pdata = &bcm281xx_pinctrl_pdata; struct pinctrl_dev *pctl; + int rc; + + /* Set device pointer in platform data */ + pdata->dev = &pdev->dev; + + /* Get the data to use from OF match */ + pdata->info = of_device_get_match_data(&pdev->dev); + if (!pdata->info) { + dev_err(&pdev->dev, "Failed to get data from OF match\n"); + return -ENODEV; + } /* So far We can assume there is only 1 bank of registers */ pdata->reg_base = devm_platform_ioremap_resource(pdev, 0); @@ -1404,15 +2114,27 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) /* Initialize the dynamic part of pinctrl_desc */ pdata->regmap = devm_regmap_init_mmio(&pdev->dev, pdata->reg_base, - &bcm281xx_pinctrl_regmap_config); + pdata->info->regmap_config); if (IS_ERR(pdata->regmap)) { dev_err(&pdev->dev, "Regmap MMIO init failed.\n"); return -ENODEV; } bcm281xx_pinctrl_desc.name = dev_name(&pdev->dev); - bcm281xx_pinctrl_desc.pins = bcm281xx_pinctrl.pins; - bcm281xx_pinctrl_desc.npins = bcm281xx_pinctrl.npins; + bcm281xx_pinctrl_desc.pins = pdata->info->pins; + bcm281xx_pinctrl_desc.npins = pdata->info->npins; + + /* + * For BCM21664, lock all pins by default; they will be unlocked + * as needed + */ + if (pdata->info->device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_lock_all(pdata); + if (rc) { + dev_err(&pdev->dev, "Failed to lock all pins\n"); + return rc; + } + } pctl = devm_pinctrl_register(&pdev->dev, &bcm281xx_pinctrl_desc, pdata); if (IS_ERR(pctl)) { @@ -1426,7 +2148,8 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) } static const struct of_device_id bcm281xx_pinctrl_of_match[] = { - { .compatible = "brcm,bcm11351-pinctrl", }, + { .compatible = "brcm,bcm11351-pinctrl", .data = &bcm281xx_pinctrl }, + { .compatible = "brcm,bcm21664-pinctrl", .data = &bcm21664_pinctrl }, { }, }; diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index cc1fe0555e19..eaeec096bc9a 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -346,14 +346,14 @@ static int bcm2835_gpio_get_direction(struct gpio_chip *chip, unsigned int offse struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); - /* Alternative function doesn't clearly provide a direction */ - if (fsel > BCM2835_FSEL_GPIO_OUT) - return -EINVAL; - - if (fsel == BCM2835_FSEL_GPIO_IN) - return GPIO_LINE_DIRECTION_IN; + if (fsel == BCM2835_FSEL_GPIO_OUT) + return GPIO_LINE_DIRECTION_OUT; - return GPIO_LINE_DIRECTION_OUT; + /* + * Alternative function doesn't clearly provide a direction. Default + * to INPUT. + */ + return GPIO_LINE_DIRECTION_IN; } static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 6a94ecd6a8de..0b7f74beb6a6 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -143,10 +143,14 @@ static int dt_to_map_one_config(struct pinctrl *p, pctldev = get_pinctrl_dev_from_of_node(np_pctldev); if (pctldev) break; - /* Do not defer probing of hogs (circular loop) */ + /* + * Do not defer probing of hogs (circular loop) + * + * Return 1 to let the caller catch the case. + */ if (np_pctldev == p->dev->of_node) { of_node_put(np_pctldev); - return -ENODEV; + return 1; } } of_node_put(np_pctldev); @@ -265,6 +269,8 @@ int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) ret = dt_to_map_one_config(p, pctldev, statename, np_config); of_node_put(np_config); + if (ret == 1) + continue; if (ret < 0) goto err; } diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig index 14c26c023590..248c2e558ff3 100644 --- a/drivers/pinctrl/intel/Kconfig +++ b/drivers/pinctrl/intel/Kconfig @@ -39,7 +39,6 @@ config PINCTRL_INTEL config PINCTRL_INTEL_PLATFORM tristate "Intel pinctrl and GPIO platform driver" - depends on ACPI select PINCTRL_INTEL help This pinctrl driver provides an interface that allows configuring @@ -141,7 +140,6 @@ config PINCTRL_METEORLAKE config PINCTRL_METEORPOINT tristate "Intel Meteor Point pinctrl and GPIO driver" - depends on ACPI select PINCTRL_INTEL help Meteor Point is the PCH of Intel Meteor Lake. This pinctrl driver diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 7340dc20349c..969137c4cb06 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1355,6 +1355,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) void __iomem *reg; unsigned long pending; + chained_irq_enter(chip, desc); + /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < vg->chip.ngpio; base += 32) { reg = byt_gpio_reg(vg, base, BYT_INT_STAT_REG); @@ -1369,7 +1371,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) for_each_set_bit(pin, &pending, 32) generic_handle_domain_irq(vg->chip.irq.domain, base + pin); } - chip->irq_eoi(data); + + chained_irq_exit(chip, desc); } static bool byt_direct_irq_sanity_check(struct intel_pinctrl *vg, int pin, u32 conf0) @@ -1557,16 +1560,14 @@ static int byt_set_soc_data(struct intel_pinctrl *vg, vg->soc = soc; vg->ncommunities = vg->soc->ncommunities; - vg->communities = devm_kcalloc(vg->dev, vg->ncommunities, - sizeof(*vg->communities), GFP_KERNEL); + vg->communities = devm_kmemdup_array(vg->dev, vg->soc->communities, vg->ncommunities, + sizeof(*vg->soc->communities), GFP_KERNEL); if (!vg->communities) return -ENOMEM; for (i = 0; i < vg->soc->ncommunities; i++) { struct intel_community *comm = vg->communities + i; - *comm = vg->soc->communities[i]; - comm->pad_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(comm->pad_regs)) return PTR_ERR(comm->pad_regs); diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index c673e262e1db..69b18ce0f685 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1631,9 +1631,8 @@ static int chv_pinctrl_probe(struct platform_device *pdev) pctrl->soc = soc_data; pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kmemdup(dev, pctrl->soc->communities, - pctrl->ncommunities * sizeof(*pctrl->communities), - GFP_KERNEL); + pctrl->communities = devm_kmemdup_array(dev, pctrl->soc->communities, pctrl->ncommunities, + sizeof(*pctrl->soc->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 527e4b87ae52..d889c7c878e2 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1543,7 +1543,6 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl, .clk_rate = 19200000, .npwm = 1, .base_unit_bits = 22, - .bypass = true, }; struct pwm_chip *chip; @@ -1577,8 +1576,8 @@ int intel_pinctrl_probe(struct platform_device *pdev, * to the registers. */ pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kcalloc(dev, pctrl->ncommunities, - sizeof(*pctrl->communities), GFP_KERNEL); + pctrl->communities = devm_kmemdup_array(dev, pctrl->soc->communities, pctrl->ncommunities, + sizeof(*pctrl->soc->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; @@ -1588,8 +1587,6 @@ int intel_pinctrl_probe(struct platform_device *pdev, u32 offset; u32 value; - *community = pctrl->soc->communities[i]; - regs = devm_platform_ioremap_resource(pdev, community->barno); if (IS_ERR(regs)) return PTR_ERR(regs); @@ -1941,3 +1938,4 @@ MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("PWM_LPSS"); diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c index cc5ede17c383..ac5459a4c63e 100644 --- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c +++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c @@ -549,6 +549,8 @@ static void lp_gpio_irq_handler(struct irq_desc *desc) unsigned long pending; u32 base, pin; + chained_irq_enter(chip, desc); + /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); @@ -560,7 +562,8 @@ static void lp_gpio_irq_handler(struct irq_desc *desc) for_each_set_bit(pin, &pending, 32) generic_handle_domain_irq(lg->chip.irq.domain, base + pin); } - chip->irq_eoi(data); + + chained_irq_exit(chip, desc); } static void lp_irq_ack(struct irq_data *d) diff --git a/drivers/pinctrl/intel/pinctrl-tangier.c b/drivers/pinctrl/intel/pinctrl-tangier.c index d3baf0f4eea0..ac61e632b487 100644 --- a/drivers/pinctrl/intel/pinctrl-tangier.c +++ b/drivers/pinctrl/intel/pinctrl-tangier.c @@ -524,7 +524,6 @@ static int tng_pinctrl_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct tng_family *families; struct tng_pinctrl *tp; - size_t families_len; void __iomem *regs; unsigned int i; @@ -543,8 +542,8 @@ static int tng_pinctrl_probe(struct platform_device *pdev, * Make a copy of the families which we can use to hold pointers * to the registers. */ - families_len = size_mul(sizeof(*families), tp->nfamilies); - families = devm_kmemdup(dev, tp->families, families_len, GFP_KERNEL); + families = devm_kmemdup_array(dev, tp->families, tp->nfamilies, + sizeof(*tp->families), GFP_KERNEL); if (!families) return -ENOMEM; diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c index 27f0a54e12bf..ced4ee509b5b 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.c +++ b/drivers/pinctrl/mediatek/mtk-eint.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2014-2018 MediaTek Inc. +// Copyright (c) 2014-2025 MediaTek Inc. /* * Library for MediaTek External Interrupt Support * * Author: Maoguang Meng <maoguang.meng@mediatek.com> * Sean Wang <sean.wang@mediatek.com> + * Hao Chang <ot_chhao.chang@mediatek.com> + * Qingliang Li <qingliang.li@mediatek.com> * */ @@ -20,6 +22,7 @@ #include <linux/platform_device.h> #include "mtk-eint.h" +#include "pinctrl-mtk-common-v2.h" #define MTK_EINT_EDGE_SENSITIVE 0 #define MTK_EINT_LEVEL_SENSITIVE 1 @@ -68,13 +71,11 @@ static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint, unsigned int eint_num, unsigned int offset) { - unsigned int eint_base = 0; + unsigned int idx = eint->pins[eint_num].index; + unsigned int inst = eint->pins[eint_num].instance; void __iomem *reg; - if (eint_num >= eint->hw->ap_num) - eint_base = eint->hw->ap_num; - - reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4; + reg = eint->base[inst] + offset + (idx / 32 * 4); return reg; } @@ -83,7 +84,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint, unsigned int eint_num) { unsigned int sens; - unsigned int bit = BIT(eint_num % 32); + unsigned int bit = BIT(eint->pins[eint_num].index % 32); void __iomem *reg = mtk_eint_get_offset(eint, eint_num, eint->regs->sens); @@ -92,7 +93,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint, else sens = MTK_EINT_EDGE_SENSITIVE; - if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE) + if (eint->pins[eint_num].debounce && sens != MTK_EINT_EDGE_SENSITIVE) return 1; else return 0; @@ -102,9 +103,9 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq) { int start_level, curr_level; unsigned int reg_offset; - u32 mask = BIT(hwirq & 0x1f); - u32 port = (hwirq >> 5) & eint->hw->port_mask; - void __iomem *reg = eint->base + (port << 2); + unsigned int mask = BIT(eint->pins[hwirq].index & 0x1f); + unsigned int port = (eint->pins[hwirq].index >> 5) & eint->hw->port_mask; + void __iomem *reg = eint->base[eint->pins[hwirq].instance] + (port << 2); curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq); @@ -126,11 +127,13 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq) static void mtk_eint_mask(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int idx = eint->pins[d->hwirq].index; + unsigned int inst = eint->pins[d->hwirq].instance; + unsigned int mask = BIT(idx & 0x1f); void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->mask_set); - eint->cur_mask[d->hwirq >> 5] &= ~mask; + eint->cur_mask[inst][idx >> 5] &= ~mask; writel(mask, reg); } @@ -138,22 +141,24 @@ static void mtk_eint_mask(struct irq_data *d) static void mtk_eint_unmask(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int idx = eint->pins[d->hwirq].index; + unsigned int inst = eint->pins[d->hwirq].instance; + unsigned int mask = BIT(idx & 0x1f); void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->mask_clr); - eint->cur_mask[d->hwirq >> 5] |= mask; + eint->cur_mask[inst][idx >> 5] |= mask; writel(mask, reg); - if (eint->dual_edge[d->hwirq]) + if (eint->pins[d->hwirq].dual_edge) mtk_eint_flip_edge(eint, d->hwirq); } static unsigned int mtk_eint_get_mask(struct mtk_eint *eint, unsigned int eint_num) { - unsigned int bit = BIT(eint_num % 32); + unsigned int bit = BIT(eint->pins[eint_num].index % 32); void __iomem *reg = mtk_eint_get_offset(eint, eint_num, eint->regs->mask); @@ -163,7 +168,7 @@ static unsigned int mtk_eint_get_mask(struct mtk_eint *eint, static void mtk_eint_ack(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int mask = BIT(eint->pins[d->hwirq].index & 0x1f); void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->ack); @@ -174,7 +179,7 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); bool masked; - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int mask = BIT(eint->pins[d->hwirq].index & 0x1f); void __iomem *reg; if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) || @@ -186,9 +191,9 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) } if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - eint->dual_edge[d->hwirq] = 1; + eint->pins[d->hwirq].dual_edge = 1; else - eint->dual_edge[d->hwirq] = 0; + eint->pins[d->hwirq].dual_edge = 0; if (!mtk_eint_get_mask(eint, d->hwirq)) { mtk_eint_mask(d); @@ -223,27 +228,32 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - int shift = d->hwirq & 0x1f; - int reg = d->hwirq >> 5; + unsigned int idx = eint->pins[d->hwirq].index; + unsigned int inst = eint->pins[d->hwirq].instance; + unsigned int shift = idx & 0x1f; + unsigned int port = idx >> 5; if (on) - eint->wake_mask[reg] |= BIT(shift); + eint->wake_mask[inst][port] |= BIT(shift); else - eint->wake_mask[reg] &= ~BIT(shift); + eint->wake_mask[inst][port] &= ~BIT(shift); return 0; } static void mtk_eint_chip_write_mask(const struct mtk_eint *eint, - void __iomem *base, u32 *buf) + void __iomem *base, unsigned int **buf) { - int port; + int inst, port, port_num; void __iomem *reg; - for (port = 0; port < eint->hw->ports; port++) { - reg = base + (port << 2); - writel_relaxed(~buf[port], reg + eint->regs->mask_set); - writel_relaxed(buf[port], reg + eint->regs->mask_clr); + for (inst = 0; inst < eint->nbase; inst++) { + port_num = DIV_ROUND_UP(eint->base_pin_num[inst], 32); + for (port = 0; port < port_num; port++) { + reg = eint->base[inst] + (port << 2); + writel_relaxed(~buf[inst][port], reg + eint->regs->mask_set); + writel_relaxed(buf[inst][port], reg + eint->regs->mask_clr); + } } } @@ -303,15 +313,18 @@ static struct irq_chip mtk_eint_irq_chip = { static unsigned int mtk_eint_hw_init(struct mtk_eint *eint) { - void __iomem *dom_en = eint->base + eint->regs->dom_en; - void __iomem *mask_set = eint->base + eint->regs->mask_set; - unsigned int i; - - for (i = 0; i < eint->hw->ap_num; i += 32) { - writel(0xffffffff, dom_en); - writel(0xffffffff, mask_set); - dom_en += 4; - mask_set += 4; + void __iomem *dom_reg, *mask_reg; + unsigned int i, j; + + for (i = 0; i < eint->nbase; i++) { + dom_reg = eint->base[i] + eint->regs->dom_en; + mask_reg = eint->base[i] + eint->regs->mask_set; + for (j = 0; j < eint->base_pin_num[i]; j += 32) { + writel(0xffffffff, dom_reg); + writel(0xffffffff, mask_reg); + dom_reg += 4; + mask_reg += 4; + } } return 0; @@ -322,14 +335,16 @@ mtk_eint_debounce_process(struct mtk_eint *eint, int index) { unsigned int rst, ctrl_offset; unsigned int bit, dbnc; + unsigned int inst = eint->pins[index].instance; + unsigned int idx = eint->pins[index].index; - ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl; - dbnc = readl(eint->base + ctrl_offset); - bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8); + ctrl_offset = (idx / 4) * 4 + eint->regs->dbnc_ctrl; + dbnc = readl(eint->base[inst] + ctrl_offset); + bit = MTK_EINT_DBNC_SET_EN << ((idx % 4) * 8); if ((bit & dbnc) > 0) { - ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set; - rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8); - writel(rst, eint->base + ctrl_offset); + ctrl_offset = (idx / 4) * 4 + eint->regs->dbnc_set; + rst = MTK_EINT_DBNC_RST_BIT << ((idx % 4) * 8); + writel(rst, eint->base[inst] + ctrl_offset); } } @@ -337,65 +352,68 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct mtk_eint *eint = irq_desc_get_handler_data(desc); - unsigned int status, eint_num; - int offset, mask_offset, index; - void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat); + unsigned int i, j, port, status, shift, mask, eint_num; + void __iomem *reg; int dual_edge, start_level, curr_level; chained_irq_enter(chip, desc); - for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32, - reg += 4) { - status = readl(reg); - while (status) { - offset = __ffs(status); - mask_offset = eint_num >> 5; - index = eint_num + offset; - status &= ~BIT(offset); - - /* - * If we get an interrupt on pin that was only required - * for wake (but no real interrupt requested), mask the - * interrupt (as would mtk_eint_resume do anyway later - * in the resume sequence). - */ - if (eint->wake_mask[mask_offset] & BIT(offset) && - !(eint->cur_mask[mask_offset] & BIT(offset))) { - writel_relaxed(BIT(offset), reg - - eint->regs->stat + - eint->regs->mask_set); - } - - dual_edge = eint->dual_edge[index]; - if (dual_edge) { - /* - * Clear soft-irq in case we raised it last - * time. - */ - writel(BIT(offset), reg - eint->regs->stat + - eint->regs->soft_clr); - - start_level = - eint->gpio_xlate->get_gpio_state(eint->pctl, - index); - } - - generic_handle_domain_irq(eint->domain, index); - - if (dual_edge) { - curr_level = mtk_eint_flip_edge(eint, index); + for (i = 0; i < eint->nbase; i++) { + for (j = 0; j < eint->base_pin_num[i]; j += 32) { + port = j >> 5; + status = readl(eint->base[i] + port * 4 + eint->regs->stat); + while (status) { + shift = __ffs(status); + status &= ~BIT(shift); + mask = BIT(shift); + eint_num = eint->pin_list[i][shift + j]; /* - * If level changed, we might lost one edge - * interrupt, raised it through soft-irq. + * If we get an interrupt on pin that was only required + * for wake (but no real interrupt requested), mask the + * interrupt (as would mtk_eint_resume do anyway later + * in the resume sequence). */ - if (start_level != curr_level) - writel(BIT(offset), reg - - eint->regs->stat + - eint->regs->soft_set); + if (eint->wake_mask[i][port] & mask && + !(eint->cur_mask[i][port] & mask)) { + reg = mtk_eint_get_offset(eint, eint_num, + eint->regs->mask_set); + writel_relaxed(mask, reg); + } + + dual_edge = eint->pins[eint_num].dual_edge; + if (dual_edge) { + /* + * Clear soft-irq in case we raised it last + * time. + */ + reg = mtk_eint_get_offset(eint, eint_num, + eint->regs->soft_clr); + writel(mask, reg); + + start_level = + eint->gpio_xlate->get_gpio_state(eint->pctl, + eint_num); + } + + generic_handle_domain_irq(eint->domain, eint_num); + + if (dual_edge) { + curr_level = mtk_eint_flip_edge(eint, eint_num); + + /* + * If level changed, we might lost one edge + * interrupt, raised it through soft-irq. + */ + if (start_level != curr_level) { + reg = mtk_eint_get_offset(eint, eint_num, + eint->regs->soft_set); + writel(mask, reg); + } + } + + if (eint->pins[eint_num].debounce) + mtk_eint_debounce_process(eint, eint_num); } - - if (index < eint->hw->db_cnt) - mtk_eint_debounce_process(eint, index); } } chained_irq_exit(chip, desc); @@ -423,6 +441,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, int virq, eint_offset; unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc; + unsigned int inst = eint->pins[eint_num].instance; + unsigned int idx = eint->pins[eint_num].index; struct irq_data *d; if (!eint->hw->db_time) @@ -432,8 +452,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, eint_offset = (eint_num % 4) * 8; d = irq_get_irq_data(virq); - set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set; - clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr; + set_offset = (idx / 4) * 4 + eint->regs->dbnc_set; + clr_offset = (idx / 4) * 4 + eint->regs->dbnc_clr; if (!mtk_eint_can_en_debounce(eint, eint_num)) return -EINVAL; @@ -454,12 +474,12 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, } clr_bit = 0xff << eint_offset; - writel(clr_bit, eint->base + clr_offset); + writel(clr_bit, eint->base[inst] + clr_offset); bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) << eint_offset; rst = MTK_EINT_DBNC_RST_BIT << eint_offset; - writel(rst | bit, eint->base + set_offset); + writel(rst | bit, eint->base[inst] + set_offset); /* * Delay a while (more than 2T) to wait for hw debounce counter reset @@ -487,32 +507,69 @@ EXPORT_SYMBOL_GPL(mtk_eint_find_irq); int mtk_eint_do_init(struct mtk_eint *eint) { - int i; + unsigned int size, i, port, inst = 0; + struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl; /* If clients don't assign a specific regs, let's use generic one */ if (!eint->regs) eint->regs = &mtk_generic_eint_regs; - eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports, - sizeof(*eint->wake_mask), GFP_KERNEL); - if (!eint->wake_mask) + eint->base_pin_num = devm_kmalloc_array(eint->dev, eint->nbase, sizeof(u16), + GFP_KERNEL | __GFP_ZERO); + if (!eint->base_pin_num) return -ENOMEM; - eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports, - sizeof(*eint->cur_mask), GFP_KERNEL); - if (!eint->cur_mask) - return -ENOMEM; + if (eint->nbase == 1) { + size = eint->hw->ap_num * sizeof(struct mtk_eint_pin); + eint->pins = devm_kmalloc(eint->dev, size, GFP_KERNEL); + if (!eint->pins) + goto err_pins; + + eint->base_pin_num[inst] = eint->hw->ap_num; + for (i = 0; i < eint->hw->ap_num; i++) { + eint->pins[i].instance = inst; + eint->pins[i].index = i; + eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0; + } + } - eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num, - sizeof(int), GFP_KERNEL); - if (!eint->dual_edge) - return -ENOMEM; + if (hw && hw->soc && hw->soc->eint_pin) { + eint->pins = hw->soc->eint_pin; + for (i = 0; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; + if (inst >= eint->nbase) + continue; + eint->base_pin_num[inst]++; + } + } + + eint->pin_list = devm_kmalloc(eint->dev, eint->nbase * sizeof(u16 *), GFP_KERNEL); + if (!eint->pin_list) + goto err_pin_list; + + eint->wake_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL); + if (!eint->wake_mask) + goto err_wake_mask; + + eint->cur_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL); + if (!eint->cur_mask) + goto err_cur_mask; + + for (i = 0; i < eint->nbase; i++) { + eint->pin_list[i] = devm_kzalloc(eint->dev, eint->base_pin_num[i] * sizeof(u16), + GFP_KERNEL); + port = DIV_ROUND_UP(eint->base_pin_num[i], 32); + eint->wake_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL); + eint->cur_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL); + if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i]) + goto err_eint; + } eint->domain = irq_domain_add_linear(eint->dev->of_node, eint->hw->ap_num, &irq_domain_simple_ops, NULL); if (!eint->domain) - return -ENOMEM; + goto err_eint; if (eint->hw->db_time) { for (i = 0; i < MTK_EINT_DBNC_MAX; i++) @@ -523,8 +580,11 @@ int mtk_eint_do_init(struct mtk_eint *eint) mtk_eint_hw_init(eint); for (i = 0; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; + if (inst >= eint->nbase) + continue; + eint->pin_list[inst][eint->pins[i].index] = i; int virq = irq_create_mapping(eint->domain, i); - irq_set_chip_and_handler(virq, &mtk_eint_irq_chip, handle_level_irq); irq_set_chip_data(virq, eint); @@ -534,6 +594,27 @@ int mtk_eint_do_init(struct mtk_eint *eint) eint); return 0; + +err_eint: + for (i = 0; i < eint->nbase; i++) { + if (eint->cur_mask[i]) + devm_kfree(eint->dev, eint->cur_mask[i]); + if (eint->wake_mask[i]) + devm_kfree(eint->dev, eint->wake_mask[i]); + if (eint->pin_list[i]) + devm_kfree(eint->dev, eint->pin_list[i]); + } + devm_kfree(eint->dev, eint->cur_mask); +err_cur_mask: + devm_kfree(eint->dev, eint->wake_mask); +err_wake_mask: + devm_kfree(eint->dev, eint->pin_list); +err_pin_list: + if (eint->nbase == 1) + devm_kfree(eint->dev, eint->pins); +err_pins: + devm_kfree(eint->dev, eint->base_pin_num); + return -ENOMEM; } EXPORT_SYMBOL_GPL(mtk_eint_do_init); diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h index 6139b16cd225..f7f58cca0d5e 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.h +++ b/drivers/pinctrl/mediatek/mtk-eint.h @@ -1,10 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2014-2018 MediaTek Inc. + * Copyright (C) 2014-2025 MediaTek Inc. * * Author: Maoguang Meng <maoguang.meng@mediatek.com> * Sean Wang <sean.wang@mediatek.com> - * + * Hao Chang <ot_chhao.chang@mediatek.com> + * Qingliang Li <qingliang.li@mediatek.com> */ #ifndef __MTK_EINT_H #define __MTK_EINT_H @@ -40,6 +41,14 @@ struct mtk_eint_hw { const unsigned int *db_time; }; +struct mtk_eint_pin { + u16 number; + u8 instance; + u8 index; + bool debounce; + bool dual_edge; +}; + extern const unsigned int debounce_time_mt2701[]; extern const unsigned int debounce_time_mt6765[]; extern const unsigned int debounce_time_mt6795[]; @@ -56,17 +65,21 @@ struct mtk_eint_xt { struct mtk_eint { struct device *dev; - void __iomem *base; + void __iomem **base; + u8 nbase; + u16 *base_pin_num; struct irq_domain *domain; int irq; int *dual_edge; - u32 *wake_mask; - u32 *cur_mask; + u16 **pin_list; + u32 **wake_mask; + u32 **cur_mask; /* Used to fit into various EINT device */ const struct mtk_eint_hw *hw; const struct mtk_eint_regs *regs; + struct mtk_eint_pin *pins; u16 num_db_time; /* Used to fit into various pinctrl device */ diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c index 00e95682b9f8..d1556b75d9ef 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of_address.h> #include <linux/of_irq.h> #include "mtk-eint.h" @@ -367,7 +368,7 @@ static const struct mtk_eint_xt mtk_eint_xt = { int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int ret; + int ret, i, j, count_reg_names; if (!IS_ENABLED(CONFIG_EINT_MTK)) return 0; @@ -379,10 +380,24 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) if (!hw->eint) return -ENOMEM; - hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint"); - if (IS_ERR(hw->eint->base)) { - ret = PTR_ERR(hw->eint->base); - goto err_free_eint; + count_reg_names = of_property_count_strings(np, "reg-names"); + if (count_reg_names < hw->soc->nbase_names) + return -EINVAL; + + hw->eint->nbase = count_reg_names - hw->soc->nbase_names; + hw->eint->base = devm_kmalloc_array(&pdev->dev, hw->eint->nbase, + sizeof(*hw->eint->base), GFP_KERNEL | __GFP_ZERO); + if (!hw->eint->base) { + ret = -ENOMEM; + goto err_free_base; + } + + for (i = hw->soc->nbase_names, j = 0; i < count_reg_names; i++, j++) { + hw->eint->base[j] = of_iomap(np, i); + if (IS_ERR(hw->eint->base[j])) { + ret = PTR_ERR(hw->eint->base[j]); + goto err_free_eint; + } } hw->eint->irq = irq_of_parse_and_map(np, 0); @@ -401,9 +416,19 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) hw->eint->pctl = hw; hw->eint->gpio_xlate = &mtk_eint_xt; - return mtk_eint_do_init(hw->eint); + ret = mtk_eint_do_init(hw->eint); + if (ret) + goto err_free_eint; + + return 0; err_free_eint: + for (j = 0; j < hw->eint->nbase; j++) { + if (hw->eint->base[j]) + iounmap(hw->eint->base[j]); + } + devm_kfree(hw->dev, hw->eint->base); +err_free_base: devm_kfree(hw->dev, hw->eint); hw->eint = NULL; return ret; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h index 9c271dc2b521..36d2898037dd 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h @@ -242,6 +242,7 @@ struct mtk_pin_soc { unsigned int nfuncs; const struct mtk_eint_regs *eint_regs; const struct mtk_eint_hw *eint_hw; + struct mtk_eint_pin *eint_pin; /* Specific parameters per SoC */ u8 gpio_m; diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h index 948ce126aa0c..d8c1822662fc 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.h +++ b/drivers/pinctrl/mediatek/pinctrl-paris.h @@ -49,6 +49,13 @@ __VA_ARGS__, { } }, \ } +#define MTK_EINT_PIN(_number, _instance, _index, _debounce) { \ + .number = _number, \ + .instance = _instance, \ + .index = _index, \ + .debounce = _debounce, \ + } + #define PINCTRL_PIN_GROUP(_name_, id) \ { \ .grp = PINCTRL_PINGROUP(_name_,id##_pins, ARRAY_SIZE(id##_pins)), \ diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index cc397896762c..90639bc171f6 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -67,6 +67,17 @@ config PINCTRL_MESON_S4 select PINCTRL_MESON_AXG_PMX default y +config PINCTRL_AMLOGIC_A4 + bool "AMLOGIC pincontrol" + depends on ARM64 + default y + help + This is the driver for the pin controller found on Amlogic SoCs. + + This driver is simplify subsequent support for new amlogic SoCs, + to support new Amlogic SoCs, only need to add the corresponding dts file, + no additional binding header files or C file are added. + config PINCTRL_AMLOGIC_C3 tristate "Amlogic C3 SoC pinctrl driver" depends on ARM64 diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index 9e538b9ffb9b..c92a65a83344 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o obj-$(CONFIG_PINCTRL_MESON_A1) += pinctrl-meson-a1.o obj-$(CONFIG_PINCTRL_MESON_S4) += pinctrl-meson-s4.o +obj-$(CONFIG_PINCTRL_AMLOGIC_A4) += pinctrl-amlogic-a4.o obj-$(CONFIG_PINCTRL_AMLOGIC_C3) += pinctrl-amlogic-c3.o obj-$(CONFIG_PINCTRL_AMLOGIC_T7) += pinctrl-amlogic-t7.o diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c new file mode 100644 index 000000000000..ee7bbc72f9b3 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c @@ -0,0 +1,1053 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + * Author: Xianwei Zhao <xianwei.zhao@amlogic.com> + */ + +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/string_helpers.h> + +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <dt-bindings/pinctrl/amlogic,pinctrl.h> + +#include "../core.h" +#include "../pinconf.h" + +#define gpio_chip_to_bank(chip) \ + container_of(chip, struct aml_gpio_bank, gpio_chip) + +#define AML_REG_PULLEN 0 +#define AML_REG_PULL 1 +#define AML_REG_DIR 2 +#define AML_REG_OUT 3 +#define AML_REG_IN 4 +#define AML_REG_DS 5 +#define AML_NUM_REG 6 + +enum aml_pinconf_drv { + PINCONF_DRV_500UA, + PINCONF_DRV_2500UA, + PINCONF_DRV_3000UA, + PINCONF_DRV_4000UA, +}; + +struct aml_pio_control { + u32 gpio_offset; + u32 reg_offset[AML_NUM_REG]; + u32 bit_offset[AML_NUM_REG]; +}; + +struct aml_reg_bit { + u32 bank_id; + u32 reg_offs[AML_NUM_REG]; + u32 bit_offs[AML_NUM_REG]; +}; + +struct aml_pctl_data { + unsigned int number; + struct aml_reg_bit rb_offs[]; +}; + +struct aml_pmx_func { + const char *name; + const char **groups; + unsigned int ngroups; +}; + +struct aml_pctl_group { + const char *name; + unsigned int npins; + unsigned int *pins; + unsigned int *func; +}; + +struct aml_gpio_bank { + struct gpio_chip gpio_chip; + struct aml_pio_control pc; + u32 bank_id; + unsigned int pin_base; + struct regmap *reg_mux; + struct regmap *reg_gpio; + struct regmap *reg_ds; +}; + +struct aml_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + struct aml_gpio_bank *banks; + int nbanks; + struct aml_pmx_func *functions; + int nfunctions; + struct aml_pctl_group *groups; + int ngroups; + + const struct aml_pctl_data *data; +}; + +static const unsigned int aml_bit_strides[AML_NUM_REG] = { + 1, 1, 1, 1, 1, 2 +}; + +static const unsigned int aml_def_regoffs[AML_NUM_REG] = { + 3, 4, 2, 1, 0, 7 +}; + +static const char *aml_bank_name[31] = { +"GPIOA", "GPIOB", "GPIOC", "GPIOD", "GPIOE", "GPIOF", "GPIOG", +"GPIOH", "GPIOI", "GPIOJ", "GPIOK", "GPIOL", "GPIOM", "GPION", +"GPIOO", "GPIOP", "GPIOQ", "GPIOR", "GPIOS", "GPIOT", "GPIOU", +"GPIOV", "GPIOW", "GPIOX", "GPIOY", "GPIOZ", "GPIODV", "GPIOAO", +"GPIOCC", "TEST_N", "ANALOG" +}; + +static int aml_pmx_calc_reg_and_offset(struct pinctrl_gpio_range *range, + unsigned int pin, unsigned int *reg, + unsigned int *offset) +{ + unsigned int shift; + + shift = (pin - range->pin_base) << 2; + *reg = (shift / 32) * 4; + *offset = shift % 32; + + return 0; +} + +static int aml_pctl_set_function(struct aml_pinctrl *info, + struct pinctrl_gpio_range *range, + int pin_id, int func) +{ + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + int reg; + int offset; + + if (!bank->reg_mux) + return 0; + + aml_pmx_calc_reg_and_offset(range, pin_id, ®, &offset); + return regmap_update_bits(bank->reg_mux, reg, + 0xf << offset, (func & 0xf) << offset); +} + +static int aml_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *aml_pmx_get_fname(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int aml_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **grps, + unsigned * const ngrps) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *grps = info->functions[selector].groups; + *ngrps = info->functions[selector].ngroups; + + return 0; +} + +static int aml_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned int fselector, + unsigned int group_id) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct aml_pctl_group *group = &info->groups[group_id]; + struct pinctrl_gpio_range *range; + int i; + + for (i = 0; i < group->npins; i++) { + range = pinctrl_find_gpio_range_from_pin(pctldev, group->pins[i]); + aml_pctl_set_function(info, range, group->pins[i], group->func[i]); + } + + return 0; +} + +static int aml_pmx_request_gpio(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return aml_pctl_set_function(info, range, pin, 0); +} + +static const struct pinmux_ops aml_pmx_ops = { + .set_mux = aml_pmx_set_mux, + .get_functions_count = aml_pmx_get_funcs_count, + .get_function_name = aml_pmx_get_fname, + .get_function_groups = aml_pmx_get_groups, + .gpio_request_enable = aml_pmx_request_gpio, +}; + +static int aml_calc_reg_and_bit(struct pinctrl_gpio_range *range, + unsigned int pin, + unsigned int reg_type, + unsigned int *reg, unsigned int *bit) +{ + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + + *bit = (pin - range->pin_base) * aml_bit_strides[reg_type] + + bank->pc.bit_offset[reg_type]; + *reg = (bank->pc.reg_offset[reg_type] + (*bit / 32)) * 4; + *bit &= 0x1f; + + return 0; +} + +static int aml_pinconf_get_pull(struct aml_pinctrl *info, unsigned int pin) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, val; + int ret, conf; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, ®, &bit); + + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + if (!(val & BIT(bit))) { + conf = PIN_CONFIG_BIAS_DISABLE; + } else { + aml_calc_reg_and_bit(range, pin, AML_REG_PULL, ®, &bit); + + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + if (val & BIT(bit)) + conf = PIN_CONFIG_BIAS_PULL_UP; + else + conf = PIN_CONFIG_BIAS_PULL_DOWN; + } + + return conf; +} + +static int aml_pinconf_get_drive_strength(struct aml_pinctrl *info, + unsigned int pin, + u16 *drive_strength_ua) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit; + unsigned int val; + int ret; + + if (!bank->reg_ds) + return -EOPNOTSUPP; + + aml_calc_reg_and_bit(range, pin, AML_REG_DS, ®, &bit); + ret = regmap_read(bank->reg_ds, reg, &val); + if (ret) + return ret; + + switch ((val >> bit) & 0x3) { + case PINCONF_DRV_500UA: + *drive_strength_ua = 500; + break; + case PINCONF_DRV_2500UA: + *drive_strength_ua = 2500; + break; + case PINCONF_DRV_3000UA: + *drive_strength_ua = 3000; + break; + case PINCONF_DRV_4000UA: + *drive_strength_ua = 4000; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int aml_pinconf_get_gpio_bit(struct aml_pinctrl *info, + unsigned int pin, + unsigned int reg_type) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, val; + int ret; + + aml_calc_reg_and_bit(range, pin, reg_type, ®, &bit); + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + return BIT(bit) & val ? 1 : 0; +} + +static int aml_pinconf_get_output(struct aml_pinctrl *info, + unsigned int pin) +{ + int ret = aml_pinconf_get_gpio_bit(info, pin, AML_REG_DIR); + + if (ret < 0) + return ret; + + return !ret; +} + +static int aml_pinconf_get_drive(struct aml_pinctrl *info, + unsigned int pin) +{ + return aml_pinconf_get_gpio_bit(info, pin, AML_REG_OUT); +} + +static int aml_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *config) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param = pinconf_to_config_param(*config); + u16 arg; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + if (aml_pinconf_get_pull(info, pin) == param) + arg = 1; + else + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = aml_pinconf_get_drive_strength(info, pin, &arg); + if (ret) + return ret; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = aml_pinconf_get_output(info, pin); + if (ret <= 0) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_OUTPUT: + ret = aml_pinconf_get_output(info, pin); + if (ret <= 0) + return -EINVAL; + + ret = aml_pinconf_get_drive(info, pin); + if (ret < 0) + return -EINVAL; + + arg = ret; + break; + + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + dev_dbg(info->dev, "pinconf for pin %u is %lu\n", pin, *config); + + return 0; +} + +static int aml_pinconf_disable_bias(struct aml_pinctrl *info, + unsigned int pin) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit = 0; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, ®, &bit); + + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0); +} + +static int aml_pinconf_enable_bias(struct aml_pinctrl *info, unsigned int pin, + bool pull_up) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, val = 0; + int ret; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULL, ®, &bit); + if (pull_up) + val = BIT(bit); + + ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), val); + if (ret) + return ret; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, ®, &bit); + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit)); +} + +static int aml_pinconf_set_drive_strength(struct aml_pinctrl *info, + unsigned int pin, + u16 drive_strength_ua) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, ds_val; + + if (!bank->reg_ds) { + dev_err(info->dev, "drive-strength not supported\n"); + return -EOPNOTSUPP; + } + + aml_calc_reg_and_bit(range, pin, AML_REG_DS, ®, &bit); + + if (drive_strength_ua <= 500) { + ds_val = PINCONF_DRV_500UA; + } else if (drive_strength_ua <= 2500) { + ds_val = PINCONF_DRV_2500UA; + } else if (drive_strength_ua <= 3000) { + ds_val = PINCONF_DRV_3000UA; + } else if (drive_strength_ua <= 4000) { + ds_val = PINCONF_DRV_4000UA; + } else { + dev_warn_once(info->dev, + "pin %u: invalid drive-strength : %d , default to 4mA\n", + pin, drive_strength_ua); + ds_val = PINCONF_DRV_4000UA; + } + + return regmap_update_bits(bank->reg_ds, reg, 0x3 << bit, ds_val << bit); +} + +static int aml_pinconf_set_gpio_bit(struct aml_pinctrl *info, + unsigned int pin, + unsigned int reg_type, + bool arg) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit; + + aml_calc_reg_and_bit(range, pin, reg_type, ®, &bit); + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), + arg ? BIT(bit) : 0); +} + +static int aml_pinconf_set_output(struct aml_pinctrl *info, + unsigned int pin, + bool out) +{ + return aml_pinconf_set_gpio_bit(info, pin, AML_REG_DIR, !out); +} + +static int aml_pinconf_set_drive(struct aml_pinctrl *info, + unsigned int pin, + bool high) +{ + return aml_pinconf_set_gpio_bit(info, pin, AML_REG_OUT, high); +} + +static int aml_pinconf_set_output_drive(struct aml_pinctrl *info, + unsigned int pin, + bool high) +{ + int ret; + + ret = aml_pinconf_set_output(info, pin, true); + if (ret) + return ret; + + return aml_pinconf_set_drive(info, pin, high); +} + +static int aml_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param; + unsigned int arg = 0; + int i, ret; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + + switch (param) { + case PIN_CONFIG_DRIVE_STRENGTH_UA: + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_OUTPUT: + arg = pinconf_to_config_argument(configs[i]); + break; + + default: + break; + } + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + ret = aml_pinconf_disable_bias(info, pin); + break; + case PIN_CONFIG_BIAS_PULL_UP: + ret = aml_pinconf_enable_bias(info, pin, true); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = aml_pinconf_enable_bias(info, pin, false); + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = aml_pinconf_set_drive_strength(info, pin, arg); + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = aml_pinconf_set_output(info, pin, arg); + break; + case PIN_CONFIG_OUTPUT: + ret = aml_pinconf_set_output_drive(info, pin, arg); + break; + default: + ret = -ENOTSUPP; + } + + if (ret) + return ret; + } + + return 0; +} + +static int aml_pinconf_group_set(struct pinctrl_dev *pcdev, + unsigned int num_group, + unsigned long *configs, + unsigned int num_configs) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev); + int i; + + for (i = 0; i < info->groups[num_group].npins; i++) { + aml_pinconf_set(pcdev, info->groups[num_group].pins[i], configs, + num_configs); + } + + return 0; +} + +static int aml_pinconf_group_get(struct pinctrl_dev *pcdev, + unsigned int group, unsigned long *config) +{ + return -EOPNOTSUPP; +} + +static const struct pinconf_ops aml_pinconf_ops = { + .pin_config_get = aml_pinconf_get, + .pin_config_set = aml_pinconf_set, + .pin_config_group_get = aml_pinconf_group_get, + .pin_config_group_set = aml_pinconf_group_set, + .is_generic = true, +}; + +static int aml_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *aml_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int aml_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *npins) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins; + + return 0; +} + +static inline const struct aml_pctl_group * + aml_pctl_find_group_by_name(const struct aml_pinctrl *info, + const char *name) +{ + int i; + + for (i = 0; i < info->ngroups; i++) { + if (!strcmp(info->groups[i].name, name)) + return &info->groups[i]; + } + + return NULL; +} + +static void aml_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, " %s", dev_name(pcdev->dev)); +} + +static const struct pinctrl_ops aml_pctrl_ops = { + .get_groups_count = aml_get_groups_count, + .get_group_name = aml_get_group_name, + .get_group_pins = aml_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pinmux, + .dt_free_map = pinconf_generic_dt_free_map, + .pin_dbg_show = aml_pin_dbg_show, +}; + +static int aml_pctl_parse_functions(struct device_node *np, + struct aml_pinctrl *info, u32 index, + int *grp_index) +{ + struct device *dev = info->dev; + struct aml_pmx_func *func; + struct aml_pctl_group *grp; + int ret, i; + + func = &info->functions[index]; + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups == 0) + return dev_err_probe(dev, -EINVAL, "No groups defined\n"); + + func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + i = 0; + for_each_child_of_node_scoped(np, child) { + func->groups[i++] = child->name; + grp = &info->groups[*grp_index]; + grp->name = child->name; + *grp_index += 1; + ret = pinconf_generic_parse_dt_pinmux(child, dev, &grp->pins, + &grp->func, &grp->npins); + if (ret) { + dev_err(dev, "function :%s, groups:%s fail\n", func->name, child->name); + return ret; + } + } + dev_dbg(dev, "Function[%d\t name:%s,\tgroups:%d]\n", index, func->name, func->ngroups); + + return 0; +} + +static u32 aml_bank_pins(struct device_node *np) +{ + struct of_phandle_args of_args; + + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return 0; + else + return of_args.args[2]; +} + +static int aml_bank_number(struct device_node *np) +{ + struct of_phandle_args of_args; + + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return -EINVAL; + else + return of_args.args[1] >> 8; +} + +static unsigned int aml_count_pins(struct device_node *np) +{ + struct device_node *child; + unsigned int pins = 0; + + for_each_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) + pins += aml_bank_pins(child); + } + + return pins; +} + +/* + * A pinctrl device contains two types of nodes. The one named GPIO + * bank which includes gpio-controller property. The other one named + * function which includes one or more pin groups. The pin group + * include pinmux property(global index in pinctrl dev, and mux vlaue + * in mux reg) and pin configuration properties. + */ +static void aml_pctl_dt_child_count(struct aml_pinctrl *info, + struct device_node *np) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + info->nbanks++; + } else { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } + } +} + +static struct regmap *aml_map_resource(struct device *dev, unsigned int id, + struct device_node *node, char *name) +{ + struct resource res; + void __iomem *base; + int i; + + struct regmap_config aml_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + + i = of_property_match_string(node, "reg-names", name); + if (i < 0) + return NULL; + if (of_address_to_resource(node, i, &res)) + return NULL; + base = devm_ioremap_resource(dev, &res); + if (IS_ERR(base)) + return ERR_CAST(base); + + aml_regmap_config.max_register = resource_size(&res) - 4; + aml_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%s", aml_bank_name[id], name); + if (!aml_regmap_config.name) + return ERR_PTR(-ENOMEM); + + return devm_regmap_init_mmio(dev, base, &aml_regmap_config); +} + +static inline int aml_gpio_calc_reg_and_bit(struct aml_gpio_bank *bank, + unsigned int reg_type, + unsigned int gpio, + unsigned int *reg, + unsigned int *bit) +{ + *bit = gpio * aml_bit_strides[reg_type] + bank->pc.bit_offset[reg_type]; + *reg = (bank->pc.reg_offset[reg_type] + (*bit / 32)) * 4; + *bit &= 0x1f; + + return 0; +} + +static int aml_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg, val; + int ret; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); + + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + return BIT(bit) & val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; +} + +static int aml_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); + + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit)); +} + +static int aml_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg; + int ret; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); + ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0); + if (ret < 0) + return ret; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_OUT, gpio, ®, &bit); + + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), + value ? BIT(bit) : 0); +} + +static void aml_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_OUT, gpio, ®, &bit); + + regmap_update_bits(bank->reg_gpio, reg, BIT(bit), + value ? BIT(bit) : 0); +} + +static int aml_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int reg, bit, val; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_IN, gpio, ®, &bit); + regmap_read(bank->reg_gpio, reg, &val); + + return !!(val & BIT(bit)); +} + +static const struct gpio_chip aml_gpio_template = { + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .set_config = gpiochip_generic_config, + .set = aml_gpio_set, + .get = aml_gpio_get, + .direction_input = aml_gpio_direction_input, + .direction_output = aml_gpio_direction_output, + .get_direction = aml_gpio_get_direction, + .can_sleep = false, +}; + +static void init_bank_register_bit(struct aml_pinctrl *info, + struct aml_gpio_bank *bank) +{ + const struct aml_pctl_data *data = info->data; + const struct aml_reg_bit *aml_rb; + bool def_offs = true; + int i; + + if (data) { + for (i = 0; i < data->number; i++) { + aml_rb = &data->rb_offs[i]; + if (bank->bank_id == aml_rb->bank_id) { + def_offs = false; + break; + } + } + } + + if (def_offs) { + for (i = 0; i < AML_NUM_REG; i++) { + bank->pc.reg_offset[i] = aml_def_regoffs[i]; + bank->pc.bit_offset[i] = 0; + } + } else { + for (i = 0; i < AML_NUM_REG; i++) { + bank->pc.reg_offset[i] = aml_rb->reg_offs[i]; + bank->pc.bit_offset[i] = aml_rb->bit_offs[i]; + } + } +} + +static int aml_gpiolib_register_bank(struct aml_pinctrl *info, + int bank_nr, struct device_node *np) +{ + struct aml_gpio_bank *bank = &info->banks[bank_nr]; + struct device *dev = info->dev; + int ret = 0; + + ret = aml_bank_number(np); + if (ret < 0) { + dev_err(dev, "get num=%d bank identity fail\n", bank_nr); + return -EINVAL; + } + bank->bank_id = ret; + + bank->reg_mux = aml_map_resource(dev, bank->bank_id, np, "mux"); + if (IS_ERR_OR_NULL(bank->reg_mux)) { + if (bank->bank_id == AMLOGIC_GPIO_TEST_N || + bank->bank_id == AMLOGIC_GPIO_ANALOG) + bank->reg_mux = NULL; + else + return dev_err_probe(dev, bank->reg_mux ? PTR_ERR(bank->reg_mux) : -ENOENT, + "mux registers not found\n"); + } + + bank->reg_gpio = aml_map_resource(dev, bank->bank_id, np, "gpio"); + if (IS_ERR_OR_NULL(bank->reg_gpio)) + return dev_err_probe(dev, bank->reg_gpio ? PTR_ERR(bank->reg_gpio) : -ENOENT, + "gpio registers not found\n"); + + bank->reg_ds = aml_map_resource(dev, bank->bank_id, np, "ds"); + if (IS_ERR_OR_NULL(bank->reg_ds)) { + dev_dbg(info->dev, "ds registers not found - skipping\n"); + bank->reg_ds = bank->reg_gpio; + } + + bank->gpio_chip = aml_gpio_template; + bank->gpio_chip.base = -1; + bank->gpio_chip.ngpio = aml_bank_pins(np); + bank->gpio_chip.fwnode = of_fwnode_handle(np); + bank->gpio_chip.parent = dev; + + init_bank_register_bit(info, bank); + bank->gpio_chip.label = aml_bank_name[bank->bank_id]; + + bank->pin_base = bank->bank_id << 8; + + return 0; +} + +static int aml_pctl_probe_dt(struct platform_device *pdev, + struct pinctrl_desc *pctl_desc, + struct aml_pinctrl *info) +{ + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pdesc; + struct device_node *np = dev->of_node; + int grp_index = 0; + int i = 0, j = 0, k = 0, bank; + int ret = 0; + + aml_pctl_dt_child_count(info, np); + if (!info->nbanks) + return dev_err_probe(dev, -EINVAL, "you need at least one gpio bank\n"); + + dev_dbg(dev, "nbanks = %d\n", info->nbanks); + dev_dbg(dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(dev, "ngroups = %d\n", info->ngroups); + + info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL); + + info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL); + + info->banks = devm_kcalloc(dev, info->nbanks, sizeof(*info->banks), GFP_KERNEL); + + if (!info->functions || !info->groups || !info->banks) + return -ENOMEM; + + info->data = (struct aml_pctl_data *)of_device_get_match_data(dev); + + pctl_desc->npins = aml_count_pins(np); + + pdesc = devm_kcalloc(dev, pctl_desc->npins, sizeof(*pdesc), GFP_KERNEL); + if (!pdesc) + return -ENOMEM; + + pctl_desc->pins = pdesc; + + bank = 0; + for_each_child_of_node_scoped(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + const char *bank_name = NULL; + char **pin_names; + + ret = aml_gpiolib_register_bank(info, bank, child); + if (ret) + return ret; + + k = info->banks[bank].pin_base; + bank_name = info->banks[bank].gpio_chip.label; + + pin_names = devm_kasprintf_strarray(dev, bank_name, + info->banks[bank].gpio_chip.ngpio); + if (IS_ERR(pin_names)) + return PTR_ERR(pin_names); + + for (j = 0; j < info->banks[bank].gpio_chip.ngpio; j++, k++) { + pdesc->number = k; + pdesc->name = pin_names[j]; + pdesc++; + } + bank++; + } else { + ret = aml_pctl_parse_functions(child, info, + i++, &grp_index); + if (ret) + return ret; + } + } + + return 0; +} + +static int aml_pctl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct aml_pinctrl *info; + struct pinctrl_desc *pctl_desc; + int ret, i; + + pctl_desc = devm_kzalloc(dev, sizeof(*pctl_desc), GFP_KERNEL); + if (!pctl_desc) + return -ENOMEM; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = dev; + platform_set_drvdata(pdev, info); + ret = aml_pctl_probe_dt(pdev, pctl_desc, info); + if (ret) + return ret; + + pctl_desc->owner = THIS_MODULE; + pctl_desc->pctlops = &aml_pctrl_ops; + pctl_desc->pmxops = &aml_pmx_ops; + pctl_desc->confops = &aml_pinconf_ops; + pctl_desc->name = dev_name(dev); + + info->pctl = devm_pinctrl_register(dev, pctl_desc, info); + if (IS_ERR(info->pctl)) + return dev_err_probe(dev, PTR_ERR(info->pctl), "Failed pinctrl registration\n"); + + for (i = 0; i < info->nbanks; i++) { + ret = gpiochip_add_data(&info->banks[i].gpio_chip, &info->banks[i]); + if (ret) + return dev_err_probe(dev, ret, "Failed to add gpiochip(%d)!\n", i); + } + + return 0; +} + +static const struct of_device_id aml_pctl_of_match[] = { + { .compatible = "amlogic,pinctrl-a4", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, aml_pctl_dt_match); + +static struct platform_driver aml_pctl_driver = { + .driver = { + .name = "amlogic-pinctrl", + .of_match_table = aml_pctl_of_match, + }, + .probe = aml_pctl_probe, +}; +module_platform_driver(aml_pctl_driver); + +MODULE_AUTHOR("Xianwei Zhao <xianwei.zhao@amlogic.com>"); +MODULE_DESCRIPTION("Pin controller and GPIO driver for Amlogic SoC"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index 59c4e7c6cdde..06ae1fe8b8c5 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -98,12 +98,6 @@ static const u32 ds_3300mv_tbl[] = { 17100, 25600, 34100, 42800, 48000, 56000, 77000, 82000, }; -struct ma35_pin_func { - const char *name; - const char **groups; - u32 ngroups; -}; - struct ma35_pin_setting { u32 offset; u32 shift; @@ -112,13 +106,6 @@ struct ma35_pin_setting { unsigned int nconfigs; }; -struct ma35_pin_group { - const char *name; - unsigned int npins; - unsigned int *pins; - struct ma35_pin_setting *settings; -}; - struct ma35_pin_bank { void __iomem *reg_base; struct clk *clk; @@ -147,9 +134,9 @@ struct ma35_pinctrl { struct pinctrl_dev *pctl; const struct ma35_pinctrl_soc_info *info; struct regmap *regmap; - struct ma35_pin_group *groups; + struct group_desc *groups; unsigned int ngroups; - struct ma35_pin_func *functions; + struct pinfunction *functions; unsigned int nfunctions; }; @@ -166,7 +153,7 @@ static const char *ma35_get_group_name(struct pinctrl_dev *pctldev, unsigned int { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); - return npctl->groups[selector].name; + return npctl->groups[selector].grp.name; } static int ma35_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, @@ -177,19 +164,19 @@ static int ma35_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selecto if (selector >= npctl->ngroups) return -EINVAL; - *pins = npctl->groups[selector].pins; - *npins = npctl->groups[selector].npins; + *pins = npctl->groups[selector].grp.pins; + *npins = npctl->groups[selector].grp.npins; return 0; } -static struct ma35_pin_group *ma35_pinctrl_find_group_by_name( - const struct ma35_pinctrl *npctl, const char *name) +static struct group_desc * +ma35_pinctrl_find_group_by_name(const struct ma35_pinctrl *npctl, const char *name) { int i; for (i = 0; i < npctl->ngroups; i++) { - if (!strcmp(npctl->groups[i].name, name)) + if (!strcmp(npctl->groups[i].grp.name, name)) return &npctl->groups[i]; } return NULL; @@ -201,9 +188,10 @@ static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, unsigned int *num_maps) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); - struct ma35_pin_group *grp; + struct ma35_pin_setting *setting; struct pinctrl_map *new_map; struct device_node *parent; + struct group_desc *grp; int map_num = 1; int i; @@ -217,7 +205,7 @@ static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, return -EINVAL; } - map_num += grp->npins; + map_num += grp->grp.npins; new_map = kcalloc(map_num, sizeof(*new_map), GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -229,17 +217,19 @@ static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, if (!parent) return -EINVAL; + setting = grp->data; + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; new_map[0].data.mux.function = parent->name; new_map[0].data.mux.group = np->name; of_node_put(parent); new_map++; - for (i = 0; i < grp->npins; i++) { + for (i = 0; i < grp->grp.npins; i++) { new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; - new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, grp->pins[i]); - new_map[i].data.configs.configs = grp->settings[i].configs; - new_map[i].data.configs.num_configs = grp->settings[i].nconfigs; + new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, grp->grp.pins[i]); + new_map[i].data.configs.configs = setting[i].configs; + new_map[i].data.configs.num_configs = setting[i].nconfigs; } dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", (*map)->data.mux.function, (*map)->data.mux.group, map_num); @@ -287,14 +277,14 @@ static int ma35_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selecto unsigned int group) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); - struct ma35_pin_group *grp = &npctl->groups[group]; - struct ma35_pin_setting *setting = grp->settings; + struct group_desc *grp = &npctl->groups[group]; + struct ma35_pin_setting *setting = grp->data; u32 i, regval; dev_dbg(npctl->dev, "enable function %s group %s\n", - npctl->functions[selector].name, npctl->groups[group].name); + npctl->functions[selector].name, grp->grp.name); - for (i = 0; i < grp->npins; i++) { + for (i = 0; i < grp->grp.npins; i++) { regmap_read(npctl->regmap, setting->offset, ®val); regval &= ~GENMASK(setting->shift + MA35_MFP_BITS_PER_PORT - 1, setting->shift); @@ -529,7 +519,6 @@ static int ma35_gpiolib_register(struct platform_device *pdev, struct ma35_pinct bank->irqtype = 0; bank->irqinten = 0; bank->chip.label = bank->name; - bank->chip.of_gpio_n_cells = 2; bank->chip.parent = &pdev->dev; bank->chip.request = ma35_gpio_core_to_request; bank->chip.direction_input = ma35_gpio_core_direction_in; @@ -986,22 +975,22 @@ static const struct pinconf_ops ma35_pinconf_ops = { .is_generic = true, }; -static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_group *grp, +static int ma35_pinctrl_parse_groups(struct fwnode_handle *fwnode, struct group_desc *grp, struct ma35_pinctrl *npctl, u32 index) { + struct device_node *np = to_of_node(fwnode); struct ma35_pin_setting *pin; unsigned long *configs; unsigned int nconfigs; + unsigned int *pins; int i, j, count, ret; u32 *elems; - grp->name = np->name; - ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &nconfigs); if (ret) return ret; - count = of_property_count_elems_of_size(np, "nuvoton,pins", sizeof(u32)); + count = fwnode_property_count_u32(fwnode, "nuvoton,pins"); if (!count || count % 3) return -EINVAL; @@ -1009,21 +998,22 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_gro if (!elems) return -ENOMEM; - ret = of_property_read_u32_array(np, "nuvoton,pins", elems, count); + grp->grp.name = np->name; + + ret = fwnode_property_read_u32_array(fwnode, "nuvoton,pins", elems, count); if (ret) return -EINVAL; + grp->grp.npins = count / 3; - grp->npins = count / 3; - - grp->pins = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL); - if (!grp->pins) + pins = devm_kcalloc(npctl->dev, grp->grp.npins, sizeof(*pins), GFP_KERNEL); + if (!pins) return -ENOMEM; + grp->grp.pins = pins; - grp->settings = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->settings), GFP_KERNEL); - if (!grp->settings) + pin = devm_kcalloc(npctl->dev, grp->grp.npins, sizeof(*pin), GFP_KERNEL); + if (!pin) return -ENOMEM; - - pin = grp->settings; + grp->data = pin; for (i = 0, j = 0; i < count; i += 3, j++) { pin->offset = elems[i] * MA35_MFP_REG_SZ_PER_BANK + MA35_MFP_REG_BASE; @@ -1031,19 +1021,21 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_gro pin->muxval = elems[i + 2]; pin->configs = configs; pin->nconfigs = nconfigs; - grp->pins[j] = npctl->info->get_pin_num(pin->offset, pin->shift); + pins[j] = npctl->info->get_pin_num(pin->offset, pin->shift); pin++; } return 0; } -static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinctrl *npctl, +static int ma35_pinctrl_parse_functions(struct fwnode_handle *fwnode, struct ma35_pinctrl *npctl, u32 index) { - struct device_node *child; - struct ma35_pin_func *func; - struct ma35_pin_group *grp; + struct device_node *np = to_of_node(fwnode); + struct fwnode_handle *child; + struct pinfunction *func; + struct group_desc *grp; static u32 grp_index; + const char **groups; u32 ret, i = 0; dev_dbg(npctl->dev, "parse function(%d): %s\n", index, np->name); @@ -1055,31 +1047,34 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc if (func->ngroups <= 0) return 0; - func->groups = devm_kcalloc(npctl->dev, func->ngroups, sizeof(char *), GFP_KERNEL); - if (!func->groups) + groups = devm_kcalloc(npctl->dev, func->ngroups, sizeof(*groups), GFP_KERNEL); + if (!groups) return -ENOMEM; - for_each_child_of_node(np, child) { - func->groups[i] = child->name; + fwnode_for_each_child_node(fwnode, child) { + struct device_node *node = to_of_node(child); + + groups[i] = node->name; grp = &npctl->groups[grp_index++]; ret = ma35_pinctrl_parse_groups(child, grp, npctl, i++); if (ret) { - of_node_put(child); + fwnode_handle_put(child); return ret; } } + + func->groups = groups; return 0; } static int ma35_pinctrl_probe_dt(struct platform_device *pdev, struct ma35_pinctrl *npctl) { + struct device *dev = &pdev->dev; struct fwnode_handle *child; u32 idx = 0; int ret; - device_for_each_child_node(&pdev->dev, child) { - if (fwnode_property_present(child, "gpio-controller")) - continue; + for_each_gpiochip_node(dev, child) { npctl->nfunctions++; npctl->ngroups += of_get_child_count(to_of_node(child)); } @@ -1097,11 +1092,8 @@ static int ma35_pinctrl_probe_dt(struct platform_device *pdev, struct ma35_pinct if (!npctl->groups) return -ENOMEM; - device_for_each_child_node(&pdev->dev, child) { - if (fwnode_property_present(child, "gpio-controller")) - continue; - - ret = ma35_pinctrl_parse_functions(to_of_node(child), npctl, idx++); + for_each_gpiochip_node(dev, child) { + ret = ma35_pinctrl_parse_functions(child, npctl, idx++); if (ret) { fwnode_handle_put(child); dev_err(&pdev->dev, "failed to parse function\n"); @@ -1146,7 +1138,7 @@ int ma35_pinctrl_probe(struct platform_device *pdev, const struct ma35_pinctrl_s npctl->info = info; npctl->dev = &pdev->dev; - npctl->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "nuvoton,sys"); + npctl->regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev), "nuvoton,sys"); if (IS_ERR(npctl->regmap)) return dev_err_probe(&pdev->dev, PTR_ERR(npctl->regmap), "No syscfg phandle specified\n"); diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c index 8bb9a5a35954..eafa06ca0879 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c @@ -9,7 +9,6 @@ #include <linux/io.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm.h> diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index 62a46d824b46..dfd32feb3428 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -7,10 +7,8 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/mfd/syscon.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> @@ -504,17 +502,6 @@ static const int lkgpo2_pins[] = { 9 }; static const int nprd_smi_pins[] = { 190 }; -/* - * pin: name, number - * group: name, npins, pins - * function: name, ngroups, groups - */ -struct npcm7xx_group { - const char *name; - const unsigned int *pins; - int npins; -}; - #define NPCM7XX_GRPS \ NPCM7XX_GRP(smb0), \ NPCM7XX_GRP(smb0b), \ @@ -642,22 +629,14 @@ enum { #undef NPCM7XX_GRP }; -static struct npcm7xx_group npcm7xx_groups[] = { -#define NPCM7XX_GRP(x) { .name = #x, .pins = x ## _pins, \ - .npins = ARRAY_SIZE(x ## _pins) } +static struct pingroup npcm7xx_groups[] = { +#define NPCM7XX_GRP(x) PINCTRL_PINGROUP(#x, x ## _pins, ARRAY_SIZE(x ## _pins)) NPCM7XX_GRPS #undef NPCM7XX_GRP }; #define NPCM7XX_SFUNC(a) NPCM7XX_FUNC(a, #a) #define NPCM7XX_FUNC(a, b...) static const char *a ## _grp[] = { b } -#define NPCM7XX_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ - .groups = nm ## _grp } -struct npcm7xx_func { - const char *name; - const unsigned int ngroups; - const char *const *groups; -}; NPCM7XX_SFUNC(smb0); NPCM7XX_SFUNC(smb0b); @@ -776,7 +755,8 @@ NPCM7XX_SFUNC(lkgpo2); NPCM7XX_SFUNC(nprd_smi); /* Function names */ -static struct npcm7xx_func npcm7xx_funcs[] = { +static struct pinfunction npcm7xx_funcs[] = { +#define NPCM7XX_MKFUNC(nm) PINCTRL_PINFUNCTION(#nm, nm ## _grp, ARRAY_SIZE(nm ## _grp)) NPCM7XX_MKFUNC(smb0), NPCM7XX_MKFUNC(smb0b), NPCM7XX_MKFUNC(smb0c), @@ -892,6 +872,7 @@ static struct npcm7xx_func npcm7xx_funcs[] = { NPCM7XX_MKFUNC(lkgpo1), NPCM7XX_MKFUNC(lkgpo2), NPCM7XX_MKFUNC(nprd_smi), +#undef NPCM7XX_MKFUNC }; #define NPCM7XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k) \ @@ -1849,22 +1830,13 @@ static struct pinctrl_desc npcm7xx_pinctrl_desc = { static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) { int ret = -ENXIO; - struct resource res; struct device *dev = pctrl->dev; struct fwnode_reference_args args; struct fwnode_handle *child; int id = 0; for_each_gpiochip_node(dev, child) { - struct device_node *np = to_of_node(child); - - ret = of_address_to_resource(np, 0, &res); - if (ret < 0) { - dev_err(dev, "Resource fail for GPIO bank %u\n", id); - return ret; - } - - pctrl->gpio_bank[id].base = ioremap(res.start, resource_size(&res)); + pctrl->gpio_bank[id].base = fwnode_iomap(child, 0); if (!pctrl->gpio_bank[id].base) return -EINVAL; @@ -1886,7 +1858,7 @@ static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) return ret; } - ret = irq_of_parse_and_map(np, 0); + ret = fwnode_irq_get(child, 0); if (!ret) { dev_err(dev, "No IRQ for GPIO bank %u\n", id); return -EINVAL; diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index d09a5e9b2eca..be3db8ab406c 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -587,17 +587,6 @@ static const int hgpio5_pins[] = { 25 }; static const int hgpio6_pins[] = { 59 }; static const int hgpio7_pins[] = { 60 }; -/* - * pin: name, number - * group: name, npins, pins - * function: name, ngroups, groups - */ -struct npcm8xx_pingroup { - const char *name; - const unsigned int *pins; - int npins; -}; - #define NPCM8XX_GRPS \ NPCM8XX_GRP(gpi36), \ NPCM8XX_GRP(gpi35), \ @@ -829,22 +818,14 @@ enum { #undef NPCM8XX_GRP }; -static struct npcm8xx_pingroup npcm8xx_pingroups[] = { -#define NPCM8XX_GRP(x) { .name = #x, .pins = x ## _pins, \ - .npins = ARRAY_SIZE(x ## _pins) } +static struct pingroup npcm8xx_pingroups[] = { +#define NPCM8XX_GRP(x) PINCTRL_PINGROUP(#x, x ## _pins, ARRAY_SIZE(x ## _pins)) NPCM8XX_GRPS #undef NPCM8XX_GRP }; #define NPCM8XX_SFUNC(a) NPCM8XX_FUNC(a, #a) #define NPCM8XX_FUNC(a, b...) static const char *a ## _grp[] = { b } -#define NPCM8XX_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ - .groups = nm ## _grp } -struct npcm8xx_func { - const char *name; - const unsigned int ngroups; - const char *const *groups; -}; NPCM8XX_SFUNC(gpi36); NPCM8XX_SFUNC(gpi35); @@ -1067,7 +1048,8 @@ NPCM8XX_SFUNC(hgpio6); NPCM8XX_SFUNC(hgpio7); /* Function names */ -static struct npcm8xx_func npcm8xx_funcs[] = { +static struct pinfunction npcm8xx_funcs[] = { +#define NPCM8XX_MKFUNC(nm) PINCTRL_PINFUNCTION(#nm, nm ## _grp, ARRAY_SIZE(nm ## _grp)) NPCM8XX_MKFUNC(gpi36), NPCM8XX_MKFUNC(gpi35), NPCM8XX_MKFUNC(tp_jtag3), @@ -1287,15 +1269,18 @@ static struct npcm8xx_func npcm8xx_funcs[] = { NPCM8XX_MKFUNC(hgpio5), NPCM8XX_MKFUNC(hgpio6), NPCM8XX_MKFUNC(hgpio7), +#undef NPCM8XX_MKFUNC }; #define NPCM8XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) \ - [a] { .fn0 = fn_ ## b, .reg0 = NPCM8XX_GCR_ ## c, .bit0 = d, \ + [a] = { \ + .flag = q, \ + .fn0 = fn_ ## b, .reg0 = NPCM8XX_GCR_ ## c, .bit0 = d, \ .fn1 = fn_ ## e, .reg1 = NPCM8XX_GCR_ ## f, .bit1 = g, \ .fn2 = fn_ ## h, .reg2 = NPCM8XX_GCR_ ## i, .bit2 = j, \ .fn3 = fn_ ## k, .reg3 = NPCM8XX_GCR_ ## l, .bit3 = m, \ .fn4 = fn_ ## n, .reg4 = NPCM8XX_GCR_ ## o, .bit4 = p, \ - .flag = q } + } /* Drive strength controlled by NPCM8XX_GP_N_ODSC */ #define DRIVE_STRENGTH_LO_SHIFT 8 @@ -2361,8 +2346,8 @@ static int npcm8xx_gpio_fw(struct npcm8xx_pinctrl *pctrl) return dev_err_probe(dev, ret, "gpio-ranges fail for GPIO bank %u\n", id); ret = fwnode_irq_get(child, 0); - if (!ret) - return dev_err_probe(dev, ret, "No IRQ for GPIO bank %u\n", id); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to retrieve IRQ for bank %u\n", id); pctrl->gpio_bank[id].irq = ret; pctrl->gpio_bank[id].irq_chip = npcmgpio_irqchip; @@ -2439,7 +2424,7 @@ static int npcm8xx_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pctrl); pctrl->gcr_regmap = - syscon_regmap_lookup_by_phandle(dev->of_node, "nuvoton,sysgcr"); + syscon_regmap_lookup_by_phandle(dev_of_node(dev), "nuvoton,sysgcr"); if (IS_ERR(pctrl->gcr_regmap)) return dev_err_probe(dev, PTR_ERR(pctrl->gcr_regmap), "Failed to find nuvoton,sysgcr property\n"); diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c index cdad4ef11a2f..4264ca749175 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c +++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c @@ -10,7 +10,6 @@ // block, shared between all GPIO banks #include <linux/device.h> -#include <linux/fwnode.h> #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -18,6 +17,7 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/pinctrl/pinconf.h> @@ -482,13 +482,6 @@ static const struct pingroup wpcm450_groups[] = { #define WPCM450_SFUNC(a) WPCM450_FUNC(a, #a) #define WPCM450_FUNC(a, b...) static const char *a ## _grp[] = { b } -#define WPCM450_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ - .groups = nm ## _grp } -struct wpcm450_func { - const char *name; - const unsigned int ngroups; - const char *const *groups; -}; WPCM450_SFUNC(smb3); WPCM450_SFUNC(smb4); @@ -555,7 +548,8 @@ WPCM450_FUNC(gpio, WPCM450_GRPS); #undef WPCM450_GRP /* Function names */ -static struct wpcm450_func wpcm450_funcs[] = { +static struct pinfunction wpcm450_funcs[] = { +#define WPCM450_MKFUNC(nm) PINCTRL_PINFUNCTION(#nm, nm ## _grp, ARRAY_SIZE(nm ## _grp)) WPCM450_MKFUNC(smb3), WPCM450_MKFUNC(smb4), WPCM450_MKFUNC(smb5), @@ -616,6 +610,7 @@ static struct wpcm450_func wpcm450_funcs[] = { WPCM450_MKFUNC(hg6), WPCM450_MKFUNC(hg7), WPCM450_MKFUNC(gpio), +#undef WPCM450_MKFUNC }; #define WPCM450_PINCFG(a, b, c, d, e, f, g) \ @@ -1033,7 +1028,7 @@ static int wpcm450_gpio_register(struct platform_device *pdev, return dev_err_probe(dev, PTR_ERR(pctrl->gpio_base), "Resource fail for GPIO controller\n"); - device_for_each_child_node(dev, child) { + for_each_gpiochip_node(dev, child) { void __iomem *dat = NULL; void __iomem *set = NULL; void __iomem *dirout = NULL; @@ -1044,9 +1039,6 @@ static int wpcm450_gpio_register(struct platform_device *pdev, u32 reg; int i; - if (!fwnode_property_read_bool(child, "gpio-controller")) - continue; - ret = fwnode_property_read_u32(child, "reg", ®); if (ret < 0) return ret; diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 42547f64453e..d67838afb085 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -234,6 +234,67 @@ static void parse_dt_cfg(struct device_node *np, } /** + * pinconf_generic_parse_dt_pinmux() + * parse the pinmux properties into generic pin mux values. + * @np: node containing the pinmux properties + * @dev: pincontrol core device + * @pid: array with pin identity entries + * @pmux: array with pin mux value entries + * @npins: number of pins + * + * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. + */ +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + unsigned int **pid, unsigned int **pmux, + unsigned int *npins) +{ + unsigned int *pid_t; + unsigned int *pmux_t; + struct property *prop; + unsigned int npins_t, i; + u32 value; + int ret; + + prop = of_find_property(np, "pinmux", NULL); + if (!prop) { + dev_info(dev, "Missing pinmux property\n"); + return -ENOENT; + } + + if (!pid || !pmux || !npins) { + dev_err(dev, "parameters error\n"); + return -EINVAL; + } + + npins_t = prop->length / sizeof(u32); + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); + if (!pid_t || !pmux_t) { + dev_err(dev, "kalloc memory fail\n"); + return -ENOMEM; + } + for (i = 0; i < npins_t; i++) { + ret = of_property_read_u32_index(np, "pinmux", i, &value); + if (ret) { + dev_err(dev, "get pinmux value fail\n"); + goto exit; + } + pmux_t[i] = value & 0xff; + pid_t[i] = (value >> 8) & 0xffffff; + } + *pid = pid_t; + *pmux = pmux_t; + *npins = npins_t; + + return 0; +exit: + devm_kfree(dev, pid_t); + devm_kfree(dev, pmux_t); + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux); + +/** * pinconf_generic_parse_dt_config() * parse the config properties into generic pinconfig values. * @np: node containing the pinconfig properties @@ -295,6 +356,75 @@ out: } EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config); +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct device *dev = pctldev->dev; + struct device_node *pnode; + unsigned long *configs = NULL; + unsigned int num_configs = 0; + struct property *prop; + unsigned int reserved_maps; + int reserve; + int ret; + + prop = of_find_property(np, "pinmux", NULL); + if (!prop) { + dev_info(dev, "Missing pinmux property\n"); + return -ENOENT; + } + + pnode = of_get_parent(np); + if (!pnode) { + dev_info(dev, "Missing function node\n"); + return -EINVAL; + } + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(dev, "%pOF: could not parse node property\n", np); + return ret; + } + + reserve = 1; + if (num_configs) + reserve++; + + ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, + num_maps, reserve); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_add_map_mux(pctldev, map, + &reserved_maps, num_maps, np->name, + pnode->name); + if (ret < 0) + goto exit; + + if (num_configs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, &reserved_maps, + num_maps, np->name, configs, + num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + goto exit; + } + +exit: + kfree(configs); + if (ret) + pinctrl_utils_free_map(pctldev, *map, *num_maps); + + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_pinmux); + int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned int *reserved_maps, unsigned int *num_maps, diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index a14c950bc700..a171195b3615 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -138,4 +138,8 @@ int pinconf_generic_parse_dt_config(struct device_node *np, struct pinctrl_dev *pctldev, unsigned long **configs, unsigned int *nconfigs); + +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + unsigned int **pid, unsigned int **pmux, + unsigned int *npins); #endif diff --git a/drivers/pinctrl/pinctrl-amdisp.c b/drivers/pinctrl/pinctrl-amdisp.c new file mode 100644 index 000000000000..9256ed67bb20 --- /dev/null +++ b/drivers/pinctrl/pinctrl-amdisp.c @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ISP Pinctrl Driver + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. + * + */ + +#include <linux/gpio/driver.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "pinctrl-amdisp.h" + +#define DRV_NAME "amdisp-pinctrl" +#define GPIO_CONTROL_PIN 4 +#define GPIO_OFFSET_0 0x0 +#define GPIO_OFFSET_1 0x4 +#define GPIO_OFFSET_2 0x50 + +static const u32 gpio_offset[] = { + GPIO_OFFSET_0, + GPIO_OFFSET_1, + GPIO_OFFSET_2 +}; + +struct amdisp_pinctrl_data { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + const struct amdisp_function *functions; + unsigned int nfunctions; + const struct amdisp_pingroup *groups; + unsigned int ngroups; +}; + +static const struct amdisp_pinctrl_data amdisp_pinctrl_data = { + .pins = amdisp_pins, + .npins = ARRAY_SIZE(amdisp_pins), + .functions = amdisp_functions, + .nfunctions = ARRAY_SIZE(amdisp_functions), + .groups = amdisp_groups, + .ngroups = ARRAY_SIZE(amdisp_groups), +}; + +struct amdisp_pinctrl { + struct device *dev; + struct pinctrl_dev *pctrl; + struct pinctrl_desc desc; + struct pinctrl_gpio_range gpio_range; + struct gpio_chip gc; + const struct amdisp_pinctrl_data *data; + void __iomem *gpiobase; + raw_spinlock_t lock; +}; + +static int amdisp_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->ngroups; +} + +static const char *amdisp_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->groups[group].name; +} + +static int amdisp_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->data->groups[group].pins; + *num_pins = pctrl->data->groups[group].npins; + return 0; +} + +const struct pinctrl_ops amdisp_pinctrl_ops = { + .get_groups_count = amdisp_get_groups_count, + .get_group_name = amdisp_get_group_name, + .get_group_pins = amdisp_get_group_pins, +}; + +static int amdisp_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + /* amdisp gpio only has output mode */ + return GPIO_LINE_DIRECTION_OUT; +} + +static int amdisp_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + return -EOPNOTSUPP; +} + +static int amdisp_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, + int value) +{ + /* Nothing to do, amdisp gpio only has output mode */ + return 0; +} + +static int amdisp_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + unsigned long flags; + u32 pin_reg; + struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return !!(pin_reg & BIT(GPIO_CONTROL_PIN)); +} + +static void amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + unsigned long flags; + u32 pin_reg; + struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]); + if (value) + pin_reg |= BIT(GPIO_CONTROL_PIN); + else + pin_reg &= ~BIT(GPIO_CONTROL_PIN); + writel(pin_reg, pctrl->gpiobase + gpio_offset[gpio]); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static int amdisp_gpiochip_add(struct platform_device *pdev, + struct amdisp_pinctrl *pctrl) +{ + struct gpio_chip *gc = &pctrl->gc; + struct pinctrl_gpio_range *grange = &pctrl->gpio_range; + int ret; + + gc->label = dev_name(pctrl->dev); + gc->parent = &pdev->dev; + gc->names = amdisp_range_pins_name; + gc->request = gpiochip_generic_request; + gc->free = gpiochip_generic_free; + gc->get_direction = amdisp_gpio_get_direction; + gc->direction_input = amdisp_gpio_direction_input; + gc->direction_output = amdisp_gpio_direction_output; + gc->get = amdisp_gpio_get; + gc->set = amdisp_gpio_set; + gc->base = -1; + gc->ngpio = ARRAY_SIZE(amdisp_range_pins); + + grange->id = 0; + grange->pin_base = 0; + grange->base = 0; + grange->pins = amdisp_range_pins; + grange->npins = ARRAY_SIZE(amdisp_range_pins); + grange->name = gc->label; + grange->gc = gc; + + ret = devm_gpiochip_add_data(&pdev->dev, gc, pctrl); + if (ret) + return ret; + + pinctrl_add_gpio_range(pctrl->pctrl, grange); + + return 0; +} + +static int amdisp_pinctrl_probe(struct platform_device *pdev) +{ + struct amdisp_pinctrl *pctrl; + struct resource *res; + int ret; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pdev->dev.init_name = DRV_NAME; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + pctrl->gpiobase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->gpiobase)) + return PTR_ERR(pctrl->gpiobase); + + platform_set_drvdata(pdev, pctrl); + + pctrl->dev = &pdev->dev; + pctrl->data = &amdisp_pinctrl_data; + pctrl->desc.owner = THIS_MODULE; + pctrl->desc.pctlops = &amdisp_pinctrl_ops; + pctrl->desc.pmxops = NULL; + pctrl->desc.name = dev_name(&pdev->dev); + pctrl->desc.pins = pctrl->data->pins; + pctrl->desc.npins = pctrl->data->npins; + ret = devm_pinctrl_register_and_init(&pdev->dev, &pctrl->desc, + pctrl, &pctrl->pctrl); + if (ret) + return ret; + + ret = pinctrl_enable(pctrl->pctrl); + if (ret) + return ret; + + ret = amdisp_gpiochip_add(pdev, pctrl); + if (ret) + return ret; + + return 0; +} + +static struct platform_driver amdisp_pinctrl_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = amdisp_pinctrl_probe, +}; +module_platform_driver(amdisp_pinctrl_driver); + +MODULE_AUTHOR("Benjamin Chan <benjamin.chan@amd.com>"); +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); +MODULE_DESCRIPTION("AMDISP pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/pinctrl/pinctrl-amdisp.h b/drivers/pinctrl/pinctrl-amdisp.h new file mode 100644 index 000000000000..9e3597a03227 --- /dev/null +++ b/drivers/pinctrl/pinctrl-amdisp.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ISP Pinctrl Driver + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. + * + */ + +static const struct pinctrl_pin_desc amdisp_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), /* sensor0 control */ + PINCTRL_PIN(1, "GPIO_1"), /* sensor1 control */ + PINCTRL_PIN(2, "GPIO_2"), /* sensor2 control */ +}; + +#define AMDISP_GPIO_PINS(pin) \ +static const unsigned int gpio##pin##_pins[] = { pin } +AMDISP_GPIO_PINS(0); +AMDISP_GPIO_PINS(1); +AMDISP_GPIO_PINS(2); + +static const unsigned int amdisp_range_pins[] = { + 0, 1, 2 +}; + +static const char * const amdisp_range_pins_name[] = { + "gpio0", "gpio1", "gpio2" +}; + +enum amdisp_functions { + mux_gpio, + mux_NA +}; + +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2" +}; + +/** + * struct amdisp_function - a pinmux function + * @name: Name of the pinmux function. + * @groups: List of pingroups for this function. + * @ngroups: Number of entries in @groups. + */ +struct amdisp_function { + const char *name; + const char * const *groups; + unsigned int ngroups; +}; + +#define FUNCTION(fname) \ + [mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct amdisp_function amdisp_functions[] = { + FUNCTION(gpio), +}; + +/** + * struct amdisp_pingroup - a pinmux group + * @name: Name of the pinmux group. + * @pins: List of pins for this group. + * @npins: Number of entries in @pins. + * @funcs: List of functions belongs to this group. + * @nfuncs: Number of entries in @funcs. + * @offset: Group offset in amdisp pinmux groups. + */ +struct amdisp_pingroup { + const char *name; + const unsigned int *pins; + unsigned int npins; + unsigned int *funcs; + unsigned int nfuncs; + unsigned int offset; +}; + +#define PINGROUP(id, f0) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + mux_##f0, \ + }, \ + .nfuncs = 1, \ + .offset = id, \ + } + +static const struct amdisp_pingroup amdisp_groups[] = { + PINGROUP(0, gpio), + PINGROUP(1, gpio), + PINGROUP(2, gpio), +}; diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index d73004b4a45e..3cfbcaee9e65 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -40,6 +40,7 @@ /* Port Select configures the port */ #define CY8C95X0_PORTSEL 0x18 + /* Port settings, write PORTSEL first */ #define CY8C95X0_INTMASK 0x19 #define CY8C95X0_SELPWM 0x1A @@ -53,6 +54,9 @@ #define CY8C95X0_DRV_PP_FAST 0x21 #define CY8C95X0_DRV_PP_SLOW 0x22 #define CY8C95X0_DRV_HIZ 0x23 + +/* Internal device configuration */ +#define CY8C95X0_ENABLE_WDE 0x2D #define CY8C95X0_DEVID 0x2E #define CY8C95X0_WATCHDOG 0x2F #define CY8C95X0_COMMAND 0x30 @@ -137,7 +141,7 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = { * @irq_trig_low: I/O bits affected by a low voltage level * @irq_trig_high: I/O bits affected by a high voltage level * @push_pull: I/O bits configured as push pull driver - * @shiftmask: Mask used to compensate for Gport2 width + * @map: Mask used to compensate for Gport2 width * @nport: Number of Gports in this chip * @gpio_chip: gpiolib chip * @driver_data: private driver data @@ -158,7 +162,7 @@ struct cy8c95x0_pinctrl { DECLARE_BITMAP(irq_trig_low, MAX_LINE); DECLARE_BITMAP(irq_trig_high, MAX_LINE); DECLARE_BITMAP(push_pull, MAX_LINE); - DECLARE_BITMAP(shiftmask, MAX_LINE); + DECLARE_BITMAP(map, MAX_LINE); unsigned int nport; struct gpio_chip gpio_chip; unsigned long driver_data; @@ -310,9 +314,6 @@ static const char * const cy8c95x0_groups[] = { "gp77", }; -static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip, - unsigned int pin, bool input); - static inline u8 cypress_get_port(struct cy8c95x0_pinctrl *chip, unsigned int pin) { /* Account for GPORT2 which only has 4 bits */ @@ -477,20 +478,14 @@ static const struct regmap_config cy8c9520_i2c_regmap = { #endif }; -static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, - unsigned int reg, - unsigned int port, - unsigned int mask, - unsigned int val, - bool *change, bool async, - bool force) +/* Caller should never modify PORTSEL directly */ +static int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, + unsigned int reg, unsigned int port, + unsigned int mask, unsigned int val, + bool *change, bool async, bool force) { int ret, off, i; - /* Caller should never modify PORTSEL directly */ - if (reg == CY8C95X0_PORTSEL) - return -EINVAL; - /* Registers behind the PORTSEL mux have their own range in regmap */ if (cy8c95x0_muxed_register(reg)) { off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port); @@ -507,7 +502,8 @@ static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip if (ret < 0) return ret; - /* Mimic what hardware does and update the cache when a WC bit is written. + /* + * Mimic what hardware does and update the cache when a WC bit is written. * Allows to mark the registers as non-volatile and reduces I/O cycles. */ if (cy8c95x0_wc_register(reg) && (mask & val)) { @@ -523,7 +519,7 @@ static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip regcache_cache_only(chip->regmap, false); } - return ret; + return 0; } /** @@ -575,12 +571,13 @@ static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned i } /** - * cy8c95x0_regmap_read() - reads a register using the regmap cache + * cy8c95x0_regmap_read_bits() - reads a register using the regmap cache * @chip: The pinctrl to work on * @reg: The register to read from. Can be direct access or muxed register. * @port: The port to be used for muxed registers or quick path direct access * registers. Otherwise unused. - * @read_val: Value read from hardware or cache + * @mask: Bitmask to apply + * @val: Value read from hardware or cache * * This function handles the register reads from the direct access registers and * the muxed registers while caching all register accesses, internally handling @@ -590,10 +587,12 @@ static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned i * * Return: 0 for successful request, else a corresponding error value */ -static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg, - unsigned int port, unsigned int *read_val) +static int cy8c95x0_regmap_read_bits(struct cy8c95x0_pinctrl *chip, unsigned int reg, + unsigned int port, unsigned int mask, unsigned int *val) { - int off, ret; + unsigned int off; + unsigned int tmp; + int ret; /* Registers behind the PORTSEL mux have their own range in regmap */ if (cy8c95x0_muxed_register(reg)) { @@ -605,11 +604,14 @@ static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg, else off = reg; } - guard(mutex)(&chip->i2c_lock); - ret = regmap_read(chip->regmap, off, read_val); + scoped_guard(mutex, &chip->i2c_lock) + ret = regmap_read(chip->regmap, off, &tmp); + if (ret) + return ret; - return ret; + *val = tmp & mask; + return 0; } static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, @@ -617,26 +619,18 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, { DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); + unsigned long bits, offset; int write_val; - u8 bits; int ret; /* Add the 4 bit gap of Gport2 */ - bitmap_andnot(tmask, mask, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tmask, tmask, 4, MAX_LINE); - bitmap_replace(tmask, tmask, mask, chip->shiftmask, BANK_SZ * 3); - - bitmap_andnot(tval, val, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tval, tval, 4, MAX_LINE); - bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3); - - for (unsigned int i = 0; i < chip->nport; i++) { - /* Skip over unused banks */ - bits = bitmap_get_value8(tmask, i * BANK_SZ); - if (!bits) - continue; + bitmap_scatter(tmask, mask, chip->map, MAX_LINE); + bitmap_scatter(tval, val, chip->map, MAX_LINE); + + for_each_set_clump8(offset, bits, tmask, chip->tpin) { + unsigned int i = offset / 8; - write_val = bitmap_get_value8(tval, i * BANK_SZ); + write_val = bitmap_get_value8(tval, offset); ret = cy8c95x0_regmap_update_bits(chip, reg, i, bits, write_val); if (ret < 0) { @@ -653,40 +647,54 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, { DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); - DECLARE_BITMAP(tmp, MAX_LINE); - int read_val; - u8 bits; + unsigned long bits, offset; + unsigned int read_val; int ret; /* Add the 4 bit gap of Gport2 */ - bitmap_andnot(tmask, mask, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tmask, tmask, 4, MAX_LINE); - bitmap_replace(tmask, tmask, mask, chip->shiftmask, BANK_SZ * 3); - - bitmap_andnot(tval, val, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tval, tval, 4, MAX_LINE); - bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3); - - for (unsigned int i = 0; i < chip->nport; i++) { - /* Skip over unused banks */ - bits = bitmap_get_value8(tmask, i * BANK_SZ); - if (!bits) - continue; + bitmap_scatter(tmask, mask, chip->map, MAX_LINE); + bitmap_scatter(tval, val, chip->map, MAX_LINE); + + for_each_set_clump8(offset, bits, tmask, chip->tpin) { + unsigned int i = offset / 8; - ret = cy8c95x0_regmap_read(chip, reg, i, &read_val); + ret = cy8c95x0_regmap_read_bits(chip, reg, i, bits, &read_val); if (ret < 0) { dev_err(chip->dev, "failed reading register %d, port %u: err %d\n", reg, i, ret); return ret; } - read_val &= bits; - read_val |= bitmap_get_value8(tval, i * BANK_SZ) & ~bits; - bitmap_set_value8(tval, read_val, i * BANK_SZ); + read_val |= bitmap_get_value8(tval, offset) & ~bits; + bitmap_set_value8(tval, read_val, offset); } /* Fill the 4 bit gap of Gport2 */ - bitmap_shift_right(tmp, tval, 4, MAX_LINE); - bitmap_replace(val, tmp, tval, chip->shiftmask, MAX_LINE); + bitmap_gather(val, tval, chip->map, MAX_LINE); + + return 0; +} + +static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip, unsigned int pin, bool input) +{ + u8 port = cypress_get_port(chip, pin); + u8 bit = cypress_get_pin_mask(chip, pin); + int ret; + + ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, input ? bit : 0); + if (ret) + return ret; + + /* + * Disable driving the pin by forcing it to HighZ. Only setting + * the direction register isn't sufficient in Push-Pull mode. + */ + if (input && test_bit(pin, chip->push_pull)) { + ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DRV_HIZ, port, bit, bit); + if (ret) + return ret; + + __clear_bit(pin, chip->push_pull); + } return 0; } @@ -717,10 +725,10 @@ static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off) struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc); u8 port = cypress_get_port(chip, off); u8 bit = cypress_get_pin_mask(chip, off); - u32 reg_val; + unsigned int reg_val; int ret; - ret = cy8c95x0_regmap_read(chip, CY8C95X0_INPUT, port, ®_val); + ret = cy8c95x0_regmap_read_bits(chip, CY8C95X0_INPUT, port, bit, ®_val); if (ret < 0) { /* * NOTE: @@ -731,7 +739,7 @@ static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off) return 0; } - return !!(reg_val & bit); + return reg_val ? 1 : 0; } static void cy8c95x0_gpio_set_value(struct gpio_chip *gc, unsigned int off, @@ -749,14 +757,14 @@ static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off) struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc); u8 port = cypress_get_port(chip, off); u8 bit = cypress_get_pin_mask(chip, off); - u32 reg_val; + unsigned int reg_val; int ret; - ret = cy8c95x0_regmap_read(chip, CY8C95X0_DIRECTION, port, ®_val); + ret = cy8c95x0_regmap_read_bits(chip, CY8C95X0_DIRECTION, port, bit, ®_val); if (ret < 0) return ret; - if (reg_val & bit) + if (reg_val) return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_OUT; @@ -769,8 +777,8 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, enum pin_config_param param = pinconf_to_config_param(*config); u8 port = cypress_get_port(chip, off); u8 bit = cypress_get_pin_mask(chip, off); + unsigned int reg_val; unsigned int reg; - u32 reg_val; u16 arg = 0; int ret; @@ -827,16 +835,16 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, * Writing 1 to one of the drive mode registers will automatically * clear conflicting set bits in the other drive mode registers. */ - ret = cy8c95x0_regmap_read(chip, reg, port, ®_val); + ret = cy8c95x0_regmap_read_bits(chip, reg, port, bit, ®_val); if (ret < 0) return ret; - if (reg_val & bit) + if (reg_val) arg = 1; if (param == PIN_CONFIG_OUTPUT_ENABLE) arg = !arg; - *config = pinconf_to_config_packed(param, (u16)arg); + *config = pinconf_to_config_packed(param, arg); return 0; } @@ -1095,7 +1103,7 @@ static irqreturn_t cy8c95x0_irq_handler(int irq, void *devid) if (!ret) return IRQ_RETVAL(0); - ret = 0; + ret = false; for_each_set_bit(level, pending, MAX_LINE) { /* Already accounted for 4bit gap in GPort2 */ nested_irq = irq_find_mapping(gc->irq.domain, level); @@ -1114,7 +1122,7 @@ static irqreturn_t cy8c95x0_irq_handler(int irq, void *devid) else handle_nested_irq(nested_irq); - ret = 1; + ret = true; } return IRQ_RETVAL(ret); @@ -1248,32 +1256,6 @@ static int cy8c95x0_gpio_request_enable(struct pinctrl_dev *pctldev, return cy8c95x0_set_mode(chip, pin, false); } -static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip, - unsigned int pin, bool input) -{ - u8 port = cypress_get_port(chip, pin); - u8 bit = cypress_get_pin_mask(chip, pin); - int ret; - - ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, input ? bit : 0); - if (ret) - return ret; - - /* - * Disable driving the pin by forcing it to HighZ. Only setting - * the direction register isn't sufficient in Push-Pull mode. - */ - if (input && test_bit(pin, chip->push_pull)) { - ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DRV_HIZ, port, bit, bit); - if (ret) - return ret; - - __clear_bit(pin, chip->push_pull); - } - - return 0; -} - static int cy8c95x0_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int pin, bool input) @@ -1305,7 +1287,7 @@ static int cy8c95x0_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *configs, unsigned int num_configs) { struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev); - int ret = 0; + int ret; int i; for (i = 0; i < num_configs; i++) { @@ -1314,7 +1296,7 @@ static int cy8c95x0_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return ret; } - return ret; + return 0; } static const struct pinconf_ops cy8c95x0_pinconf_ops = { @@ -1486,8 +1468,11 @@ static int cy8c95x0_probe(struct i2c_client *client) return PTR_ERR(chip->regmap); bitmap_zero(chip->push_pull, MAX_LINE); - bitmap_zero(chip->shiftmask, MAX_LINE); - bitmap_set(chip->shiftmask, 0, 20); + + /* Setup HW pins mapping */ + bitmap_fill(chip->map, MAX_LINE); + bitmap_clear(chip->map, 20, 4); + mutex_init(&chip->i2c_lock); if (dmi_first_match(cy8c95x0_dmi_acpi_irq_info)) { diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index bc7ee54e062b..a9e48eac15f6 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -3,7 +3,7 @@ * Ingenic SoCs pinctrl driver * * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net> - * Copyright (c) 2017, 2019 Paul Boddie <paul@boddie.org.uk> + * Copyright (c) 2017, 2019, 2020, 2023 Paul Boddie <paul@boddie.org.uk> * Copyright (c) 2019, 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> */ @@ -58,6 +58,8 @@ #define JZ4770_GPIO_FLAG 0x50 #define JZ4770_GPIO_PEN 0x70 +#define X1600_GPIO_PU 0x80 + #define X1830_GPIO_PEL 0x110 #define X1830_GPIO_PEH 0x120 #define X1830_GPIO_SR 0x150 @@ -112,6 +114,7 @@ enum jz_version { ID_JZ4780, ID_X1000, ID_X1500, + ID_X1600, ID_X1830, ID_X2000, ID_X2100, @@ -162,6 +165,7 @@ static const unsigned long enabled_socs = IS_ENABLED(CONFIG_MACH_JZ4780) << ID_JZ4780 | IS_ENABLED(CONFIG_MACH_X1000) << ID_X1000 | IS_ENABLED(CONFIG_MACH_X1500) << ID_X1500 | + IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; @@ -206,6 +210,14 @@ static int jz4730_nand_cs5_pins[] = { 0x57, }; static int jz4730_pwm_pwm0_pins[] = { 0x5e, }; static int jz4730_pwm_pwm1_pins[] = { 0x5f, }; +static int jz4730_mii_pins[] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x19, 0x7a, 0x1b, 0x7c, }; + +static int jz4730_i2s_mclk_pins[] = { 0x44, }; +static int jz4730_i2s_acreset_pins[] = { 0x45, }; +static int jz4730_i2s_data_pins[] = { 0x46, 0x47, }; +static int jz4730_i2s_clock_pins[] = { 0x4d, 0x4e, }; + static u8 jz4730_lcd_8bit_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, }; static const struct group_desc jz4730_groups[] = { @@ -227,6 +239,12 @@ static const struct group_desc jz4730_groups[] = { INGENIC_PIN_GROUP("nand-cs5", jz4730_nand_cs5, 1), INGENIC_PIN_GROUP("pwm0", jz4730_pwm_pwm0, 1), INGENIC_PIN_GROUP("pwm1", jz4730_pwm_pwm1, 1), + INGENIC_PIN_GROUP("mii", jz4730_mii, 1), + INGENIC_PIN_GROUP("i2s-mclk-out", jz4730_i2s_mclk, 1), + INGENIC_PIN_GROUP("i2s-acreset", jz4730_i2s_acreset, 1), + INGENIC_PIN_GROUP("i2s-data", jz4730_i2s_data, 1), + INGENIC_PIN_GROUP("i2s-master", jz4730_i2s_clock, 1), + INGENIC_PIN_GROUP("i2s-slave", jz4730_i2s_clock, 2), }; static const char *jz4730_mmc_groups[] = { "mmc-1bit", "mmc-4bit", }; @@ -242,6 +260,8 @@ static const char *jz4730_nand_groups[] = { }; static const char *jz4730_pwm0_groups[] = { "pwm0", }; static const char *jz4730_pwm1_groups[] = { "pwm1", }; +static const char *jz4730_mii_groups[] = { "mii", }; +static const char *jz4730_i2s_groups[] = { "i2s-data", "i2s-master", "i2s-slave", }; static const struct function_desc jz4730_functions[] = { INGENIC_PIN_FUNCTION("mmc", jz4730_mmc), @@ -253,6 +273,8 @@ static const struct function_desc jz4730_functions[] = { INGENIC_PIN_FUNCTION("nand", jz4730_nand), INGENIC_PIN_FUNCTION("pwm0", jz4730_pwm0), INGENIC_PIN_FUNCTION("pwm1", jz4730_pwm1), + INGENIC_PIN_FUNCTION("mii", jz4730_mii), + INGENIC_PIN_FUNCTION("i2s", jz4730_i2s), }; static const struct ingenic_chip_info jz4730_chip_info = { @@ -2351,6 +2373,233 @@ static const struct ingenic_chip_info x1500_chip_info = { .access_table = &x1000_access_table, }; +static const u32 x1600_pull_ups[4] = { + 0xffffffff, 0xdffbf7bf, 0x987e0000, 0x0000003f, +}; + +static const u32 x1600_pull_downs[4] = { + 0x00000000, 0x00000000, 0x07000007, 0x00000000, +}; + +static int x1600_uart0_data_pins[] = { 0x27, 0x28, }; +static int x1600_uart0_hwflow_pins[] = { 0x29, 0x2a, }; +static int x1600_uart1_data_pins[] = { 0x23, 0x22, }; +static int x1600_uart1_hwflow_pins[] = { 0x25, 0x24, }; +static int x1600_uart2_data_a_pins[] = { 0x1f, 0x1e, }; +static int x1600_uart2_data_b_pins[] = { 0x21, 0x20, }; +static int x1600_uart3_data_b_pins[] = { 0x25, 0x24, }; +static int x1600_uart3_data_d_pins[] = { 0x65, 0x64, }; +static int x1600_sfc_pins[] = { 0x53, 0x54, 0x55, 0x56, 0x51, 0x52, 0x24, }; +static int x1600_ssi_dt_a_pins[] = { 0x1e, }; +static int x1600_ssi_dt_b_pins[] = { 0x2d, }; +static int x1600_ssi_dr_a_pins[] = { 0x1d, }; +static int x1600_ssi_dr_b_pins[] = { 0x2e, }; +static int x1600_ssi_clk_a_pins[] = { 0x1f, }; +static int x1600_ssi_clk_b_pins[] = { 0x2c, }; +static int x1600_ssi_ce0_a_pins[] = { 0x1c, }; +static int x1600_ssi_ce0_b_pins[] = { 0x31, }; +static int x1600_ssi_ce1_a_pins[] = { 0x22, }; +static int x1600_ssi_ce1_b_pins[] = { 0x30, }; +static int x1600_mmc0_1bit_b_pins[] = { 0x2c, 0x2d, 0x2e, }; +static int x1600_mmc0_4bit_b_pins[] = { 0x2f, 0x30, 0x31, }; +static int x1600_mmc0_1bit_c_pins[] = { 0x51, 0x53, 0x54, }; +static int x1600_mmc0_4bit_c_pins[] = { 0x56, 0x55, 0x52, }; +static int x1600_mmc1_1bit_pins[] = { 0x60, 0x61, 0x62, }; +static int x1600_mmc1_4bit_pins[] = { 0x63, 0x64, 0x65, }; +static int x1600_i2c0_a_pins[] = { 0x1d, 0x1c, }; +static int x1600_i2c0_b_pins[] = { 0x3f, 0x3e, }; +static int x1600_i2c1_b_15_pins[] = { 0x30, 0x2f, }; +static int x1600_i2c1_b_19_pins[] = { 0x34, 0x33, }; +static int x1600_i2s_data_tx_pins[] = { 0x39, }; +static int x1600_i2s_data_rx_pins[] = { 0x35, }; +static int x1600_i2s_clk_rx_pins[] = { 0x37, 0x38, }; +static int x1600_i2s_clk_tx_pins[] = { 0x3b, 0x3c, }; +static int x1600_i2s_sysclk_pins[] = { 0x36, 0x3a, }; + +static int x1600_cim_pins[] = { + 0x14, 0x16, 0x15, 0x18, 0x13, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +}; + +static int x1600_slcd_8bit_pins[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x17, 0x19, 0x1a, 0x1b, +}; + +static int x1600_slcd_16bit_pins[] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +}; + +static int x1600_lcd_16bit_pins[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x18, 0x19, 0x1a, 0x1b, +}; + +static int x1600_lcd_18bit_pins[] = { + 0x10, 0x11, +}; + +static int x1600_lcd_24bit_pins[] = { + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, +}; + +static int x1600_pwm_pwm0_pins[] = { 0x40, }; +static int x1600_pwm_pwm1_pins[] = { 0x41, }; +static int x1600_pwm_pwm2_pins[] = { 0x42, }; +static int x1600_pwm_pwm3_pins[] = { 0x58, }; +static int x1600_pwm_pwm4_pins[] = { 0x59, }; +static int x1600_pwm_pwm5_b_pins[] = { 0x33, }; +static int x1600_pwm_pwm5_c_pins[] = { 0x5a, }; +static int x1600_pwm_pwm6_b9_pins[] = { 0x29, }; +static int x1600_pwm_pwm6_b20_pins[] = { 0x34, }; +static int x1600_pwm_pwm7_b10_pins[] = { 0x2a, }; +static int x1600_pwm_pwm7_b21_pins[] = { 0x35, }; + +static int x1600_mac_pins[] = { + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, +}; + +static int x1600_sfc_funcs[] = { 0, 0, 0, 0, 0, 0, 2, }; + +static const struct group_desc x1600_groups[] = { + INGENIC_PIN_GROUP("uart0-data", x1600_uart0_data, 0), + INGENIC_PIN_GROUP("uart0-hwflow", x1600_uart0_hwflow, 0), + INGENIC_PIN_GROUP("uart1-data", x1600_uart1_data, 1), + INGENIC_PIN_GROUP("uart1-hwflow", x1600_uart1_hwflow, 1), + INGENIC_PIN_GROUP("uart2-data-a", x1600_uart2_data_a, 2), + INGENIC_PIN_GROUP("uart2-data-b", x1600_uart2_data_b, 1), + INGENIC_PIN_GROUP("uart3-data-b", x1600_uart3_data_b, 0), + INGENIC_PIN_GROUP("uart3-data-d", x1600_uart3_data_d, 2), + INGENIC_PIN_GROUP_FUNCS("sfc", x1600_sfc, x1600_sfc_funcs), + INGENIC_PIN_GROUP("ssi-dt-a", x1600_ssi_dt_a, 0), + INGENIC_PIN_GROUP("ssi-dt-b", x1600_ssi_dt_b, 1), + INGENIC_PIN_GROUP("ssi-dr-a", x1600_ssi_dr_a, 0), + INGENIC_PIN_GROUP("ssi-dr-b", x1600_ssi_dr_b, 1), + INGENIC_PIN_GROUP("ssi-clk-a", x1600_ssi_clk_a, 0), + INGENIC_PIN_GROUP("ssi-clk-b", x1600_ssi_clk_b, 1), + INGENIC_PIN_GROUP("ssi-ce0-a", x1600_ssi_ce0_a, 0), + INGENIC_PIN_GROUP("ssi-ce0-b", x1600_ssi_ce0_b, 1), + INGENIC_PIN_GROUP("ssi-ce1-a", x1600_ssi_ce1_a, 2), + INGENIC_PIN_GROUP("ssi-ce1-b", x1600_ssi_ce1_b, 1), + INGENIC_PIN_GROUP("mmc0-1bit-b", x1600_mmc0_1bit_b, 0), + INGENIC_PIN_GROUP("mmc0-4bit-b", x1600_mmc0_4bit_b, 0), + INGENIC_PIN_GROUP("mmc0-1bit-c", x1600_mmc0_1bit_c, 1), + INGENIC_PIN_GROUP("mmc0-4bit-c", x1600_mmc0_4bit_c, 1), + INGENIC_PIN_GROUP("mmc1-1bit", x1600_mmc1_1bit, 0), + INGENIC_PIN_GROUP("mmc1-4bit", x1600_mmc1_4bit, 0), + INGENIC_PIN_GROUP("i2c0-data-a", x1600_i2c0_a, 2), + INGENIC_PIN_GROUP("i2c0-data-b", x1600_i2c0_b, 0), + INGENIC_PIN_GROUP("i2c1-data-b-15", x1600_i2c1_b_15, 2), + INGENIC_PIN_GROUP("i2c1-data-b-19", x1600_i2c1_b_19, 0), + INGENIC_PIN_GROUP("i2s-data-tx", x1600_i2s_data_tx, 0), + INGENIC_PIN_GROUP("i2s-data-rx", x1600_i2s_data_rx, 0), + INGENIC_PIN_GROUP("i2s-clk-rx", x1600_i2s_clk_rx, 0), + INGENIC_PIN_GROUP("i2s-clk-tx", x1600_i2s_clk_tx, 0), + INGENIC_PIN_GROUP("i2s-sysclk", x1600_i2s_sysclk, 0), + INGENIC_PIN_GROUP("cim-data", x1600_cim, 2), + INGENIC_PIN_GROUP("slcd-8bit", x1600_slcd_8bit, 1), + INGENIC_PIN_GROUP("slcd-16bit", x1600_slcd_16bit, 1), + INGENIC_PIN_GROUP("lcd-16bit", x1600_lcd_16bit, 0), + INGENIC_PIN_GROUP("lcd-18bit", x1600_lcd_18bit, 0), + INGENIC_PIN_GROUP("lcd-24bit", x1600_lcd_24bit, 0), + INGENIC_PIN_GROUP("pwm0", x1600_pwm_pwm0, 0), + INGENIC_PIN_GROUP("pwm1", x1600_pwm_pwm1, 0), + INGENIC_PIN_GROUP("pwm2", x1600_pwm_pwm2, 0), + INGENIC_PIN_GROUP("pwm3", x1600_pwm_pwm3, 1), + INGENIC_PIN_GROUP("pwm4", x1600_pwm_pwm4, 1), + INGENIC_PIN_GROUP("pwm5-b", x1600_pwm_pwm5_b, 2), + INGENIC_PIN_GROUP("pwm5-c", x1600_pwm_pwm5_c, 1), + INGENIC_PIN_GROUP("pwm6-b9", x1600_pwm_pwm6_b9, 1), + INGENIC_PIN_GROUP("pwm6-b20", x1600_pwm_pwm6_b20, 2), + INGENIC_PIN_GROUP("pwm7-b10", x1600_pwm_pwm7_b10, 1), + INGENIC_PIN_GROUP("pwm7-b21", x1600_pwm_pwm7_b21, 2), + INGENIC_PIN_GROUP("mac", x1600_mac, 1), +}; + +static const char * const x1600_uart0_groups[] = { "uart0-data", "uart0-hwflow", }; +static const char * const x1600_uart1_groups[] = { "uart1-data", "uart1-hwflow", }; +static const char * const x1600_uart2_groups[] = { "uart2-data-a", "uart2-data-b", }; +static const char * const x1600_uart3_groups[] = { "uart3-data-b", "uart3-data-d", }; + +static const char * const x1600_sfc_groups[] = { "sfc", }; + +static const char * const x1600_ssi_groups[] = { + "ssi-dt-a", "ssi-dt-b", + "ssi-dr-a", "ssi-dr-b", + "ssi-clk-a", "ssi-clk-b", + "ssi-ce0-a", "ssi-ce0-b", + "ssi-ce1-a", "ssi-ce1-b", +}; + +static const char * const x1600_mmc0_groups[] = { "mmc0-1bit-b", "mmc0-4bit-b", + "mmc0-1bit-c", "mmc0-4bit-c", +}; + +static const char * const x1600_mmc1_groups[] = { "mmc1-1bit", "mmc1-4bit", }; + +static const char * const x1600_i2c0_groups[] = { "i2c0-data-a", "i2c0-data-b", }; +static const char * const x1600_i2c1_groups[] = { "i2c1-data-b-15", "i2c1-data-b-19", }; + +static const char * const x1600_i2s_groups[] = { + "i2s-data-tx", "i2s-data-rx", "i2s-clk-rx", "i2s-clk-tx", "i2s-sysclk", +}; + +static const char * const x1600_cim_groups[] = { "cim-data", }; + +static const char * const x1600_lcd_groups[] = { "slcd-8bit", "slcd-16bit", + "lcd-16bit", "lcd-18bit", "lcd-24bit", "lcd-no-pins", +}; + +static const char * const x1600_pwm0_groups[] = { "pwm0", }; +static const char * const x1600_pwm1_groups[] = { "pwm1", }; +static const char * const x1600_pwm2_groups[] = { "pwm2", }; +static const char * const x1600_pwm3_groups[] = { "pwm3", }; +static const char * const x1600_pwm4_groups[] = { "pwm4", }; +static const char * const x1600_pwm5_groups[] = { "pwm5-b", "pwm5-c", }; +static const char * const x1600_pwm6_groups[] = { "pwm6-b9", "pwm6-b20", }; +static const char * const x1600_pwm7_groups[] = { "pwm7-b10", "pwm7-b21", }; + +static const char * const x1600_mac_groups[] = { "mac", }; + +static const struct function_desc x1600_functions[] = { + INGENIC_PIN_FUNCTION("uart0", x1600_uart0), + INGENIC_PIN_FUNCTION("uart1", x1600_uart1), + INGENIC_PIN_FUNCTION("uart2", x1600_uart2), + INGENIC_PIN_FUNCTION("uart3", x1600_uart3), + INGENIC_PIN_FUNCTION("sfc", x1600_sfc), + INGENIC_PIN_FUNCTION("ssi", x1600_ssi), + INGENIC_PIN_FUNCTION("mmc0", x1600_mmc0), + INGENIC_PIN_FUNCTION("mmc1", x1600_mmc1), + INGENIC_PIN_FUNCTION("i2c0", x1600_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x1600_i2c1), + INGENIC_PIN_FUNCTION("i2s", x1600_i2s), + INGENIC_PIN_FUNCTION("cim", x1600_cim), + INGENIC_PIN_FUNCTION("lcd", x1600_lcd), + INGENIC_PIN_FUNCTION("pwm0", x1600_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x1600_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x1600_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x1600_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x1600_pwm4), + INGENIC_PIN_FUNCTION("pwm5", x1600_pwm5), + INGENIC_PIN_FUNCTION("pwm6", x1600_pwm6), + INGENIC_PIN_FUNCTION("pwm7", x1600_pwm7), + INGENIC_PIN_FUNCTION("mac", x1600_mac), +}; + +static const struct ingenic_chip_info x1600_chip_info = { + .num_chips = 4, + .reg_offset = 0x100, + .version = ID_X1600, + .groups = x1600_groups, + .num_groups = ARRAY_SIZE(x1600_groups), + .functions = x1600_functions, + .num_functions = ARRAY_SIZE(x1600_functions), + .pull_ups = x1600_pull_ups, + .pull_downs = x1600_pull_downs, + .access_table = &x1000_access_table, +}; + static const u32 x1830_pull_ups[4] = { 0x5fdfffc0, 0xffffefff, 0x1ffffbff, 0x0fcff3fc, }; @@ -3860,7 +4109,9 @@ static int ingenic_pinconf_get(struct pinctrl_dev *pctldev, pulldown = (bias == GPIO_PULL_DOWN) && (jzpc->info->pull_downs[offt] & BIT(idx)); } else { - if (is_soc_or_above(jzpc, ID_JZ4770)) + if (is_soc_or_above(jzpc, ID_X1600)) + pull = ingenic_get_pin_config(jzpc, pin, X1600_GPIO_PU); + else if (is_soc_or_above(jzpc, ID_JZ4770)) pull = !ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PEN); else if (is_soc_or_above(jzpc, ID_JZ4740)) pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS); @@ -3959,6 +4210,8 @@ static void ingenic_set_bias(struct ingenic_pinctrl *jzpc, REG_SET(X1830_GPIO_PEH), bias << idxh); } + } else if (is_soc_or_above(jzpc, ID_X1600)) { + ingenic_config_pin(jzpc, pin, X1600_GPIO_PU, bias); } else if (is_soc_or_above(jzpc, ID_JZ4770)) { ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PEN, !bias); } else if (is_soc_or_above(jzpc, ID_JZ4740)) { @@ -4150,6 +4403,7 @@ static const struct of_device_id ingenic_gpio_of_matches[] __initconst = { { .compatible = "ingenic,jz4775-gpio" }, { .compatible = "ingenic,jz4780-gpio" }, { .compatible = "ingenic,x1000-gpio" }, + { .compatible = "ingenic,x1600-gpio" }, { .compatible = "ingenic,x1830-gpio" }, { .compatible = "ingenic,x2000-gpio" }, { .compatible = "ingenic,x2100-gpio" }, @@ -4398,6 +4652,10 @@ static const struct of_device_id ingenic_pinctrl_of_matches[] = { .data = IF_ENABLED(CONFIG_MACH_X1500, &x1500_chip_info) }, { + .compatible = "ingenic,x1600-pinctrl", + .data = IF_ENABLED(CONFIG_MACH_X1600, &x1600_chip_info) + }, + { .compatible = "ingenic,x1830-pinctrl", .data = IF_ENABLED(CONFIG_MACH_X1830, &x1830_chip_info) }, diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index b96e6368a956..4d1f41488017 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -382,6 +382,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) { struct mcp23s08 *mcp = data; int intcap, intcon, intf, i, gpio, gpio_orig, intcap_mask, defval, gpinten; + bool need_unmask = false; unsigned long int enabled_interrupts; unsigned int child_irq; bool intf_set, intcap_changed, gpio_bit_changed, @@ -396,9 +397,6 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) goto unlock; } - if (mcp_read(mcp, MCP_INTCAP, &intcap)) - goto unlock; - if (mcp_read(mcp, MCP_INTCON, &intcon)) goto unlock; @@ -408,6 +406,16 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) if (mcp_read(mcp, MCP_DEFVAL, &defval)) goto unlock; + /* Mask level interrupts to avoid their immediate reactivation after clearing */ + if (intcon) { + need_unmask = true; + if (mcp_write(mcp, MCP_GPINTEN, gpinten & ~intcon)) + goto unlock; + } + + if (mcp_read(mcp, MCP_INTCAP, &intcap)) + goto unlock; + /* This clears the interrupt(configurable on S18) */ if (mcp_read(mcp, MCP_GPIO, &gpio)) goto unlock; @@ -470,9 +478,18 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) } } + if (need_unmask) { + mutex_lock(&mcp->lock); + goto unlock; + } + return IRQ_HANDLED; unlock: + if (need_unmask) + if (mcp_write(mcp, MCP_GPINTEN, gpinten)) + dev_err(mcp->chip.parent, "can't unmask GPINTEN\n"); + mutex_unlock(&mcp->lock); return IRQ_HANDLED; } diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 53408344927a..8c50e0091b32 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -1393,12 +1393,6 @@ static int pistachio_gpio_register(struct pistachio_pinctrl *pctl) dev_err(pctl->dev, "Failed to retrieve IRQ for bank %u\n", i); goto err; } - if (!ret) { - fwnode_handle_put(child); - dev_err(pctl->dev, "No IRQ for bank %u\n", i); - ret = -EINVAL; - goto err; - } irq = ret; bank = &pctl->gpio_banks[i]; diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 15145882950f..930c454e0cec 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -2003,6 +2003,115 @@ static int rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, return 0; } +#define RK3528_DRV_BITS_PER_PIN 8 +#define RK3528_DRV_PINS_PER_REG 2 +#define RK3528_DRV_GPIO0_OFFSET 0x100 +#define RK3528_DRV_GPIO1_OFFSET 0x20120 +#define RK3528_DRV_GPIO2_OFFSET 0x30160 +#define RK3528_DRV_GPIO3_OFFSET 0x20190 +#define RK3528_DRV_GPIO4_OFFSET 0x101C0 + +static int rk3528_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *regmap = info->regmap_base; + + if (bank->bank_num == 0) + *reg = RK3528_DRV_GPIO0_OFFSET; + else if (bank->bank_num == 1) + *reg = RK3528_DRV_GPIO1_OFFSET; + else if (bank->bank_num == 2) + *reg = RK3528_DRV_GPIO2_OFFSET; + else if (bank->bank_num == 3) + *reg = RK3528_DRV_GPIO3_OFFSET; + else if (bank->bank_num == 4) + *reg = RK3528_DRV_GPIO4_OFFSET; + else + dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); + + *reg += ((pin_num / RK3528_DRV_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_DRV_PINS_PER_REG; + *bit *= RK3528_DRV_BITS_PER_PIN; + + return 0; +} + +#define RK3528_PULL_BITS_PER_PIN 2 +#define RK3528_PULL_PINS_PER_REG 8 +#define RK3528_PULL_GPIO0_OFFSET 0x200 +#define RK3528_PULL_GPIO1_OFFSET 0x20210 +#define RK3528_PULL_GPIO2_OFFSET 0x30220 +#define RK3528_PULL_GPIO3_OFFSET 0x20230 +#define RK3528_PULL_GPIO4_OFFSET 0x10240 + +static int rk3528_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *regmap = info->regmap_base; + + if (bank->bank_num == 0) + *reg = RK3528_PULL_GPIO0_OFFSET; + else if (bank->bank_num == 1) + *reg = RK3528_PULL_GPIO1_OFFSET; + else if (bank->bank_num == 2) + *reg = RK3528_PULL_GPIO2_OFFSET; + else if (bank->bank_num == 3) + *reg = RK3528_PULL_GPIO3_OFFSET; + else if (bank->bank_num == 4) + *reg = RK3528_PULL_GPIO4_OFFSET; + else + dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); + + *reg += ((pin_num / RK3528_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_PULL_PINS_PER_REG; + *bit *= RK3528_PULL_BITS_PER_PIN; + + return 0; +} + +#define RK3528_SMT_BITS_PER_PIN 1 +#define RK3528_SMT_PINS_PER_REG 8 +#define RK3528_SMT_GPIO0_OFFSET 0x400 +#define RK3528_SMT_GPIO1_OFFSET 0x20410 +#define RK3528_SMT_GPIO2_OFFSET 0x30420 +#define RK3528_SMT_GPIO3_OFFSET 0x20430 +#define RK3528_SMT_GPIO4_OFFSET 0x10440 + +static int rk3528_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, + struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *regmap = info->regmap_base; + + if (bank->bank_num == 0) + *reg = RK3528_SMT_GPIO0_OFFSET; + else if (bank->bank_num == 1) + *reg = RK3528_SMT_GPIO1_OFFSET; + else if (bank->bank_num == 2) + *reg = RK3528_SMT_GPIO2_OFFSET; + else if (bank->bank_num == 3) + *reg = RK3528_SMT_GPIO3_OFFSET; + else if (bank->bank_num == 4) + *reg = RK3528_SMT_GPIO4_OFFSET; + else + dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); + + *reg += ((pin_num / RK3528_SMT_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_SMT_PINS_PER_REG; + *bit *= RK3528_SMT_BITS_PER_PIN; + + return 0; +} + #define RK3562_DRV_BITS_PER_PIN 8 #define RK3562_DRV_PINS_PER_REG 2 #define RK3562_DRV_GPIO0_OFFSET 0x20070 @@ -2640,7 +2749,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, rmask_bits = RK3588_DRV_BITS_PER_PIN; ret = strength; goto config; - } else if (ctrl->type == RK3562 || + } else if (ctrl->type == RK3528 || + ctrl->type == RK3562 || ctrl->type == RK3568) { rmask_bits = RK3568_DRV_BITS_PER_PIN; ret = (1 << (strength + 1)) - 1; @@ -2785,6 +2895,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) case RK3328: case RK3368: case RK3399: + case RK3528: case RK3562: case RK3568: case RK3576: @@ -2846,6 +2957,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, case RK3328: case RK3368: case RK3399: + case RK3528: case RK3562: case RK3568: case RK3576: @@ -3115,6 +3227,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, case RK3328: case RK3368: case RK3399: + case RK3528: case RK3562: case RK3568: case RK3576: @@ -4237,6 +4350,49 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = { .drv_calc_reg = rk3399_calc_drv_reg_and_bit, }; +static struct rockchip_pin_bank rk3528_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0, 0, 0, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(1, 32, "gpio1", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20020, 0x20028, 0x20030, 0x20038), + PIN_BANK_IOMUX_FLAGS_OFFSET(2, 32, "gpio2", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x30040, 0, 0, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(3, 32, "gpio3", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20060, 0x20068, 0x20070, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(4, 32, "gpio4", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x10080, 0x10088, 0x10090, 0x10098), +}; + +static struct rockchip_pin_ctrl rk3528_pin_ctrl = { + .pin_banks = rk3528_pin_banks, + .nr_banks = ARRAY_SIZE(rk3528_pin_banks), + .label = "RK3528-GPIO", + .type = RK3528, + .pull_calc_reg = rk3528_calc_pull_reg_and_bit, + .drv_calc_reg = rk3528_calc_drv_reg_and_bit, + .schmitt_calc_reg = rk3528_calc_schmitt_reg_and_bit, +}; + static struct rockchip_pin_bank rk3562_pin_banks[] = { PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_WIDTH_4BIT, @@ -4404,6 +4560,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = { .data = &rk3368_pin_ctrl }, { .compatible = "rockchip,rk3399-pinctrl", .data = &rk3399_pin_ctrl }, + { .compatible = "rockchip,rk3528-pinctrl", + .data = &rk3528_pin_ctrl }, { .compatible = "rockchip,rk3562-pinctrl", .data = &rk3562_pin_ctrl }, { .compatible = "rockchip,rk3568-pinctrl", diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h index 87a20cec8e21..35cd38079d1e 100644 --- a/drivers/pinctrl/pinctrl-rockchip.h +++ b/drivers/pinctrl/pinctrl-rockchip.h @@ -196,6 +196,7 @@ enum rockchip_pinctrl_type { RK3328, RK3368, RK3399, + RK3528, RK3562, RK3568, RK3576, diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c index 9e34b92ff5f2..9fd7a8fb2bc4 100644 --- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c +++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c @@ -281,9 +281,8 @@ static int pxa2xx_build_functions(struct pxa_pinctrl *pctl) for (df = pctl->ppins[i].functions; df->name; df++) if (!pxa2xx_find_function(pctl, df->name, functions)) (functions + pctl->nfuncs++)->name = df->name; - pctl->functions = devm_kmemdup(pctl->dev, functions, - pctl->nfuncs * sizeof(*functions), - GFP_KERNEL); + pctl->functions = devm_kmemdup_array(pctl->dev, functions, pctl->nfuncs, + sizeof(*functions), GFP_KERNEL); if (!pctl->functions) return -ENOMEM; @@ -314,7 +313,8 @@ static int pxa2xx_build_groups(struct pxa_pinctrl *pctl) pctl->ppins[j].pin.name; func = pctl->functions + i; func->ngroups = ngroups; - func->groups = devm_kmemdup(pctl->dev, gtmp, ngroups * sizeof(*gtmp), GFP_KERNEL); + func->groups = devm_kmemdup_array(pctl->dev, gtmp, ngroups, + sizeof(*gtmp), GFP_KERNEL); if (!func->groups) return -ENOMEM; } diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm index 35f47660a56b..0bb44c9a4c06 100644 --- a/drivers/pinctrl/qcom/Kconfig.msm +++ b/drivers/pinctrl/qcom/Kconfig.msm @@ -138,10 +138,10 @@ config PINCTRL_MSM8916 Qualcomm TLMM block found on the Qualcomm 8916 platform. config PINCTRL_MSM8917 - tristate "Qualcomm 8917 pin controller driver" + tristate "Qualcomm 8917/8937 pin controller driver" help This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found on the Qualcomm MSM8917 platform. + Qualcomm TLMM block found on the Qualcomm MSM8917, MSM8937 platform. config PINCTRL_MSM8953 tristate "Qualcomm 8953 pin controller driver" @@ -437,4 +437,14 @@ config PINCTRL_X1E80100 Say Y here to compile statically, or M here to compile it as a module. If unsure, say N. +config PINCTRL_TLMM_TEST + tristate "Qualcomm TLMM test driver" + depends on ARM64 || COMPILE_TEST + depends on KUNIT + help + This driver provides test cases for the interrupt capabilities of + TLMM driver (pinctrl-msm). Specify a floating gpio to use for testing + using the module parameter "gpio" and execute the kunit suite. + If unsure, say N. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 5c4100925cf9..954f5291cc37 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -71,3 +71,4 @@ obj-$(CONFIG_PINCTRL_SM8750) += pinctrl-sm8750.o obj-$(CONFIG_PINCTRL_SC8280XP_LPASS_LPI) += pinctrl-sc8280xp-lpass-lpi.o obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o obj-$(CONFIG_PINCTRL_X1E80100) += pinctrl-x1e80100.o +obj-$(CONFIG_PINCTRL_TLMM_TEST) += tlmm-test.o diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 47daa47153c9..82f0cc43bbf4 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1045,8 +1045,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) const struct msm_pingroup *g; u32 intr_target_mask = GENMASK(2, 0); unsigned long flags; - bool was_enabled; - u32 val; + u32 val, oldval; if (msm_gpio_needs_dual_edge_parent_workaround(d, type)) { set_bit(d->hwirq, pctrl->dual_edge_irqs); @@ -1108,8 +1107,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) * internal circuitry of TLMM, toggling the RAW_STATUS * could cause the INTR_STATUS to be set for EDGE interrupts. */ - val = msm_readl_intr_cfg(pctrl, g); - was_enabled = val & BIT(g->intr_raw_status_bit); + val = oldval = msm_readl_intr_cfg(pctrl, g); val |= BIT(g->intr_raw_status_bit); if (g->intr_detection_width == 2) { val &= ~(3 << g->intr_detection_bit); @@ -1162,9 +1160,11 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) /* * The first time we set RAW_STATUS_EN it could trigger an interrupt. * Clear the interrupt. This is safe because we have - * IRQCHIP_SET_TYPE_MASKED. + * IRQCHIP_SET_TYPE_MASKED. When changing the interrupt type, we could + * also still have a non-matching interrupt latched, so clear whenever + * making changes to the interrupt configuration. */ - if (!was_enabled) + if (val != oldval) msm_ack_intr_status(pctrl, g); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8917.c b/drivers/pinctrl/qcom/pinctrl-msm8917.c index cff137bb3b23..350636807b07 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8917.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8917.c @@ -539,6 +539,7 @@ enum msm8917_functions { msm_mux_webcam_standby, msm_mux_wsa_io, msm_mux_wsa_irq, + msm_mux_wsa_reset, msm_mux__, }; @@ -1123,6 +1124,10 @@ static const char * const wsa_io_groups[] = { "gpio94", "gpio95", }; +static const char * const wsa_reset_groups[] = { + "gpio96", +}; + static const char * const blsp_spi8_groups[] = { "gpio96", "gpio97", "gpio98", "gpio99", }; @@ -1378,6 +1383,7 @@ static const struct pinfunction msm8917_functions[] = { MSM_PIN_FUNCTION(webcam_standby), MSM_PIN_FUNCTION(wsa_io), MSM_PIN_FUNCTION(wsa_irq), + MSM_PIN_FUNCTION(wsa_reset), }; static const struct msm_pingroup msm8917_groups[] = { @@ -1616,5 +1622,5 @@ static void __exit msm8917_pinctrl_exit(void) } module_exit(msm8917_pinctrl_exit); -MODULE_DESCRIPTION("Qualcomm msm8917 pinctrl driver"); +MODULE_DESCRIPTION("Qualcomm msm8917/msm8937 pinctrl driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c index 8fdea25d8d67..a5b38221aea8 100644 --- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c +++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2025, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2023, Linaro Limited */ @@ -467,6 +467,7 @@ enum sa8775p_functions { msm_mux_edp2_lcd, msm_mux_edp3_hot, msm_mux_edp3_lcd, + msm_mux_egpio, msm_mux_emac0_mcg0, msm_mux_emac0_mcg1, msm_mux_emac0_mcg2, @@ -744,6 +745,13 @@ static const char * const edp3_lcd_groups[] = { "gpio49", }; +static const char *const egpio_groups[] = { + "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", + "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137", + "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143", + "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", +}; + static const char * const emac0_mcg0_groups[] = { "gpio12", }; @@ -1209,6 +1217,7 @@ static const struct pinfunction sa8775p_functions[] = { MSM_PIN_FUNCTION(edp2_lcd), MSM_PIN_FUNCTION(edp3_hot), MSM_PIN_FUNCTION(edp3_lcd), + MSM_PIN_FUNCTION(egpio), MSM_PIN_FUNCTION(emac0_mcg0), MSM_PIN_FUNCTION(emac0_mcg1), MSM_PIN_FUNCTION(emac0_mcg2), @@ -1454,29 +1463,29 @@ static const struct msm_pingroup sa8775p_groups[] = { [123] = PINGROUP(123, hs2_mi2s, phase_flag, _, _, _, _, _, _, _), [124] = PINGROUP(124, hs2_mi2s, phase_flag, _, _, _, _, _, _, _), [125] = PINGROUP(125, hs2_mi2s, phase_flag, _, _, _, _, _, _, _), - [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _), - [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _), - [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _), - [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _), - [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _), - [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _), - [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _), - [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _), - [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _), - [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _), - [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _), - [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _), - [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _), - [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _), - [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _), - [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _), - [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _), - [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _), - [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, _), - [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _), - [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _), - [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _), - [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, _, _, _, _, _, _, _, _, egpio), + [127] = PINGROUP(127, _, _, _, _, _, _, _, _, egpio), + [128] = PINGROUP(128, _, _, _, _, _, _, _, _, egpio), + [129] = PINGROUP(129, _, _, _, _, _, _, _, _, egpio), + [130] = PINGROUP(130, _, _, _, _, _, _, _, _, egpio), + [131] = PINGROUP(131, _, _, _, _, _, _, _, _, egpio), + [132] = PINGROUP(132, _, _, _, _, _, _, _, _, egpio), + [133] = PINGROUP(133, _, _, _, _, _, _, _, _, egpio), + [134] = PINGROUP(134, _, _, _, _, _, _, _, _, egpio), + [135] = PINGROUP(135, _, _, _, _, _, _, _, _, egpio), + [136] = PINGROUP(136, _, _, _, _, _, _, _, _, egpio), + [137] = PINGROUP(137, _, _, _, _, _, _, _, _, egpio), + [138] = PINGROUP(138, _, _, _, _, _, _, _, _, egpio), + [139] = PINGROUP(139, _, _, _, _, _, _, _, _, egpio), + [140] = PINGROUP(140, _, _, _, _, _, _, _, _, egpio), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, egpio), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, egpio), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, egpio), + [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, egpio), + [145] = PINGROUP(145, _, _, _, _, _, _, _, _, egpio), + [146] = PINGROUP(146, _, _, _, _, _, _, _, _, egpio), + [147] = PINGROUP(147, _, _, _, _, _, _, _, _, egpio), + [148] = PINGROUP(148, _, _, _, _, _, _, _, _, egpio), [149] = UFS_RESET(ufs_reset, 0x1a2000), [150] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x199000, 15, 0), [151] = SDC_QDSD_PINGROUP(sdc1_clk, 0x199000, 13, 6), @@ -1511,6 +1520,7 @@ static const struct msm_pinctrl_soc_data sa8775p_pinctrl = { .ngpios = 150, .wakeirq_map = sa8775p_pdc_map, .nwakeirq_map = ARRAY_SIZE(sa8775p_pdc_map), + .egpio_func = 9, }; static int sa8775p_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/pinctrl/qcom/tlmm-test.c b/drivers/pinctrl/qcom/tlmm-test.c new file mode 100644 index 000000000000..fd02bf3a76cb --- /dev/null +++ b/drivers/pinctrl/qcom/tlmm-test.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define pr_fmt(fmt) "tlmm-test: " fmt + +#include <kunit/test.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> + +/* + * This TLMM test module serves the purpose of validating that the TLMM driver + * (pinctrl-msm) delivers expected number of interrupts in response to changing + * GPIO state. + * + * To achieve this without external equipment the test takes a module parameter + * "gpio", which the tester is expected to specify an unused and non-connected + * pin. The GPIO state is then driven by adjusting the bias of the pin, at + * suitable times through the different test cases. + * + * Upon execution, the test initialization will find the TLMM node (subject to + * tlmm_of_match[] allow listing) and create the necessary references + * dynamically, rather then relying on e.g. Devicetree and phandles. + */ + +#define MSM_PULL_MASK GENMASK(2, 0) +#define MSM_PULL_DOWN 1 +#define MSM_PULL_UP 3 +#define TLMM_REG_SIZE 0x1000 + +static int tlmm_test_gpio = -1; +module_param_named(gpio, tlmm_test_gpio, int, 0600); + +static struct { + void __iomem *base; + void __iomem *reg; + int irq; + + u32 low_val; + u32 high_val; +} tlmm_suite; + +/** + * struct tlmm_test_priv - Per-test context + * @intr_count: number of times hard handler was hit with TLMM_TEST_COUNT op set + * @thread_count: number of times thread handler was hit with TLMM_TEST_COUNT op set + * @intr_op: operations to be performed by the hard IRQ handler + * @intr_op_remain: number of times the TLMM_TEST_THEN_* operations should be + * performed by the hard IRQ handler + * @thread_op: operations to be performed by the threaded IRQ handler + * @thread_op_remain: number of times the TLMM_TEST_THEN_* operations should + * be performed by the threaded IRQ handler + */ +struct tlmm_test_priv { + atomic_t intr_count; + atomic_t thread_count; + + unsigned int intr_op; + atomic_t intr_op_remain; + + unsigned int thread_op; + atomic_t thread_op_remain; +}; + +/* Operation masks for @intr_op and @thread_op */ +#define TLMM_TEST_COUNT BIT(0) +#define TLMM_TEST_OUTPUT_LOW BIT(1) +#define TLMM_TEST_OUTPUT_HIGH BIT(2) +#define TLMM_TEST_THEN_HIGH BIT(3) +#define TLMM_TEST_THEN_LOW BIT(4) +#define TLMM_TEST_WAKE_THREAD BIT(5) + +static void tlmm_output_low(void) +{ + writel(tlmm_suite.low_val, tlmm_suite.reg); + readl(tlmm_suite.reg); +} + +static void tlmm_output_high(void) +{ + writel(tlmm_suite.high_val, tlmm_suite.reg); + readl(tlmm_suite.reg); +} + +static irqreturn_t tlmm_test_intr_fn(int irq, void *dev_id) +{ + struct tlmm_test_priv *priv = dev_id; + + if (priv->intr_op & TLMM_TEST_COUNT) + atomic_inc(&priv->intr_count); + + if (priv->intr_op & TLMM_TEST_OUTPUT_LOW) + tlmm_output_low(); + if (priv->intr_op & TLMM_TEST_OUTPUT_HIGH) + tlmm_output_high(); + + if (atomic_dec_if_positive(&priv->intr_op_remain) > 0) { + udelay(1); + + if (priv->intr_op & TLMM_TEST_THEN_LOW) + tlmm_output_low(); + if (priv->intr_op & TLMM_TEST_THEN_HIGH) + tlmm_output_high(); + } + + return priv->intr_op & TLMM_TEST_WAKE_THREAD ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +static irqreturn_t tlmm_test_intr_thread_fn(int irq, void *dev_id) +{ + struct tlmm_test_priv *priv = dev_id; + + if (priv->thread_op & TLMM_TEST_COUNT) + atomic_inc(&priv->thread_count); + + if (priv->thread_op & TLMM_TEST_OUTPUT_LOW) + tlmm_output_low(); + if (priv->thread_op & TLMM_TEST_OUTPUT_HIGH) + tlmm_output_high(); + + if (atomic_dec_if_positive(&priv->thread_op_remain) > 0) { + udelay(1); + if (priv->thread_op & TLMM_TEST_THEN_LOW) + tlmm_output_low(); + if (priv->thread_op & TLMM_TEST_THEN_HIGH) + tlmm_output_high(); + } + + return IRQ_HANDLED; +} + +static void tlmm_test_request_hard_irq(struct kunit *test, unsigned long irqflags) +{ + struct tlmm_test_priv *priv = test->priv; + int ret; + + ret = request_irq(tlmm_suite.irq, tlmm_test_intr_fn, irqflags, test->name, priv); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void tlmm_test_request_threaded_irq(struct kunit *test, unsigned long irqflags) +{ + struct tlmm_test_priv *priv = test->priv; + int ret; + + ret = request_threaded_irq(tlmm_suite.irq, + tlmm_test_intr_fn, tlmm_test_intr_thread_fn, + irqflags, test->name, priv); + + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void tlmm_test_silent(struct kunit *test, unsigned long irqflags) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT; + + /* GPIO line at non-triggering level */ + if (irqflags == IRQF_TRIGGER_LOW || irqflags == IRQF_TRIGGER_FALLING) + tlmm_output_high(); + else + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, irqflags); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 0); +} + +/* + * Test that no RISING interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_rising(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_RISING); +} + +/* + * Test that no FALLING interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_falling(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_FALLING); +} + +/* + * Test that no LOW interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_low(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_LOW); +} + +/* + * Test that no HIGH interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_high(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_HIGH); +} + +/* + * Square wave with 10 high pulses, assert that we get 10 rising interrupts + */ +static void tlmm_test_rising(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT; + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING); + for (i = 0; i < 10; i++) { + tlmm_output_low(); + msleep(20); + tlmm_output_high(); + msleep(20); + } + + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Square wave with 10 low pulses, assert that we get 10 falling interrupts + */ +static void tlmm_test_falling(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT; + + tlmm_output_high(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_FALLING); + for (i = 0; i < 10; i++) { + tlmm_output_high(); + msleep(20); + tlmm_output_low(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Drive line low 10 times, handler drives it high to "clear the interrupt + * source", assert we get 10 interrupts + */ +static void tlmm_test_low(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH; + atomic_set(&priv->intr_op_remain, 9); + + tlmm_output_high(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_LOW); + for (i = 0; i < 10; i++) { + msleep(20); + tlmm_output_low(); + } + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Drive line high 10 times, handler drives it low to "clear the interrupt + * source", assert we get 10 interrupts + */ +static void tlmm_test_high(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW; + atomic_set(&priv->intr_op_remain, 9); + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_HIGH); + for (i = 0; i < 10; i++) { + msleep(20); + tlmm_output_high(); + } + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Handler drives GPIO high to "clear the interrupt source", then low to + * simulate a new interrupt, repeated 10 times, assert we get 10 interrupts + */ +static void tlmm_test_falling_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH | TLMM_TEST_THEN_LOW; + atomic_set(&priv->intr_op_remain, 10); + + tlmm_output_high(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_FALLING); + msleep(20); + tlmm_output_low(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Handler drives GPIO low to "clear the interrupt source", then high to + * simulate a new interrupt, repeated 10 times, assert we get 10 interrupts + */ +static void tlmm_test_rising_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW | TLMM_TEST_THEN_HIGH; + atomic_set(&priv->intr_op_remain, 10); + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING); + msleep(20); + tlmm_output_high(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Square wave with 10 high pulses, assert that we get 10 rising hard and + * 10 threaded interrupts + */ +static void tlmm_test_thread_rising(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT; + + tlmm_output_low(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_RISING); + for (i = 0; i < 10; i++) { + tlmm_output_low(); + msleep(20); + tlmm_output_high(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Square wave with 10 low pulses, assert that we get 10 falling interrupts + */ +static void tlmm_test_thread_falling(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT; + + tlmm_output_high(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_FALLING); + for (i = 0; i < 10; i++) { + tlmm_output_high(); + msleep(20); + tlmm_output_low(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Drive line high 10 times, threaded handler drives it low to "clear the + * interrupt source", assert we get 10 interrupts + */ +static void tlmm_test_thread_high(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW; + + tlmm_output_low(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_HIGH | IRQF_ONESHOT); + for (i = 0; i < 10; i++) { + tlmm_output_high(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Drive line low 10 times, threaded handler drives it high to "clear the + * interrupt source", assert we get 10 interrupts + */ +static void tlmm_test_thread_low(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH; + + tlmm_output_high(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_LOW | IRQF_ONESHOT); + for (i = 0; i < 10; i++) { + tlmm_output_low(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Handler drives GPIO low to "clear the interrupt source", then high in the + * threaded handler to simulate a new interrupt, repeated 10 times, assert we + * get 10 interrupts + */ +static void tlmm_test_thread_rising_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_THEN_HIGH; + atomic_set(&priv->thread_op_remain, 10); + + tlmm_output_low(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_RISING); + msleep(20); + tlmm_output_high(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Handler drives GPIO high to "clear the interrupt source", then low in the + * threaded handler to simulate a new interrupt, repeated 10 times, assert we + * get 10 interrupts + */ +static void tlmm_test_thread_falling_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_THEN_LOW; + atomic_set(&priv->thread_op_remain, 10); + + tlmm_output_high(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_FALLING); + msleep(20); + tlmm_output_low(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Validate that edge interrupts occurring while irq is disabled is delivered + * once the interrupt is reenabled. + */ +static void tlmm_test_rising_while_disabled(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + unsigned int after_edge; + unsigned int before_edge; + + priv->intr_op = TLMM_TEST_COUNT; + atomic_set(&priv->thread_op_remain, 10); + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING); + msleep(20); + + disable_irq(tlmm_suite.irq); + before_edge = atomic_read(&priv->intr_count); + + tlmm_output_high(); + msleep(20); + after_edge = atomic_read(&priv->intr_count); + + msleep(20); + enable_irq(tlmm_suite.irq); + msleep(20); + + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, before_edge, 0); + KUNIT_ASSERT_EQ(test, after_edge, 0); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 1); +} + +static int tlmm_test_init(struct kunit *test) +{ + struct tlmm_test_priv *priv; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + + atomic_set(&priv->intr_count, 0); + atomic_set(&priv->thread_count, 0); + + atomic_set(&priv->intr_op_remain, 0); + atomic_set(&priv->thread_op_remain, 0); + + test->priv = priv; + + return 0; +} + +/* + * NOTE: When adding compatibles to this list, ensure that TLMM_REG_SIZE and + * pull configuration values are supported and correct. + */ +static const struct of_device_id tlmm_of_match[] = { + { .compatible = "qcom,sc8280xp-tlmm" }, + { .compatible = "qcom,x1e80100-tlmm" }, + {} +}; + +static int tlmm_test_init_suite(struct kunit_suite *suite) +{ + struct of_phandle_args args = {}; + struct resource res; + int ret; + u32 val; + + if (tlmm_test_gpio < 0) { + pr_err("use the tlmm-test.gpio module parameter to specify which GPIO to use\n"); + return -EINVAL; + } + + struct device_node *tlmm __free(device_node) = of_find_matching_node(NULL, tlmm_of_match); + if (!tlmm) { + pr_err("failed to find tlmm node\n"); + return -EINVAL; + } + + ret = of_address_to_resource(tlmm, 0, &res); + if (ret < 0) + return ret; + + tlmm_suite.base = ioremap(res.start, resource_size(&res)); + if (!tlmm_suite.base) + return -ENOMEM; + + args.np = tlmm; + args.args_count = 2; + args.args[0] = tlmm_test_gpio; + args.args[1] = 0; + + tlmm_suite.irq = irq_create_of_mapping(&args); + if (!tlmm_suite.irq) { + pr_err("failed to map TLMM irq %d\n", args.args[0]); + goto err_unmap; + } + + tlmm_suite.reg = tlmm_suite.base + tlmm_test_gpio * TLMM_REG_SIZE; + val = readl(tlmm_suite.reg) & ~MSM_PULL_MASK; + tlmm_suite.low_val = val | MSM_PULL_DOWN; + tlmm_suite.high_val = val | MSM_PULL_UP; + + return 0; + +err_unmap: + iounmap(tlmm_suite.base); + tlmm_suite.base = NULL; + return -EINVAL; +} + +static void tlmm_test_exit_suite(struct kunit_suite *suite) +{ + irq_dispose_mapping(tlmm_suite.irq); + iounmap(tlmm_suite.base); + + tlmm_suite.base = NULL; + tlmm_suite.irq = -1; +} + +static struct kunit_case tlmm_test_cases[] = { + KUNIT_CASE(tlmm_test_silent_rising), + KUNIT_CASE(tlmm_test_silent_falling), + KUNIT_CASE(tlmm_test_silent_low), + KUNIT_CASE(tlmm_test_silent_high), + KUNIT_CASE(tlmm_test_rising), + KUNIT_CASE(tlmm_test_falling), + KUNIT_CASE(tlmm_test_high), + KUNIT_CASE(tlmm_test_low), + KUNIT_CASE(tlmm_test_rising_in_handler), + KUNIT_CASE(tlmm_test_falling_in_handler), + KUNIT_CASE(tlmm_test_thread_rising), + KUNIT_CASE(tlmm_test_thread_falling), + KUNIT_CASE(tlmm_test_thread_high), + KUNIT_CASE(tlmm_test_thread_low), + KUNIT_CASE(tlmm_test_thread_rising_in_handler), + KUNIT_CASE(tlmm_test_thread_falling_in_handler), + KUNIT_CASE(tlmm_test_rising_while_disabled), + {} +}; + +static struct kunit_suite tlmm_test_suite = { + .name = "tlmm-test", + .init = tlmm_test_init, + .suite_init = tlmm_test_init_suite, + .suite_exit = tlmm_test_exit_suite, + .test_cases = tlmm_test_cases, +}; + +kunit_test_suites(&tlmm_test_suite); + +MODULE_DESCRIPTION("Qualcomm TLMM test"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c index dd1f8c29d3e7..3b5812963850 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza2.c +++ b/drivers/pinctrl/renesas/pinctrl-rza2.c @@ -246,6 +246,9 @@ static int rza2_gpio_register(struct rza2_pinctrl_priv *priv) int ret; chip.label = devm_kasprintf(priv->dev, GFP_KERNEL, "%pOFn", np); + if (!chip.label) + return -ENOMEM; + chip.parent = priv->dev; chip.ngpio = priv->npins; @@ -256,6 +259,8 @@ static int rza2_gpio_register(struct rza2_pinctrl_priv *priv) return ret; } + of_node_put(of_args.np); + if ((of_args.args[0] != 0) || (of_args.args[1] != 0) || (of_args.args[2] != priv->npins)) { diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index ce4a07a3df49..c72e250f4a15 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -318,6 +318,7 @@ struct rzg2l_pinctrl_pin_settings { * @pmc: PMC registers cache * @pfc: PFC registers cache * @iolh: IOLH registers cache + * @pupd: PUPD registers cache * @ien: IEN registers cache * @sd_ch: SD_CH registers cache * @eth_poc: ET_POC registers cache @@ -331,6 +332,7 @@ struct rzg2l_pinctrl_reg_cache { u32 *pfc; u32 *iolh[2]; u32 *ien[2]; + u32 *pupd[2]; u8 sd_ch[2]; u8 eth_poc[2]; u8 eth_mode; @@ -2712,6 +2714,11 @@ static int rzg2l_pinctrl_reg_cache_alloc(struct rzg2l_pinctrl *pctrl) if (!cache->ien[i]) return -ENOMEM; + cache->pupd[i] = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->pupd[i]), + GFP_KERNEL); + if (!cache->pupd[i]) + return -ENOMEM; + /* Allocate dedicated cache. */ dedicated_cache->iolh[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins, sizeof(*dedicated_cache->iolh[i]), @@ -2756,6 +2763,8 @@ static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl) if (ret) return dev_err_probe(pctrl->dev, ret, "Unable to parse gpio-ranges\n"); + of_node_put(of_args.np); + if (of_args.args[0] != 0 || of_args.args[1] != 0 || of_args.args[2] != pctrl->data->n_port_pins) return dev_err_probe(pctrl->dev, -EINVAL, @@ -2953,7 +2962,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache; for (u32 port = 0; port < nports; port++) { - bool has_iolh, has_ien; + bool has_iolh, has_ien, has_pupd; u32 off, caps; u8 pincnt; u64 cfg; @@ -2965,6 +2974,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen caps = FIELD_GET(PIN_CFG_MASK, cfg); has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)); has_ien = !!(caps & PIN_CFG_IEN); + has_pupd = !!(caps & PIN_CFG_PUPD); if (suspend) RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PFC(off), cache->pfc[port]); @@ -2983,6 +2993,15 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen } } + if (has_pupd) { + RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PUPD(off), + cache->pupd[0][port]); + if (pincnt >= 4) { + RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PUPD(off), + cache->pupd[1][port]); + } + } + RZG2L_PCTRL_REG_ACCESS16(suspend, pctrl->base + PM(off), cache->pm[port]); RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + P(off), cache->p[port]); @@ -3386,6 +3405,7 @@ static struct platform_driver rzg2l_pinctrl_driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(rzg2l_pinctrl_of_table), .pm = pm_sleep_ptr(&rzg2l_pinctrl_pm_ops), + .suppress_bind_attrs = true, }, .probe = rzg2l_pinctrl_probe, }; diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c index 4062c56619f5..8c7169db4fcc 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c +++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c @@ -940,6 +940,8 @@ static int rzv2m_gpio_register(struct rzv2m_pinctrl *pctrl) return ret; } + of_node_put(of_args.np); + if (of_args.args[0] != 0 || of_args.args[1] != 0 || of_args.args[2] != pctrl->data->n_port_pins) { dev_err(pctrl->dev, "gpio-ranges does not match selected SOC\n"); diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index 3ea7106ce5ea..dd07720e32cc 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -41,6 +41,15 @@ static const struct samsung_pin_bank_type exynos5433_bank_type_alive = { }; /* + * Bank type for alive type. Bit fields: + * CON: 4, DAT: 1, PUD: 2, DRV: 3 + */ +static const struct samsung_pin_bank_type exynos7870_bank_type_alive = { + .fld_width = { 4, 1, 2, 3, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, +}; + +/* * Bank type for non-alive type. Bit fields: * CON: 4, DAT: 1, PUD: 4, DRV: 4, CONPDN: 2, PUDPDN: 4 */ @@ -70,6 +79,174 @@ static const struct samsung_pin_bank_type exynos8895_bank_type_off = { /* Pad retention control code for accessing PMU regmap */ static atomic_t exynos_shared_retention_refcnt; +/* pin banks of exynos2200 pin-controller - ALIVE */ +static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst = { + EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00), + EXYNOS850_PIN_BANK_EINTW(8, 0x20, "gpa1", 0x04), + EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa2", 0x08), + EXYNOS850_PIN_BANK_EINTW(8, 0x60, "gpa3", 0x0c), + EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpa4", 0x10), + EXYNOS_PIN_BANK_EINTN(4, 0xa0, "gpq0"), + EXYNOS_PIN_BANK_EINTN(2, 0xc0, "gpq1"), + EXYNOS_PIN_BANK_EINTN(2, 0xe0, "gpq2"), +}; + +/* pin banks of exynos2200 pin-controller - CMGP */ +static const struct samsung_pin_bank_data exynos2200_pin_banks1[] __initconst = { + EXYNOS850_PIN_BANK_EINTW(2, 0x0, "gpm0", 0x00), + EXYNOS850_PIN_BANK_EINTW(2, 0x20, "gpm1", 0x04), + EXYNOS850_PIN_BANK_EINTW(2, 0x40, "gpm2", 0x08), + EXYNOS850_PIN_BANK_EINTW(2, 0x60, "gpm3", 0x0c), + EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpm4", 0x10), + EXYNOS850_PIN_BANK_EINTW(2, 0xa0, "gpm5", 0x14), + EXYNOS850_PIN_BANK_EINTW(2, 0xc0, "gpm6", 0x18), + EXYNOS850_PIN_BANK_EINTW(2, 0xe0, "gpm7", 0x1c), + EXYNOS850_PIN_BANK_EINTW(2, 0x100, "gpm8", 0x20), + EXYNOS850_PIN_BANK_EINTW(2, 0x120, "gpm9", 0x24), + EXYNOS850_PIN_BANK_EINTW(2, 0x140, "gpm10", 0x28), + EXYNOS850_PIN_BANK_EINTW(2, 0x160, "gpm11", 0x2c), + EXYNOS850_PIN_BANK_EINTW(2, 0x180, "gpm12", 0x30), + EXYNOS850_PIN_BANK_EINTW(2, 0x1a0, "gpm13", 0x34), + EXYNOS850_PIN_BANK_EINTW(1, 0x1c0, "gpm14", 0x38), + EXYNOS850_PIN_BANK_EINTW(1, 0x1e0, "gpm15", 0x3c), + EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm16", 0x40), + EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm17", 0x44), + EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm20", 0x48), + EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm21", 0x4c), + EXYNOS850_PIN_BANK_EINTW(1, 0x280, "gpm22", 0x50), + EXYNOS850_PIN_BANK_EINTW(1, 0x2a0, "gpm23", 0x54), + EXYNOS850_PIN_BANK_EINTW(1, 0x2c0, "gpm24", 0x58), +}; + +/* pin banks of exynos2200 pin-controller - HSI1 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks2[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpf0", 0x00), +}; + +/* pin banks of exynos2200 pin-controller - UFS */ +static const struct samsung_pin_bank_data exynos2200_pin_banks3[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(7, 0x0, "gpf1", 0x00), +}; + +/* pin banks of exynos2200 pin-controller - HSI1UFS */ +static const struct samsung_pin_bank_data exynos2200_pin_banks4[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(2, 0x0, "gpf2", 0x00), +}; + +/* pin banks of exynos2200 pin-controller - PERIC0 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks5[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpb0", 0x00), + EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpb1", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpb2", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpb3", 0x0c), + EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10), + EXYNOS850_PIN_BANK_EINTG(2, 0xa0, "gpc0", 0x14), + EXYNOS850_PIN_BANK_EINTG(2, 0xc0, "gpc1", 0x18), + EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpc2", 0x1c), + EXYNOS850_PIN_BANK_EINTG(7, 0x100, "gpg1", 0x20), + EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpg2", 0x24), +}; + +/* pin banks of exynos2200 pin-controller - PERIC1 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks6[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpp7", 0x00), + EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp8", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp9", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpp10", 0x0c), +}; + +/* pin banks of exynos2200 pin-controller - PERIC2 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks7[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpp0", 0x00), + EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpp3", 0x0c), + EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp5", 0x10), + EXYNOS850_PIN_BANK_EINTG(4, 0xa0, "gpp6", 0x14), + EXYNOS850_PIN_BANK_EINTG(4, 0xc0, "gpp11", 0x18), + EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpc3", 0x1c), + EXYNOS850_PIN_BANK_EINTG(2, 0x100, "gpc4", 0x20), + EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpc5", 0x24), + EXYNOS850_PIN_BANK_EINTG(2, 0x140, "gpc6", 0x28), + EXYNOS850_PIN_BANK_EINTG(2, 0x160, "gpc7", 0x2c), + EXYNOS850_PIN_BANK_EINTG(2, 0x180, "gpc8", 0x30), + EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpc9", 0x34), + EXYNOS850_PIN_BANK_EINTG(5, 0x1c0, "gpg0", 0x38), +}; + +/* pin banks of exynos2200 pin-controller - VTS */ +static const struct samsung_pin_bank_data exynos2200_pin_banks8[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(7, 0x0, "gpv0", 0x00), +}; + +static const struct samsung_pin_ctrl exynos2200_pin_ctrl[] = { + { + /* pin-controller instance 0 ALIVE data */ + .pin_banks = exynos2200_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 CMGP data */ + .pin_banks = exynos2200_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 2 HSI1 data */ + .pin_banks = exynos2200_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks2), + }, { + /* pin-controller instance 3 UFS data */ + .pin_banks = exynos2200_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 4 HSI1UFS data */ + .pin_banks = exynos2200_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 5 PERIC0 data */ + .pin_banks = exynos2200_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 6 PERIC1 data */ + .pin_banks = exynos2200_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 7 PERIC2 data */ + .pin_banks = exynos2200_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 8 VTS data */ + .pin_banks = exynos2200_pin_banks8, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks8), + }, +}; + +const struct samsung_pinctrl_of_match_data exynos2200_of_data __initconst = { + .ctrl = exynos2200_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos2200_pin_ctrl), +}; + /* pin banks of exynos5433 pin-controller - ALIVE */ static const struct samsung_pin_bank_data exynos5433_pin_banks0[] __initconst = { /* Must start with EINTG banks, ordered by EINT group number. */ @@ -450,6 +627,136 @@ const struct samsung_pinctrl_of_match_data exynos7_of_data __initconst = { .num_ctrl = ARRAY_SIZE(exynos7_pin_ctrl), }; +/* pin banks of exynos7870 pin-controller 0 (ALIVE) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks0[] __initconst = { + EXYNOS7870_PIN_BANK_EINTN(6, 0x000, "etc0"), + EXYNOS7870_PIN_BANK_EINTN(3, 0x020, "etc1"), + EXYNOS7870_PIN_BANK_EINTW(8, 0x040, "gpa0", 0x00), + EXYNOS7870_PIN_BANK_EINTW(8, 0x060, "gpa1", 0x04), + EXYNOS7870_PIN_BANK_EINTW(8, 0x080, "gpa2", 0x08), + EXYNOS7870_PIN_BANK_EINTN(2, 0x0c0, "gpq0"), +}; + +/* pin banks of exynos7870 pin-controller 1 (DISPAUD) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks1[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpz0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(6, 0x020, "gpz1", 0x04), + EXYNOS8895_PIN_BANK_EINTG(4, 0x040, "gpz2", 0x08), +}; + +/* pin banks of exynos7870 pin-controller 2 (ESE) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks2[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(5, 0x000, "gpc7", 0x00), +}; + +/* pin banks of exynos7870 pin-controller 3 (FSYS) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks3[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpr0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04), + EXYNOS8895_PIN_BANK_EINTG(2, 0x040, "gpr2", 0x08), + EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpr3", 0x0c), + EXYNOS8895_PIN_BANK_EINTG(6, 0x080, "gpr4", 0x10), +}; + +/* pin banks of exynos7870 pin-controller 4 (MIF) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks4[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(2, 0x000, "gpm0", 0x00), +}; + +/* pin banks of exynos7870 pin-controller 5 (NFC) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks5[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpc2", 0x00), +}; + +/* pin banks of exynos7870 pin-controller 6 (TOP) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks6[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpb0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(3, 0x020, "gpc0", 0x04), + EXYNOS8895_PIN_BANK_EINTG(4, 0x040, "gpc1", 0x08), + EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpc4", 0x0c), + EXYNOS8895_PIN_BANK_EINTG(2, 0x080, "gpc5", 0x10), + EXYNOS8895_PIN_BANK_EINTG(4, 0x0a0, "gpc6", 0x14), + EXYNOS8895_PIN_BANK_EINTG(2, 0x0c0, "gpc8", 0x18), + EXYNOS8895_PIN_BANK_EINTG(2, 0x0e0, "gpc9", 0x1c), + EXYNOS8895_PIN_BANK_EINTG(7, 0x100, "gpd1", 0x20), + EXYNOS8895_PIN_BANK_EINTG(6, 0x120, "gpd2", 0x24), + EXYNOS8895_PIN_BANK_EINTG(8, 0x140, "gpd3", 0x28), + EXYNOS8895_PIN_BANK_EINTG(7, 0x160, "gpd4", 0x2c), + EXYNOS8895_PIN_BANK_EINTG(3, 0x1a0, "gpe0", 0x34), + EXYNOS8895_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38), + EXYNOS8895_PIN_BANK_EINTG(2, 0x1e0, "gpf1", 0x3c), + EXYNOS8895_PIN_BANK_EINTG(2, 0x200, "gpf2", 0x40), + EXYNOS8895_PIN_BANK_EINTG(4, 0x220, "gpf3", 0x44), + EXYNOS8895_PIN_BANK_EINTG(5, 0x240, "gpf4", 0x48), +}; + +/* pin banks of exynos7870 pin-controller 7 (TOUCH) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks7[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpc3", 0x00), +}; + +static const struct samsung_pin_ctrl exynos7870_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 Alive data */ + .pin_banks = exynos7870_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks0), + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 DISPAUD data */ + .pin_banks = exynos7870_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks1), + }, { + /* pin-controller instance 2 ESE data */ + .pin_banks = exynos7870_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 3 FSYS data */ + .pin_banks = exynos7870_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 4 MIF data */ + .pin_banks = exynos7870_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 5 NFC data */ + .pin_banks = exynos7870_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 6 TOP data */ + .pin_banks = exynos7870_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 7 TOUCH data */ + .pin_banks = exynos7870_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, +}; + +const struct samsung_pinctrl_of_match_data exynos7870_of_data __initconst = { + .ctrl = exynos7870_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos7870_pin_ctrl), +}; + /* pin banks of exynos7885 pin-controller 0 (ALIVE) */ static const struct samsung_pin_bank_data exynos7885_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTN(3, 0x000, "etc0"), @@ -1370,83 +1677,83 @@ const struct samsung_pinctrl_of_match_data fsd_of_data __initconst = { /* pin banks of gs101 pin-controller (ALIVE) */ static const struct samsung_pin_bank_data gs101_pin_alive[] = { - EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00), - EXYNOS850_PIN_BANK_EINTW(7, 0x20, "gpa1", 0x04), - EXYNOS850_PIN_BANK_EINTW(5, 0x40, "gpa2", 0x08), - EXYNOS850_PIN_BANK_EINTW(4, 0x60, "gpa3", 0x0c), - EXYNOS850_PIN_BANK_EINTW(4, 0x80, "gpa4", 0x10), - EXYNOS850_PIN_BANK_EINTW(7, 0xa0, "gpa5", 0x14), - EXYNOS850_PIN_BANK_EINTW(8, 0xc0, "gpa9", 0x18), - EXYNOS850_PIN_BANK_EINTW(2, 0xe0, "gpa10", 0x1c), + GS101_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00, 0x00), + GS101_PIN_BANK_EINTW(7, 0x20, "gpa1", 0x04, 0x08), + GS101_PIN_BANK_EINTW(5, 0x40, "gpa2", 0x08, 0x10), + GS101_PIN_BANK_EINTW(4, 0x60, "gpa3", 0x0c, 0x18), + GS101_PIN_BANK_EINTW(4, 0x80, "gpa4", 0x10, 0x1c), + GS101_PIN_BANK_EINTW(7, 0xa0, "gpa5", 0x14, 0x20), + GS101_PIN_BANK_EINTW(8, 0xc0, "gpa9", 0x18, 0x28), + GS101_PIN_BANK_EINTW(2, 0xe0, "gpa10", 0x1c, 0x30), }; /* pin banks of gs101 pin-controller (FAR_ALIVE) */ static const struct samsung_pin_bank_data gs101_pin_far_alive[] = { - EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa6", 0x00), - EXYNOS850_PIN_BANK_EINTW(4, 0x20, "gpa7", 0x04), - EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa8", 0x08), - EXYNOS850_PIN_BANK_EINTW(2, 0x60, "gpa11", 0x0c), + GS101_PIN_BANK_EINTW(8, 0x0, "gpa6", 0x00, 0x00), + GS101_PIN_BANK_EINTW(4, 0x20, "gpa7", 0x04, 0x08), + GS101_PIN_BANK_EINTW(8, 0x40, "gpa8", 0x08, 0x0c), + GS101_PIN_BANK_EINTW(2, 0x60, "gpa11", 0x0c, 0x14), }; /* pin banks of gs101 pin-controller (GSACORE) */ static const struct samsung_pin_bank_data gs101_pin_gsacore[] = { - EXYNOS850_PIN_BANK_EINTG(2, 0x0, "gps0", 0x00), - EXYNOS850_PIN_BANK_EINTG(8, 0x20, "gps1", 0x04), - EXYNOS850_PIN_BANK_EINTG(3, 0x40, "gps2", 0x08), + GS101_PIN_BANK_EINTG(2, 0x0, "gps0", 0x00, 0x00), + GS101_PIN_BANK_EINTG(8, 0x20, "gps1", 0x04, 0x04), + GS101_PIN_BANK_EINTG(3, 0x40, "gps2", 0x08, 0x0c), }; /* pin banks of gs101 pin-controller (GSACTRL) */ static const struct samsung_pin_bank_data gs101_pin_gsactrl[] = { - EXYNOS850_PIN_BANK_EINTW(6, 0x0, "gps3", 0x00), + GS101_PIN_BANK_EINTW(6, 0x0, "gps3", 0x00, 0x00), }; /* pin banks of gs101 pin-controller (PERIC0) */ static const struct samsung_pin_bank_data gs101_pin_peric0[] = { - EXYNOS850_PIN_BANK_EINTG(5, 0x0, "gpp0", 0x00), - EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04), - EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08), - EXYNOS850_PIN_BANK_EINTG(2, 0x60, "gpp3", 0x0c), - EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10), - EXYNOS850_PIN_BANK_EINTG(2, 0xa0, "gpp5", 0x14), - EXYNOS850_PIN_BANK_EINTG(4, 0xc0, "gpp6", 0x18), - EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpp7", 0x1c), - EXYNOS850_PIN_BANK_EINTG(4, 0x100, "gpp8", 0x20), - EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpp9", 0x24), - EXYNOS850_PIN_BANK_EINTG(4, 0x140, "gpp10", 0x28), - EXYNOS850_PIN_BANK_EINTG(2, 0x160, "gpp11", 0x2c), - EXYNOS850_PIN_BANK_EINTG(4, 0x180, "gpp12", 0x30), - EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpp13", 0x34), - EXYNOS850_PIN_BANK_EINTG(4, 0x1c0, "gpp14", 0x38), - EXYNOS850_PIN_BANK_EINTG(2, 0x1e0, "gpp15", 0x3c), - EXYNOS850_PIN_BANK_EINTG(4, 0x200, "gpp16", 0x40), - EXYNOS850_PIN_BANK_EINTG(2, 0x220, "gpp17", 0x44), - EXYNOS850_PIN_BANK_EINTG(4, 0x240, "gpp18", 0x48), - EXYNOS850_PIN_BANK_EINTG(4, 0x260, "gpp19", 0x4c), + GS101_PIN_BANK_EINTG(5, 0x0, "gpp0", 0x00, 0x00), + GS101_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04, 0x08), + GS101_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08, 0x0c), + GS101_PIN_BANK_EINTG(2, 0x60, "gpp3", 0x0c, 0x10), + GS101_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10, 0x14), + GS101_PIN_BANK_EINTG(2, 0xa0, "gpp5", 0x14, 0x18), + GS101_PIN_BANK_EINTG(4, 0xc0, "gpp6", 0x18, 0x1c), + GS101_PIN_BANK_EINTG(2, 0xe0, "gpp7", 0x1c, 0x20), + GS101_PIN_BANK_EINTG(4, 0x100, "gpp8", 0x20, 0x24), + GS101_PIN_BANK_EINTG(2, 0x120, "gpp9", 0x24, 0x28), + GS101_PIN_BANK_EINTG(4, 0x140, "gpp10", 0x28, 0x2c), + GS101_PIN_BANK_EINTG(2, 0x160, "gpp11", 0x2c, 0x30), + GS101_PIN_BANK_EINTG(4, 0x180, "gpp12", 0x30, 0x34), + GS101_PIN_BANK_EINTG(2, 0x1a0, "gpp13", 0x34, 0x38), + GS101_PIN_BANK_EINTG(4, 0x1c0, "gpp14", 0x38, 0x3c), + GS101_PIN_BANK_EINTG(2, 0x1e0, "gpp15", 0x3c, 0x40), + GS101_PIN_BANK_EINTG(4, 0x200, "gpp16", 0x40, 0x44), + GS101_PIN_BANK_EINTG(2, 0x220, "gpp17", 0x44, 0x48), + GS101_PIN_BANK_EINTG(4, 0x240, "gpp18", 0x48, 0x4c), + GS101_PIN_BANK_EINTG(4, 0x260, "gpp19", 0x4c, 0x50), }; /* pin banks of gs101 pin-controller (PERIC1) */ static const struct samsung_pin_bank_data gs101_pin_peric1[] = { - EXYNOS850_PIN_BANK_EINTG(8, 0x0, "gpp20", 0x00), - EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp21", 0x04), - EXYNOS850_PIN_BANK_EINTG(2, 0x40, "gpp22", 0x08), - EXYNOS850_PIN_BANK_EINTG(8, 0x60, "gpp23", 0x0c), - EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp24", 0x10), - EXYNOS850_PIN_BANK_EINTG(4, 0xa0, "gpp25", 0x14), - EXYNOS850_PIN_BANK_EINTG(5, 0xc0, "gpp26", 0x18), - EXYNOS850_PIN_BANK_EINTG(4, 0xe0, "gpp27", 0x1c), + GS101_PIN_BANK_EINTG(8, 0x0, "gpp20", 0x00, 0x00), + GS101_PIN_BANK_EINTG(4, 0x20, "gpp21", 0x04, 0x08), + GS101_PIN_BANK_EINTG(2, 0x40, "gpp22", 0x08, 0x0c), + GS101_PIN_BANK_EINTG(8, 0x60, "gpp23", 0x0c, 0x10), + GS101_PIN_BANK_EINTG(4, 0x80, "gpp24", 0x10, 0x18), + GS101_PIN_BANK_EINTG(4, 0xa0, "gpp25", 0x14, 0x1c), + GS101_PIN_BANK_EINTG(5, 0xc0, "gpp26", 0x18, 0x20), + GS101_PIN_BANK_EINTG(4, 0xe0, "gpp27", 0x1c, 0x28), }; /* pin banks of gs101 pin-controller (HSI1) */ static const struct samsung_pin_bank_data gs101_pin_hsi1[] = { - EXYNOS850_PIN_BANK_EINTG(6, 0x0, "gph0", 0x00), - EXYNOS850_PIN_BANK_EINTG(7, 0x20, "gph1", 0x04), + GS101_PIN_BANK_EINTG(6, 0x0, "gph0", 0x00, 0x00), + GS101_PIN_BANK_EINTG(7, 0x20, "gph1", 0x04, 0x08), }; /* pin banks of gs101 pin-controller (HSI2) */ static const struct samsung_pin_bank_data gs101_pin_hsi2[] = { - EXYNOS850_PIN_BANK_EINTG(6, 0x0, "gph2", 0x00), - EXYNOS850_PIN_BANK_EINTG(2, 0x20, "gph3", 0x04), - EXYNOS850_PIN_BANK_EINTG(6, 0x40, "gph4", 0x08), + GS101_PIN_BANK_EINTG(6, 0x0, "gph2", 0x00, 0x00), + GS101_PIN_BANK_EINTG(2, 0x20, "gph3", 0x04, 0x08), + GS101_PIN_BANK_EINTG(6, 0x40, "gph4", 0x08, 0x0c), }; static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = { diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 7b7ff7ffeb56..b483270ddc53 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -112,6 +112,25 @@ .pctl_res_idx = pctl_idx, \ } \ +#define EXYNOS7870_PIN_BANK_EINTN(pins, reg, id) \ + { \ + .type = &exynos7870_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_NONE, \ + .name = id \ + } + +#define EXYNOS7870_PIN_BANK_EINTW(pins, reg, id, offs) \ + { \ + .type = &exynos7870_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id \ + } + #define EXYNOS850_PIN_BANK_EINTN(pins, reg, id) \ { \ .type = &exynos850_bank_type_alive, \ @@ -175,6 +194,28 @@ .name = id \ } +#define GS101_PIN_BANK_EINTG(pins, reg, id, offs, fltcon_offs) \ + { \ + .type = &exynos850_bank_type_off, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_GPIO, \ + .eint_offset = offs, \ + .eint_fltcon_offset = fltcon_offs, \ + .name = id \ + } + +#define GS101_PIN_BANK_EINTW(pins, reg, id, offs, fltcon_offs) \ + { \ + .type = &exynos850_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .eint_fltcon_offset = fltcon_offs, \ + .name = id \ + } + /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index cfced7afd4ca..2896eb2de2c0 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1230,6 +1230,7 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, bank->eint_con_offset = bdata->eint_con_offset; bank->eint_mask_offset = bdata->eint_mask_offset; bank->eint_pend_offset = bdata->eint_pend_offset; + bank->eint_fltcon_offset = bdata->eint_fltcon_offset; bank->name = bdata->name; raw_spin_lock_init(&bank->slock); @@ -1469,10 +1470,14 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { #ifdef CONFIG_PINCTRL_EXYNOS_ARM64 { .compatible = "google,gs101-pinctrl", .data = &gs101_of_data }, + { .compatible = "samsung,exynos2200-pinctrl", + .data = &exynos2200_of_data }, { .compatible = "samsung,exynos5433-pinctrl", .data = &exynos5433_of_data }, { .compatible = "samsung,exynos7-pinctrl", .data = &exynos7_of_data }, + { .compatible = "samsung,exynos7870-pinctrl", + .data = &exynos7870_of_data }, { .compatible = "samsung,exynos7885-pinctrl", .data = &exynos7885_of_data }, { .compatible = "samsung,exynos850-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index bb0689d52ea0..3cf758df7d69 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -144,6 +144,7 @@ struct samsung_pin_bank_type { * @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank. * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank. * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank. + * @eint_fltcon_offset: GS101 SoC-specific EINT filter config register offset. * @name: name to be prefixed for each pin in this pin bank. */ struct samsung_pin_bank_data { @@ -158,6 +159,7 @@ struct samsung_pin_bank_data { u32 eint_con_offset; u32 eint_mask_offset; u32 eint_pend_offset; + u32 eint_fltcon_offset; const char *name; }; @@ -175,6 +177,7 @@ struct samsung_pin_bank_data { * @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank. * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank. * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank. + * @eint_fltcon_offset: GS101 SoC-specific EINT filter config register offset. * @name: name to be prefixed for each pin in this pin bank. * @id: id of the bank, propagated to the pin range. * @pin_base: starting pin number of the bank. @@ -201,6 +204,7 @@ struct samsung_pin_bank { u32 eint_con_offset; u32 eint_mask_offset; u32 eint_pend_offset; + u32 eint_fltcon_offset; const char *name; u32 id; @@ -373,6 +377,7 @@ struct samsung_pmx_func { }; /* list of all exported SoC specific data */ +extern const struct samsung_pinctrl_of_match_data exynos2200_of_data; extern const struct samsung_pinctrl_of_match_data exynos3250_of_data; extern const struct samsung_pinctrl_of_match_data exynos4210_of_data; extern const struct samsung_pinctrl_of_match_data exynos4x12_of_data; @@ -382,6 +387,7 @@ extern const struct samsung_pinctrl_of_match_data exynos5410_of_data; extern const struct samsung_pinctrl_of_match_data exynos5420_of_data; extern const struct samsung_pinctrl_of_match_data exynos5433_of_data; extern const struct samsung_pinctrl_of_match_data exynos7_of_data; +extern const struct samsung_pinctrl_of_match_data exynos7870_of_data; extern const struct samsung_pinctrl_of_match_data exynos7885_of_data; extern const struct samsung_pinctrl_of_match_data exynos850_of_data; extern const struct samsung_pinctrl_of_match_data exynos8895_of_data; diff --git a/drivers/pinctrl/sophgo/Kconfig b/drivers/pinctrl/sophgo/Kconfig index c05f909a8838..9b0a3a4753b1 100644 --- a/drivers/pinctrl/sophgo/Kconfig +++ b/drivers/pinctrl/sophgo/Kconfig @@ -3,17 +3,21 @@ # Sophgo SoC PINCTRL drivers # -config PINCTRL_SOPHGO_CV18XX - bool +config PINCTRL_SOPHGO_COMMON + tristate select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS select GENERIC_PINCONF +config PINCTRL_SOPHGO_CV18XX_OPS + bool + config PINCTRL_SOPHGO_CV1800B tristate "Sophgo CV1800B SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for CV1800B SoC. This pin controller allows selecting the mux function for @@ -24,7 +28,8 @@ config PINCTRL_SOPHGO_CV1812H tristate "Sophgo CV1812H SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for CV1812H SoC. This pin controller allows selecting the mux function for @@ -35,7 +40,8 @@ config PINCTRL_SOPHGO_SG2000 tristate "Sophgo SG2000 SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for SG2000 SoC. This pin controller allows selecting the mux function for @@ -46,9 +52,37 @@ config PINCTRL_SOPHGO_SG2002 tristate "Sophgo SG2002 SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for SG2002 SoC. This pin controller allows selecting the mux function for each pin. This driver can also be built as a module called pinctrl-sg2002. + +config PINCTRL_SOPHGO_SG2042_OPS + bool + +config PINCTRL_SOPHGO_SG2042 + tristate "Sophgo SG2042 SoC Pinctrl driver" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on OF + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_SG2042_OPS + help + Say Y to select the pinctrl driver for SG2042 SoC. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-sg2042. + +config PINCTRL_SOPHGO_SG2044 + tristate "Sophgo SG2044 SoC Pinctrl driver" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on OF + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_SG2042_OPS + help + Say Y to select the pinctrl driver for SG2044 SoC. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-sg2044. diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile index 4113a5c9191b..479c65e6dbc0 100644 --- a/drivers/pinctrl/sophgo/Makefile +++ b/drivers/pinctrl/sophgo/Makefile @@ -1,7 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PINCTRL_SOPHGO_CV18XX) += pinctrl-cv18xx.o +obj-$(CONFIG_PINCTRL_SOPHGO_COMMON) += pinctrl-sophgo.o +pinctrl-sophgo-objs += pinctrl-sophgo-common.o +pinctrl-sophgo-$(CONFIG_PINCTRL_SOPHGO_CV18XX_OPS) += pinctrl-cv18xx.o +pinctrl-sophgo-$(CONFIG_PINCTRL_SOPHGO_SG2042_OPS) += pinctrl-sg2042-ops.o + obj-$(CONFIG_PINCTRL_SOPHGO_CV1800B) += pinctrl-cv1800b.o obj-$(CONFIG_PINCTRL_SOPHGO_CV1812H) += pinctrl-cv1812h.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2000) += pinctrl-sg2000.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2002) += pinctrl-sg2002.o +obj-$(CONFIG_PINCTRL_SOPHGO_SG2042) += pinctrl-sg2042.o +obj-$(CONFIG_PINCTRL_SOPHGO_SG2044) += pinctrl-sg2044.o diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c index 3322906689e7..82db60212477 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c @@ -34,8 +34,9 @@ static const char *const cv1800b_power_domain_desc[] = { [VDDIO_SD0_SPI] = "VDDIO_SD0_SPI", }; -static int cv1800b_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int cv1800b_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -54,8 +55,9 @@ static int cv1800b_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int cv1800b_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int cv1800b_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -108,9 +110,10 @@ static const u32 cv1800b_eth_oc_map[] = { 17800 }; -static int cv1800b_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1800b_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -153,9 +156,10 @@ static const u32 cv1800b_18od33_3v3_schmitt_map[] = { 1100000 }; -static int cv1800b_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1800b_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -177,11 +181,11 @@ static int cv1800b_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops cv1800b_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops cv1800b_vddio_cfg_ops = { .get_pull_up = cv1800b_get_pull_up, .get_pull_down = cv1800b_get_pull_down, .get_oc_map = cv1800b_get_oc_map, - .get_schmitt_map = cv1800b_get_schmitt_map, + .get_schmitt_map = cv1800b_get_schmitt_map, }; static const struct pinctrl_pin_desc cv1800b_pins[] = { @@ -433,13 +437,18 @@ static const struct cv1800_pin cv1800b_pin_data[ARRAY_SIZE(cv1800b_pins)] = { CV1800_PINCONF_AREA_SYS, 0x120, 5), }; -static const struct cv1800_pinctrl_data cv1800b_pindata = { +static const struct sophgo_pinctrl_data cv1800b_pindata = { .pins = cv1800b_pins, .pindata = cv1800b_pin_data, .pdnames = cv1800b_power_domain_desc, .vddio_ops = &cv1800b_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(cv1800b_pins), - .npd = ARRAY_SIZE(cv1800b_power_domain_desc), + .npds = ARRAY_SIZE(cv1800b_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id cv1800b_pinctrl_ids[] = { @@ -449,7 +458,7 @@ static const struct of_device_id cv1800b_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, cv1800b_pinctrl_ids); static struct platform_driver cv1800b_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "cv1800b-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c index 5632290b46fa..881a4d7ef589 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c @@ -40,8 +40,9 @@ static const char *const cv1812h_power_domain_desc[] = { [VDDIO_VIVO] = "VDDIO_VIVO", }; -static int cv1812h_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int cv1812h_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -60,8 +61,9 @@ static int cv1812h_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int cv1812h_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int cv1812h_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -114,9 +116,10 @@ static const u32 cv1812h_eth_oc_map[] = { 17800 }; -static int cv1812h_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1812h_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -159,9 +162,10 @@ static const u32 cv1812h_18od33_3v3_schmitt_map[] = { 1100000 }; -static int cv1812h_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1812h_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -183,11 +187,11 @@ static int cv1812h_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops cv1812h_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops cv1812h_vddio_cfg_ops = { .get_pull_up = cv1812h_get_pull_up, .get_pull_down = cv1812h_get_pull_down, .get_oc_map = cv1812h_get_oc_map, - .get_schmitt_map = cv1812h_get_schmitt_map, + .get_schmitt_map = cv1812h_get_schmitt_map, }; static const struct pinctrl_pin_desc cv1812h_pins[] = { @@ -742,13 +746,18 @@ static const struct cv1800_pin cv1812h_pin_data[ARRAY_SIZE(cv1812h_pins)] = { CV1800_PINCONF_AREA_RTC, 0x028), }; -static const struct cv1800_pinctrl_data cv1812h_pindata = { +static const struct sophgo_pinctrl_data cv1812h_pindata = { .pins = cv1812h_pins, .pindata = cv1812h_pin_data, .pdnames = cv1812h_power_domain_desc, .vddio_ops = &cv1812h_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(cv1812h_pins), - .npd = ARRAY_SIZE(cv1812h_power_domain_desc), + .npds = ARRAY_SIZE(cv1812h_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id cv1812h_pinctrl_ids[] = { @@ -758,7 +767,7 @@ static const struct of_device_id cv1812h_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, cv1812h_pinctrl_ids); static struct platform_driver cv1812h_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "cv1812h-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c index 57f2674e75d6..c3a2dcf71f2a 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c @@ -15,8 +15,6 @@ #include <linux/seq_file.h> #include <linux/spinlock.h> -#include <linux/pinctrl/consumer.h> -#include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> @@ -24,35 +22,15 @@ #include <dt-bindings/pinctrl/pinctrl-cv18xx.h> -#include "../core.h" #include "../pinctrl-utils.h" -#include "../pinconf.h" #include "../pinmux.h" #include "pinctrl-cv18xx.h" -struct cv1800_pinctrl { - struct device *dev; - struct pinctrl_dev *pctl_dev; - const struct cv1800_pinctrl_data *data; - struct pinctrl_desc pdesc; +struct cv1800_priv { u32 *power_cfg; - - struct mutex mutex; - raw_spinlock_t lock; - void __iomem *regs[2]; }; -struct cv1800_pin_mux_config { - struct cv1800_pin *pin; - u32 config; -}; - -static unsigned int cv1800_dt_get_pin(u32 value) -{ - return value & GENMASK(15, 0); -} - static unsigned int cv1800_dt_get_pin_mux(u32 value) { return (value >> 16) & GENMASK(7, 0); @@ -66,40 +44,28 @@ static unsigned int cv1800_dt_get_pin_mux2(u32 value) #define cv1800_pinctrl_get_component_addr(pctrl, _comp) \ ((pctrl)->regs[(_comp)->area] + (_comp)->offset) -static int cv1800_cmp_pin(const void *key, const void *pivot) -{ - const struct cv1800_pin *pin = pivot; - int pin_id = (long)key; - int pivid = pin->pin; - - return pin_id - pivid; -} - -static int cv1800_set_power_cfg(struct cv1800_pinctrl *pctrl, +static int cv1800_set_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain, u32 cfg) { - if (domain >= pctrl->data->npd) + struct cv1800_priv *priv = pctrl->priv_ctrl; + + if (domain >= pctrl->data->npds) return -ENOTSUPP; - if (pctrl->power_cfg[domain] && pctrl->power_cfg[domain] != cfg) + if (priv->power_cfg[domain] && priv->power_cfg[domain] != cfg) return -EINVAL; - pctrl->power_cfg[domain] = cfg; + priv->power_cfg[domain] = cfg; return 0; } -static int cv1800_get_power_cfg(struct cv1800_pinctrl *pctrl, +static int cv1800_get_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain) { - return pctrl->power_cfg[domain]; -} + struct cv1800_priv *priv = pctrl->priv_ctrl; -static struct cv1800_pin *cv1800_get_pin(struct cv1800_pinctrl *pctrl, - unsigned long pin) -{ - return bsearch((void *)pin, pctrl->data->pindata, pctrl->data->npins, - sizeof(struct cv1800_pin), cv1800_cmp_pin); + return priv->power_cfg[domain]; } #define PIN_BGA_ID_OFFSET 8 @@ -112,7 +78,7 @@ static const char *const io_type_desc[] = { "ETH" }; -static const char *cv1800_get_power_cfg_desc(struct cv1800_pinctrl *pctrl, +static const char *cv1800_get_power_cfg_desc(struct sophgo_pinctrl *pctrl, u8 domain) { return pctrl->data->pdnames[domain]; @@ -121,53 +87,57 @@ static const char *cv1800_get_power_cfg_desc(struct cv1800_pinctrl *pctrl, static void cv1800_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *seq, unsigned int pin_id) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); + u32 pin_hwid = pin->pin.id; u32 value; void __iomem *reg; - if (pin->pin >> PIN_BGA_ID_OFFSET) + if (pin_hwid >> PIN_BGA_ID_OFFSET) seq_printf(seq, "pos: %c%u ", - 'A' + (pin->pin >> PIN_BGA_ID_OFFSET) - 1, - pin->pin & PIN_BGA_ID_MASK); + 'A' + (pin_hwid >> PIN_BGA_ID_OFFSET) - 1, + pin_hwid & PIN_BGA_ID_MASK); else - seq_printf(seq, "pos: %u ", pin->pin); + seq_printf(seq, "pos: %u ", pin_hwid); seq_printf(seq, "power-domain: %s ", cv1800_get_power_cfg_desc(pctrl, pin->power_domain)); seq_printf(seq, "type: %s ", io_type_desc[type]); - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux); + reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux); value = readl(reg); seq_printf(seq, "mux: 0x%08x ", value); - if (pin->flags & CV1800_PIN_HAVE_MUX2) { - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux2); + if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { + reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); value = readl(reg); seq_printf(seq, "mux2: 0x%08x ", value); } if (type == IO_TYPE_1V8_ONLY || type == IO_TYPE_1V8_OR_3V3) { - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); + reg = cv1800_pinctrl_get_component_addr(priv, &pin->conf); value = readl(reg); seq_printf(seq, "conf: 0x%08x ", value); } } -static int cv1800_verify_pinmux_config(const struct cv1800_pin_mux_config *config) +static int cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config *config) { + struct cv1800_pin *pin = sophgo_to_cv1800_pin(config->pin); unsigned int mux = cv1800_dt_get_pin_mux(config->config); unsigned int mux2 = cv1800_dt_get_pin_mux2(config->config); - if (mux > config->pin->mux.max) + if (mux > pin->mux.max) return -EINVAL; - if (config->pin->flags & CV1800_PIN_HAVE_MUX2) { - if (mux != config->pin->mux2.pfunc) + if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { + if (mux != pin->mux2.pfunc) return -EINVAL; - if (mux2 > config->pin->mux2.max) + if (mux2 > pin->mux2.max) return -EINVAL; } else { if (mux2 != PIN_MUX_INVALD) @@ -177,9 +147,10 @@ static int cv1800_verify_pinmux_config(const struct cv1800_pin_mux_config *confi return 0; } -static int cv1800_verify_pin_group(const struct cv1800_pin_mux_config *mux, - unsigned long npins) +static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux, + unsigned int npins) { + struct cv1800_pin *pin; enum cv1800_pin_io_type type; u8 power_domain; int i; @@ -187,232 +158,78 @@ static int cv1800_verify_pin_group(const struct cv1800_pin_mux_config *mux, if (npins == 1) return 0; - type = cv1800_pin_io_type(mux[0].pin); - power_domain = mux[0].pin->power_domain; + pin = sophgo_to_cv1800_pin(mux[0].pin); + type = cv1800_pin_io_type(pin); + power_domain = pin->power_domain; for (i = 0; i < npins; i++) { - if (type != cv1800_pin_io_type(mux[i].pin) || - power_domain != mux[i].pin->power_domain) + pin = sophgo_to_cv1800_pin(mux[i].pin); + + if (type != cv1800_pin_io_type(pin) || + power_domain != pin->power_domain) return -ENOTSUPP; } return 0; } -static int cv1800_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np, - struct pinctrl_map **maps, - unsigned int *num_maps) +static int cv1800_dt_node_to_map_post(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct device *dev = pctrl->dev; - struct device_node *child; - struct pinctrl_map *map; - const char **grpnames; - const char *grpname; - int ngroups = 0; - int nmaps = 0; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(pinmuxs[0].pin); + u32 power; int ret; - for_each_available_child_of_node(np, child) - ngroups += 1; - - grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL); - if (!grpnames) - return -ENOMEM; - - map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - - ngroups = 0; - mutex_lock(&pctrl->mutex); - for_each_available_child_of_node(np, child) { - int npins = of_property_count_u32_elems(child, "pinmux"); - unsigned int *pins; - struct cv1800_pin_mux_config *pinmuxs; - u32 config, power; - int i; - - if (npins < 1) { - dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n", - np, child); - ret = -EINVAL; - goto dt_failed; - } - - grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", - np, child); - if (!grpname) { - ret = -ENOMEM; - goto dt_failed; - } - - grpnames[ngroups++] = grpname; - - pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); - if (!pins) { - ret = -ENOMEM; - goto dt_failed; - } - - pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL); - if (!pinmuxs) { - ret = -ENOMEM; - goto dt_failed; - } - - for (i = 0; i < npins; i++) { - ret = of_property_read_u32_index(child, "pinmux", - i, &config); - if (ret) - goto dt_failed; - - pins[i] = cv1800_dt_get_pin(config); - pinmuxs[i].config = config; - pinmuxs[i].pin = cv1800_get_pin(pctrl, pins[i]); - - if (!pinmuxs[i].pin) { - dev_err(dev, "failed to get pin %d\n", pins[i]); - ret = -ENODEV; - goto dt_failed; - } - - ret = cv1800_verify_pinmux_config(&pinmuxs[i]); - if (ret) { - dev_err(dev, "group %s pin %d is invalid\n", - grpname, i); - goto dt_failed; - } - } - - ret = cv1800_verify_pin_group(pinmuxs, npins); - if (ret) { - dev_err(dev, "group %s is invalid\n", grpname); - goto dt_failed; - } - - ret = of_property_read_u32(child, "power-source", &power); - if (ret) - goto dt_failed; - - if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) { - dev_err(dev, "group %s have unsupported power: %u\n", - grpname, power); - ret = -ENOTSUPP; - goto dt_failed; - } - - ret = cv1800_set_power_cfg(pctrl, pinmuxs[0].pin->power_domain, - power); - if (ret) - goto dt_failed; - - map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; - map[nmaps].data.mux.function = np->name; - map[nmaps].data.mux.group = grpname; - nmaps += 1; - - ret = pinconf_generic_parse_dt_config(child, pctldev, - &map[nmaps].data.configs.configs, - &map[nmaps].data.configs.num_configs); - if (ret) { - dev_err(dev, "failed to parse pin config of group %s: %d\n", - grpname, ret); - goto dt_failed; - } - - ret = pinctrl_generic_add_group(pctldev, grpname, - pins, npins, pinmuxs); - if (ret < 0) { - dev_err(dev, "failed to add group %s: %d\n", grpname, ret); - goto dt_failed; - } - - /* don't create a map if there are no pinconf settings */ - if (map[nmaps].data.configs.num_configs == 0) - continue; - - map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; - map[nmaps].data.configs.group_or_pin = grpname; - nmaps += 1; - } - - ret = pinmux_generic_add_function(pctldev, np->name, - grpnames, ngroups, NULL); - if (ret < 0) { - dev_err(dev, "error adding function %s: %d\n", np->name, ret); - goto function_failed; - } - - *maps = map; - *num_maps = nmaps; - mutex_unlock(&pctrl->mutex); + ret = of_property_read_u32(cur, "power-source", &power); + if (ret) + return ret; - return 0; + if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) + return -ENOTSUPP; -dt_failed: - of_node_put(child); -function_failed: - pinctrl_utils_free_map(pctldev, map, nmaps); - mutex_unlock(&pctrl->mutex); - return ret; + return cv1800_set_power_cfg(pctrl, pin->power_domain, power); } -static const struct pinctrl_ops cv1800_pctrl_ops = { +const struct pinctrl_ops cv1800_pctrl_ops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = cv1800_pctrl_dbg_show, - .dt_node_to_map = cv1800_pctrl_dt_node_to_map, + .dt_node_to_map = sophgo_pctrl_dt_node_to_map, .dt_free_map = pinctrl_utils_free_map, }; +EXPORT_SYMBOL_GPL(cv1800_pctrl_ops); -static int cv1800_pmx_set_mux(struct pinctrl_dev *pctldev, - unsigned int fsel, unsigned int gsel) +static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct group_desc *group; - const struct cv1800_pin_mux_config *configs; - unsigned int i; - - group = pinctrl_generic_get_group(pctldev, gsel); - if (!group) - return -EINVAL; - - configs = group->data; - - for (i = 0; i < group->grp.npins; i++) { - const struct cv1800_pin *pin = configs[i].pin; - u32 value = configs[i].config; - void __iomem *reg_mux; - void __iomem *reg_mux2; - unsigned long flags; - u32 mux; - u32 mux2; - - reg_mux = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux); - reg_mux2 = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux2); - mux = cv1800_dt_get_pin_mux(value); - mux2 = cv1800_dt_get_pin_mux2(value); - - raw_spin_lock_irqsave(&pctrl->lock, flags); - writel_relaxed(mux, reg_mux); - if (mux2 != PIN_MUX_INVALD) - writel_relaxed(mux2, reg_mux2); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); - } - - return 0; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); + struct cv1800_priv *priv = pctrl->priv_ctrl; + void __iomem *reg_mux; + void __iomem *reg_mux2; + u32 mux; + u32 mux2; + + reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux); + reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); + mux = cv1800_dt_get_pin_mux(config); + mux2 = cv1800_dt_get_pin_mux2(config); + + writel_relaxed(mux, reg_mux); + if (mux2 != PIN_MUX_INVALD) + writel_relaxed(mux2, reg_mux2); } -static const struct pinmux_ops cv1800_pmx_ops = { +const struct pinmux_ops cv1800_pmx_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, - .set_mux = cv1800_pmx_set_mux, + .set_mux = sophgo_pmx_set_mux, .strict = true, }; +EXPORT_SYMBOL_GPL(cv1800_pmx_ops); #define PIN_IO_PULLUP BIT(2) #define PIN_IO_PULLDOWN BIT(3) @@ -421,94 +238,14 @@ static const struct pinmux_ops cv1800_pmx_ops = { #define PIN_IO_BUS_HOLD BIT(10) #define PIN_IO_OUT_FAST_SLEW BIT(11) -static u32 cv1800_pull_down_typical_resistor(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin) -{ - return pctrl->data->vddio_ops->get_pull_down(pin, pctrl->power_cfg); -} - -static u32 cv1800_pull_up_typical_resistor(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin) -{ - return pctrl->data->vddio_ops->get_pull_up(pin, pctrl->power_cfg); -} - -static int cv1800_pinctrl_oc2reg(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 target) -{ - const u32 *map; - int i, len; - - len = pctrl->data->vddio_ops->get_oc_map(pin, pctrl->power_cfg, &map); - if (len < 0) - return len; - - for (i = 0; i < len; i++) { - if (map[i] >= target) - return i; - } - - return -EINVAL; -} - -static int cv1800_pinctrl_reg2oc(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 reg) -{ - const u32 *map; - int len; - - len = pctrl->data->vddio_ops->get_oc_map(pin, pctrl->power_cfg, &map); - if (len < 0) - return len; - - if (reg >= len) - return -EINVAL; - - return map[reg]; -} - -static int cv1800_pinctrl_schmitt2reg(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 target) -{ - const u32 *map; - int i, len; - - len = pctrl->data->vddio_ops->get_schmitt_map(pin, pctrl->power_cfg, - &map); - if (len < 0) - return len; - - for (i = 0; i < len; i++) { - if (map[i] == target) - return i; - } - - return -EINVAL; -} - -static int cv1800_pinctrl_reg2schmitt(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 reg) -{ - const u32 *map; - int len; - - len = pctrl->data->vddio_ops->get_schmitt_map(pin, pctrl->power_cfg, - &map); - if (len < 0) - return len; - - if (reg >= len) - return -EINVAL; - - return map[reg]; -} - static int cv1800_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; int param = pinconf_to_config_param(*config); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type; u32 value; u32 arg; @@ -522,28 +259,28 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO) return -ENOTSUPP; - value = readl(cv1800_pinctrl_get_component_addr(pctrl, &pin->conf)); + value = readl(cv1800_pinctrl_get_component_addr(priv, &pin->conf)); switch (param) { case PIN_CONFIG_BIAS_PULL_DOWN: enabled = FIELD_GET(PIN_IO_PULLDOWN, value); - arg = cv1800_pull_down_typical_resistor(pctrl, pin); + arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_BIAS_PULL_UP: enabled = FIELD_GET(PIN_IO_PULLUP, value); - arg = cv1800_pull_up_typical_resistor(pctrl, pin); + arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_DRIVE_STRENGTH_UA: enabled = true; arg = FIELD_GET(PIN_IO_DRIVE, value); - ret = cv1800_pinctrl_reg2oc(pctrl, pin, arg); + ret = sophgo_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; break; case PIN_CONFIG_INPUT_SCHMITT_UV: arg = FIELD_GET(PIN_IO_SCHMITT, value); - ret = cv1800_pinctrl_reg2schmitt(pctrl, pin, arg); + ret = sophgo_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; @@ -570,14 +307,16 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, return enabled ? 0 : -EINVAL; } -static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, +static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, unsigned long *configs, unsigned int num_configs, - u32 *value) + u32 *value, u32 *mask) { + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); int i; - u32 v = 0; + u32 v = 0, m = 0; enum cv1800_pin_io_type type; int ret; @@ -596,24 +335,30 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, case PIN_CONFIG_BIAS_PULL_DOWN: v &= ~PIN_IO_PULLDOWN; v |= FIELD_PREP(PIN_IO_PULLDOWN, arg); + m |= PIN_IO_PULLDOWN; break; case PIN_CONFIG_BIAS_PULL_UP: v &= ~PIN_IO_PULLUP; v |= FIELD_PREP(PIN_IO_PULLUP, arg); + m |= PIN_IO_PULLUP; break; case PIN_CONFIG_DRIVE_STRENGTH_UA: - ret = cv1800_pinctrl_oc2reg(pctrl, pin, arg); + ret = sophgo_pinctrl_oc2reg(pctrl, sp, + priv->power_cfg, arg); if (ret < 0) return ret; v &= ~PIN_IO_DRIVE; v |= FIELD_PREP(PIN_IO_DRIVE, ret); + m |= PIN_IO_DRIVE; break; case PIN_CONFIG_INPUT_SCHMITT_UV: - ret = cv1800_pinctrl_schmitt2reg(pctrl, pin, arg); + ret = sophgo_pinctrl_schmitt2reg(pctrl, sp, + priv->power_cfg, arg); if (ret < 0) return ret; v &= ~PIN_IO_SCHMITT; v |= FIELD_PREP(PIN_IO_SCHMITT, ret); + m |= PIN_IO_SCHMITT; break; case PIN_CONFIG_POWER_SOURCE: /* Ignore power source as it is always fixed */ @@ -621,10 +366,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, case PIN_CONFIG_SLEW_RATE: v &= ~PIN_IO_OUT_FAST_SLEW; v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg); + m |= PIN_IO_OUT_FAST_SLEW; break; case PIN_CONFIG_BIAS_BUS_HOLD: v &= ~PIN_IO_BUS_HOLD; v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg); + m |= PIN_IO_BUS_HOLD; break; default: return -ENOTSUPP; @@ -632,134 +379,73 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, } *value = v; + *mask = m; return 0; } -static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl, - unsigned int pin_id, - u32 value) +static int cv1800_set_pinconf_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask) { - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); - unsigned long flags; + struct cv1800_priv *priv = pctrl->priv_ctrl; + struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); void __iomem *addr; + u32 reg; - if (!pin) - return -EINVAL; - - addr = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); + addr = cv1800_pinctrl_get_component_addr(priv, &pin->conf); - raw_spin_lock_irqsave(&pctrl->lock, flags); - writel(value, addr); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); + reg = readl(addr); + reg &= ~mask; + reg |= value; + writel(reg, addr); return 0; } -static int cv1800_pconf_set(struct pinctrl_dev *pctldev, - unsigned int pin_id, unsigned long *configs, - unsigned int num_configs) -{ - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); - u32 value; - - if (!pin) - return -ENODEV; - - if (cv1800_pinconf_compute_config(pctrl, pin, - configs, num_configs, &value)) - return -ENOTSUPP; - - return cv1800_pin_set_config(pctrl, pin_id, value); -} - -static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, - unsigned int gsel, - unsigned long *configs, - unsigned int num_configs) -{ - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct group_desc *group; - const struct cv1800_pin_mux_config *pinmuxs; - u32 value; - int i; - - group = pinctrl_generic_get_group(pctldev, gsel); - if (!group) - return -EINVAL; - - pinmuxs = group->data; - - if (cv1800_pinconf_compute_config(pctrl, pinmuxs[0].pin, - configs, num_configs, &value)) - return -ENOTSUPP; - - for (i = 0; i < group->grp.npins; i++) - cv1800_pin_set_config(pctrl, group->grp.pins[i], value); - - return 0; -} - -static const struct pinconf_ops cv1800_pconf_ops = { +const struct pinconf_ops cv1800_pconf_ops = { .pin_config_get = cv1800_pconf_get, - .pin_config_set = cv1800_pconf_set, - .pin_config_group_set = cv1800_pconf_group_set, + .pin_config_set = sophgo_pconf_set, + .pin_config_group_set = sophgo_pconf_group_set, .is_generic = true, }; +EXPORT_SYMBOL_GPL(cv1800_pconf_ops); -int cv1800_pinctrl_probe(struct platform_device *pdev) +static int cv1800_pinctrl_init(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl) { - struct device *dev = &pdev->dev; - struct cv1800_pinctrl *pctrl; - const struct cv1800_pinctrl_data *pctrl_data; - int ret; - - pctrl_data = device_get_match_data(dev); - if (!pctrl_data) - return -ENODEV; + const struct sophgo_pinctrl_data *pctrl_data = pctrl->data; + struct cv1800_priv *priv; - if (pctrl_data->npins == 0 || pctrl_data->npd == 0) - return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); - - pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); - if (!pctrl) + priv = devm_kzalloc(&pdev->dev, sizeof(struct cv1800_priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - pctrl->power_cfg = devm_kcalloc(dev, pctrl_data->npd, - sizeof(u32), GFP_KERNEL); - if (!pctrl->power_cfg) + priv->power_cfg = devm_kcalloc(&pdev->dev, pctrl_data->npds, + sizeof(u32), GFP_KERNEL); + if (!priv->power_cfg) return -ENOMEM; - pctrl->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); - if (IS_ERR(pctrl->regs[0])) - return PTR_ERR(pctrl->regs[0]); - - pctrl->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); - if (IS_ERR(pctrl->regs[1])) - return PTR_ERR(pctrl->regs[1]); - - pctrl->pdesc.name = dev_name(dev); - pctrl->pdesc.pins = pctrl_data->pins; - pctrl->pdesc.npins = pctrl_data->npins; - pctrl->pdesc.pctlops = &cv1800_pctrl_ops; - pctrl->pdesc.pmxops = &cv1800_pmx_ops; - pctrl->pdesc.confops = &cv1800_pconf_ops; - pctrl->pdesc.owner = THIS_MODULE; - - pctrl->data = pctrl_data; - pctrl->dev = dev; - raw_spin_lock_init(&pctrl->lock); - mutex_init(&pctrl->mutex); + priv->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); + if (IS_ERR(priv->regs[0])) + return PTR_ERR(priv->regs[0]); - platform_set_drvdata(pdev, pctrl); + priv->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); + if (IS_ERR(priv->regs[1])) + return PTR_ERR(priv->regs[1]); - ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, - pctrl, &pctrl->pctl_dev); - if (ret) - return dev_err_probe(dev, ret, - "fail to register pinctrl driver\n"); + pctrl->priv_ctrl = priv; - return pinctrl_enable(pctrl->pctl_dev); + return 0; } -EXPORT_SYMBOL_GPL(cv1800_pinctrl_probe); + +const struct sophgo_cfg_ops cv1800_cfg_ops = { + .pctrl_init = cv1800_pinctrl_init, + .verify_pinmux_config = cv1800_verify_pinmux_config, + .verify_pin_group = cv1800_verify_pin_group, + .dt_node_to_map_post = cv1800_dt_node_to_map_post, + .compute_pinconf_config = cv1800_pinconf_compute_config, + .set_pinconf_config = cv1800_set_pinconf_config, + .set_pinmux_config = cv1800_set_pinmux_config, +}; +EXPORT_SYMBOL_GPL(cv1800_cfg_ops); diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h index 1a9998abb3b7..759c0e604acf 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h @@ -8,13 +8,14 @@ #include <linux/bits.h> #include <linux/bitfield.h> -#include <linux/device.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinconf.h> +#include "pinctrl-sophgo.h" + enum cv1800_pin_io_type { IO_TYPE_1V8_ONLY = 0, IO_TYPE_1V8_OR_3V3 = 1, @@ -49,58 +50,37 @@ struct cv1800_pinconf { #define CV1800_PIN_FLAG_IO_TYPE(type) \ FIELD_PREP_CONST(CV1800_PIN_IO_TYPE, type) struct cv1800_pin { - u16 pin; - u16 flags; + struct sophgo_pin pin; u8 power_domain; struct cv1800_pinmux mux; struct cv1800_pinmux2 mux2; struct cv1800_pinconf conf; }; +#define sophgo_to_cv1800_pin(_pin) \ + container_of((_pin), struct cv1800_pin, pin) + #define PIN_POWER_STATE_1V8 1800 #define PIN_POWER_STATE_3V3 3300 -/** - * struct cv1800_vddio_cfg_ops - pin vddio operations - * - * @get_pull_up: get resistor for pull up; - * @get_pull_down: get resistor for pull down. - * @get_oc_map: get mapping for typical low level output current value to - * register value map. - * @get_schmitt_map: get mapping for register value to typical schmitt - * threshold. - */ -struct cv1800_vddio_cfg_ops { - int (*get_pull_up)(struct cv1800_pin *pin, const u32 *psmap); - int (*get_pull_down)(struct cv1800_pin *pin, const u32 *psmap); - int (*get_oc_map)(struct cv1800_pin *pin, const u32 *psmap, - const u32 **map); - int (*get_schmitt_map)(struct cv1800_pin *pin, const u32 *psmap, - const u32 **map); -}; - -struct cv1800_pinctrl_data { - const struct pinctrl_pin_desc *pins; - const struct cv1800_pin *pindata; - const char * const *pdnames; - const struct cv1800_vddio_cfg_ops *vddio_ops; - u16 npins; - u16 npd; -}; - -static inline enum cv1800_pin_io_type cv1800_pin_io_type(struct cv1800_pin *pin) +static inline enum cv1800_pin_io_type cv1800_pin_io_type(const struct cv1800_pin *pin) { - return FIELD_GET(CV1800_PIN_IO_TYPE, pin->flags); + return FIELD_GET(CV1800_PIN_IO_TYPE, pin->pin.flags); }; -int cv1800_pinctrl_probe(struct platform_device *pdev); +extern const struct pinctrl_ops cv1800_pctrl_ops; +extern const struct pinmux_ops cv1800_pmx_ops; +extern const struct pinconf_ops cv1800_pconf_ops; +extern const struct sophgo_cfg_ops cv1800_cfg_ops; #define CV1800_FUNC_PIN(_id, _power_domain, _type, \ _mux_area, _mux_offset, _mux_func_max) \ { \ - .pin = (_id), \ + .pin = { \ + .id = (_id), \ + .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ + }, \ .power_domain = (_power_domain), \ - .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ .mux = { \ .area = (_mux_area), \ .offset = (_mux_offset), \ @@ -112,9 +92,11 @@ int cv1800_pinctrl_probe(struct platform_device *pdev); _mux_area, _mux_offset, _mux_func_max, \ _conf_area, _conf_offset) \ { \ - .pin = (_id), \ + .pin = { \ + .id = (_id), \ + .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ + }, \ .power_domain = (_power_domain), \ - .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ .mux = { \ .area = (_mux_area), \ .offset = (_mux_offset), \ @@ -132,10 +114,12 @@ int cv1800_pinctrl_probe(struct platform_device *pdev); _mux2_func_max, \ _conf_area, _conf_offset) \ { \ - .pin = (_id), \ + .pin = { \ + .id = (_id), \ + .flags = CV1800_PIN_FLAG_IO_TYPE(_type) | \ + CV1800_PIN_HAVE_MUX2, \ + }, \ .power_domain = (_power_domain), \ - .flags = CV1800_PIN_FLAG_IO_TYPE(_type) | \ - CV1800_PIN_HAVE_MUX2, \ .mux = { \ .area = (_mux_area), \ .offset = (_mux_offset), \ diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2000.c b/drivers/pinctrl/sophgo/pinctrl-sg2000.c index 63c05b4dd68f..0e303d2fa104 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2000.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2000.c @@ -40,8 +40,9 @@ static const char *const sg2000_power_domain_desc[] = { [VDDIO_VIVO] = "VDDIO_VIVO", }; -static int sg2000_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int sg2000_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -60,8 +61,9 @@ static int sg2000_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int sg2000_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int sg2000_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -114,9 +116,10 @@ static const u32 sg2000_eth_oc_map[] = { 17800 }; -static int sg2000_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2000_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -159,9 +162,10 @@ static const u32 sg2000_18od33_3v3_schmitt_map[] = { 1100000 }; -static int sg2000_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2000_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -183,11 +187,11 @@ static int sg2000_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops sg2000_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops sg2000_vddio_cfg_ops = { .get_pull_up = sg2000_get_pull_up, .get_pull_down = sg2000_get_pull_down, .get_oc_map = sg2000_get_oc_map, - .get_schmitt_map = sg2000_get_schmitt_map, + .get_schmitt_map = sg2000_get_schmitt_map, }; static const struct pinctrl_pin_desc sg2000_pins[] = { @@ -742,13 +746,18 @@ static const struct cv1800_pin sg2000_pin_data[ARRAY_SIZE(sg2000_pins)] = { CV1800_PINCONF_AREA_RTC, 0x028), }; -static const struct cv1800_pinctrl_data sg2000_pindata = { +static const struct sophgo_pinctrl_data sg2000_pindata = { .pins = sg2000_pins, .pindata = sg2000_pin_data, .pdnames = sg2000_power_domain_desc, .vddio_ops = &sg2000_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(sg2000_pins), - .npd = ARRAY_SIZE(sg2000_power_domain_desc), + .npds = ARRAY_SIZE(sg2000_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id sg2000_pinctrl_ids[] = { @@ -758,7 +767,7 @@ static const struct of_device_id sg2000_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, sg2000_pinctrl_ids); static struct platform_driver sg2000_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "sg2000-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2002.c b/drivers/pinctrl/sophgo/pinctrl-sg2002.c index 5c49208dcb59..2443fff1bc00 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2002.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2002.c @@ -34,8 +34,9 @@ static const char *const sg2002_power_domain_desc[] = { [VDDIO_SD1] = "VDDIO_SD1", }; -static int sg2002_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int sg2002_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -54,8 +55,9 @@ static int sg2002_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int sg2002_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int sg2002_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -108,9 +110,10 @@ static const u32 sg2002_eth_oc_map[] = { 17800 }; -static int sg2002_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2002_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -153,9 +156,10 @@ static const u32 sg2002_18od33_3v3_schmitt_map[] = { 1100000 }; -static int sg2002_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2002_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -177,11 +181,11 @@ static int sg2002_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops sg2002_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops sg2002_vddio_cfg_ops = { .get_pull_up = sg2002_get_pull_up, .get_pull_down = sg2002_get_pull_down, .get_oc_map = sg2002_get_oc_map, - .get_schmitt_map = sg2002_get_schmitt_map, + .get_schmitt_map = sg2002_get_schmitt_map, }; static const struct pinctrl_pin_desc sg2002_pins[] = { @@ -513,13 +517,18 @@ static const struct cv1800_pin sg2002_pin_data[ARRAY_SIZE(sg2002_pins)] = { CV1800_PINCONF_AREA_SYS, 0xc84), }; -static const struct cv1800_pinctrl_data sg2002_pindata = { +static const struct sophgo_pinctrl_data sg2002_pindata = { .pins = sg2002_pins, .pindata = sg2002_pin_data, .pdnames = sg2002_power_domain_desc, .vddio_ops = &sg2002_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(sg2002_pins), - .npd = ARRAY_SIZE(sg2002_power_domain_desc), + .npds = ARRAY_SIZE(sg2002_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id sg2002_pinctrl_ids[] = { @@ -529,7 +538,7 @@ static const struct of_device_id sg2002_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, sg2002_pinctrl_ids); static struct platform_driver sg2002_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "sg2002-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c b/drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c new file mode 100644 index 000000000000..0526aa3f8438 --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo sg2042 SoCs pinctrl driver. + * + * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> + * + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/export.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/spinlock.h> + +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "../pinctrl-utils.h" +#include "../pinmux.h" + +#include "pinctrl-sg2042.h" + +#define PIN_IO_PULL_ONE_ENABLE BIT(0) +#define PIN_IO_PULL_DIR_UP (BIT(1) | PIN_IO_PULL_ONE_ENABLE) +#define PIN_IO_PULL_DIR_DOWN (0 | PIN_IO_PULL_ONE_ENABLE) +#define PIN_IO_PULL_ONE_MASK GENMASK(1, 0) + +#define PIN_IO_PULL_UP BIT(2) +#define PIN_IO_PULL_UP_DONW BIT(3) +#define PIN_IO_PULL_UP_MASK GENMASK(3, 2) + +#define PIN_IO_MUX GENMASK(5, 4) +#define PIN_IO_DRIVE GENMASK(9, 6) +#define PIN_IO_SCHMITT_ENABLE BIT(10) +#define PIN_IO_OUTPUT_ENABLE BIT(11) + +struct sg2042_priv { + void __iomem *regs; +}; + +static u8 sg2042_dt_get_pin_mux(u32 value) +{ + return value >> 16; +} + +static inline u32 sg2042_get_pin_reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp) +{ + struct sg2042_priv *priv = pctrl->priv_ctrl; + const struct sg2042_pin *pin = sophgo_to_sg2042_pin(sp); + void __iomem *reg = priv->regs + pin->offset; + + if (sp->flags & PIN_FLAG_WRITE_HIGH) + return readl(reg) >> 16; + else + return readl(reg) & 0xffff; +} + +static int sg2042_set_pin_reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask) +{ + struct sg2042_priv *priv = pctrl->priv_ctrl; + const struct sg2042_pin *pin = sophgo_to_sg2042_pin(sp); + void __iomem *reg = priv->regs + pin->offset; + u32 v = readl(reg); + + if (sp->flags & PIN_FLAG_WRITE_HIGH) { + v &= ~(mask << 16); + v |= value << 16; + } else { + v &= ~mask; + v |= value; + } + + writel(v, reg); + + return 0; +} + +static void sg2042_pctrl_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *seq, unsigned int pin_id) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + u32 value, mux; + + value = sg2042_get_pin_reg(pctrl, sp); + mux = FIELD_GET(PIN_IO_MUX, value); + seq_printf(seq, "mux:%u reg:0x%04x ", mux, value); +} + +const struct pinctrl_ops sg2042_pctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .pin_dbg_show = sg2042_pctrl_dbg_show, + .dt_node_to_map = sophgo_pctrl_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; +EXPORT_SYMBOL_GPL(sg2042_pctrl_ops); + +static void sg2042_set_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config) +{ + u32 mux = sg2042_dt_get_pin_mux(config); + + if (!(sp->flags & PIN_FLAG_NO_PINMUX)) + sg2042_set_pin_reg(pctrl, sp, mux, PIN_IO_MUX); +} + +const struct pinmux_ops sg2042_pmx_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = sophgo_pmx_set_mux, + .strict = true, +}; +EXPORT_SYMBOL_GPL(sg2042_pmx_ops); + +static int sg2042_pconf_get(struct pinctrl_dev *pctldev, + unsigned int pin_id, unsigned long *config) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int param = pinconf_to_config_param(*config); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + u32 value; + u32 arg; + bool enabled; + int ret; + + if (!sp) + return -EINVAL; + + value = sg2042_get_pin_reg(pctrl, sp); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) + arg = FIELD_GET(PIN_IO_PULL_ONE_ENABLE, value); + else + arg = FIELD_GET(PIN_IO_PULL_UP_MASK, value); + enabled = arg == 0; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + arg = FIELD_GET(PIN_IO_PULL_ONE_MASK, value); + enabled = arg == PIN_IO_PULL_DIR_DOWN; + } else { + enabled = FIELD_GET(PIN_IO_PULL_UP_DONW, value) != 0; + } + arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, NULL); + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + arg = FIELD_GET(PIN_IO_PULL_ONE_MASK, value); + enabled = arg == PIN_IO_PULL_DIR_UP; + } else { + enabled = FIELD_GET(PIN_IO_PULL_UP, value) != 0; + } + arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, NULL); + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + enabled = FIELD_GET(PIN_IO_OUTPUT_ENABLE, value) != 0; + arg = FIELD_GET(PIN_IO_DRIVE, value); + ret = sophgo_pinctrl_reg2oc(pctrl, sp, NULL, arg); + if (ret < 0) + return ret; + arg = ret; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + arg = FIELD_GET(PIN_IO_SCHMITT_ENABLE, value); + enabled = arg != 0; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return enabled ? 0 : -EINVAL; +} + +static int sg2042_pinconf_compute_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + unsigned long *configs, + unsigned int num_configs, + u32 *value, u32 *mask) +{ + int i; + u16 v = 0, m = 0; + int ret; + + if (!sp) + return -EINVAL; + + for (i = 0; i < num_configs; i++) { + int param = pinconf_to_config_param(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + v &= ~PIN_IO_PULL_ONE_ENABLE; + m |= PIN_IO_PULL_ONE_ENABLE; + } else { + v &= ~PIN_IO_PULL_UP_MASK; + m |= PIN_IO_PULL_UP_MASK; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + v &= ~PIN_IO_PULL_ONE_MASK; + v |= PIN_IO_PULL_DIR_DOWN; + m |= PIN_IO_PULL_ONE_MASK; + } else { + v |= PIN_IO_PULL_UP_DONW; + m |= PIN_IO_PULL_UP_DONW; + } + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + v &= ~PIN_IO_PULL_ONE_MASK; + v |= PIN_IO_PULL_DIR_UP; + m |= PIN_IO_PULL_ONE_MASK; + } else { + v |= PIN_IO_PULL_UP; + m |= PIN_IO_PULL_UP; + } + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + v &= ~(PIN_IO_DRIVE | PIN_IO_OUTPUT_ENABLE); + if (arg != 0) { + ret = sophgo_pinctrl_oc2reg(pctrl, sp, NULL, arg); + if (ret < 0) + return ret; + if (!(sp->flags & PIN_FLAG_NO_OEX_EN)) + v |= PIN_IO_OUTPUT_ENABLE; + v |= FIELD_PREP(PIN_IO_DRIVE, ret); + } + m |= PIN_IO_DRIVE | PIN_IO_OUTPUT_ENABLE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + v |= PIN_IO_SCHMITT_ENABLE; + m |= PIN_IO_SCHMITT_ENABLE; + break; + default: + return -ENOTSUPP; + } + } + + *value = v; + *mask = m; + + return 0; +} + +const struct pinconf_ops sg2042_pconf_ops = { + .pin_config_get = sg2042_pconf_get, + .pin_config_set = sophgo_pconf_set, + .pin_config_group_set = sophgo_pconf_group_set, + .is_generic = true, +}; +EXPORT_SYMBOL_GPL(sg2042_pconf_ops); + +static int sophgo_pinctrl_init(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl) +{ + struct sg2042_priv *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + pctrl->priv_ctrl = priv; + + return 0; +} + +const struct sophgo_cfg_ops sg2042_cfg_ops = { + .pctrl_init = sophgo_pinctrl_init, + .compute_pinconf_config = sg2042_pinconf_compute_config, + .set_pinconf_config = sg2042_set_pin_reg, + .set_pinmux_config = sg2042_set_pinmux_config, +}; +EXPORT_SYMBOL_GPL(sg2042_cfg_ops); diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.c b/drivers/pinctrl/sophgo/pinctrl-sg2042.c new file mode 100644 index 000000000000..185305ac897d --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.c @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SG2042 SoC pinctrl driver. + * + * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include <dt-bindings/pinctrl/pinctrl-sg2042.h> + +#include "pinctrl-sg2042.h" + +static int sg2042_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 35000; +} + +static int sg2042_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 28000; +} + +static const u32 sg2042_oc_map[] = { + 5400, 8100, 10700, 13400, + 16100, 18800, 21400, 24100, + 26800, 29400, 32100, 34800, + 37400, 40100, 42800, 45400 +}; + +static int sg2042_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, + const u32 **map) +{ + *map = sg2042_oc_map; + return ARRAY_SIZE(sg2042_oc_map); +} + +static const struct sophgo_vddio_cfg_ops sg2042_vddio_cfg_ops = { + .get_pull_up = sg2042_get_pull_up, + .get_pull_down = sg2042_get_pull_down, + .get_oc_map = sg2042_get_oc_map, +}; + +static const struct pinctrl_pin_desc sg2042_pins[] = { + PINCTRL_PIN(PIN_LPC_LCLK, "lpc_lclk"), + PINCTRL_PIN(PIN_LPC_LFRAME, "lpc_lframe"), + PINCTRL_PIN(PIN_LPC_LAD0, "lpc_lad0"), + PINCTRL_PIN(PIN_LPC_LAD1, "lpc_lad1"), + PINCTRL_PIN(PIN_LPC_LAD2, "lpc_lad2"), + PINCTRL_PIN(PIN_LPC_LAD3, "lpc_lad3"), + PINCTRL_PIN(PIN_LPC_LDRQ0, "lpc_ldrq0"), + PINCTRL_PIN(PIN_LPC_LDRQ1, "lpc_ldrq1"), + PINCTRL_PIN(PIN_LPC_SERIRQ, "lpc_serirq"), + PINCTRL_PIN(PIN_LPC_CLKRUN, "lpc_clkrun"), + PINCTRL_PIN(PIN_LPC_LPME, "lpc_lpme"), + PINCTRL_PIN(PIN_LPC_LPCPD, "lpc_lpcpd"), + PINCTRL_PIN(PIN_LPC_LSMI, "lpc_lsmi"), + PINCTRL_PIN(PIN_PCIE0_L0_RESET, "pcie0_l0_reset"), + PINCTRL_PIN(PIN_PCIE0_L1_RESET, "pcie0_l1_reset"), + PINCTRL_PIN(PIN_PCIE0_L0_WAKEUP, "pcie0_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L1_WAKEUP, "pcie0_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L0_CLKREQ_IN, "pcie0_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE0_L1_CLKREQ_IN, "pcie0_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L0_RESET, "pcie1_l0_reset"), + PINCTRL_PIN(PIN_PCIE1_L1_RESET, "pcie1_l1_reset"), + PINCTRL_PIN(PIN_PCIE1_L0_WAKEUP, "pcie1_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L1_WAKEUP, "pcie1_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L0_CLKREQ_IN, "pcie1_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L1_CLKREQ_IN, "pcie1_l1_clkreq_in"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL1, "spif0_clk_sel1"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL0, "spif0_clk_sel0"), + PINCTRL_PIN(PIN_SPIF0_WP, "spif0_wp"), + PINCTRL_PIN(PIN_SPIF0_HOLD, "spif0_hold"), + PINCTRL_PIN(PIN_SPIF0_SDI, "spif0_sdi"), + PINCTRL_PIN(PIN_SPIF0_CS, "spif0_cs"), + PINCTRL_PIN(PIN_SPIF0_SCK, "spif0_sck"), + PINCTRL_PIN(PIN_SPIF0_SDO, "spif0_sdo"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL1, "spif1_clk_sel1"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL0, "spif1_clk_sel0"), + PINCTRL_PIN(PIN_SPIF1_WP, "spif1_wp"), + PINCTRL_PIN(PIN_SPIF1_HOLD, "spif1_hold"), + PINCTRL_PIN(PIN_SPIF1_SDI, "spif1_sdi"), + PINCTRL_PIN(PIN_SPIF1_CS, "spif1_cs"), + PINCTRL_PIN(PIN_SPIF1_SCK, "spif1_sck"), + PINCTRL_PIN(PIN_SPIF1_SDO, "spif1_sdo"), + PINCTRL_PIN(PIN_EMMC_WP, "emmc_wp"), + PINCTRL_PIN(PIN_EMMC_CD, "emmc_cd"), + PINCTRL_PIN(PIN_EMMC_RST, "emmc_rst"), + PINCTRL_PIN(PIN_EMMC_PWR_EN, "emmc_pwr_en"), + PINCTRL_PIN(PIN_SDIO_CD, "sdio_cd"), + PINCTRL_PIN(PIN_SDIO_WP, "sdio_wp"), + PINCTRL_PIN(PIN_SDIO_RST, "sdio_rst"), + PINCTRL_PIN(PIN_SDIO_PWR_EN, "sdio_pwr_en"), + PINCTRL_PIN(PIN_RGMII0_TXD0, "rgmii0_txd0"), + PINCTRL_PIN(PIN_RGMII0_TXD1, "rgmii0_txd1"), + PINCTRL_PIN(PIN_RGMII0_TXD2, "rgmii0_txd2"), + PINCTRL_PIN(PIN_RGMII0_TXD3, "rgmii0_txd3"), + PINCTRL_PIN(PIN_RGMII0_TXCTRL, "rgmii0_txctrl"), + PINCTRL_PIN(PIN_RGMII0_RXD0, "rgmii0_rxd0"), + PINCTRL_PIN(PIN_RGMII0_RXD1, "rgmii0_rxd1"), + PINCTRL_PIN(PIN_RGMII0_RXD2, "rgmii0_rxd2"), + PINCTRL_PIN(PIN_RGMII0_RXD3, "rgmii0_rxd3"), + PINCTRL_PIN(PIN_RGMII0_RXCTRL, "rgmii0_rxctrl"), + PINCTRL_PIN(PIN_RGMII0_TXC, "rgmii0_txc"), + PINCTRL_PIN(PIN_RGMII0_RXC, "rgmii0_rxc"), + PINCTRL_PIN(PIN_RGMII0_REFCLKO, "rgmii0_refclko"), + PINCTRL_PIN(PIN_RGMII0_IRQ, "rgmii0_irq"), + PINCTRL_PIN(PIN_RGMII0_MDC, "rgmii0_mdc"), + PINCTRL_PIN(PIN_RGMII0_MDIO, "rgmii0_mdio"), + PINCTRL_PIN(PIN_PWM0, "pwm0"), + PINCTRL_PIN(PIN_PWM1, "pwm1"), + PINCTRL_PIN(PIN_PWM2, "pwm2"), + PINCTRL_PIN(PIN_PWM3, "pwm3"), + PINCTRL_PIN(PIN_FAN0, "fan0"), + PINCTRL_PIN(PIN_FAN1, "fan1"), + PINCTRL_PIN(PIN_FAN2, "fan2"), + PINCTRL_PIN(PIN_FAN3, "fan3"), + PINCTRL_PIN(PIN_IIC0_SDA, "iic0_sda"), + PINCTRL_PIN(PIN_IIC0_SCL, "iic0_scl"), + PINCTRL_PIN(PIN_IIC1_SDA, "iic1_sda"), + PINCTRL_PIN(PIN_IIC1_SCL, "iic1_scl"), + PINCTRL_PIN(PIN_IIC2_SDA, "iic2_sda"), + PINCTRL_PIN(PIN_IIC2_SCL, "iic2_scl"), + PINCTRL_PIN(PIN_IIC3_SDA, "iic3_sda"), + PINCTRL_PIN(PIN_IIC3_SCL, "iic3_scl"), + PINCTRL_PIN(PIN_UART0_TX, "uart0_tx"), + PINCTRL_PIN(PIN_UART0_RX, "uart0_rx"), + PINCTRL_PIN(PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(PIN_UART1_TX, "uart1_tx"), + PINCTRL_PIN(PIN_UART1_RX, "uart1_rx"), + PINCTRL_PIN(PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(PIN_UART2_TX, "uart2_tx"), + PINCTRL_PIN(PIN_UART2_RX, "uart2_rx"), + PINCTRL_PIN(PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(PIN_UART3_TX, "uart3_tx"), + PINCTRL_PIN(PIN_UART3_RX, "uart3_rx"), + PINCTRL_PIN(PIN_UART3_RTS, "uart3_rts"), + PINCTRL_PIN(PIN_UART3_CTS, "uart3_cts"), + PINCTRL_PIN(PIN_SPI0_CS0, "spi0_cs0"), + PINCTRL_PIN(PIN_SPI0_CS1, "spi0_cs1"), + PINCTRL_PIN(PIN_SPI0_SDI, "spi0_sdi"), + PINCTRL_PIN(PIN_SPI0_SDO, "spi0_sdo"), + PINCTRL_PIN(PIN_SPI0_SCK, "spi0_sck"), + PINCTRL_PIN(PIN_SPI1_CS0, "spi1_cs0"), + PINCTRL_PIN(PIN_SPI1_CS1, "spi1_cs1"), + PINCTRL_PIN(PIN_SPI1_SDI, "spi1_sdi"), + PINCTRL_PIN(PIN_SPI1_SDO, "spi1_sdo"), + PINCTRL_PIN(PIN_SPI1_SCK, "spi1_sck"), + PINCTRL_PIN(PIN_JTAG0_TDO, "jtag0_tdo"), + PINCTRL_PIN(PIN_JTAG0_TCK, "jtag0_tck"), + PINCTRL_PIN(PIN_JTAG0_TDI, "jtag0_tdi"), + PINCTRL_PIN(PIN_JTAG0_TMS, "jtag0_tms"), + PINCTRL_PIN(PIN_JTAG0_TRST, "jtag0_trst"), + PINCTRL_PIN(PIN_JTAG0_SRST, "jtag0_srst"), + PINCTRL_PIN(PIN_JTAG1_TDO, "jtag1_tdo"), + PINCTRL_PIN(PIN_JTAG1_TCK, "jtag1_tck"), + PINCTRL_PIN(PIN_JTAG1_TDI, "jtag1_tdi"), + PINCTRL_PIN(PIN_JTAG1_TMS, "jtag1_tms"), + PINCTRL_PIN(PIN_JTAG1_TRST, "jtag1_trst"), + PINCTRL_PIN(PIN_JTAG1_SRST, "jtag1_srst"), + PINCTRL_PIN(PIN_JTAG2_TDO, "jtag2_tdo"), + PINCTRL_PIN(PIN_JTAG2_TCK, "jtag2_tck"), + PINCTRL_PIN(PIN_JTAG2_TDI, "jtag2_tdi"), + PINCTRL_PIN(PIN_JTAG2_TMS, "jtag2_tms"), + PINCTRL_PIN(PIN_JTAG2_TRST, "jtag2_trst"), + PINCTRL_PIN(PIN_JTAG2_SRST, "jtag2_srst"), + PINCTRL_PIN(PIN_GPIO0, "gpio0"), + PINCTRL_PIN(PIN_GPIO1, "gpio1"), + PINCTRL_PIN(PIN_GPIO2, "gpio2"), + PINCTRL_PIN(PIN_GPIO3, "gpio3"), + PINCTRL_PIN(PIN_GPIO4, "gpio4"), + PINCTRL_PIN(PIN_GPIO5, "gpio5"), + PINCTRL_PIN(PIN_GPIO6, "gpio6"), + PINCTRL_PIN(PIN_GPIO7, "gpio7"), + PINCTRL_PIN(PIN_GPIO8, "gpio8"), + PINCTRL_PIN(PIN_GPIO9, "gpio9"), + PINCTRL_PIN(PIN_GPIO10, "gpio10"), + PINCTRL_PIN(PIN_GPIO11, "gpio11"), + PINCTRL_PIN(PIN_GPIO12, "gpio12"), + PINCTRL_PIN(PIN_GPIO13, "gpio13"), + PINCTRL_PIN(PIN_GPIO14, "gpio14"), + PINCTRL_PIN(PIN_GPIO15, "gpio15"), + PINCTRL_PIN(PIN_GPIO16, "gpio16"), + PINCTRL_PIN(PIN_GPIO17, "gpio17"), + PINCTRL_PIN(PIN_GPIO18, "gpio18"), + PINCTRL_PIN(PIN_GPIO19, "gpio19"), + PINCTRL_PIN(PIN_GPIO20, "gpio20"), + PINCTRL_PIN(PIN_GPIO21, "gpio21"), + PINCTRL_PIN(PIN_GPIO22, "gpio22"), + PINCTRL_PIN(PIN_GPIO23, "gpio23"), + PINCTRL_PIN(PIN_GPIO24, "gpio24"), + PINCTRL_PIN(PIN_GPIO25, "gpio25"), + PINCTRL_PIN(PIN_GPIO26, "gpio26"), + PINCTRL_PIN(PIN_GPIO27, "gpio27"), + PINCTRL_PIN(PIN_GPIO28, "gpio28"), + PINCTRL_PIN(PIN_GPIO29, "gpio29"), + PINCTRL_PIN(PIN_GPIO30, "gpio30"), + PINCTRL_PIN(PIN_GPIO31, "gpio31"), + PINCTRL_PIN(PIN_MODE_SEL0, "mode_sel0"), + PINCTRL_PIN(PIN_MODE_SEL1, "mode_sel1"), + PINCTRL_PIN(PIN_MODE_SEL2, "mode_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL0, "boot_sel0"), + PINCTRL_PIN(PIN_BOOT_SEL1, "boot_sel1"), + PINCTRL_PIN(PIN_BOOT_SEL2, "boot_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL3, "boot_sel3"), + PINCTRL_PIN(PIN_BOOT_SEL4, "boot_sel4"), + PINCTRL_PIN(PIN_BOOT_SEL5, "boot_sel5"), + PINCTRL_PIN(PIN_BOOT_SEL6, "boot_sel6"), + PINCTRL_PIN(PIN_BOOT_SEL7, "boot_sel7"), + PINCTRL_PIN(PIN_MULTI_SCKT, "multi_sckt"), + PINCTRL_PIN(PIN_SCKT_ID0, "sckt_id0"), + PINCTRL_PIN(PIN_SCKT_ID1, "sckt_id1"), + PINCTRL_PIN(PIN_PLL_CLK_IN_MAIN, "pll_clk_in_main"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_L, "pll_clk_in_ddr_l"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_R, "pll_clk_in_ddr_r"), + PINCTRL_PIN(PIN_XTAL_32K, "xtal_32k"), + PINCTRL_PIN(PIN_SYS_RST, "sys_rst"), + PINCTRL_PIN(PIN_PWR_BUTTON, "pwr_button"), + PINCTRL_PIN(PIN_TEST_EN, "test_en"), + PINCTRL_PIN(PIN_TEST_MODE_MBIST, "test_mode_mbist"), + PINCTRL_PIN(PIN_TEST_MODE_SCAN, "test_mode_scan"), + PINCTRL_PIN(PIN_TEST_MODE_BSD, "test_mode_bsd"), + PINCTRL_PIN(PIN_BISR_BYP, "bisr_byp"), +}; + +static const struct sg2042_pin sg2042_pin_data[ARRAY_SIZE(sg2042_pins)] = { + SG2042_GENERAL_PIN(PIN_LPC_LCLK, 0x000, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LFRAME, 0x000, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD0, 0x004, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD1, 0x004, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD2, 0x008, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD3, 0x008, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LDRQ0, 0x00c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LDRQ1, 0x00c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_SERIRQ, 0x010, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_CLKRUN, 0x010, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LPME, 0x014, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LPCPD, 0x014, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LSMI, 0x018, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_RESET, 0x018, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_RESET, 0x01c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_WAKEUP, 0x01c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_WAKEUP, 0x020, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_CLKREQ_IN, 0x020, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_CLKREQ_IN, 0x024, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_RESET, 0x024, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_RESET, 0x028, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_WAKEUP, 0x028, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_WAKEUP, 0x02c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_CLKREQ_IN, 0x02c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_CLKREQ_IN, 0x030, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL1, 0x030, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL0, 0x034, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_WP, 0x034, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_HOLD, 0x038, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_SDI, 0x038, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_CS, 0x03c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_SCK, 0x03c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_SDO, 0x040, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL1, 0x040, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL0, 0x044, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_WP, 0x044, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_HOLD, 0x048, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_SDI, 0x048, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_CS, 0x04c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_SCK, 0x04c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_SDO, 0x050, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_WP, 0x050, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_CD, 0x054, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_RST, 0x054, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_PWR_EN, 0x058, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_CD, 0x058, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_WP, 0x05c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_RST, 0x05c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_PWR_EN, 0x060, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD0, 0x060, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD1, 0x064, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD2, 0x064, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD3, 0x068, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXCTRL, 0x068, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD0, 0x06c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD1, 0x06c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD2, 0x070, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD3, 0x070, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXCTRL, 0x074, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXC, 0x074, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXC, 0x078, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_REFCLKO, 0x078, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_IRQ, 0x07c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_MDC, 0x07c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_MDIO, 0x080, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PWM0, 0x080, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PWM1, 0x084, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PWM2, 0x084, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PWM3, 0x088, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN0, 0x088, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN1, 0x08c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN2, 0x08c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN3, 0x090, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_IIC0_SDA, 0x090, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC0_SCL, 0x094, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SDA, 0x094, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC1_SCL, 0x098, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC2_SDA, 0x098, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SCL, 0x09c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SDA, 0x09c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC3_SCL, 0x0a0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART0_TX, 0x0a0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART0_RX, 0x0a4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART0_RTS, 0x0a4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART0_CTS, 0x0a8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_TX, 0x0a8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_RX, 0x0ac, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_RTS, 0x0ac, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_CTS, 0x0b0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_TX, 0x0b0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_RX, 0x0b4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_RTS, 0x0b4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_CTS, 0x0b8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_TX, 0x0b8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_RX, 0x0bc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_RTS, 0x0bc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_CTS, 0x0c0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_CS0, 0x0c0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_CS1, 0x0c4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_SDI, 0x0c4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_SDO, 0x0c8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_SCK, 0x0c8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_CS0, 0x0cc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_CS1, 0x0cc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_SDI, 0x0d0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_SDO, 0x0d0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_SCK, 0x0d4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TDO, 0x0d4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TCK, 0x0d8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TDI, 0x0d8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TMS, 0x0dc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TRST, 0x0dc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_SRST, 0x0e0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TDO, 0x0e0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TCK, 0x0e4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TDI, 0x0e4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TMS, 0x0e8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TRST, 0x0e8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_SRST, 0x0ec, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TDO, 0x0ec, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TCK, 0x0f0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TDI, 0x0f0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TMS, 0x0f4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TRST, 0x0f4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_SRST, 0x0f8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO0, 0x0f8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO1, 0x0fc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO2, 0x0fc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO3, 0x100, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO4, 0x100, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO5, 0x104, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO6, 0x104, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO7, 0x108, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO8, 0x108, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO9, 0x10c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO10, 0x10c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO11, 0x110, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO12, 0x110, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO13, 0x114, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO14, 0x114, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO15, 0x118, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO16, 0x118, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO17, 0x11c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO18, 0x11c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO19, 0x120, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO20, 0x120, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO21, 0x124, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO22, 0x124, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO23, 0x128, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO24, 0x128, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO25, 0x12c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO26, 0x12c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO27, 0x130, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO28, 0x130, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO29, 0x134, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO30, 0x134, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO31, 0x138, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_MODE_SEL0, 0x138, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL1, 0x13c, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL2, 0x13c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL0, 0x140, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL1, 0x140, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL2, 0x144, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL3, 0x144, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL4, 0x148, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL5, 0x148, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL6, 0x14c, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL7, 0x14c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MULTI_SCKT, 0x150, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID0, 0x150, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID1, 0x154, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_MAIN, 0x154, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_L, 0x158, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_R, 0x158, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_XTAL_32K, 0x15c, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SYS_RST, 0x15c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PWR_BUTTON, 0x160, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_EN, 0x160, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_MBIST, 0x164, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_SCAN, 0x164, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_BSD, 0x168, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BISR_BYP, 0x168, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), +}; + +static const struct sophgo_pinctrl_data sg2042_pindata = { + .pins = sg2042_pins, + .pindata = sg2042_pin_data, + .vddio_ops = &sg2042_vddio_cfg_ops, + .cfg_ops = &sg2042_cfg_ops, + .pctl_ops = &sg2042_pctrl_ops, + .pmx_ops = &sg2042_pmx_ops, + .pconf_ops = &sg2042_pconf_ops, + .npins = ARRAY_SIZE(sg2042_pins), + .pinsize = sizeof(struct sg2042_pin), +}; + +static const struct of_device_id sg2042_pinctrl_ids[] = { + { .compatible = "sophgo,sg2042-pinctrl", .data = &sg2042_pindata }, + { } +}; +MODULE_DEVICE_TABLE(of, sg2042_pinctrl_ids); + +static struct platform_driver sg2042_pinctrl_driver = { + .probe = sophgo_pinctrl_probe, + .driver = { + .name = "sg2042-pinctrl", + .suppress_bind_attrs = true, + .of_match_table = sg2042_pinctrl_ids, + }, +}; +module_platform_driver(sg2042_pinctrl_driver); + +MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.h b/drivers/pinctrl/sophgo/pinctrl-sg2042.h new file mode 100644 index 000000000000..d481973fcf97 --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> + */ + +#ifndef _PINCTRL_SOPHGO_SG2042_H +#define _PINCTRL_SOPHGO_SG2042_H + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinconf.h> + +#include "pinctrl-sophgo.h" + +#define PIN_FLAG_DEFAULT 0 +#define PIN_FLAG_WRITE_HIGH BIT(0) +#define PIN_FLAG_ONLY_ONE_PULL BIT(1) +#define PIN_FLAG_NO_PINMUX BIT(2) +#define PIN_FLAG_NO_OEX_EN BIT(3) +#define PIN_FLAG_IS_ETH BIT(4) + +struct sg2042_pin { + struct sophgo_pin pin; + u16 offset; +}; + +#define sophgo_to_sg2042_pin(_pin) \ + container_of((_pin), struct sg2042_pin, pin) + +extern const struct pinctrl_ops sg2042_pctrl_ops; +extern const struct pinmux_ops sg2042_pmx_ops; +extern const struct pinconf_ops sg2042_pconf_ops; +extern const struct sophgo_cfg_ops sg2042_cfg_ops; + +#define SG2042_GENERAL_PIN(_id, _offset, _flag) \ + { \ + .pin = { \ + .id = (_id), \ + .flags = (_flag), \ + }, \ + .offset = (_offset), \ + } + +#endif diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2044.c b/drivers/pinctrl/sophgo/pinctrl-sg2044.c new file mode 100644 index 000000000000..b0c46d8954ca --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2044.c @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SG2042 SoC pinctrl driver. + * + * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include <dt-bindings/pinctrl/pinctrl-sg2044.h> + +#include "pinctrl-sg2042.h" + +static int sg2044_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 19500; +} + +static int sg2044_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 23200; +} + +static const u32 sg2044_oc_map[] = { + 3200, 6400, 9600, 12700, + 15900, 19100, 22200, 25300, + 29500, 32700, 35900, 39000, + 42000, 45200, 48300, 51400 +}; + +static int sg2044_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, + const u32 **map) +{ + *map = sg2044_oc_map; + return ARRAY_SIZE(sg2044_oc_map); +} + +static const struct sophgo_vddio_cfg_ops sg2044_vddio_cfg_ops = { + .get_pull_up = sg2044_get_pull_up, + .get_pull_down = sg2044_get_pull_down, + .get_oc_map = sg2044_get_oc_map, +}; + +static const struct pinctrl_pin_desc sg2044_pins[] = { + PINCTRL_PIN(PIN_IIC0_SMBSUS_IN, "iic0_smbsus_in"), + PINCTRL_PIN(PIN_IIC0_SMBSUS_OUT, "iic0_smbsus_out"), + PINCTRL_PIN(PIN_IIC0_SMBALERT, "iic0_smbalert"), + PINCTRL_PIN(PIN_IIC1_SMBSUS_IN, "iic1_smbsus_in"), + PINCTRL_PIN(PIN_IIC1_SMBSUS_OUT, "iic1_smbsus_out"), + PINCTRL_PIN(PIN_IIC1_SMBALERT, "iic1_smbalert"), + PINCTRL_PIN(PIN_IIC2_SMBSUS_IN, "iic2_smbsus_in"), + PINCTRL_PIN(PIN_IIC2_SMBSUS_OUT, "iic2_smbsus_out"), + PINCTRL_PIN(PIN_IIC2_SMBALERT, "iic2_smbalert"), + PINCTRL_PIN(PIN_IIC3_SMBSUS_IN, "iic3_smbsus_in"), + PINCTRL_PIN(PIN_IIC3_SMBSUS_OUT, "iic3_smbsus_out"), + PINCTRL_PIN(PIN_IIC3_SMBALERT, "iic3_smbalert"), + PINCTRL_PIN(PIN_PCIE0_L0_RESET, "pcie0_l0_reset"), + PINCTRL_PIN(PIN_PCIE0_L1_RESET, "pcie0_l1_reset"), + PINCTRL_PIN(PIN_PCIE0_L0_WAKEUP, "pcie0_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L1_WAKEUP, "pcie0_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L0_CLKREQ_IN, "pcie0_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE0_L1_CLKREQ_IN, "pcie0_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L0_RESET, "pcie1_l0_reset"), + PINCTRL_PIN(PIN_PCIE1_L1_RESET, "pcie1_l1_reset"), + PINCTRL_PIN(PIN_PCIE1_L0_WAKEUP, "pcie1_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L1_WAKEUP, "pcie1_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L0_CLKREQ_IN, "pcie1_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L1_CLKREQ_IN, "pcie1_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE2_L0_RESET, "pcie2_l0_reset"), + PINCTRL_PIN(PIN_PCIE2_L1_RESET, "pcie2_l1_reset"), + PINCTRL_PIN(PIN_PCIE2_L0_WAKEUP, "pcie2_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE2_L1_WAKEUP, "pcie2_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE2_L0_CLKREQ_IN, "pcie2_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE2_L1_CLKREQ_IN, "pcie2_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE3_L0_RESET, "pcie3_l0_reset"), + PINCTRL_PIN(PIN_PCIE3_L1_RESET, "pcie3_l1_reset"), + PINCTRL_PIN(PIN_PCIE3_L0_WAKEUP, "pcie3_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE3_L1_WAKEUP, "pcie3_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE3_L0_CLKREQ_IN, "pcie3_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE3_L1_CLKREQ_IN, "pcie3_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE4_L0_RESET, "pcie4_l0_reset"), + PINCTRL_PIN(PIN_PCIE4_L1_RESET, "pcie4_l1_reset"), + PINCTRL_PIN(PIN_PCIE4_L0_WAKEUP, "pcie4_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE4_L1_WAKEUP, "pcie4_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE4_L0_CLKREQ_IN, "pcie4_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE4_L1_CLKREQ_IN, "pcie4_l1_clkreq_in"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL1, "spif0_clk_sel1"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL0, "spif0_clk_sel0"), + PINCTRL_PIN(PIN_SPIF0_WP, "spif0_wp"), + PINCTRL_PIN(PIN_SPIF0_HOLD, "spif0_hold"), + PINCTRL_PIN(PIN_SPIF0_SDI, "spif0_sdi"), + PINCTRL_PIN(PIN_SPIF0_CS, "spif0_cs"), + PINCTRL_PIN(PIN_SPIF0_SCK, "spif0_sck"), + PINCTRL_PIN(PIN_SPIF0_SDO, "spif0_sdo"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL1, "spif1_clk_sel1"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL0, "spif1_clk_sel0"), + PINCTRL_PIN(PIN_SPIF1_WP, "spif1_wp"), + PINCTRL_PIN(PIN_SPIF1_HOLD, "spif1_hold"), + PINCTRL_PIN(PIN_SPIF1_SDI, "spif1_sdi"), + PINCTRL_PIN(PIN_SPIF1_CS, "spif1_cs"), + PINCTRL_PIN(PIN_SPIF1_SCK, "spif1_sck"), + PINCTRL_PIN(PIN_SPIF1_SDO, "spif1_sdo"), + PINCTRL_PIN(PIN_EMMC_WP, "emmc_wp"), + PINCTRL_PIN(PIN_EMMC_CD, "emmc_cd"), + PINCTRL_PIN(PIN_EMMC_RST, "emmc_rst"), + PINCTRL_PIN(PIN_EMMC_PWR_EN, "emmc_pwr_en"), + PINCTRL_PIN(PIN_SDIO_CD, "sdio_cd"), + PINCTRL_PIN(PIN_SDIO_WP, "sdio_wp"), + PINCTRL_PIN(PIN_SDIO_RST, "sdio_rst"), + PINCTRL_PIN(PIN_SDIO_PWR_EN, "sdio_pwr_en"), + PINCTRL_PIN(PIN_RGMII0_TXD0, "rgmii0_txd0"), + PINCTRL_PIN(PIN_RGMII0_TXD1, "rgmii0_txd1"), + PINCTRL_PIN(PIN_RGMII0_TXD2, "rgmii0_txd2"), + PINCTRL_PIN(PIN_RGMII0_TXD3, "rgmii0_txd3"), + PINCTRL_PIN(PIN_RGMII0_TXCTRL, "rgmii0_txctrl"), + PINCTRL_PIN(PIN_RGMII0_RXD0, "rgmii0_rxd0"), + PINCTRL_PIN(PIN_RGMII0_RXD1, "rgmii0_rxd1"), + PINCTRL_PIN(PIN_RGMII0_RXD2, "rgmii0_rxd2"), + PINCTRL_PIN(PIN_RGMII0_RXD3, "rgmii0_rxd3"), + PINCTRL_PIN(PIN_RGMII0_RXCTRL, "rgmii0_rxctrl"), + PINCTRL_PIN(PIN_RGMII0_TXC, "rgmii0_txc"), + PINCTRL_PIN(PIN_RGMII0_RXC, "rgmii0_rxc"), + PINCTRL_PIN(PIN_RGMII0_REFCLKO, "rgmii0_refclko"), + PINCTRL_PIN(PIN_RGMII0_IRQ, "rgmii0_irq"), + PINCTRL_PIN(PIN_RGMII0_MDC, "rgmii0_mdc"), + PINCTRL_PIN(PIN_RGMII0_MDIO, "rgmii0_mdio"), + PINCTRL_PIN(PIN_PWM0, "pwm0"), + PINCTRL_PIN(PIN_PWM1, "pwm1"), + PINCTRL_PIN(PIN_PWM2, "pwm2"), + PINCTRL_PIN(PIN_PWM3, "pwm3"), + PINCTRL_PIN(PIN_FAN0, "fan0"), + PINCTRL_PIN(PIN_FAN1, "fan1"), + PINCTRL_PIN(PIN_FAN2, "fan2"), + PINCTRL_PIN(PIN_FAN3, "fan3"), + PINCTRL_PIN(PIN_IIC0_SDA, "iic0_sda"), + PINCTRL_PIN(PIN_IIC0_SCL, "iic0_scl"), + PINCTRL_PIN(PIN_IIC1_SDA, "iic1_sda"), + PINCTRL_PIN(PIN_IIC1_SCL, "iic1_scl"), + PINCTRL_PIN(PIN_IIC2_SDA, "iic2_sda"), + PINCTRL_PIN(PIN_IIC2_SCL, "iic2_scl"), + PINCTRL_PIN(PIN_IIC3_SDA, "iic3_sda"), + PINCTRL_PIN(PIN_IIC3_SCL, "iic3_scl"), + PINCTRL_PIN(PIN_UART0_TX, "uart0_tx"), + PINCTRL_PIN(PIN_UART0_RX, "uart0_rx"), + PINCTRL_PIN(PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(PIN_UART1_TX, "uart1_tx"), + PINCTRL_PIN(PIN_UART1_RX, "uart1_rx"), + PINCTRL_PIN(PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(PIN_UART2_TX, "uart2_tx"), + PINCTRL_PIN(PIN_UART2_RX, "uart2_rx"), + PINCTRL_PIN(PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(PIN_UART3_TX, "uart3_tx"), + PINCTRL_PIN(PIN_UART3_RX, "uart3_rx"), + PINCTRL_PIN(PIN_UART3_RTS, "uart3_rts"), + PINCTRL_PIN(PIN_UART3_CTS, "uart3_cts"), + PINCTRL_PIN(PIN_SPI0_CS0, "spi0_cs0"), + PINCTRL_PIN(PIN_SPI0_CS1, "spi0_cs1"), + PINCTRL_PIN(PIN_SPI0_SDI, "spi0_sdi"), + PINCTRL_PIN(PIN_SPI0_SDO, "spi0_sdo"), + PINCTRL_PIN(PIN_SPI0_SCK, "spi0_sck"), + PINCTRL_PIN(PIN_SPI1_CS0, "spi1_cs0"), + PINCTRL_PIN(PIN_SPI1_CS1, "spi1_cs1"), + PINCTRL_PIN(PIN_SPI1_SDI, "spi1_sdi"), + PINCTRL_PIN(PIN_SPI1_SDO, "spi1_sdo"), + PINCTRL_PIN(PIN_SPI1_SCK, "spi1_sck"), + PINCTRL_PIN(PIN_JTAG0_TDO, "jtag0_tdo"), + PINCTRL_PIN(PIN_JTAG0_TCK, "jtag0_tck"), + PINCTRL_PIN(PIN_JTAG0_TDI, "jtag0_tdi"), + PINCTRL_PIN(PIN_JTAG0_TMS, "jtag0_tms"), + PINCTRL_PIN(PIN_JTAG0_TRST, "jtag0_trst"), + PINCTRL_PIN(PIN_JTAG0_SRST, "jtag0_srst"), + PINCTRL_PIN(PIN_JTAG1_TDO, "jtag1_tdo"), + PINCTRL_PIN(PIN_JTAG1_TCK, "jtag1_tck"), + PINCTRL_PIN(PIN_JTAG1_TDI, "jtag1_tdi"), + PINCTRL_PIN(PIN_JTAG1_TMS, "jtag1_tms"), + PINCTRL_PIN(PIN_JTAG1_TRST, "jtag1_trst"), + PINCTRL_PIN(PIN_JTAG1_SRST, "jtag1_srst"), + PINCTRL_PIN(PIN_JTAG2_TDO, "jtag2_tdo"), + PINCTRL_PIN(PIN_JTAG2_TCK, "jtag2_tck"), + PINCTRL_PIN(PIN_JTAG2_TDI, "jtag2_tdi"), + PINCTRL_PIN(PIN_JTAG2_TMS, "jtag2_tms"), + PINCTRL_PIN(PIN_JTAG2_TRST, "jtag2_trst"), + PINCTRL_PIN(PIN_JTAG2_SRST, "jtag2_srst"), + PINCTRL_PIN(PIN_JTAG3_TDO, "jtag3_tdo"), + PINCTRL_PIN(PIN_JTAG3_TCK, "jtag3_tck"), + PINCTRL_PIN(PIN_JTAG3_TDI, "jtag3_tdi"), + PINCTRL_PIN(PIN_JTAG3_TMS, "jtag3_tms"), + PINCTRL_PIN(PIN_JTAG3_TRST, "jtag3_trst"), + PINCTRL_PIN(PIN_JTAG3_SRST, "jtag3_srst"), + PINCTRL_PIN(PIN_GPIO0, "gpio0"), + PINCTRL_PIN(PIN_GPIO1, "gpio1"), + PINCTRL_PIN(PIN_GPIO2, "gpio2"), + PINCTRL_PIN(PIN_GPIO3, "gpio3"), + PINCTRL_PIN(PIN_GPIO4, "gpio4"), + PINCTRL_PIN(PIN_GPIO5, "gpio5"), + PINCTRL_PIN(PIN_GPIO6, "gpio6"), + PINCTRL_PIN(PIN_GPIO7, "gpio7"), + PINCTRL_PIN(PIN_GPIO8, "gpio8"), + PINCTRL_PIN(PIN_GPIO9, "gpio9"), + PINCTRL_PIN(PIN_GPIO10, "gpio10"), + PINCTRL_PIN(PIN_GPIO11, "gpio11"), + PINCTRL_PIN(PIN_GPIO12, "gpio12"), + PINCTRL_PIN(PIN_GPIO13, "gpio13"), + PINCTRL_PIN(PIN_GPIO14, "gpio14"), + PINCTRL_PIN(PIN_GPIO15, "gpio15"), + PINCTRL_PIN(PIN_GPIO16, "gpio16"), + PINCTRL_PIN(PIN_GPIO17, "gpio17"), + PINCTRL_PIN(PIN_GPIO18, "gpio18"), + PINCTRL_PIN(PIN_GPIO19, "gpio19"), + PINCTRL_PIN(PIN_GPIO20, "gpio20"), + PINCTRL_PIN(PIN_GPIO21, "gpio21"), + PINCTRL_PIN(PIN_GPIO22, "gpio22"), + PINCTRL_PIN(PIN_GPIO23, "gpio23"), + PINCTRL_PIN(PIN_GPIO24, "gpio24"), + PINCTRL_PIN(PIN_GPIO25, "gpio25"), + PINCTRL_PIN(PIN_GPIO26, "gpio26"), + PINCTRL_PIN(PIN_GPIO27, "gpio27"), + PINCTRL_PIN(PIN_GPIO28, "gpio28"), + PINCTRL_PIN(PIN_GPIO29, "gpio29"), + PINCTRL_PIN(PIN_GPIO30, "gpio30"), + PINCTRL_PIN(PIN_GPIO31, "gpio31"), + PINCTRL_PIN(PIN_MODE_SEL0, "mode_sel0"), + PINCTRL_PIN(PIN_MODE_SEL1, "mode_sel1"), + PINCTRL_PIN(PIN_MODE_SEL2, "mode_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL0, "boot_sel0"), + PINCTRL_PIN(PIN_BOOT_SEL1, "boot_sel1"), + PINCTRL_PIN(PIN_BOOT_SEL2, "boot_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL3, "boot_sel3"), + PINCTRL_PIN(PIN_BOOT_SEL4, "boot_sel4"), + PINCTRL_PIN(PIN_BOOT_SEL5, "boot_sel5"), + PINCTRL_PIN(PIN_BOOT_SEL6, "boot_sel6"), + PINCTRL_PIN(PIN_BOOT_SEL7, "boot_sel7"), + PINCTRL_PIN(PIN_MULTI_SCKT, "multi_sckt"), + PINCTRL_PIN(PIN_SCKT_ID0, "sckt_id0"), + PINCTRL_PIN(PIN_SCKT_ID1, "sckt_id1"), + PINCTRL_PIN(PIN_PLL_CLK_IN_MAIN, "pll_clk_in_main"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_0, "pll_clk_in_ddr_0"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_1, "pll_clk_in_ddr_1"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_2, "pll_clk_in_ddr_2"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_3, "pll_clk_in_ddr_3"), + PINCTRL_PIN(PIN_XTAL_32K, "xtal_32k"), + PINCTRL_PIN(PIN_SYS_RST, "sys_rst"), + PINCTRL_PIN(PIN_PWR_BUTTON, "pwr_button"), + PINCTRL_PIN(PIN_TEST_EN, "test_en"), + PINCTRL_PIN(PIN_TEST_MODE_MBIST, "test_mode_mbist"), + PINCTRL_PIN(PIN_TEST_MODE_SCAN, "test_mode_scan"), + PINCTRL_PIN(PIN_TEST_MODE_BSD, "test_mode_bsd"), + PINCTRL_PIN(PIN_BISR_BYP, "bisr_byp"), +}; + +static const struct sg2042_pin sg2044_pin_data[ARRAY_SIZE(sg2044_pins)] = { + SG2042_GENERAL_PIN(PIN_IIC0_SMBSUS_IN, 0x000, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC0_SMBSUS_OUT, 0x000, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC0_SMBALERT, 0x004, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SMBSUS_IN, 0x004, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC1_SMBSUS_OUT, 0x008, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SMBALERT, 0x008, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SMBSUS_IN, 0x00c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC2_SMBSUS_OUT, 0x00c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SMBALERT, 0x010, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SMBSUS_IN, 0x010, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC3_SMBSUS_OUT, 0x014, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SMBALERT, 0x014, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_RESET, 0x018, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_RESET, 0x018, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_WAKEUP, 0x01c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_WAKEUP, 0x01c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_CLKREQ_IN, 0x020, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_CLKREQ_IN, 0x020, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_RESET, 0x024, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_RESET, 0x024, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_WAKEUP, 0x028, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_WAKEUP, 0x028, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_CLKREQ_IN, 0x02c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_CLKREQ_IN, 0x02c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE2_L0_RESET, 0x030, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE2_L1_RESET, 0x030, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE2_L0_WAKEUP, 0x034, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE2_L1_WAKEUP, 0x034, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE2_L0_CLKREQ_IN, 0x038, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE2_L1_CLKREQ_IN, 0x038, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE3_L0_RESET, 0x03c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE3_L1_RESET, 0x03c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE3_L0_WAKEUP, 0x040, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE3_L1_WAKEUP, 0x040, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE3_L0_CLKREQ_IN, 0x044, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE3_L1_CLKREQ_IN, 0x044, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE4_L0_RESET, 0x048, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE4_L1_RESET, 0x048, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE4_L0_WAKEUP, 0x04c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE4_L1_WAKEUP, 0x04c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE4_L0_CLKREQ_IN, 0x050, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE4_L1_CLKREQ_IN, 0x050, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL1, 0x054, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL0, 0x054, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_WP, 0x058, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_HOLD, 0x058, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_SDI, 0x05c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_CS, 0x05c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_SCK, 0x060, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_SDO, 0x060, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL1, 0x064, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL0, 0x064, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_WP, 0x068, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_HOLD, 0x068, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_SDI, 0x06c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_CS, 0x06c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_SCK, 0x070, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_SDO, 0x070, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_EMMC_WP, 0x074, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_EMMC_CD, 0x074, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_EMMC_RST, 0x078, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_EMMC_PWR_EN, 0x078, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SDIO_CD, 0x07c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SDIO_WP, 0x07c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SDIO_RST, 0x080, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SDIO_PWR_EN, 0x080, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD0, 0x084, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD1, 0x084, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD2, 0x088, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD3, 0x088, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXCTRL, 0x08c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD0, 0x08c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD1, 0x090, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD2, 0x090, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD3, 0x094, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXCTRL, 0x094, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXC, 0x098, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXC, 0x098, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_REFCLKO, 0x09c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_IRQ, 0x09c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_MDC, 0x0a0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_MDIO, 0x0a0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PWM0, 0x0a4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PWM1, 0x0a4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PWM2, 0x0a8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PWM3, 0x0a8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_FAN0, 0x0ac, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_FAN1, 0x0ac, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_FAN2, 0x0b0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_FAN3, 0x0b0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC0_SDA, 0x0b4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC0_SCL, 0x0b4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC1_SDA, 0x0b8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SCL, 0x0b8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SDA, 0x0bc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC2_SCL, 0x0bc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC3_SDA, 0x0c0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SCL, 0x0c0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART0_TX, 0x0c4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART0_RX, 0x0c4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART0_RTS, 0x0c8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART0_CTS, 0x0c8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART1_TX, 0x0cc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART1_RX, 0x0cc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART1_RTS, 0x0d0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART1_CTS, 0x0d0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART2_TX, 0x0d4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART2_RX, 0x0d4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART2_RTS, 0x0d8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART2_CTS, 0x0d8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART3_TX, 0x0dc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART3_RX, 0x0dc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART3_RTS, 0x0e0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART3_CTS, 0x0e0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI0_CS0, 0x0e4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI0_CS1, 0x0e4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI0_SDI, 0x0e8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI0_SDO, 0x0e8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI0_SCK, 0x0ec, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI1_CS0, 0x0ec, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI1_CS1, 0x0f0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI1_SDI, 0x0f0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI1_SDO, 0x0f4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI1_SCK, 0x0f4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG0_TDO, 0x0f8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG0_TCK, 0x0f8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG0_TDI, 0x0fc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG0_TMS, 0x0fc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG0_TRST, 0x100, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG0_SRST, 0x100, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG1_TDO, 0x104, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG1_TCK, 0x104, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG1_TDI, 0x108, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG1_TMS, 0x108, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG1_TRST, 0x10c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG1_SRST, 0x10c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG2_TDO, 0x110, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG2_TCK, 0x110, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG2_TDI, 0x114, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG2_TMS, 0x114, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG2_TRST, 0x118, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG2_SRST, 0x118, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG3_TDO, 0x11c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG3_TCK, 0x11c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG3_TDI, 0x120, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG3_TMS, 0x120, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG3_TRST, 0x124, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG3_SRST, 0x124, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO0, 0x128, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO1, 0x128, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO2, 0x12c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO3, 0x12c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO4, 0x130, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO5, 0x130, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO6, 0x134, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO7, 0x134, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO8, 0x138, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO9, 0x138, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO10, 0x13c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO11, 0x13c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO12, 0x140, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO13, 0x140, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO14, 0x144, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO15, 0x144, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO16, 0x148, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO17, 0x148, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO18, 0x14c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO19, 0x14c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO20, 0x150, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO21, 0x150, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO22, 0x154, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO23, 0x154, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO24, 0x158, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO25, 0x158, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO26, 0x15c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO27, 0x15c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO28, 0x160, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO29, 0x160, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO30, 0x164, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO31, 0x164, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_MODE_SEL0, 0x168, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL1, 0x168, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL2, 0x16c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL0, 0x16c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL1, 0x170, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL2, 0x170, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL3, 0x174, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL4, 0x174, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL5, 0x178, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL6, 0x178, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL7, 0x17c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MULTI_SCKT, 0x17c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID0, 0x180, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID1, 0x180, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_MAIN, 0x184, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_0, 0x184, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_1, 0x188, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_2, 0x188, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_3, 0x18c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_XTAL_32K, 0x18c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SYS_RST, 0x190, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PWR_BUTTON, 0x190, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_EN, 0x194, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_MBIST, 0x194, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_SCAN, 0x198, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_BSD, 0x198, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BISR_BYP, 0x19c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), +}; + +static const struct sophgo_pinctrl_data sg2044_pindata = { + .pins = sg2044_pins, + .pindata = sg2044_pin_data, + .vddio_ops = &sg2044_vddio_cfg_ops, + .cfg_ops = &sg2042_cfg_ops, + .pctl_ops = &sg2042_pctrl_ops, + .pmx_ops = &sg2042_pmx_ops, + .pconf_ops = &sg2042_pconf_ops, + .npins = ARRAY_SIZE(sg2044_pins), + .pinsize = sizeof(struct sg2042_pin), +}; + +static const struct of_device_id sg2044_pinctrl_ids[] = { + { .compatible = "sophgo,sg2044-pinctrl", .data = &sg2044_pindata }, + { } +}; +MODULE_DEVICE_TABLE(of, sg2044_pinctrl_ids); + +static struct platform_driver sg2044_pinctrl_driver = { + .probe = sophgo_pinctrl_probe, + .driver = { + .name = "sg2044-pinctrl", + .suppress_bind_attrs = true, + .of_match_table = sg2044_pinctrl_ids, + }, +}; +module_platform_driver(sg2044_pinctrl_driver); + +MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c b/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c new file mode 100644 index 000000000000..7f1fd68db19e --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SoCs pinctrl common ops. + * + * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> + * + */ + +#include <linux/bsearch.h> +#include <linux/cleanup.h> +#include <linux/export.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/spinlock.h> + +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> + +#include "../pinctrl-utils.h" +#include "../pinconf.h" +#include "../pinmux.h" + +#include "pinctrl-sophgo.h" + +static u16 sophgo_dt_get_pin(u32 value) +{ + return value; +} + +static int sophgo_cmp_pin(const void *key, const void *pivot) +{ + const struct sophgo_pin *pin = pivot; + int pin_id = (long)key; + int pivid = pin->id; + + return pin_id - pivid; +} + +const struct sophgo_pin *sophgo_get_pin(struct sophgo_pinctrl *pctrl, + unsigned long pin_id) +{ + return bsearch((void *)pin_id, pctrl->data->pindata, pctrl->data->npins, + pctrl->data->pinsize, sophgo_cmp_pin); +} + +static int sophgo_verify_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin_mux_config *config) +{ + if (pctrl->data->cfg_ops->verify_pinmux_config) + return pctrl->data->cfg_ops->verify_pinmux_config(config); + return 0; +} + +static int sophgo_verify_pin_group(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin_mux_config *config, + unsigned int npins) +{ + if (pctrl->data->cfg_ops->verify_pin_group) + return pctrl->data->cfg_ops->verify_pin_group(config, npins); + return 0; +} + +static int sophgo_dt_node_to_map_post(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *config, + unsigned int npins) +{ + if (pctrl->data->cfg_ops->dt_node_to_map_post) + return pctrl->data->cfg_ops->dt_node_to_map_post(cur, pctrl, + config, npins); + return 0; +} + +int sophgo_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, + struct pinctrl_map **maps, unsigned int *num_maps) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pctrl->dev; + struct device_node *child; + struct pinctrl_map *map; + const char **grpnames; + const char *grpname; + int ngroups = 0; + int nmaps = 0; + int ret; + + for_each_available_child_of_node(np, child) + ngroups += 1; + + grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL); + if (!grpnames) + return -ENOMEM; + + map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + ngroups = 0; + guard(mutex)(&pctrl->mutex); + for_each_available_child_of_node(np, child) { + int npins = of_property_count_u32_elems(child, "pinmux"); + unsigned int *pins; + struct sophgo_pin_mux_config *pinmuxs; + u32 config; + int i; + + if (npins < 1) { + dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n", + np, child); + ret = -EINVAL; + goto dt_failed; + } + + grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", + np, child); + if (!grpname) { + ret = -ENOMEM; + goto dt_failed; + } + + grpnames[ngroups++] = grpname; + + pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); + if (!pins) { + ret = -ENOMEM; + goto dt_failed; + } + + pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL); + if (!pinmuxs) { + ret = -ENOMEM; + goto dt_failed; + } + + for (i = 0; i < npins; i++) { + ret = of_property_read_u32_index(child, "pinmux", + i, &config); + if (ret) + goto dt_failed; + + pins[i] = sophgo_dt_get_pin(config); + pinmuxs[i].config = config; + pinmuxs[i].pin = sophgo_get_pin(pctrl, pins[i]); + + if (!pinmuxs[i].pin) { + dev_err(dev, "failed to get pin %d\n", pins[i]); + ret = -ENODEV; + goto dt_failed; + } + + ret = sophgo_verify_pinmux_config(pctrl, &pinmuxs[i]); + if (ret) { + dev_err(dev, "group %s pin %d is invalid\n", + grpname, i); + goto dt_failed; + } + } + + ret = sophgo_verify_pin_group(pctrl, pinmuxs, npins); + if (ret) { + dev_err(dev, "group %s is invalid\n", grpname); + goto dt_failed; + } + + ret = sophgo_dt_node_to_map_post(child, pctrl, pinmuxs, npins); + if (ret) + goto dt_failed; + + map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + map[nmaps].data.mux.function = np->name; + map[nmaps].data.mux.group = grpname; + nmaps += 1; + + ret = pinconf_generic_parse_dt_config(child, pctldev, + &map[nmaps].data.configs.configs, + &map[nmaps].data.configs.num_configs); + if (ret) { + dev_err(dev, "failed to parse pin config of group %s: %d\n", + grpname, ret); + goto dt_failed; + } + + ret = pinctrl_generic_add_group(pctldev, grpname, + pins, npins, pinmuxs); + if (ret < 0) { + dev_err(dev, "failed to add group %s: %d\n", grpname, ret); + goto dt_failed; + } + + /* don't create a map if there are no pinconf settings */ + if (map[nmaps].data.configs.num_configs == 0) + continue; + + map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + map[nmaps].data.configs.group_or_pin = grpname; + nmaps += 1; + } + + ret = pinmux_generic_add_function(pctldev, np->name, + grpnames, ngroups, NULL); + if (ret < 0) { + dev_err(dev, "error adding function %s: %d\n", np->name, ret); + goto function_failed; + } + + *maps = map; + *num_maps = nmaps; + + return 0; + +dt_failed: + of_node_put(child); +function_failed: + pinctrl_utils_free_map(pctldev, map, nmaps); + return ret; +} + +int sophgo_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct group_desc *group; + const struct sophgo_pin_mux_config *configs; + unsigned int i; + + group = pinctrl_generic_get_group(pctldev, gsel); + if (!group) + return -EINVAL; + + configs = group->data; + + for (i = 0; i < group->grp.npins; i++) { + const struct sophgo_pin *pin = configs[i].pin; + u32 value = configs[i].config; + + guard(raw_spinlock_irqsave)(&pctrl->lock); + + pctrl->data->cfg_ops->set_pinmux_config(pctrl, pin, value); + } + + return 0; +} + +static int sophgo_pin_set_config(struct sophgo_pinctrl *pctrl, + unsigned int pin_id, + u32 value, u32 mask) +{ + const struct sophgo_pin *pin = sophgo_get_pin(pctrl, pin_id); + + if (!pin) + return -EINVAL; + + guard(raw_spinlock_irqsave)(&pctrl->lock); + + return pctrl->data->cfg_ops->set_pinconf_config(pctrl, pin, value, mask); +} + +int sophgo_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, + unsigned long *configs, unsigned int num_configs) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct sophgo_pin *pin = sophgo_get_pin(pctrl, pin_id); + u32 value, mask; + + if (!pin) + return -ENODEV; + + if (pctrl->data->cfg_ops->compute_pinconf_config(pctrl, pin, + configs, num_configs, + &value, &mask)) + return -ENOTSUPP; + + return sophgo_pin_set_config(pctrl, pin_id, value, mask); +} + +int sophgo_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int gsel, + unsigned long *configs, unsigned int num_configs) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct group_desc *group; + const struct sophgo_pin_mux_config *pinmuxs; + u32 value, mask; + int i; + + group = pinctrl_generic_get_group(pctldev, gsel); + if (!group) + return -EINVAL; + + pinmuxs = group->data; + + if (pctrl->data->cfg_ops->compute_pinconf_config(pctrl, pinmuxs[0].pin, + configs, num_configs, + &value, &mask)) + return -ENOTSUPP; + + for (i = 0; i < group->grp.npins; i++) + sophgo_pin_set_config(pctrl, group->grp.pins[i], value, mask); + + return 0; +} + +u32 sophgo_pinctrl_typical_pull_down(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg) +{ + return pctrl->data->vddio_ops->get_pull_down(pin, power_cfg); +} + +u32 sophgo_pinctrl_typical_pull_up(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg) +{ + return pctrl->data->vddio_ops->get_pull_up(pin, power_cfg); +} + +int sophgo_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target) +{ + const u32 *map; + int i, len; + + if (!pctrl->data->vddio_ops->get_oc_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); + if (len < 0) + return len; + + for (i = 0; i < len; i++) { + if (map[i] >= target) + return i; + } + + return -EINVAL; +} + +int sophgo_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg) +{ + const u32 *map; + int len; + + if (!pctrl->data->vddio_ops->get_oc_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); + if (len < 0) + return len; + + if (reg >= len) + return -EINVAL; + + return map[reg]; +} + +int sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target) +{ + const u32 *map; + int i, len; + + if (!pctrl->data->vddio_ops->get_schmitt_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); + if (len < 0) + return len; + + for (i = 0; i < len; i++) { + if (map[i] == target) + return i; + } + + return -EINVAL; +} + +int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg) +{ + const u32 *map; + int len; + + if (!pctrl->data->vddio_ops->get_schmitt_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); + if (len < 0) + return len; + + if (reg >= len) + return -EINVAL; + + return map[reg]; +} + +int sophgo_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sophgo_pinctrl *pctrl; + const struct sophgo_pinctrl_data *pctrl_data; + int ret; + + pctrl_data = device_get_match_data(dev); + if (!pctrl_data) + return -ENODEV; + + if (pctrl_data->npins == 0) + return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->pdesc.name = dev_name(dev); + pctrl->pdesc.pins = pctrl_data->pins; + pctrl->pdesc.npins = pctrl_data->npins; + pctrl->pdesc.pctlops = pctrl_data->pctl_ops; + pctrl->pdesc.pmxops = pctrl_data->pmx_ops; + pctrl->pdesc.confops = pctrl_data->pconf_ops; + pctrl->pdesc.owner = THIS_MODULE; + + pctrl->data = pctrl_data; + pctrl->dev = dev; + raw_spin_lock_init(&pctrl->lock); + mutex_init(&pctrl->mutex); + + ret = pctrl->data->cfg_ops->pctrl_init(pdev, pctrl); + if (ret) + return ret; + + platform_set_drvdata(pdev, pctrl); + + ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, + pctrl, &pctrl->pctrl_dev); + if (ret) + return dev_err_probe(dev, ret, + "fail to register pinctrl driver\n"); + + return pinctrl_enable(pctrl->pctrl_dev); +} +EXPORT_SYMBOL_GPL(sophgo_pinctrl_probe); + +MODULE_DESCRIPTION("Common pinctrl helper function for the Sophgo SoC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h new file mode 100644 index 000000000000..4cd9b5484894 --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> + */ + +#ifndef _PINCTRL_SOPHGO_H +#define _PINCTRL_SOPHGO_H + +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#include "../core.h" + +struct sophgo_pinctrl; + +struct sophgo_pin { + u16 id; + u16 flags; +}; + +struct sophgo_pin_mux_config { + const struct sophgo_pin *pin; + u32 config; +}; + +/** + * struct sophgo_cfg_ops - pin configuration operations + * + * @pctrl_init: soc specific init callback + * @verify_pinmux_config: verify the pinmux config for a pin + * @verify_pin_group: verify the whole pinmux group + * @dt_node_to_map_post: post init for the pinmux config map + * @compute_pinconf_config: compute pinconf config + * @set_pinconf_config: set pinconf config (the caller holds lock) + * @set_pinmux_config: set mux config (the caller holds lock) + */ +struct sophgo_cfg_ops { + int (*pctrl_init)(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl); + int (*verify_pinmux_config)(const struct sophgo_pin_mux_config *config); + int (*verify_pin_group)(const struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins); + int (*dt_node_to_map_post)(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins); + int (*compute_pinconf_config)(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + unsigned long *configs, + unsigned int num_configs, + u32 *value, u32 *mask); + int (*set_pinconf_config)(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask); + void (*set_pinmux_config)(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config); +}; + +/** + * struct sophgo_vddio_cfg_ops - pin vddio operations + * + * @get_pull_up: get resistor for pull up; + * @get_pull_down: get resistor for pull down. + * @get_oc_map: get mapping for typical low level output current value to + * register value map. + * @get_schmitt_map: get mapping for register value to typical schmitt + * threshold. + */ +struct sophgo_vddio_cfg_ops { + int (*get_pull_up)(const struct sophgo_pin *pin, const u32 *psmap); + int (*get_pull_down)(const struct sophgo_pin *pin, const u32 *psmap); + int (*get_oc_map)(const struct sophgo_pin *pin, const u32 *psmap, + const u32 **map); + int (*get_schmitt_map)(const struct sophgo_pin *pin, const u32 *psmap, + const u32 **map); +}; + +struct sophgo_pinctrl_data { + const struct pinctrl_pin_desc *pins; + const void *pindata; + const char * const *pdnames; + const struct sophgo_vddio_cfg_ops *vddio_ops; + const struct sophgo_cfg_ops *cfg_ops; + const struct pinctrl_ops *pctl_ops; + const struct pinmux_ops *pmx_ops; + const struct pinconf_ops *pconf_ops; + u16 npins; + u16 npds; + u16 pinsize; +}; + +struct sophgo_pinctrl { + struct device *dev; + struct pinctrl_dev *pctrl_dev; + const struct sophgo_pinctrl_data *data; + struct pinctrl_desc pdesc; + + struct mutex mutex; + raw_spinlock_t lock; + void *priv_ctrl; +}; + +const struct sophgo_pin *sophgo_get_pin(struct sophgo_pinctrl *pctrl, + unsigned long pin_id); +int sophgo_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, + struct pinctrl_map **maps, unsigned int *num_maps); +int sophgo_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel); +int sophgo_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, + unsigned long *configs, unsigned int num_configs); +int sophgo_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int gsel, + unsigned long *configs, unsigned int num_configs); +u32 sophgo_pinctrl_typical_pull_down(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg); +u32 sophgo_pinctrl_typical_pull_up(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg); +int sophgo_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target); +int sophgo_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg); +int sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target); +int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg); +int sophgo_pinctrl_probe(struct platform_device *pdev); + +#endif /* _PINCTRL_SOPHGO_H */ diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c index 59fd555ff38d..67e867b04a02 100644 --- a/drivers/pinctrl/spacemit/pinctrl-k1.c +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c @@ -9,6 +9,7 @@ #include <linux/seq_file.h> #include <linux/spinlock.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> @@ -749,7 +750,10 @@ static int spacemit_pinctrl_probe(struct platform_device *pdev) pctrl->data = pctrl_data; pctrl->dev = dev; raw_spin_lock_init(&pctrl->lock); - mutex_init(&pctrl->mutex); + + ret = devm_mutex_init(dev, &pctrl->mutex); + if (ret) + return ret; platform_set_drvdata(pdev, pctrl); diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index a78fdbbdfc0c..dc62eba96348 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -131,4 +131,14 @@ config PINCTRL_SUN50I_H616_R default ARM64 && ARCH_SUNXI select PINCTRL_SUNXI +config PINCTRL_SUN55I_A523 + bool "Support for the Allwinner A523 PIO" + default ARM64 && ARCH_SUNXI + select PINCTRL_SUNXI + +config PINCTRL_SUN55I_A523_R + bool "Support for the Allwinner A523 R-PIO" + default ARM64 && ARCH_SUNXI + select PINCTRL_SUNXI + endif diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index 2ff5a55927ad..951b3f1e4b4f 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Core obj-y += pinctrl-sunxi.o +obj-y += pinctrl-sunxi-dt.o # SoC Drivers obj-$(CONFIG_PINCTRL_SUNIV_F1C100S) += pinctrl-suniv-f1c100s.o @@ -26,5 +27,7 @@ obj-$(CONFIG_PINCTRL_SUN50I_H6) += pinctrl-sun50i-h6.o obj-$(CONFIG_PINCTRL_SUN50I_H6_R) += pinctrl-sun50i-h6-r.o obj-$(CONFIG_PINCTRL_SUN50I_H616) += pinctrl-sun50i-h616.o obj-$(CONFIG_PINCTRL_SUN50I_H616_R) += pinctrl-sun50i-h616-r.o +obj-$(CONFIG_PINCTRL_SUN55I_A523) += pinctrl-sun55i-a523.o +obj-$(CONFIG_PINCTRL_SUN55I_A523_R) += pinctrl-sun55i-a523-r.o obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o obj-$(CONFIG_PINCTRL_SUN9I_A80_R) += pinctrl-sun9i-a80-r.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c index 8e2aab542fcf..8efe35b77af4 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c @@ -820,15 +820,13 @@ static const struct sunxi_pinctrl_desc d1_pinctrl_data = { static int d1_pinctrl_probe(struct platform_device *pdev) { - unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - - return sunxi_pinctrl_init_with_variant(pdev, &d1_pinctrl_data, variant); + return sunxi_pinctrl_init_with_flags(pdev, &d1_pinctrl_data, + SUNXI_PINCTRL_NEW_REG_LAYOUT); } static const struct of_device_id d1_pinctrl_match[] = { { .compatible = "allwinner,sun20i-d1-pinctrl", - .data = (void *)PINCTRL_SUN20I_D1 }, {} }; diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c index fa47fe36ee5b..b2e82bf927b3 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c @@ -17,6 +17,10 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN4I_A10 BIT(0) +#define PINCTRL_SUN7I_A20 BIT(1) +#define PINCTRL_SUN8I_R40 BIT(2) + static const struct sunxi_desc_pin sun4i_a10_pins[] = { SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), SUNXI_FUNCTION(0x0, "gpio_in"), @@ -1295,8 +1299,8 @@ static int sun4i_a10_pinctrl_probe(struct platform_device *pdev) { unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, &sun4i_a10_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun4i_a10_pinctrl_data, + variant); } static const struct of_device_id sun4i_a10_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c new file mode 100644 index 000000000000..69cd2b4ebd7d --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner A523 SoC r-pinctrl driver. + * + * Copyright (C) 2024 Arm Ltd. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-sunxi.h" + +static const u8 a523_r_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] = +/* PL PM */ + { 14, 6 }; + +static const unsigned int a523_r_irq_bank_map[] = { 0, 1 }; + +static const u8 a523_r_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] = +/* PL PM */ + { 14, 14 }; + +static struct sunxi_pinctrl_desc a523_r_pinctrl_data = { + .irq_banks = ARRAY_SIZE(a523_r_irq_bank_map), + .irq_bank_map = a523_r_irq_bank_map, + .irq_read_needs_mux = true, + .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL, + .pin_base = PL_BASE, +}; + +static int a523_r_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_dt_table_init(pdev, a523_r_nr_bank_pins, + a523_r_irq_bank_muxes, + &a523_r_pinctrl_data, + SUNXI_PINCTRL_NEW_REG_LAYOUT); +} + +static const struct of_device_id a523_r_pinctrl_match[] = { + { .compatible = "allwinner,sun55i-a523-r-pinctrl", }, + {} +}; + +static struct platform_driver a523_r_pinctrl_driver = { + .probe = a523_r_pinctrl_probe, + .driver = { + .name = "sun55i-a523-r-pinctrl", + .of_match_table = a523_r_pinctrl_match, + }, +}; +builtin_platform_driver(a523_r_pinctrl_driver); diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c new file mode 100644 index 000000000000..7d2308c37d29 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner A523 SoC pinctrl driver. + * + * Copyright (C) 2023 Arm Ltd. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-sunxi.h" + +static const u8 a523_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] = +/* PA PB PC PD PE PF PG PH PI PJ PK */ + { 0, 15, 17, 24, 16, 7, 15, 20, 17, 28, 24 }; + +static const unsigned int a523_irq_bank_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + +static const u8 a523_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] = +/* PA PB PC PD PE PF PG PH PI PJ PK */ + { 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}; + +static struct sunxi_pinctrl_desc a523_pinctrl_data = { + .irq_banks = ARRAY_SIZE(a523_irq_bank_map), + .irq_bank_map = a523_irq_bank_map, + .irq_read_needs_mux = true, + .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL, +}; + +static int a523_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_dt_table_init(pdev, a523_nr_bank_pins, + a523_irq_bank_muxes, + &a523_pinctrl_data, + SUNXI_PINCTRL_NEW_REG_LAYOUT | + SUNXI_PINCTRL_ELEVEN_BANKS); +} + +static const struct of_device_id a523_pinctrl_match[] = { + { .compatible = "allwinner,sun55i-a523-pinctrl", }, + {} +}; + +static struct platform_driver a523_pinctrl_driver = { + .probe = a523_pinctrl_probe, + .driver = { + .name = "sun55i-a523-pinctrl", + .of_match_table = a523_pinctrl_match, + }, +}; +builtin_platform_driver(a523_pinctrl_driver); diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i.c b/drivers/pinctrl/sunxi/pinctrl-sun5i.c index 06ecb121c827..6eef314c9377 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun5i.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun5i.c @@ -16,6 +16,10 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN5I_A10S BIT(0) +#define PINCTRL_SUN5I_A13 BIT(1) +#define PINCTRL_SUN5I_GR8 BIT(2) + static const struct sunxi_desc_pin sun5i_pins[] = { SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 0), PINCTRL_SUN5I_A10S, @@ -719,8 +723,8 @@ static int sun5i_pinctrl_probe(struct platform_device *pdev) { unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, &sun5i_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun5i_pinctrl_data, + variant); } static const struct of_device_id sun5i_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c index 82ac064931df..8d8c92ce41cf 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c @@ -17,6 +17,9 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN6I_A31 BIT(0) +#define PINCTRL_SUN6I_A31S BIT(1) + static const struct sunxi_desc_pin sun6i_a31_pins[] = { SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), SUNXI_FUNCTION(0x0, "gpio_in"), @@ -972,9 +975,8 @@ static int sun6i_a31_pinctrl_probe(struct platform_device *pdev) unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, - &sun6i_a31_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun6i_a31_pinctrl_data, + variant); } static const struct of_device_id sun6i_a31_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c index 49c9a0b6a0eb..696d7dd8d87b 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c @@ -22,6 +22,9 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN8I_V3 BIT(0) +#define PINCTRL_SUN8I_V3S BIT(1) + static const struct sunxi_desc_pin sun8i_v3s_pins[] = { /* Hole */ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), @@ -552,8 +555,8 @@ static int sun8i_v3s_pinctrl_probe(struct platform_device *pdev) { unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, &sun8i_v3s_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun8i_v3s_pinctrl_data, + variant); } static const struct of_device_id sun8i_v3s_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c new file mode 100644 index 000000000000..1833078f6877 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017-2025 Arm Ltd. + * + * Generic DT driven Allwinner pinctrl driver routines. + * Builds the pin tables from minimal driver information and pin groups + * described in the DT. Then hands those tables of to the traditional + * sunxi pinctrl driver. + * sunxi_pinctrl_init() expects a table like shown below, previously spelled + * out in a per-SoC .c file. This code generates this table, like so: + * + * SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), // code iterates over every implemented + * // pin, based on pins_per_bank[] array passed in + * + * SUNXI_FUNCTION(0x0, "gpio_in"), // always added, for every pin + * SUNXI_FUNCTION(0x1, "gpio_out"), // always added, for every pin + * + * SUNXI_FUNCTION(0x2, "mmc0"), // based on pingroup found in DT: + * // mmc0-pins { + * // pins = "PF0", "PF1", ... + * // function = "mmc0"; + * // allwinner,pinmux = <2>; + * + * SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 1)), // derived by irq_bank_muxes[] + * // array passed in + */ + +#include <linux/export.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-sunxi.h" + +#define INVALID_MUX 0xff + +/* + * Return the "index"th element from the "allwinner,pinmux" property. If the + * property does not hold enough entries, return the last one instead. + * For almost every group the pinmux value is actually the same, so this + * allows to just list one value in the property. + */ +static u8 sunxi_pinctrl_dt_read_pinmux(const struct device_node *node, + int index) +{ + int ret, num_elems; + u32 value; + + num_elems = of_property_count_u32_elems(node, "allwinner,pinmux"); + if (num_elems <= 0) + return INVALID_MUX; + + if (index >= num_elems) + index = num_elems - 1; + + ret = of_property_read_u32_index(node, "allwinner,pinmux", index, + &value); + if (ret) + return INVALID_MUX; + + return value; +} + +/* + * Allocate a table with a sunxi_desc_pin structure for every pin needed. + * Fills in the respective pin names ("PA0") and their pin numbers. + * Returns the pins array. We cannot use the member in *desc yet, as this + * is marked as const, and we will need to change the array still. + */ +static struct sunxi_desc_pin *init_pins_table(struct device *dev, + const u8 *pins_per_bank, + struct sunxi_pinctrl_desc *desc) +{ + struct sunxi_desc_pin *pins, *cur_pin; + int name_size = 0; + int port_base = desc->pin_base / PINS_PER_BANK; + char *pin_names, *cur_name; + int i, j; + + /* + * Find the total number of pins. + * Also work out how much memory we need to store all the pin names. + */ + for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) { + desc->npins += pins_per_bank[i]; + if (pins_per_bank[i] < 10) { + /* 4 bytes for "PXy\0" */ + name_size += pins_per_bank[i] * 4; + } else { + /* 4 bytes for each "PXy\0" */ + name_size += 10 * 4; + + /* 5 bytes for each "PXyy\0" */ + name_size += (pins_per_bank[i] - 10) * 5; + } + } + + if (desc->npins == 0) { + dev_err(dev, "no ports defined\n"); + return ERR_PTR(-EINVAL); + } + + pins = devm_kzalloc(dev, desc->npins * sizeof(*pins), GFP_KERNEL); + if (!pins) + return ERR_PTR(-ENOMEM); + + /* Allocate memory to store the name for every pin. */ + pin_names = devm_kmalloc(dev, name_size, GFP_KERNEL); + if (!pin_names) + return ERR_PTR(-ENOMEM); + + /* Fill the pins array with the name and the number for each pin. */ + cur_name = pin_names; + cur_pin = pins; + for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) { + for (j = 0; j < pins_per_bank[i]; j++, cur_pin++) { + int nchars = sprintf(cur_name, "P%c%d", + port_base + 'A' + i, j); + + cur_pin->pin.number = (port_base + i) * PINS_PER_BANK + j; + cur_pin->pin.name = cur_name; + cur_name += nchars + 1; + } + } + + return pins; +} + +/* + * Work out the number of functions for each pin. This will visit every + * child node of the pinctrl DT node to find all advertised functions. + * Provide memory to hold the per-function information and assign it to + * the pin table. + * Fill in the GPIO in/out functions already (that every pin has), also add + * an "irq" function at the end, for those pins in IRQ-capable ports. + * We do not fill in the extra functions (those describe in DT nodes) yet. + * We (ab)use the "variant" member in each pin to keep track of the number of + * extra functions needed. At the end this will get reset to 2, so that we + * can add extra function later, after the two GPIO functions. + */ +static int prepare_function_table(struct device *dev, struct device_node *pnode, + struct sunxi_desc_pin *pins, int npins, + const u8 *irq_bank_muxes) +{ + struct device_node *node; + struct property *prop; + struct sunxi_desc_function *func; + int num_funcs, irq_bank, last_bank, i; + + /* + * We need at least three functions per pin: + * - one for GPIO in + * - one for GPIO out + * - one for the sentinel signalling the end of the list + */ + num_funcs = 3 * npins; + + /* + * Add a function for each pin in a bank supporting interrupts. + * We temporarily (ab)use the variant field to store the number of + * functions per pin. This will be cleaned back to 0 before we hand + * over the whole structure to the generic sunxi pinctrl setup code. + */ + for (i = 0; i < npins; i++) { + struct sunxi_desc_pin *pin = &pins[i]; + int bank = pin->pin.number / PINS_PER_BANK; + + if (irq_bank_muxes[bank]) { + pin->variant++; + num_funcs++; + } + } + + /* + * Go over each pin group (every child of the pinctrl DT node) and + * add the number of special functions each pins has. Also update the + * total number of functions required. + * We might slightly overshoot here in case of double definitions. + */ + for_each_child_of_node(pnode, node) { + const char *name; + + of_property_for_each_string(node, "pins", prop, name) { + for (i = 0; i < npins; i++) { + if (strcmp(pins[i].pin.name, name)) + continue; + + pins[i].variant++; + num_funcs++; + break; + } + } + } + + /* + * Allocate the memory needed for the functions in one table. + * We later use pointers into this table to mark each pin. + */ + func = devm_kzalloc(dev, num_funcs * sizeof(*func), GFP_KERNEL); + if (!func) + return -ENOMEM; + + /* + * Assign the function's memory and fill in GPIOs, IRQ and a sentinel. + * The extra functions will be filled in later. + */ + irq_bank = 0; + last_bank = 0; + for (i = 0; i < npins; i++) { + struct sunxi_desc_pin *pin = &pins[i]; + int bank = pin->pin.number / PINS_PER_BANK; + int lastfunc = pin->variant + 1; + int irq_mux = irq_bank_muxes[bank]; + + func[0].name = "gpio_in"; + func[0].muxval = 0; + func[1].name = "gpio_out"; + func[1].muxval = 1; + + if (irq_mux) { + if (bank > last_bank) + irq_bank++; + func[lastfunc].muxval = irq_mux; + func[lastfunc].irqbank = irq_bank; + func[lastfunc].irqnum = pin->pin.number % PINS_PER_BANK; + func[lastfunc].name = "irq"; + } + + if (bank > last_bank) + last_bank = bank; + + pin->functions = func; + + /* Skip over the other needed functions and the sentinel. */ + func += pin->variant + 3; + + /* + * Reset the value for filling in the remaining functions + * behind the GPIOs later. + */ + pin->variant = 2; + } + + return 0; +} + +/* + * Iterate over all pins in a single group and add the function name and its + * mux value to the respective pin. + * The "variant" member is again used to temporarily track the number of + * already added functions. + */ +static void fill_pin_function(struct device *dev, struct device_node *node, + struct sunxi_desc_pin *pins, int npins) +{ + const char *name, *funcname; + struct sunxi_desc_function *func; + struct property *prop; + int pin, i, index; + u8 muxval; + + if (of_property_read_string(node, "function", &funcname)) { + dev_warn(dev, "missing \"function\" property\n"); + return; + } + + index = 0; + of_property_for_each_string(node, "pins", prop, name) { + /* Find the index of this pin in our table. */ + for (pin = 0; pin < npins; pin++) + if (!strcmp(pins[pin].pin.name, name)) + break; + if (pin == npins) { + dev_warn(dev, "%s: cannot find pin %s\n", + of_node_full_name(node), name); + index++; + continue; + } + + /* Read the associated mux value. */ + muxval = sunxi_pinctrl_dt_read_pinmux(node, index); + if (muxval == INVALID_MUX) { + dev_warn(dev, "%s: invalid mux value for pin %s\n", + of_node_full_name(node), name); + index++; + continue; + } + + /* + * Check for double definitions by comparing the to-be-added + * function with already assigned ones. + * Ignore identical pairs (function name and mux value the + * same), but warn about conflicting assignments. + */ + for (i = 2; i < pins[pin].variant; i++) { + func = &pins[pin].functions[i]; + + /* Skip over totally unrelated functions. */ + if (strcmp(func->name, funcname) && + func->muxval != muxval) + continue; + + /* Ignore (but skip below) any identical functions. */ + if (!strcmp(func->name, funcname) && + muxval == func->muxval) + break; + + dev_warn(dev, + "pin %s: function %s redefined to mux %d\n", + name, funcname, muxval); + break; + } + + /* Skip any pins with that function already assigned. */ + if (i < pins[pin].variant) { + index++; + continue; + } + + /* Assign function and muxval to the next free slot. */ + func = &pins[pin].functions[pins[pin].variant]; + func->muxval = muxval; + func->name = funcname; + + pins[pin].variant++; + index++; + } +} + +/* + * Initialise the pinctrl table, by building it from driver provided + * information: the number of pins per bank, the IRQ capable banks and their + * IRQ mux value. + * Then iterate over all pinctrl DT node children to enter the function name + * and mux values for each mentioned pin. + * At the end hand over this structure to the actual sunxi pinctrl driver. + */ +int sunxi_pinctrl_dt_table_init(struct platform_device *pdev, + const u8 *pins_per_bank, + const u8 *irq_bank_muxes, + struct sunxi_pinctrl_desc *desc, + unsigned long flags) +{ + struct device_node *pnode = pdev->dev.of_node, *node; + struct sunxi_desc_pin *pins; + int ret, i; + + pins = init_pins_table(&pdev->dev, pins_per_bank, desc); + if (IS_ERR(pins)) + return PTR_ERR(pins); + + ret = prepare_function_table(&pdev->dev, pnode, pins, desc->npins, + irq_bank_muxes); + if (ret) + return ret; + + /* + * Now iterate over all groups and add the respective function name + * and mux values to each pin listed within. + */ + for_each_child_of_node(pnode, node) + fill_pin_function(&pdev->dev, node, pins, desc->npins); + + /* Clear the temporary storage. */ + for (i = 0; i < desc->npins; i++) + pins[i].variant = 0; + + desc->pins = pins; + + return sunxi_pinctrl_init_with_flags(pdev, desc, flags); +} diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index bde67ee31417..f1c5a991cf7b 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -58,13 +58,29 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip; * The following functions calculate the register and the bit offset to access. * They take a pin number which is relative to the start of the current device. */ + +/* + * When using the extended register layout, Bank K does not fit into the + * space used for the other banks. Instead it lives at offset 0x500. + */ +static u32 sunxi_bank_offset(const struct sunxi_pinctrl *pctl, u32 pin) +{ + u32 offset = 0; + + if (pin >= PK_BASE) { + pin -= PK_BASE; + offset = PIO_BANK_K_OFFSET; + } + + return offset + (pin / PINS_PER_BANK) * pctl->bank_mem_size; +} + static void sunxi_mux_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * MUX_FIELD_WIDTH; - *reg = bank * pctl->bank_mem_size + MUX_REGS_OFFSET + + *reg = sunxi_bank_offset(pctl, pin) + MUX_REGS_OFFSET + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(MUX_FIELD_WIDTH) - 1) << *shift; @@ -73,10 +89,9 @@ static void sunxi_mux_reg(const struct sunxi_pinctrl *pctl, static void sunxi_data_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * DATA_FIELD_WIDTH; - *reg = bank * pctl->bank_mem_size + DATA_REGS_OFFSET + + *reg = sunxi_bank_offset(pctl, pin) + DATA_REGS_OFFSET + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(DATA_FIELD_WIDTH) - 1) << *shift; @@ -85,10 +100,9 @@ static void sunxi_data_reg(const struct sunxi_pinctrl *pctl, static void sunxi_dlevel_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * pctl->dlevel_field_width; - *reg = bank * pctl->bank_mem_size + DLEVEL_REGS_OFFSET + + *reg = sunxi_bank_offset(pctl, pin) + DLEVEL_REGS_OFFSET + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(pctl->dlevel_field_width) - 1) << *shift; @@ -97,10 +111,9 @@ static void sunxi_dlevel_reg(const struct sunxi_pinctrl *pctl, static void sunxi_pull_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * PULL_FIELD_WIDTH; - *reg = bank * pctl->bank_mem_size + pctl->pull_regs_offset + + *reg = sunxi_bank_offset(pctl, pin) + pctl->pull_regs_offset + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(PULL_FIELD_WIDTH) - 1) << *shift; @@ -723,9 +736,11 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, val = uV > 1800000 && uV <= 2500000 ? BIT(bank) : 0; raw_spin_lock_irqsave(&pctl->lock, flags); - reg = readl(pctl->membase + PIO_POW_MOD_CTL_REG); + reg = readl(pctl->membase + pctl->pow_mod_sel_offset + + PIO_POW_MOD_CTL_OFS); reg &= ~BIT(bank); - writel(reg | val, pctl->membase + PIO_POW_MOD_CTL_REG); + writel(reg | val, pctl->membase + pctl->pow_mod_sel_offset + + PIO_POW_MOD_CTL_OFS); raw_spin_unlock_irqrestore(&pctl->lock, flags); fallthrough; @@ -733,9 +748,10 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, val = uV <= 1800000 ? 1 : 0; raw_spin_lock_irqsave(&pctl->lock, flags); - reg = readl(pctl->membase + PIO_POW_MOD_SEL_REG); + reg = readl(pctl->membase + pctl->pow_mod_sel_offset); reg &= ~(1 << bank); - writel(reg | val << bank, pctl->membase + PIO_POW_MOD_SEL_REG); + writel(reg | val << bank, + pctl->membase + pctl->pow_mod_sel_offset); raw_spin_unlock_irqrestore(&pctl->lock, flags); return 0; default: @@ -1472,9 +1488,9 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, return 0; } -int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, - const struct sunxi_pinctrl_desc *desc, - unsigned long variant) +int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc, + unsigned long flags) { struct device_node *node = pdev->dev.of_node; struct pinctrl_desc *pctrl_desc; @@ -1497,8 +1513,8 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, pctl->dev = &pdev->dev; pctl->desc = desc; - pctl->variant = variant; - if (pctl->variant >= PINCTRL_SUN20I_D1) { + pctl->variant = flags & SUNXI_PINCTRL_VARIANT_MASK; + if (flags & SUNXI_PINCTRL_NEW_REG_LAYOUT) { pctl->bank_mem_size = D1_BANK_MEM_SIZE; pctl->pull_regs_offset = D1_PULL_REGS_OFFSET; pctl->dlevel_field_width = D1_DLEVEL_FIELD_WIDTH; @@ -1507,6 +1523,10 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, pctl->pull_regs_offset = PULL_REGS_OFFSET; pctl->dlevel_field_width = DLEVEL_FIELD_WIDTH; } + if (flags & SUNXI_PINCTRL_ELEVEN_BANKS) + pctl->pow_mod_sel_offset = PIO_11B_POW_MOD_SEL_REG; + else + pctl->pow_mod_sel_offset = PIO_POW_MOD_SEL_REG; pctl->irq_array = devm_kcalloc(&pdev->dev, IRQ_PER_BANK * pctl->desc->irq_banks, diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index a87a2f944d60..ad26e4de16a8 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -25,10 +25,15 @@ #define PG_BASE 192 #define PH_BASE 224 #define PI_BASE 256 +#define PJ_BASE 288 +#define PK_BASE 320 #define PL_BASE 352 #define PM_BASE 384 #define PN_BASE 416 +/* maximum number of banks per controller (PA -> PK) */ +#define SUNXI_PINCTRL_MAX_BANKS 11 + #define SUNXI_PINCTRL_PIN(bank, pin) \ PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin) @@ -82,21 +87,16 @@ #define SUN4I_FUNC_INPUT 0 #define SUN4I_FUNC_IRQ 6 -#define PINCTRL_SUN5I_A10S BIT(1) -#define PINCTRL_SUN5I_A13 BIT(2) -#define PINCTRL_SUN5I_GR8 BIT(3) -#define PINCTRL_SUN6I_A31 BIT(4) -#define PINCTRL_SUN6I_A31S BIT(5) -#define PINCTRL_SUN4I_A10 BIT(6) -#define PINCTRL_SUN7I_A20 BIT(7) -#define PINCTRL_SUN8I_R40 BIT(8) -#define PINCTRL_SUN8I_V3 BIT(9) -#define PINCTRL_SUN8I_V3S BIT(10) -/* Variants below here have an updated register layout. */ -#define PINCTRL_SUN20I_D1 BIT(11) - -#define PIO_POW_MOD_SEL_REG 0x340 -#define PIO_POW_MOD_CTL_REG 0x344 +#define SUNXI_PINCTRL_VARIANT_MASK GENMASK(7, 0) +#define SUNXI_PINCTRL_NEW_REG_LAYOUT BIT(8) +#define SUNXI_PINCTRL_PORTF_SWITCH BIT(9) +#define SUNXI_PINCTRL_ELEVEN_BANKS BIT(10) + +#define PIO_POW_MOD_SEL_REG 0x340 +#define PIO_11B_POW_MOD_SEL_REG 0x380 +#define PIO_POW_MOD_CTL_OFS 0x004 + +#define PIO_BANK_K_OFFSET 0x500 enum sunxi_desc_bias_voltage { BIAS_VOLTAGE_NONE, @@ -164,7 +164,7 @@ struct sunxi_pinctrl { struct gpio_chip *chip; const struct sunxi_pinctrl_desc *desc; struct device *dev; - struct sunxi_pinctrl_regulator regulators[9]; + struct sunxi_pinctrl_regulator regulators[11]; struct irq_domain *domain; struct sunxi_pinctrl_function *functions; unsigned nfunctions; @@ -178,6 +178,7 @@ struct sunxi_pinctrl { u32 bank_mem_size; u32 pull_regs_offset; u32 dlevel_field_width; + u32 pow_mod_sel_offset; }; #define SUNXI_PIN(_pin, ...) \ @@ -299,11 +300,17 @@ static inline u32 sunxi_grp_config_reg(u16 pin) return GRP_CFG_REG + bank * 0x4; } -int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, - const struct sunxi_pinctrl_desc *desc, - unsigned long variant); +int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc, + unsigned long flags); #define sunxi_pinctrl_init(_dev, _desc) \ - sunxi_pinctrl_init_with_variant(_dev, _desc, 0) + sunxi_pinctrl_init_with_flags(_dev, _desc, 0) + +int sunxi_pinctrl_dt_table_init(struct platform_device *pdev, + const u8 *pins_per_bank, + const u8 *irq_bank_muxes, + struct sunxi_pinctrl_desc *desc, + unsigned long flags); #endif /* __PINCTRL_SUNXI_H */ diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index c83e5a65e680..11ecbd6a9b2a 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -96,6 +96,7 @@ static const struct cfg_param { {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING}, {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, {"nvidia,drive-type", TEGRA_PINCONF_PARAM_DRIVE_TYPE}, + {"nvidia,gpio-mode", TEGRA_PINCONF_PARAM_GPIO_MODE}, }; static int tegra_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, @@ -270,13 +271,16 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev, val = pmx_readl(pmx, g->mux_bank, g->mux_reg); val &= ~(0x3 << g->mux_bit); val |= i << g->mux_bit; + /* Set the SFIO/GPIO selection to SFIO when under pinmux control*/ + if (pmx->soc->sfsel_in_mux) + val |= (1 << g->sfsel_bit); pmx_writel(pmx, val, g->mux_bank, g->mux_reg); return 0; } -static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, - unsigned int offset) +static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev, + unsigned int offset) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); unsigned int group, num_pins, j; @@ -289,12 +293,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev * continue; for (j = 0; j < num_pins; j++) { if (offset == pins[j]) - return &pmx->soc->groups[group]; + return group; } } - dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset); - return NULL; + return -EINVAL; +} + +static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, + unsigned int offset, + int group_index) +{ + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + if (group_index < 0 || group_index >= pmx->soc->ngroups) + return NULL; + + return &pmx->soc->groups[group_index]; +} + +static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev, + unsigned int offset, + int group_index) +{ + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + if (group_index < 0) + return NULL; + + return &pmx->pingroup_configs[group_index]; } static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, @@ -303,12 +330,15 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tegra_pingroup *group; + struct tegra_pingroup_config *config; + int group_index; u32 value; if (!pmx->soc->sfsel_in_mux) return 0; - group = tegra_pinctrl_get_group(pctldev, offset); + group_index = tegra_pinctrl_get_group_index(pctldev, offset); + group = tegra_pinctrl_get_group(pctldev, offset, group_index); if (!group) return -EINVAL; @@ -316,7 +346,11 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, if (group->mux_reg < 0 || group->sfsel_bit < 0) return -EINVAL; + config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); + if (!config) + return -EINVAL; value = pmx_readl(pmx, group->mux_bank, group->mux_reg); + config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0; value &= ~BIT(group->sfsel_bit); pmx_writel(pmx, value, group->mux_bank, group->mux_reg); @@ -329,12 +363,15 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tegra_pingroup *group; + struct tegra_pingroup_config *config; + int group_index; u32 value; if (!pmx->soc->sfsel_in_mux) return; - group = tegra_pinctrl_get_group(pctldev, offset); + group_index = tegra_pinctrl_get_group_index(pctldev, offset); + group = tegra_pinctrl_get_group(pctldev, offset, group_index); if (!group) return; @@ -342,8 +379,12 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, if (group->mux_reg < 0 || group->sfsel_bit < 0) return; + config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); + if (!config) + return; value = pmx_readl(pmx, group->mux_bank, group->mux_reg); - value |= BIT(group->sfsel_bit); + if (config->is_sfsel) + value |= BIT(group->sfsel_bit); pmx_writel(pmx, value, group->mux_bank, group->mux_reg); } @@ -468,6 +509,16 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, *bit = g->drvtype_bit; *width = 2; break; + case TEGRA_PINCONF_PARAM_GPIO_MODE: + if (pmx->soc->sfsel_in_mux) { + *bank = g->mux_bank; + *reg = g->mux_reg; + *bit = g->sfsel_bit; + *width = 1; + } else { + *reg = -EINVAL; + } + break; default: dev_err(pmx->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; @@ -788,6 +839,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev, pmx->dev = &pdev->dev; pmx->soc = soc_data; + pmx->pingroup_configs = devm_kcalloc(&pdev->dev, + pmx->soc->ngroups, sizeof(*pmx->pingroup_configs), + GFP_KERNEL); + if (!pmx->pingroup_configs) + return -ENOMEM; + /* * Each mux group will appear in 4 functions' list of groups. * This over-allocates slightly, since not all groups are mux groups. diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h index b3289bdf727d..bc7b70913b89 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.h +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h @@ -8,6 +8,10 @@ #ifndef __PINMUX_TEGRA_H__ #define __PINMUX_TEGRA_H__ +struct tegra_pingroup_config { + bool is_sfsel; +}; + struct tegra_pmx { struct device *dev; struct pinctrl_dev *pctl; @@ -21,6 +25,8 @@ struct tegra_pmx { int nbanks; void __iomem **regs; u32 *backup_regs; + /* Array of size soc->ngroups */ + struct tegra_pingroup_config *pingroup_configs; }; enum tegra_pinconf_param { @@ -54,6 +60,8 @@ enum tegra_pinconf_param { TEGRA_PINCONF_PARAM_SLEW_RATE_RISING, /* argument: Integer, range is HW-dependant */ TEGRA_PINCONF_PARAM_DRIVE_TYPE, + /* argument: Boolean */ + TEGRA_PINCONF_PARAM_GPIO_MODE, }; enum tegra_pinconf_pull { @@ -176,16 +184,22 @@ struct tegra_pingroup { /** * struct tegra_pinctrl_soc_data - Tegra pin controller driver configuration - * @ngpios: The number of GPIO pins the pin controller HW affects. - * @pins: An array describing all pins the pin controller affects. - * All pins which are also GPIOs must be listed first within the - * array, and be numbered identically to the GPIO controller's - * numbering. - * @npins: The numbmer of entries in @pins. - * @functions: An array describing all mux functions the SoC supports. - * @nfunctions: The numbmer of entries in @functions. - * @groups: An array describing all pin groups the pin SoC supports. - * @ngroups: The numbmer of entries in @groups. + * @ngpios: The number of GPIO pins the pin controller HW affects. + * @gpio_compatible: Device-tree GPIO compatible string. + * @pins: An array describing all pins the pin controller affects. + * All pins which are also GPIOs must be listed first within the + * array, and be numbered identically to the GPIO controller's + * numbering. + * @npins: The number of entries in @pins. + * @functions: An array describing all mux functions the SoC supports. + * @nfunctions: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + * @hsm_in_mux: High-speed mode field. Only applicable to devices with one pin per group. + * @schmitt_in_mux: Schmitt trigger field. Only applicable to devices with one pin per group. + * @drvtype_in_mux: Drivetype field. Only applicable to devices with one pin per group. + * @sfsel_in_mux: Special function selection field. + * Only applicable to devices with one pin per group. */ struct tegra_pinctrl_soc_data { unsigned ngpios; diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 5accab033b8b..c976ff1c8ed9 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -10,6 +10,8 @@ * Author: Alan Cox <alan@linux.intel.com> */ +#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" + #include <linux/bits.h> #include <linux/delay.h> #include <linux/io.h> @@ -20,8 +22,6 @@ #include <linux/pwm.h> #include <linux/time.h> -#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" - #include "pwm-lpss.h" #define PWM 0x00000000 |