diff options
Diffstat (limited to 'drivers/pinctrl/nomadik')
-rw-r--r-- | drivers/pinctrl/nomadik/Kconfig | 39 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/Makefile | 8 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-ab8500.c | 485 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-ab8505.c | 381 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-abx500.c | 1104 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-abx500.h | 205 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c | 1248 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c | 368 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-nomadik.c | 1986 | ||||
-rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-nomadik.h | 189 |
10 files changed, 6013 insertions, 0 deletions
diff --git a/drivers/pinctrl/nomadik/Kconfig b/drivers/pinctrl/nomadik/Kconfig new file mode 100644 index 000000000..c3efe7d7e --- /dev/null +++ b/drivers/pinctrl/nomadik/Kconfig @@ -0,0 +1,39 @@ +if ARCH_U8500 + +config PINCTRL_ABX500 + bool "ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions" + depends on AB8500_CORE + select GENERIC_PINCONF + help + Select this to enable the ABx500 family IC GPIO driver + +config PINCTRL_AB8500 + bool "AB8500 pin controller driver" + depends on PINCTRL_ABX500 && ARCH_U8500 + +config PINCTRL_AB8505 + bool "AB8505 pin controller driver" + depends on PINCTRL_ABX500 && ARCH_U8500 + +endif + +if (ARCH_U8500 || ARCH_NOMADIK) + +config PINCTRL_NOMADIK + bool "Nomadik pin controller driver" + depends on ARCH_U8500 || ARCH_NOMADIK + depends on OF && GPIOLIB + select PINMUX + select PINCONF + select OF_GPIO + select GPIOLIB_IRQCHIP + +config PINCTRL_STN8815 + bool "STN8815 pin controller driver" + depends on PINCTRL_NOMADIK && ARCH_NOMADIK + +config PINCTRL_DB8500 + bool "DB8500 pin controller driver" + depends on PINCTRL_NOMADIK && ARCH_U8500 + +endif diff --git a/drivers/pinctrl/nomadik/Makefile b/drivers/pinctrl/nomadik/Makefile new file mode 100644 index 000000000..dd10d49da --- /dev/null +++ b/drivers/pinctrl/nomadik/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# Nomadik family pin control drivers +obj-$(CONFIG_PINCTRL_ABX500) += pinctrl-abx500.o +obj-$(CONFIG_PINCTRL_AB8500) += pinctrl-ab8500.o +obj-$(CONFIG_PINCTRL_AB8505) += pinctrl-ab8505.o +obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o +obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o +obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8500.c b/drivers/pinctrl/nomadik/pinctrl-ab8500.c new file mode 100644 index 000000000..2ac2d0ad3 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-ab8500.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) ST-Ericsson SA 2012 + * + * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/mfd/abx500/ab8500.h> +#include "pinctrl-abx500.h" + +/* All the pins that can be used for GPIO and some other functions */ +#define ABX500_GPIO(offset) (offset) + +#define AB8500_PIN_T10 ABX500_GPIO(1) +#define AB8500_PIN_T9 ABX500_GPIO(2) +#define AB8500_PIN_U9 ABX500_GPIO(3) +#define AB8500_PIN_W2 ABX500_GPIO(4) +/* hole */ +#define AB8500_PIN_Y18 ABX500_GPIO(6) +#define AB8500_PIN_AA20 ABX500_GPIO(7) +#define AB8500_PIN_W18 ABX500_GPIO(8) +#define AB8500_PIN_AA19 ABX500_GPIO(9) +#define AB8500_PIN_U17 ABX500_GPIO(10) +#define AB8500_PIN_AA18 ABX500_GPIO(11) +#define AB8500_PIN_U16 ABX500_GPIO(12) +#define AB8500_PIN_W17 ABX500_GPIO(13) +#define AB8500_PIN_F14 ABX500_GPIO(14) +#define AB8500_PIN_B17 ABX500_GPIO(15) +#define AB8500_PIN_F15 ABX500_GPIO(16) +#define AB8500_PIN_P5 ABX500_GPIO(17) +#define AB8500_PIN_R5 ABX500_GPIO(18) +#define AB8500_PIN_U5 ABX500_GPIO(19) +#define AB8500_PIN_T5 ABX500_GPIO(20) +#define AB8500_PIN_H19 ABX500_GPIO(21) +#define AB8500_PIN_G20 ABX500_GPIO(22) +#define AB8500_PIN_G19 ABX500_GPIO(23) +#define AB8500_PIN_T14 ABX500_GPIO(24) +#define AB8500_PIN_R16 ABX500_GPIO(25) +#define AB8500_PIN_M16 ABX500_GPIO(26) +#define AB8500_PIN_J6 ABX500_GPIO(27) +#define AB8500_PIN_K6 ABX500_GPIO(28) +#define AB8500_PIN_G6 ABX500_GPIO(29) +#define AB8500_PIN_H6 ABX500_GPIO(30) +#define AB8500_PIN_F5 ABX500_GPIO(31) +#define AB8500_PIN_G5 ABX500_GPIO(32) +/* hole */ +#define AB8500_PIN_R17 ABX500_GPIO(34) +#define AB8500_PIN_W15 ABX500_GPIO(35) +#define AB8500_PIN_A17 ABX500_GPIO(36) +#define AB8500_PIN_E15 ABX500_GPIO(37) +#define AB8500_PIN_C17 ABX500_GPIO(38) +#define AB8500_PIN_E16 ABX500_GPIO(39) +#define AB8500_PIN_T19 ABX500_GPIO(40) +#define AB8500_PIN_U19 ABX500_GPIO(41) +#define AB8500_PIN_U2 ABX500_GPIO(42) + +/* indicates the highest GPIO number */ +#define AB8500_GPIO_MAX_NUMBER 42 + +/* + * The names of the pins are denoted by GPIO number and ball name, even + * though they can be used for other things than GPIO, this is the first + * column in the table of the data sheet and often used on schematics and + * such. + */ +static const struct pinctrl_pin_desc ab8500_pins[] = { + PINCTRL_PIN(AB8500_PIN_T10, "GPIO1_T10"), + PINCTRL_PIN(AB8500_PIN_T9, "GPIO2_T9"), + PINCTRL_PIN(AB8500_PIN_U9, "GPIO3_U9"), + PINCTRL_PIN(AB8500_PIN_W2, "GPIO4_W2"), + /* hole */ + PINCTRL_PIN(AB8500_PIN_Y18, "GPIO6_Y18"), + PINCTRL_PIN(AB8500_PIN_AA20, "GPIO7_AA20"), + PINCTRL_PIN(AB8500_PIN_W18, "GPIO8_W18"), + PINCTRL_PIN(AB8500_PIN_AA19, "GPIO9_AA19"), + PINCTRL_PIN(AB8500_PIN_U17, "GPIO10_U17"), + PINCTRL_PIN(AB8500_PIN_AA18, "GPIO11_AA18"), + PINCTRL_PIN(AB8500_PIN_U16, "GPIO12_U16"), + PINCTRL_PIN(AB8500_PIN_W17, "GPIO13_W17"), + PINCTRL_PIN(AB8500_PIN_F14, "GPIO14_F14"), + PINCTRL_PIN(AB8500_PIN_B17, "GPIO15_B17"), + PINCTRL_PIN(AB8500_PIN_F15, "GPIO16_F15"), + PINCTRL_PIN(AB8500_PIN_P5, "GPIO17_P5"), + PINCTRL_PIN(AB8500_PIN_R5, "GPIO18_R5"), + PINCTRL_PIN(AB8500_PIN_U5, "GPIO19_U5"), + PINCTRL_PIN(AB8500_PIN_T5, "GPIO20_T5"), + PINCTRL_PIN(AB8500_PIN_H19, "GPIO21_H19"), + PINCTRL_PIN(AB8500_PIN_G20, "GPIO22_G20"), + PINCTRL_PIN(AB8500_PIN_G19, "GPIO23_G19"), + PINCTRL_PIN(AB8500_PIN_T14, "GPIO24_T14"), + PINCTRL_PIN(AB8500_PIN_R16, "GPIO25_R16"), + PINCTRL_PIN(AB8500_PIN_M16, "GPIO26_M16"), + PINCTRL_PIN(AB8500_PIN_J6, "GPIO27_J6"), + PINCTRL_PIN(AB8500_PIN_K6, "GPIO28_K6"), + PINCTRL_PIN(AB8500_PIN_G6, "GPIO29_G6"), + PINCTRL_PIN(AB8500_PIN_H6, "GPIO30_H6"), + PINCTRL_PIN(AB8500_PIN_F5, "GPIO31_F5"), + PINCTRL_PIN(AB8500_PIN_G5, "GPIO32_G5"), + /* hole */ + PINCTRL_PIN(AB8500_PIN_R17, "GPIO34_R17"), + PINCTRL_PIN(AB8500_PIN_W15, "GPIO35_W15"), + PINCTRL_PIN(AB8500_PIN_A17, "GPIO36_A17"), + PINCTRL_PIN(AB8500_PIN_E15, "GPIO37_E15"), + PINCTRL_PIN(AB8500_PIN_C17, "GPIO38_C17"), + PINCTRL_PIN(AB8500_PIN_E16, "GPIO39_E16"), + PINCTRL_PIN(AB8500_PIN_T19, "GPIO40_T19"), + PINCTRL_PIN(AB8500_PIN_U19, "GPIO41_U19"), + PINCTRL_PIN(AB8500_PIN_U2, "GPIO42_U2"), +}; + +/* + * Maps local GPIO offsets to local pin numbers + */ +static const struct abx500_pinrange ab8500_pinranges[] = { + ABX500_PINRANGE(1, 4, ABX500_ALT_A), + ABX500_PINRANGE(6, 4, ABX500_ALT_A), + ABX500_PINRANGE(10, 4, ABX500_DEFAULT), + ABX500_PINRANGE(14, 12, ABX500_ALT_A), + ABX500_PINRANGE(26, 1, ABX500_DEFAULT), + ABX500_PINRANGE(27, 6, ABX500_ALT_A), + ABX500_PINRANGE(34, 1, ABX500_ALT_A), + ABX500_PINRANGE(35, 1, ABX500_DEFAULT), + ABX500_PINRANGE(36, 7, ABX500_ALT_A), +}; + +/* + * Read the pin group names like this: + * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function + * + * The groups are arranged as sets per altfunction column, so we can + * mux in one group at a time by selecting the same altfunction for them + * all. When functions require pins on different altfunctions, you need + * to combine several groups. + */ + +/* default column */ +static const unsigned sysclkreq2_d_1_pins[] = { AB8500_PIN_T10 }; +static const unsigned sysclkreq3_d_1_pins[] = { AB8500_PIN_T9 }; +static const unsigned sysclkreq4_d_1_pins[] = { AB8500_PIN_U9 }; +static const unsigned sysclkreq6_d_1_pins[] = { AB8500_PIN_W2 }; +static const unsigned ycbcr0123_d_1_pins[] = { AB8500_PIN_Y18, AB8500_PIN_AA20, + AB8500_PIN_W18, AB8500_PIN_AA19}; +static const unsigned gpio10_d_1_pins[] = { AB8500_PIN_U17 }; +static const unsigned gpio11_d_1_pins[] = { AB8500_PIN_AA18 }; +static const unsigned gpio12_d_1_pins[] = { AB8500_PIN_U16 }; +static const unsigned gpio13_d_1_pins[] = { AB8500_PIN_W17 }; +static const unsigned pwmout1_d_1_pins[] = { AB8500_PIN_F14 }; +static const unsigned pwmout2_d_1_pins[] = { AB8500_PIN_B17 }; +static const unsigned pwmout3_d_1_pins[] = { AB8500_PIN_F15 }; + +/* audio data interface 1*/ +static const unsigned adi1_d_1_pins[] = { AB8500_PIN_P5, AB8500_PIN_R5, + AB8500_PIN_U5, AB8500_PIN_T5 }; +/* USBUICC */ +static const unsigned usbuicc_d_1_pins[] = { AB8500_PIN_H19, AB8500_PIN_G20, + AB8500_PIN_G19 }; +static const unsigned sysclkreq7_d_1_pins[] = { AB8500_PIN_T14 }; +static const unsigned sysclkreq8_d_1_pins[] = { AB8500_PIN_R16 }; +static const unsigned gpio26_d_1_pins[] = { AB8500_PIN_M16 }; +/* Digital microphone 1 and 2 */ +static const unsigned dmic12_d_1_pins[] = { AB8500_PIN_J6, AB8500_PIN_K6 }; +/* Digital microphone 3 and 4 */ +static const unsigned dmic34_d_1_pins[] = { AB8500_PIN_G6, AB8500_PIN_H6 }; +/* Digital microphone 5 and 6 */ +static const unsigned dmic56_d_1_pins[] = { AB8500_PIN_F5, AB8500_PIN_G5 }; +static const unsigned extcpena_d_1_pins[] = { AB8500_PIN_R17 }; +static const unsigned gpio35_d_1_pins[] = { AB8500_PIN_W15 }; +/* APE SPI */ +static const unsigned apespi_d_1_pins[] = { AB8500_PIN_A17, AB8500_PIN_E15, + AB8500_PIN_C17, AB8500_PIN_E16}; +/* modem SDA/SCL */ +static const unsigned modsclsda_d_1_pins[] = { AB8500_PIN_T19, AB8500_PIN_U19 }; +static const unsigned sysclkreq5_d_1_pins[] = { AB8500_PIN_U2 }; + +/* Altfunction A column */ +static const unsigned gpio1_a_1_pins[] = { AB8500_PIN_T10 }; +static const unsigned gpio2_a_1_pins[] = { AB8500_PIN_T9 }; +static const unsigned gpio3_a_1_pins[] = { AB8500_PIN_U9 }; +static const unsigned gpio4_a_1_pins[] = { AB8500_PIN_W2 }; +static const unsigned gpio6_a_1_pins[] = { AB8500_PIN_Y18 }; +static const unsigned gpio7_a_1_pins[] = { AB8500_PIN_AA20 }; +static const unsigned gpio8_a_1_pins[] = { AB8500_PIN_W18 }; +static const unsigned gpio9_a_1_pins[] = { AB8500_PIN_AA19 }; +/* YCbCr4 YCbCr5 YCbCr6 YCbCr7*/ +static const unsigned ycbcr4567_a_1_pins[] = { AB8500_PIN_U17, AB8500_PIN_AA18, + AB8500_PIN_U16, AB8500_PIN_W17}; +static const unsigned gpio14_a_1_pins[] = { AB8500_PIN_F14 }; +static const unsigned gpio15_a_1_pins[] = { AB8500_PIN_B17 }; +static const unsigned gpio16_a_1_pins[] = { AB8500_PIN_F15 }; +static const unsigned gpio17_a_1_pins[] = { AB8500_PIN_P5 }; +static const unsigned gpio18_a_1_pins[] = { AB8500_PIN_R5 }; +static const unsigned gpio19_a_1_pins[] = { AB8500_PIN_U5 }; +static const unsigned gpio20_a_1_pins[] = { AB8500_PIN_T5 }; +static const unsigned gpio21_a_1_pins[] = { AB8500_PIN_H19 }; +static const unsigned gpio22_a_1_pins[] = { AB8500_PIN_G20 }; +static const unsigned gpio23_a_1_pins[] = { AB8500_PIN_G19 }; +static const unsigned gpio24_a_1_pins[] = { AB8500_PIN_T14 }; +static const unsigned gpio25_a_1_pins[] = { AB8500_PIN_R16 }; +static const unsigned gpio27_a_1_pins[] = { AB8500_PIN_J6 }; +static const unsigned gpio28_a_1_pins[] = { AB8500_PIN_K6 }; +static const unsigned gpio29_a_1_pins[] = { AB8500_PIN_G6 }; +static const unsigned gpio30_a_1_pins[] = { AB8500_PIN_H6 }; +static const unsigned gpio31_a_1_pins[] = { AB8500_PIN_F5 }; +static const unsigned gpio32_a_1_pins[] = { AB8500_PIN_G5 }; +static const unsigned gpio34_a_1_pins[] = { AB8500_PIN_R17 }; +static const unsigned gpio36_a_1_pins[] = { AB8500_PIN_A17 }; +static const unsigned gpio37_a_1_pins[] = { AB8500_PIN_E15 }; +static const unsigned gpio38_a_1_pins[] = { AB8500_PIN_C17 }; +static const unsigned gpio39_a_1_pins[] = { AB8500_PIN_E16 }; +static const unsigned gpio40_a_1_pins[] = { AB8500_PIN_T19 }; +static const unsigned gpio41_a_1_pins[] = { AB8500_PIN_U19 }; +static const unsigned gpio42_a_1_pins[] = { AB8500_PIN_U2 }; + +/* Altfunction B colum */ +static const unsigned hiqclkena_b_1_pins[] = { AB8500_PIN_U17 }; +static const unsigned usbuiccpd_b_1_pins[] = { AB8500_PIN_AA18 }; +static const unsigned i2ctrig1_b_1_pins[] = { AB8500_PIN_U16 }; +static const unsigned i2ctrig2_b_1_pins[] = { AB8500_PIN_W17 }; + +/* Altfunction C column */ +static const unsigned usbvdat_c_1_pins[] = { AB8500_PIN_W17 }; + + +#define AB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \ + .npins = ARRAY_SIZE(a##_pins), .altsetting = b } + +static const struct abx500_pingroup ab8500_groups[] = { + /* default column */ + AB8500_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(ycbcr0123_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(gpio12_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(adi1_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(usbuicc_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(sysclkreq7_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(sysclkreq8_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(gpio26_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(gpio35_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(apespi_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT), + AB8500_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT), + /* Altfunction A column */ + AB8500_PIN_GROUP(gpio1_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio2_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio3_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio4_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio6_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio7_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio8_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio9_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(ycbcr4567_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio14_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio15_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio16_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio17_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio18_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio19_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio20_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio21_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio22_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio23_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio24_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio25_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio27_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio28_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio29_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio30_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio31_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio32_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio34_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio36_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio37_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio38_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio39_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio40_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio41_a_1, ABX500_ALT_A), + AB8500_PIN_GROUP(gpio42_a_1, ABX500_ALT_A), + /* Altfunction B column */ + AB8500_PIN_GROUP(hiqclkena_b_1, ABX500_ALT_B), + AB8500_PIN_GROUP(usbuiccpd_b_1, ABX500_ALT_B), + AB8500_PIN_GROUP(i2ctrig1_b_1, ABX500_ALT_B), + AB8500_PIN_GROUP(i2ctrig2_b_1, ABX500_ALT_B), + /* Altfunction C column */ + AB8500_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C), +}; + +/* We use this macro to define the groups applicable to a function */ +#define AB8500_FUNC_GROUPS(a, b...) \ +static const char * const a##_groups[] = { b }; + +AB8500_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1", + "sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1", + "sysclkreq7_d_1", "sysclkreq8_d_1"); +AB8500_FUNC_GROUPS(ycbcr, "ycbcr0123_d_1", "ycbcr4567_a_1"); +AB8500_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1", + "gpio6_a_1", "gpio7_a_1", "gpio8_a_1", "gpio9_a_1", + "gpio10_d_1", "gpio11_d_1", "gpio12_d_1", "gpio13_d_1", + "gpio14_a_1", "gpio15_a_1", "gpio16_a_1", "gpio17_a_1", + "gpio18_a_1", "gpio19_a_1", "gpio20_a_1", "gpio21_a_1", + "gpio22_a_1", "gpio23_a_1", "gpio24_a_1", "gpio25_a_1", + "gpio26_d_1", "gpio27_a_1", "gpio28_a_1", "gpio29_a_1", + "gpio30_a_1", "gpio31_a_1", "gpio32_a_1", "gpio34_a_1", + "gpio35_d_1", "gpio36_a_1", "gpio37_a_1", "gpio38_a_1", + "gpio39_a_1", "gpio40_a_1", "gpio41_a_1", "gpio42_a_1"); +AB8500_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1"); +AB8500_FUNC_GROUPS(adi1, "adi1_d_1"); +AB8500_FUNC_GROUPS(usbuicc, "usbuicc_d_1", "usbuiccpd_b_1"); +AB8500_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1"); +AB8500_FUNC_GROUPS(extcpena, "extcpena_d_1"); +AB8500_FUNC_GROUPS(apespi, "apespi_d_1"); +AB8500_FUNC_GROUPS(modsclsda, "modsclsda_d_1"); +AB8500_FUNC_GROUPS(hiqclkena, "hiqclkena_b_1"); +AB8500_FUNC_GROUPS(i2ctrig, "i2ctrig1_b_1", "i2ctrig2_b_1"); +AB8500_FUNC_GROUPS(usbvdat, "usbvdat_c_1"); + +#define FUNCTION(fname) \ + { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct abx500_function ab8500_functions[] = { + FUNCTION(sysclkreq), + FUNCTION(ycbcr), + FUNCTION(gpio), + FUNCTION(pwmout), + FUNCTION(adi1), + FUNCTION(usbuicc), + FUNCTION(dmic), + FUNCTION(extcpena), + FUNCTION(apespi), + FUNCTION(modsclsda), + FUNCTION(hiqclkena), + FUNCTION(i2ctrig), + FUNCTION(usbvdat), +}; + +/* + * this table translates what's is in the AB8500 specification regarding the + * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C). + * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1, + * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val), + * + * example : + * + * ALTERNATE_FUNCTIONS(13, 4, 3, 4, 0, 1 ,2), + * means that pin AB8500_PIN_W17 (pin 13) supports 4 mux (default/ALT_A, + * ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to + * select the mux. ALTA, ALTB and ALTC val indicates values to write in + * ALTERNATFUNC register. We need to specifies these values as SOC + * designers didn't apply the same logic on how to select mux in the + * ABx500 family. + * + * As this pins supports at least ALT_B mux, default mux is + * selected by writing 1 in GPIOSEL bit : + * + * | GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3 + * default | 1 | 0 | 0 + * alt_A | 0 | 0 | 0 + * alt_B | 0 | 0 | 1 + * alt_C | 0 | 1 | 0 + * + * ALTERNATE_FUNCTIONS(8, 7, UNUSED, UNUSED), + * means that pin AB8500_PIN_W18 (pin 8) supports 2 mux, so only GPIOSEL + * register is used to select the mux. As this pins doesn't support at + * least ALT_B mux, default mux is by writing 0 in GPIOSEL bit : + * + * | GPIOSEL bit=7 | alternatfunc bit2= | alternatfunc bit1= + * default | 0 | 0 | 0 + * alt_A | 1 | 0 | 0 + */ + +static struct +alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = { + ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */ + ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */ + ALTERNATE_FUNCTIONS(3, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/ + ALTERNATE_FUNCTIONS(4, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/ + /* bit 4 reserved */ + ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */ + ALTERNATE_FUNCTIONS(6, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO6, altA controlled by bit 5*/ + ALTERNATE_FUNCTIONS(7, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO7, altA controlled by bit 6*/ + ALTERNATE_FUNCTIONS(8, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO8, altA controlled by bit 7*/ + + ALTERNATE_FUNCTIONS(9, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO9, altA controlled by bit 0*/ + ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 0, 1, 0), /* GPIO10, altA and altB controlled by bit 0 */ + ALTERNATE_FUNCTIONS(11, 2, 1, UNUSED, 0, 1, 0), /* GPIO11, altA and altB controlled by bit 1 */ + ALTERNATE_FUNCTIONS(12, 3, 2, UNUSED, 0, 1, 0), /* GPIO12, altA and altB controlled by bit 2 */ + ALTERNATE_FUNCTIONS(13, 4, 3, 4, 0, 1, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */ + ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */ + ALTERNATE_FUNCTIONS(15, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */ + ALTERNATE_FUNCTIONS(16, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */ + /* + * pins 17 to 20 are special case, only bit 0 is used to select + * alternate function for these 4 pins. + * bits 1 to 3 are reserved + */ + ALTERNATE_FUNCTIONS(17, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(18, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(19, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(20, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(21, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO21, altA controlled by bit 4 */ + ALTERNATE_FUNCTIONS(22, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO22, altA controlled by bit 5 */ + ALTERNATE_FUNCTIONS(23, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO23, altA controlled by bit 6 */ + ALTERNATE_FUNCTIONS(24, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO24, altA controlled by bit 7 */ + + ALTERNATE_FUNCTIONS(25, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO25, altA controlled by bit 0 */ + /* pin 26 special case, no alternate function, bit 1 reserved */ + ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO26 */ + ALTERNATE_FUNCTIONS(27, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */ + ALTERNATE_FUNCTIONS(28, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */ + ALTERNATE_FUNCTIONS(29, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */ + ALTERNATE_FUNCTIONS(30, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */ + ALTERNATE_FUNCTIONS(31, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */ + ALTERNATE_FUNCTIONS(32, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */ + + ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */ + ALTERNATE_FUNCTIONS(34, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */ + /* pin 35 special case, no alternate function, bit 2 reserved */ + ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO35 */ + ALTERNATE_FUNCTIONS(36, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO36, altA controlled by bit 3 */ + ALTERNATE_FUNCTIONS(37, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO37, altA controlled by bit 4 */ + ALTERNATE_FUNCTIONS(38, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO38, altA controlled by bit 5 */ + ALTERNATE_FUNCTIONS(39, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO39, altA controlled by bit 6 */ + ALTERNATE_FUNCTIONS(40, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7 */ + + ALTERNATE_FUNCTIONS(41, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(42, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */ +}; + +/* + * Only some GPIOs are interrupt capable, and they are + * organized in discontiguous clusters: + * + * GPIO6 to GPIO13 + * GPIO24 and GPIO25 + * GPIO36 to GPIO41 + */ +static struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = { + GPIO_IRQ_CLUSTER(6, 13, AB8500_INT_GPIO6R), + GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R), + GPIO_IRQ_CLUSTER(36, 41, AB8500_INT_GPIO36R), +}; + +static struct abx500_pinctrl_soc_data ab8500_soc = { + .gpio_ranges = ab8500_pinranges, + .gpio_num_ranges = ARRAY_SIZE(ab8500_pinranges), + .pins = ab8500_pins, + .npins = ARRAY_SIZE(ab8500_pins), + .functions = ab8500_functions, + .nfunctions = ARRAY_SIZE(ab8500_functions), + .groups = ab8500_groups, + .ngroups = ARRAY_SIZE(ab8500_groups), + .alternate_functions = ab8500_alternate_functions, + .gpio_irq_cluster = ab8500_gpio_irq_cluster, + .ngpio_irq_cluster = ARRAY_SIZE(ab8500_gpio_irq_cluster), + .irq_gpio_rising_offset = AB8500_INT_GPIO6R, + .irq_gpio_falling_offset = AB8500_INT_GPIO6F, + .irq_gpio_factor = 1, +}; + +void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc) +{ + *soc = &ab8500_soc; +} diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c new file mode 100644 index 000000000..42c6e1f78 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) ST-Ericsson SA 2012 + * + * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/mfd/abx500/ab8500.h> +#include "pinctrl-abx500.h" + +/* All the pins that can be used for GPIO and some other functions */ +#define ABX500_GPIO(offset) (offset) + +#define AB8505_PIN_N4 ABX500_GPIO(1) +#define AB8505_PIN_R5 ABX500_GPIO(2) +#define AB8505_PIN_P5 ABX500_GPIO(3) +/* hole */ +#define AB8505_PIN_B16 ABX500_GPIO(10) +#define AB8505_PIN_B17 ABX500_GPIO(11) +/* hole */ +#define AB8505_PIN_D17 ABX500_GPIO(13) +#define AB8505_PIN_C16 ABX500_GPIO(14) +/* hole */ +#define AB8505_PIN_P2 ABX500_GPIO(17) +#define AB8505_PIN_N3 ABX500_GPIO(18) +#define AB8505_PIN_T1 ABX500_GPIO(19) +#define AB8505_PIN_P3 ABX500_GPIO(20) +/* hole */ +#define AB8505_PIN_H14 ABX500_GPIO(34) +/* hole */ +#define AB8505_PIN_J15 ABX500_GPIO(40) +#define AB8505_PIN_J14 ABX500_GPIO(41) +/* hole */ +#define AB8505_PIN_L4 ABX500_GPIO(50) +/* hole */ +#define AB8505_PIN_D16 ABX500_GPIO(52) +#define AB8505_PIN_D15 ABX500_GPIO(53) + +/* indicates the higher GPIO number */ +#define AB8505_GPIO_MAX_NUMBER 53 + +/* + * The names of the pins are denoted by GPIO number and ball name, even + * though they can be used for other things than GPIO, this is the first + * column in the table of the data sheet and often used on schematics and + * such. + */ +static const struct pinctrl_pin_desc ab8505_pins[] = { + PINCTRL_PIN(AB8505_PIN_N4, "GPIO1_N4"), + PINCTRL_PIN(AB8505_PIN_R5, "GPIO2_R5"), + PINCTRL_PIN(AB8505_PIN_P5, "GPIO3_P5"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_B16, "GPIO10_B16"), + PINCTRL_PIN(AB8505_PIN_B17, "GPIO11_B17"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_D17, "GPIO13_D17"), + PINCTRL_PIN(AB8505_PIN_C16, "GPIO14_C16"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_P2, "GPIO17_P2"), + PINCTRL_PIN(AB8505_PIN_N3, "GPIO18_N3"), + PINCTRL_PIN(AB8505_PIN_T1, "GPIO19_T1"), + PINCTRL_PIN(AB8505_PIN_P3, "GPIO20_P3"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_H14, "GPIO34_H14"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_J15, "GPIO40_J15"), + PINCTRL_PIN(AB8505_PIN_J14, "GPIO41_J14"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_L4, "GPIO50_L4"), +/* hole */ + PINCTRL_PIN(AB8505_PIN_D16, "GPIO52_D16"), + PINCTRL_PIN(AB8505_PIN_D15, "GPIO53_D15"), +}; + +/* + * Maps local GPIO offsets to local pin numbers + */ +static const struct abx500_pinrange ab8505_pinranges[] = { + ABX500_PINRANGE(1, 3, ABX500_ALT_A), + ABX500_PINRANGE(10, 2, ABX500_DEFAULT), + ABX500_PINRANGE(13, 1, ABX500_DEFAULT), + ABX500_PINRANGE(14, 1, ABX500_ALT_A), + ABX500_PINRANGE(17, 4, ABX500_ALT_A), + ABX500_PINRANGE(34, 1, ABX500_ALT_A), + ABX500_PINRANGE(40, 2, ABX500_ALT_A), + ABX500_PINRANGE(50, 1, ABX500_DEFAULT), + ABX500_PINRANGE(52, 2, ABX500_ALT_A), +}; + +/* + * Read the pin group names like this: + * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function + * + * The groups are arranged as sets per altfunction column, so we can + * mux in one group at a time by selecting the same altfunction for them + * all. When functions require pins on different altfunctions, you need + * to combine several groups. + */ + +/* default column */ +static const unsigned sysclkreq2_d_1_pins[] = { AB8505_PIN_N4 }; +static const unsigned sysclkreq3_d_1_pins[] = { AB8505_PIN_R5 }; +static const unsigned sysclkreq4_d_1_pins[] = { AB8505_PIN_P5 }; +static const unsigned gpio10_d_1_pins[] = { AB8505_PIN_B16 }; +static const unsigned gpio11_d_1_pins[] = { AB8505_PIN_B17 }; +static const unsigned gpio13_d_1_pins[] = { AB8505_PIN_D17 }; +static const unsigned pwmout1_d_1_pins[] = { AB8505_PIN_C16 }; +/* audio data interface 2*/ +static const unsigned adi2_d_1_pins[] = { AB8505_PIN_P2, AB8505_PIN_N3, + AB8505_PIN_T1, AB8505_PIN_P3 }; +static const unsigned extcpena_d_1_pins[] = { AB8505_PIN_H14 }; +/* modem SDA/SCL */ +static const unsigned modsclsda_d_1_pins[] = { AB8505_PIN_J15, AB8505_PIN_J14 }; +static const unsigned gpio50_d_1_pins[] = { AB8505_PIN_L4 }; +static const unsigned resethw_d_1_pins[] = { AB8505_PIN_D16 }; +static const unsigned service_d_1_pins[] = { AB8505_PIN_D15 }; + +/* Altfunction A column */ +static const unsigned gpio1_a_1_pins[] = { AB8505_PIN_N4 }; +static const unsigned gpio2_a_1_pins[] = { AB8505_PIN_R5 }; +static const unsigned gpio3_a_1_pins[] = { AB8505_PIN_P5 }; +static const unsigned hiqclkena_a_1_pins[] = { AB8505_PIN_B16 }; +static const unsigned pdmclk_a_1_pins[] = { AB8505_PIN_B17 }; +static const unsigned uarttxdata_a_1_pins[] = { AB8505_PIN_D17 }; +static const unsigned gpio14_a_1_pins[] = { AB8505_PIN_C16 }; +static const unsigned gpio17_a_1_pins[] = { AB8505_PIN_P2 }; +static const unsigned gpio18_a_1_pins[] = { AB8505_PIN_N3 }; +static const unsigned gpio19_a_1_pins[] = { AB8505_PIN_T1 }; +static const unsigned gpio20_a_1_pins[] = { AB8505_PIN_P3 }; +static const unsigned gpio34_a_1_pins[] = { AB8505_PIN_H14 }; +static const unsigned gpio40_a_1_pins[] = { AB8505_PIN_J15 }; +static const unsigned gpio41_a_1_pins[] = { AB8505_PIN_J14 }; +static const unsigned uartrxdata_a_1_pins[] = { AB8505_PIN_J14 }; +static const unsigned gpio50_a_1_pins[] = { AB8505_PIN_L4 }; +static const unsigned gpio52_a_1_pins[] = { AB8505_PIN_D16 }; +static const unsigned gpio53_a_1_pins[] = { AB8505_PIN_D15 }; + +/* Altfunction B colum */ +static const unsigned pdmdata_b_1_pins[] = { AB8505_PIN_B16 }; +static const unsigned extvibrapwm1_b_1_pins[] = { AB8505_PIN_D17 }; +static const unsigned extvibrapwm2_b_1_pins[] = { AB8505_PIN_L4 }; + +/* Altfunction C column */ +static const unsigned usbvdat_c_1_pins[] = { AB8505_PIN_D17 }; + +#define AB8505_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \ + .npins = ARRAY_SIZE(a##_pins), .altsetting = b } + +static const struct abx500_pingroup ab8505_groups[] = { + AB8505_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(adi2_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(gpio50_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(resethw_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(service_d_1, ABX500_DEFAULT), + AB8505_PIN_GROUP(gpio1_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio2_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio3_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(hiqclkena_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(pdmclk_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(uarttxdata_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio14_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio17_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio18_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio19_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio20_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio34_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio40_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio41_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(uartrxdata_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio52_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(gpio53_a_1, ABX500_ALT_A), + AB8505_PIN_GROUP(pdmdata_b_1, ABX500_ALT_B), + AB8505_PIN_GROUP(extvibrapwm1_b_1, ABX500_ALT_B), + AB8505_PIN_GROUP(extvibrapwm2_b_1, ABX500_ALT_B), + AB8505_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C), +}; + +/* We use this macro to define the groups applicable to a function */ +#define AB8505_FUNC_GROUPS(a, b...) \ +static const char * const a##_groups[] = { b }; + +AB8505_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1", + "sysclkreq4_d_1"); +AB8505_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", + "gpio10_d_1", "gpio11_d_1", "gpio13_d_1", "gpio14_a_1", + "gpio17_a_1", "gpio18_a_1", "gpio19_a_1", "gpio20_a_1", + "gpio34_a_1", "gpio40_a_1", "gpio41_a_1", "gpio50_d_1", + "gpio52_a_1", "gpio53_a_1"); +AB8505_FUNC_GROUPS(pwmout, "pwmout1_d_1"); +AB8505_FUNC_GROUPS(adi2, "adi2_d_1"); +AB8505_FUNC_GROUPS(extcpena, "extcpena_d_1"); +AB8505_FUNC_GROUPS(modsclsda, "modsclsda_d_1"); +AB8505_FUNC_GROUPS(resethw, "resethw_d_1"); +AB8505_FUNC_GROUPS(service, "service_d_1"); +AB8505_FUNC_GROUPS(hiqclkena, "hiqclkena_a_1"); +AB8505_FUNC_GROUPS(pdm, "pdmclk_a_1", "pdmdata_b_1"); +AB8505_FUNC_GROUPS(uartdata, "uarttxdata_a_1", "uartrxdata_a_1"); +AB8505_FUNC_GROUPS(extvibra, "extvibrapwm1_b_1", "extvibrapwm2_b_1"); +AB8505_FUNC_GROUPS(usbvdat, "usbvdat_c_1"); + +#define FUNCTION(fname) \ + { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct abx500_function ab8505_functions[] = { + FUNCTION(sysclkreq), + FUNCTION(gpio), + FUNCTION(pwmout), + FUNCTION(adi2), + FUNCTION(extcpena), + FUNCTION(modsclsda), + FUNCTION(resethw), + FUNCTION(service), + FUNCTION(hiqclkena), + FUNCTION(pdm), + FUNCTION(uartdata), + FUNCTION(extvibra), + FUNCTION(extvibra), + FUNCTION(usbvdat), +}; + +/* + * this table translates what's is in the AB8505 specification regarding the + * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C). + * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1, + * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val), + * + * example : + * + * ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), + * means that pin AB8505_PIN_D18 (pin 13) supports 4 mux (default/ALT_A, + * ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to + * select the mux. ALTA, ALTB and ALTC val indicates values to write in + * ALTERNATFUNC register. We need to specifies these values as SOC + * designers didn't apply the same logic on how to select mux in the + * ABx500 family. + * + * As this pins supports at least ALT_B mux, default mux is + * selected by writing 1 in GPIOSEL bit : + * + * | GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3 + * default | 1 | 0 | 0 + * alt_A | 0 | 0 | 1 + * alt_B | 0 | 0 | 0 + * alt_C | 0 | 1 | 0 + * + * ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED), + * means that pin AB9540_PIN_R4 (pin 1) supports 2 mux, so only GPIOSEL + * register is used to select the mux. As this pins doesn't support at + * least ALT_B mux, default mux is by writing 0 in GPIOSEL bit : + * + * | GPIOSEL bit=0 | alternatfunc bit2= | alternatfunc bit1= + * default | 0 | 0 | 0 + * alt_A | 1 | 0 | 0 + */ + +static struct +alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = { + ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */ + ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */ + ALTERNATE_FUNCTIONS(3, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/ + ALTERNATE_FUNCTIONS(4, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO4, bit 3 reserved */ + ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5, bit 4 reserved */ + ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6, bit 5 reserved */ + ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7, bit 6 reserved */ + ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8, bit 7 reserved */ + + ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9, bit 0 reserved */ + ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */ + ALTERNATE_FUNCTIONS(11, 2, 1, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */ + ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reserved */ + ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */ + ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */ + ALTERNATE_FUNCTIONS(15, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 6 reserved */ + ALTERNATE_FUNCTIONS(16, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 7 reserved */ + /* + * pins 17 to 20 are special case, only bit 0 is used to select + * alternate function for these 4 pins. + * bits 1 to 3 are reserved + */ + ALTERNATE_FUNCTIONS(17, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(18, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(19, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(20, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(21, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO21, bit 4 reserved */ + ALTERNATE_FUNCTIONS(22, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO22, bit 5 reserved */ + ALTERNATE_FUNCTIONS(23, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO23, bit 6 reserved */ + ALTERNATE_FUNCTIONS(24, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO24, bit 7 reserved */ + + ALTERNATE_FUNCTIONS(25, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO25, bit 0 reserved */ + ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26, bit 1 reserved */ + ALTERNATE_FUNCTIONS(27, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO27, bit 2 reserved */ + ALTERNATE_FUNCTIONS(28, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO28, bit 3 reserved */ + ALTERNATE_FUNCTIONS(29, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO29, bit 4 reserved */ + ALTERNATE_FUNCTIONS(30, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO30, bit 5 reserved */ + ALTERNATE_FUNCTIONS(31, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO31, bit 6 reserved */ + ALTERNATE_FUNCTIONS(32, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO32, bit 7 reserved */ + + ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33, bit 0 reserved */ + ALTERNATE_FUNCTIONS(34, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */ + ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35, bit 2 reserved */ + ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36, bit 2 reserved */ + ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37, bit 2 reserved */ + ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38, bit 2 reserved */ + ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39, bit 2 reserved */ + ALTERNATE_FUNCTIONS(40, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7*/ + + ALTERNATE_FUNCTIONS(41, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */ + ALTERNATE_FUNCTIONS(42, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO42, bit 1 reserved */ + ALTERNATE_FUNCTIONS(43, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO43, bit 2 reserved */ + ALTERNATE_FUNCTIONS(44, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO44, bit 3 reserved */ + ALTERNATE_FUNCTIONS(45, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO45, bit 4 reserved */ + ALTERNATE_FUNCTIONS(46, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO46, bit 5 reserved */ + ALTERNATE_FUNCTIONS(47, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO47, bit 6 reserved */ + ALTERNATE_FUNCTIONS(48, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO48, bit 7 reserved */ + + ALTERNATE_FUNCTIONS(49, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49, bit 0 reserved */ + ALTERNATE_FUNCTIONS(50, 1, 2, UNUSED, 1, 0, 0), /* GPIO50, altA controlled by bit 1 */ + ALTERNATE_FUNCTIONS(51, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49, bit 0 reserved */ + ALTERNATE_FUNCTIONS(52, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */ + ALTERNATE_FUNCTIONS(53, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */ +}; + +/* + * For AB8505 Only some GPIOs are interrupt capable, and they are + * organized in discontiguous clusters: + * + * GPIO10 to GPIO11 + * GPIO13 + * GPIO40 and GPIO41 + * GPIO50 + * GPIO52 to GPIO53 + */ +static struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = { + GPIO_IRQ_CLUSTER(10, 11, AB8500_INT_GPIO10R), + GPIO_IRQ_CLUSTER(13, 13, AB8500_INT_GPIO13R), + GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R), + GPIO_IRQ_CLUSTER(50, 50, AB9540_INT_GPIO50R), + GPIO_IRQ_CLUSTER(52, 53, AB9540_INT_GPIO52R), +}; + +static struct abx500_pinctrl_soc_data ab8505_soc = { + .gpio_ranges = ab8505_pinranges, + .gpio_num_ranges = ARRAY_SIZE(ab8505_pinranges), + .pins = ab8505_pins, + .npins = ARRAY_SIZE(ab8505_pins), + .functions = ab8505_functions, + .nfunctions = ARRAY_SIZE(ab8505_functions), + .groups = ab8505_groups, + .ngroups = ARRAY_SIZE(ab8505_groups), + .alternate_functions = ab8505_alternate_functions, + .gpio_irq_cluster = ab8505_gpio_irq_cluster, + .ngpio_irq_cluster = ARRAY_SIZE(ab8505_gpio_irq_cluster), + .irq_gpio_rising_offset = AB8500_INT_GPIO6R, + .irq_gpio_falling_offset = AB8500_INT_GPIO6F, + .irq_gpio_factor = 1, +}; + +void +abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc) +{ + *soc = &ab8505_soc; +} diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c new file mode 100644 index 000000000..e3689cc62 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -0,0 +1,1104 @@ +/* + * Copyright (C) ST-Ericsson SA 2013 + * + * Author: Patrice Chotard <patrice.chotard@st.com> + * License terms: GNU General Public License (GPL) version 2 + * + * Driver allows to use AxB5xx unused pins to be used as GPIO + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> +#include <linux/bitops.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/machine.h> + +#include "pinctrl-abx500.h" +#include "../core.h" +#include "../pinconf.h" +#include "../pinctrl-utils.h" + +/* + * GPIO registers offset + * Bank: 0x10 + */ +#define AB8500_GPIO_SEL1_REG 0x00 +#define AB8500_GPIO_SEL2_REG 0x01 +#define AB8500_GPIO_SEL3_REG 0x02 +#define AB8500_GPIO_SEL4_REG 0x03 +#define AB8500_GPIO_SEL5_REG 0x04 +#define AB8500_GPIO_SEL6_REG 0x05 + +#define AB8500_GPIO_DIR1_REG 0x10 +#define AB8500_GPIO_DIR2_REG 0x11 +#define AB8500_GPIO_DIR3_REG 0x12 +#define AB8500_GPIO_DIR4_REG 0x13 +#define AB8500_GPIO_DIR5_REG 0x14 +#define AB8500_GPIO_DIR6_REG 0x15 + +#define AB8500_GPIO_OUT1_REG 0x20 +#define AB8500_GPIO_OUT2_REG 0x21 +#define AB8500_GPIO_OUT3_REG 0x22 +#define AB8500_GPIO_OUT4_REG 0x23 +#define AB8500_GPIO_OUT5_REG 0x24 +#define AB8500_GPIO_OUT6_REG 0x25 + +#define AB8500_GPIO_PUD1_REG 0x30 +#define AB8500_GPIO_PUD2_REG 0x31 +#define AB8500_GPIO_PUD3_REG 0x32 +#define AB8500_GPIO_PUD4_REG 0x33 +#define AB8500_GPIO_PUD5_REG 0x34 +#define AB8500_GPIO_PUD6_REG 0x35 + +#define AB8500_GPIO_IN1_REG 0x40 +#define AB8500_GPIO_IN2_REG 0x41 +#define AB8500_GPIO_IN3_REG 0x42 +#define AB8500_GPIO_IN4_REG 0x43 +#define AB8500_GPIO_IN5_REG 0x44 +#define AB8500_GPIO_IN6_REG 0x45 +#define AB8500_GPIO_ALTFUN_REG 0x50 + +#define ABX500_GPIO_INPUT 0 +#define ABX500_GPIO_OUTPUT 1 + +struct abx500_pinctrl { + struct device *dev; + struct pinctrl_dev *pctldev; + struct abx500_pinctrl_soc_data *soc; + struct gpio_chip chip; + struct ab8500 *parent; + struct abx500_gpio_irq_cluster *irq_cluster; + int irq_cluster_size; +}; + +static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg, + unsigned offset, bool *bit) +{ + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + u8 pos = offset % 8; + u8 val; + int ret; + + reg += offset / 8; + ret = abx500_get_register_interruptible(pct->dev, + AB8500_MISC, reg, &val); + if (ret < 0) { + dev_err(pct->dev, + "%s read reg =%x, offset=%x failed (%d)\n", + __func__, reg, offset, ret); + return ret; + } + + *bit = !!(val & BIT(pos)); + + return 0; +} + +static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg, + unsigned offset, int val) +{ + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + u8 pos = offset % 8; + int ret; + + reg += offset / 8; + ret = abx500_mask_and_set_register_interruptible(pct->dev, + AB8500_MISC, reg, BIT(pos), val << pos); + if (ret < 0) + dev_err(pct->dev, "%s write reg, %x offset %x failed (%d)\n", + __func__, reg, offset, ret); + + return ret; +} + +/** + * abx500_gpio_get() - Get the particular GPIO value + * @chip: Gpio device + * @offset: GPIO number to read + */ +static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + bool bit; + bool is_out; + u8 gpio_offset = offset - 1; + int ret; + + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, + gpio_offset, &is_out); + if (ret < 0) + goto out; + + if (is_out) + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_OUT1_REG, + gpio_offset, &bit); + else + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG, + gpio_offset, &bit); +out: + if (ret < 0) { + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + return ret; + } + + return bit; +} + +static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + int ret; + + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); + if (ret < 0) + dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret); +} + +static int abx500_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, + int val) +{ + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + int ret; + + /* set direction as output */ + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_DIR1_REG, + offset, + ABX500_GPIO_OUTPUT); + if (ret < 0) + goto out; + + /* disable pull down */ + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_PUD1_REG, + offset, + ABX500_GPIO_PULL_NONE); + +out: + if (ret < 0) { + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + return ret; + } + + /* set the output as 1 or 0 */ + return abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); +} + +static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + /* set the register as input */ + return abx500_gpio_set_bits(chip, + AB8500_GPIO_DIR1_REG, + offset, + ABX500_GPIO_INPUT); +} + +static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + /* The AB8500 GPIO numbers are off by one */ + int gpio = offset + 1; + int hwirq; + int i; + + for (i = 0; i < pct->irq_cluster_size; i++) { + struct abx500_gpio_irq_cluster *cluster = + &pct->irq_cluster[i]; + + if (gpio >= cluster->start && gpio <= cluster->end) { + /* + * The ABx500 GPIO's associated IRQs are clustered together + * throughout the interrupt numbers at irregular intervals. + * To solve this quandry, we have placed the read-in values + * into the cluster information table. + */ + hwirq = gpio - cluster->start + cluster->to_irq; + return irq_create_mapping(pct->parent->domain, hwirq); + } + } + + return -EINVAL; +} + +static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, + unsigned gpio, int alt_setting) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + struct alternate_functions af = pct->soc->alternate_functions[gpio]; + int ret; + int val; + unsigned offset; + + const char *modes[] = { + [ABX500_DEFAULT] = "default", + [ABX500_ALT_A] = "altA", + [ABX500_ALT_B] = "altB", + [ABX500_ALT_C] = "altC", + }; + + /* sanity check */ + if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) || + ((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) || + ((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) { + dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio, + modes[alt_setting]); + return -EINVAL; + } + + /* on ABx5xx, there is no GPIO0, so adjust the offset */ + offset = gpio - 1; + + switch (alt_setting) { + case ABX500_DEFAULT: + /* + * for ABx5xx family, default mode is always selected by + * writing 0 to GPIOSELx register, except for pins which + * support at least ALT_B mode, default mode is selected + * by writing 1 to GPIOSELx register + */ + val = 0; + if (af.alt_bit1 != UNUSED) + val++; + + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, + offset, val); + break; + + case ABX500_ALT_A: + /* + * for ABx5xx family, alt_a mode is always selected by + * writing 1 to GPIOSELx register, except for pins which + * support at least ALT_B mode, alt_a mode is selected + * by writing 0 to GPIOSELx register and 0 in ALTFUNC + * register + */ + if (af.alt_bit1 != UNUSED) { + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, + offset, 0); + if (ret < 0) + goto out; + + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_ALTFUN_REG, + af.alt_bit1, + !!(af.alta_val & BIT(0))); + if (ret < 0) + goto out; + + if (af.alt_bit2 != UNUSED) + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_ALTFUN_REG, + af.alt_bit2, + !!(af.alta_val & BIT(1))); + } else + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, + offset, 1); + break; + + case ABX500_ALT_B: + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, + offset, 0); + if (ret < 0) + goto out; + + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, + af.alt_bit1, !!(af.altb_val & BIT(0))); + if (ret < 0) + goto out; + + if (af.alt_bit2 != UNUSED) + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_ALTFUN_REG, + af.alt_bit2, + !!(af.altb_val & BIT(1))); + break; + + case ABX500_ALT_C: + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, + offset, 0); + if (ret < 0) + goto out; + + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, + af.alt_bit2, !!(af.altc_val & BIT(0))); + if (ret < 0) + goto out; + + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, + af.alt_bit2, !!(af.altc_val & BIT(1))); + break; + + default: + dev_dbg(pct->dev, "unknown alt_setting %d\n", alt_setting); + + return -EINVAL; + } +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + + return ret; +} + +#ifdef CONFIG_DEBUG_FS +static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, + unsigned gpio) +{ + u8 mode; + bool bit_mode; + bool alt_bit1; + bool alt_bit2; + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + struct alternate_functions af = pct->soc->alternate_functions[gpio]; + /* on ABx5xx, there is no GPIO0, so adjust the offset */ + unsigned offset = gpio - 1; + int ret; + + /* + * if gpiosel_bit is set to unused, + * it means no GPIO or special case + */ + if (af.gpiosel_bit == UNUSED) + return ABX500_DEFAULT; + + /* read GpioSelx register */ + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8), + af.gpiosel_bit, &bit_mode); + if (ret < 0) + goto out; + + mode = bit_mode; + + /* sanity check */ + if ((af.alt_bit1 < UNUSED) || (af.alt_bit1 > 7) || + (af.alt_bit2 < UNUSED) || (af.alt_bit2 > 7)) { + dev_err(pct->dev, + "alt_bitX value not in correct range (-1 to 7)\n"); + return -EINVAL; + } + + /* if alt_bit2 is used, alt_bit1 must be used too */ + if ((af.alt_bit2 != UNUSED) && (af.alt_bit1 == UNUSED)) { + dev_err(pct->dev, + "if alt_bit2 is used, alt_bit1 can't be unused\n"); + return -EINVAL; + } + + /* check if pin use AlternateFunction register */ + if ((af.alt_bit1 == UNUSED) && (af.alt_bit2 == UNUSED)) + return mode; + /* + * if pin GPIOSEL bit is set and pin supports alternate function, + * it means DEFAULT mode + */ + if (mode) + return ABX500_DEFAULT; + + /* + * pin use the AlternatFunction register + * read alt_bit1 value + */ + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, + af.alt_bit1, &alt_bit1); + if (ret < 0) + goto out; + + if (af.alt_bit2 != UNUSED) { + /* read alt_bit2 value */ + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, + af.alt_bit2, + &alt_bit2); + if (ret < 0) + goto out; + } else + alt_bit2 = 0; + + mode = (alt_bit2 << 1) + alt_bit1; + if (mode == af.alta_val) + return ABX500_ALT_A; + else if (mode == af.altb_val) + return ABX500_ALT_B; + else + return ABX500_ALT_C; + +out: + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + return ret; +} + +#include <linux/seq_file.h> + +static void abx500_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, unsigned gpio) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + const char *label = gpiochip_is_requested(chip, offset - 1); + u8 gpio_offset = offset - 1; + int mode = -1; + bool is_out; + bool pd; + int ret; + + const char *modes[] = { + [ABX500_DEFAULT] = "default", + [ABX500_ALT_A] = "altA", + [ABX500_ALT_B] = "altB", + [ABX500_ALT_C] = "altC", + }; + + const char *pull_up_down[] = { + [ABX500_GPIO_PULL_DOWN] = "pull down", + [ABX500_GPIO_PULL_NONE] = "pull none", + [ABX500_GPIO_PULL_NONE + 1] = "pull none", + [ABX500_GPIO_PULL_UP] = "pull up", + }; + + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, + gpio_offset, &is_out); + if (ret < 0) + goto out; + + seq_printf(s, " gpio-%-3d (%-20.20s) %-3s", + gpio, label ?: "(none)", + is_out ? "out" : "in "); + + if (!is_out) { + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, + gpio_offset, &pd); + if (ret < 0) + goto out; + + seq_printf(s, " %-9s", pull_up_down[pd]); + } else + seq_printf(s, " %-9s", chip->get(chip, offset) ? "hi" : "lo"); + + mode = abx500_get_mode(pctldev, chip, offset); + + seq_printf(s, " %s", (mode < 0) ? "unknown" : modes[mode]); + +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); +} + +static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned i; + unsigned gpio = chip->base; + struct abx500_pinctrl *pct = gpiochip_get_data(chip); + struct pinctrl_dev *pctldev = pct->pctldev; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + /* On AB8500, there is no GPIO0, the first is the GPIO 1 */ + abx500_gpio_dbg_show_one(s, pctldev, chip, i + 1, gpio); + seq_putc(s, '\n'); + } +} + +#else +static inline void abx500_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, unsigned gpio) +{ +} +#define abx500_gpio_dbg_show NULL +#endif + +static const struct gpio_chip abx500gpio_chip = { + .label = "abx500-gpio", + .owner = THIS_MODULE, + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .direction_input = abx500_gpio_direction_input, + .get = abx500_gpio_get, + .direction_output = abx500_gpio_direction_output, + .set = abx500_gpio_set, + .to_irq = abx500_gpio_to_irq, + .dbg_show = abx500_gpio_dbg_show, +}; + +static int abx500_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + + return pct->soc->nfunctions; +} + +static const char *abx500_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + + return pct->soc->functions[function].name; +} + +static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + + *groups = pct->soc->functions[function].groups; + *num_groups = pct->soc->functions[function].ngroups; + + return 0; +} + +static int abx500_pmx_set(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip = &pct->chip; + const struct abx500_pingroup *g; + int i; + int ret = 0; + + g = &pct->soc->groups[group]; + if (g->altsetting < 0) + return -EINVAL; + + dev_dbg(pct->dev, "enable group %s, %u pins\n", g->name, g->npins); + + for (i = 0; i < g->npins; i++) { + dev_dbg(pct->dev, "setting pin %d to altsetting %d\n", + g->pins[i], g->altsetting); + + ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting); + } + + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + + return ret; +} + +static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + const struct abx500_pinrange *p; + int ret; + int i; + + /* + * Different ranges have different ways to enable GPIO function on a + * pin, so refer back to our local range type, where we handily define + * what altfunc enables GPIO for a certain pin. + */ + for (i = 0; i < pct->soc->gpio_num_ranges; i++) { + p = &pct->soc->gpio_ranges[i]; + if ((offset >= p->offset) && + (offset < (p->offset + p->npins))) + break; + } + + if (i == pct->soc->gpio_num_ranges) { + dev_err(pct->dev, "%s failed to locate range\n", __func__); + return -ENODEV; + } + + dev_dbg(pct->dev, "enable GPIO by altfunc %d at gpio %d\n", + p->altfunc, offset); + + ret = abx500_set_mode(pct->pctldev, &pct->chip, + offset, p->altfunc); + if (ret < 0) + dev_err(pct->dev, "%s setting altfunc failed\n", __func__); + + return ret; +} + +static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ +} + +static const struct pinmux_ops abx500_pinmux_ops = { + .get_functions_count = abx500_pmx_get_funcs_cnt, + .get_function_name = abx500_pmx_get_func_name, + .get_function_groups = abx500_pmx_get_func_groups, + .set_mux = abx500_pmx_set, + .gpio_request_enable = abx500_gpio_request_enable, + .gpio_disable_free = abx500_gpio_disable_free, +}; + +static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + + return pct->soc->ngroups; +} + +static const char *abx500_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + + return pct->soc->groups[selector].name; +} + +static int abx500_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + + *pins = pct->soc->groups[selector].pins; + *num_pins = pct->soc->groups[selector].npins; + + return 0; +} + +static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip = &pct->chip; + + abx500_gpio_dbg_show_one(s, pctldev, chip, offset, + chip->base + offset - 1); +} + +static int abx500_dt_add_map_mux(struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function) +{ + if (*num_maps == *reserved_maps) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +static int abx500_dt_add_map_configs(struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps, const char *group, + unsigned long *configs, unsigned num_configs) +{ + unsigned long *dup_configs; + + if (*num_maps == *reserved_maps) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) + return -ENOMEM; + + (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN; + + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +static const char *abx500_find_pin_name(struct pinctrl_dev *pctldev, + const char *pin_name) +{ + int i, pin_number; + struct abx500_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1) + for (i = 0; i < npct->soc->npins; i++) + if (npct->soc->pins[i].number == pin_number) + return npct->soc->pins[i].name; + return NULL; +} + +static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + int ret; + const char *function = NULL; + unsigned long *configs; + unsigned int nconfigs = 0; + struct property *prop; + + ret = of_property_read_string(np, "function", &function); + if (ret >= 0) { + const char *group; + + ret = of_property_count_strings(np, "groups"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "groups", prop, group) { + ret = abx500_dt_add_map_mux(map, reserved_maps, + num_maps, group, function); + if (ret < 0) + goto exit; + } + } + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &nconfigs); + if (nconfigs) { + const char *gpio_name; + const char *pin; + + ret = of_property_count_strings(np, "pins"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "pins", prop, pin) { + gpio_name = abx500_find_pin_name(pctldev, pin); + + ret = abx500_dt_add_map_configs(map, reserved_maps, + num_maps, gpio_name, configs, 1); + if (ret < 0) + goto exit; + } + } + +exit: + return ret; +} + +static int abx500_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + unsigned reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = abx500_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) { + pinctrl_utils_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; +} + +static const struct pinctrl_ops abx500_pinctrl_ops = { + .get_groups_count = abx500_get_groups_cnt, + .get_group_name = abx500_get_group_name, + .get_group_pins = abx500_get_group_pins, + .pin_dbg_show = abx500_pin_dbg_show, + .dt_node_to_map = abx500_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int abx500_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + return -ENOSYS; +} + +static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip = &pct->chip; + unsigned offset; + int ret = -EINVAL; + int i; + enum pin_config_param param; + enum pin_config_param argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + argument = pinconf_to_config_argument(configs[i]); + + dev_dbg(chip->parent, "pin %d [%#lx]: %s %s\n", + pin, configs[i], + (param == PIN_CONFIG_OUTPUT) ? "output " : "input", + (param == PIN_CONFIG_OUTPUT) ? + (argument ? "high" : "low") : + (argument ? "pull up" : "pull down")); + + /* on ABx500, there is no GPIO0, so adjust the offset */ + offset = pin - 1; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + ret = abx500_gpio_direction_input(chip, offset); + if (ret < 0) + goto out; + + /* Chip only supports pull down */ + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_PUD1_REG, offset, + ABX500_GPIO_PULL_NONE); + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = abx500_gpio_direction_input(chip, offset); + if (ret < 0) + goto out; + /* + * if argument = 1 set the pull down + * else clear the pull down + * Chip only supports pull down + */ + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_PUD1_REG, + offset, + argument ? ABX500_GPIO_PULL_DOWN : + ABX500_GPIO_PULL_NONE); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + ret = abx500_gpio_direction_input(chip, offset); + if (ret < 0) + goto out; + /* + * if argument = 1 set the pull up + * else clear the pull up + */ + ret = abx500_gpio_direction_input(chip, offset); + break; + + case PIN_CONFIG_OUTPUT: + ret = abx500_gpio_direction_output(chip, offset, + argument); + break; + + default: + dev_err(chip->parent, + "illegal configuration requested\n"); + } + } /* for each config */ +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + + return ret; +} + +static const struct pinconf_ops abx500_pinconf_ops = { + .pin_config_get = abx500_pin_config_get, + .pin_config_set = abx500_pin_config_set, + .is_generic = true, +}; + +static struct pinctrl_desc abx500_pinctrl_desc = { + .name = "pinctrl-abx500", + .pctlops = &abx500_pinctrl_ops, + .pmxops = &abx500_pinmux_ops, + .confops = &abx500_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int abx500_get_gpio_num(struct abx500_pinctrl_soc_data *soc) +{ + unsigned int lowest = 0; + unsigned int highest = 0; + unsigned int npins = 0; + int i; + + /* + * Compute number of GPIOs from the last SoC gpio range descriptors + * These ranges may include "holes" but the GPIO number space shall + * still be homogeneous, so we need to detect and account for any + * such holes so that these are included in the number of GPIO pins. + */ + for (i = 0; i < soc->gpio_num_ranges; i++) { + unsigned gstart; + unsigned gend; + const struct abx500_pinrange *p; + + p = &soc->gpio_ranges[i]; + gstart = p->offset; + gend = p->offset + p->npins - 1; + + if (i == 0) { + /* First iteration, set start values */ + lowest = gstart; + highest = gend; + } else { + if (gstart < lowest) + lowest = gstart; + if (gend > highest) + highest = gend; + } + } + /* this gives the absolute number of pins */ + npins = highest - lowest + 1; + return npins; +} + +static const struct of_device_id abx500_gpio_match[] = { + { .compatible = "stericsson,ab8500-gpio", .data = (void *)PINCTRL_AB8500, }, + { .compatible = "stericsson,ab8505-gpio", .data = (void *)PINCTRL_AB8505, }, + { } +}; + +static int abx500_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + struct abx500_pinctrl *pct; + unsigned int id = -1; + int ret; + int i; + + if (!np) { + dev_err(&pdev->dev, "gpio dt node missing\n"); + return -ENODEV; + } + + pct = devm_kzalloc(&pdev->dev, sizeof(*pct), GFP_KERNEL); + if (!pct) + return -ENOMEM; + + pct->dev = &pdev->dev; + pct->parent = dev_get_drvdata(pdev->dev.parent); + pct->chip = abx500gpio_chip; + pct->chip.parent = &pdev->dev; + pct->chip.base = -1; /* Dynamic allocation */ + + match = of_match_device(abx500_gpio_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "gpio dt not matching\n"); + return -ENODEV; + } + id = (unsigned long)match->data; + + /* Poke in other ASIC variants here */ + switch (id) { + case PINCTRL_AB8500: + abx500_pinctrl_ab8500_init(&pct->soc); + break; + case PINCTRL_AB8505: + abx500_pinctrl_ab8505_init(&pct->soc); + break; + default: + dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n", id); + return -EINVAL; + } + + if (!pct->soc) { + dev_err(&pdev->dev, "Invalid SOC data\n"); + return -EINVAL; + } + + pct->chip.ngpio = abx500_get_gpio_num(pct->soc); + pct->irq_cluster = pct->soc->gpio_irq_cluster; + pct->irq_cluster_size = pct->soc->ngpio_irq_cluster; + + ret = gpiochip_add_data(&pct->chip, pct); + if (ret) { + dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); + return ret; + } + dev_info(&pdev->dev, "added gpiochip\n"); + + abx500_pinctrl_desc.pins = pct->soc->pins; + abx500_pinctrl_desc.npins = pct->soc->npins; + pct->pctldev = devm_pinctrl_register(&pdev->dev, &abx500_pinctrl_desc, + pct); + if (IS_ERR(pct->pctldev)) { + dev_err(&pdev->dev, + "could not register abx500 pinctrl driver\n"); + ret = PTR_ERR(pct->pctldev); + goto out_rem_chip; + } + dev_info(&pdev->dev, "registered pin controller\n"); + + /* We will handle a range of GPIO pins */ + for (i = 0; i < pct->soc->gpio_num_ranges; i++) { + const struct abx500_pinrange *p = &pct->soc->gpio_ranges[i]; + + ret = gpiochip_add_pin_range(&pct->chip, + dev_name(&pdev->dev), + p->offset - 1, p->offset, p->npins); + if (ret < 0) + goto out_rem_chip; + } + + platform_set_drvdata(pdev, pct); + dev_info(&pdev->dev, "initialized abx500 pinctrl driver\n"); + + return 0; + +out_rem_chip: + gpiochip_remove(&pct->chip); + return ret; +} + +/** + * abx500_gpio_remove() - remove Ab8500-gpio driver + * @pdev: Platform device registered + */ +static int abx500_gpio_remove(struct platform_device *pdev) +{ + struct abx500_pinctrl *pct = platform_get_drvdata(pdev); + + gpiochip_remove(&pct->chip); + return 0; +} + +static struct platform_driver abx500_gpio_driver = { + .driver = { + .name = "abx500-gpio", + .of_match_table = abx500_gpio_match, + }, + .probe = abx500_gpio_probe, + .remove = abx500_gpio_remove, +}; + +static int __init abx500_gpio_init(void) +{ + return platform_driver_register(&abx500_gpio_driver); +} +core_initcall(abx500_gpio_init); diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.h b/drivers/pinctrl/nomadik/pinctrl-abx500.h new file mode 100644 index 000000000..90bb12fe8 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef PINCTRL_PINCTRL_ABx500_H +#define PINCTRL_PINCTRL_ABx500_H + +/* Package definitions */ +#define PINCTRL_AB8500 0 +#define PINCTRL_AB8505 1 + +/* pins alternate function */ +enum abx500_pin_func { + ABX500_DEFAULT, + ABX500_ALT_A, + ABX500_ALT_B, + ABX500_ALT_C, +}; + +enum abx500_gpio_pull_updown { + ABX500_GPIO_PULL_DOWN = 0x0, + ABX500_GPIO_PULL_NONE = 0x1, + ABX500_GPIO_PULL_UP = 0x3, +}; + +enum abx500_gpio_vinsel { + ABX500_GPIO_VINSEL_VBAT = 0x0, + ABX500_GPIO_VINSEL_VIN_1V8 = 0x1, + ABX500_GPIO_VINSEL_VDD_BIF = 0x2, +}; + +/** + * struct abx500_function - ABx500 pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct abx500_function { + const char *name; + const char * const *groups; + unsigned ngroups; +}; + +/** + * struct abx500_pingroup - describes a ABx500 pin group + * @name: the name of this specific pin group + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @num_pins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + * @altsetting: the altsetting to apply to all pins in this group to + * configure them to be used by a function + */ +struct abx500_pingroup { + const char *name; + const unsigned int *pins; + const unsigned npins; + int altsetting; +}; + +#define ALTERNATE_FUNCTIONS(pin, sel_bit, alt1, alt2, alta, altb, altc) \ +{ \ + .pin_number = pin, \ + .gpiosel_bit = sel_bit, \ + .alt_bit1 = alt1, \ + .alt_bit2 = alt2, \ + .alta_val = alta, \ + .altb_val = altb, \ + .altc_val = altc, \ +} + +#define UNUSED -1 +/** + * struct alternate_functions + * @pin_number: The pin number + * @gpiosel_bit: Control bit in GPIOSEL register, + * @alt_bit1: First AlternateFunction bit used to select the + * alternate function + * @alt_bit2: Second AlternateFunction bit used to select the + * alternate function + * + * these 3 following fields are necessary due to none + * coherency on how to select the altA, altB and altC + * function between the ABx500 SOC family when using + * alternatfunc register. + * @alta_val: value to write in alternatfunc to select altA function + * @altb_val: value to write in alternatfunc to select altB function + * @altc_val: value to write in alternatfunc to select altC function + */ +struct alternate_functions { + unsigned pin_number; + s8 gpiosel_bit; + s8 alt_bit1; + s8 alt_bit2; + u8 alta_val; + u8 altb_val; + u8 altc_val; +}; + +#define GPIO_IRQ_CLUSTER(a, b, c) \ +{ \ + .start = a, \ + .end = b, \ + .to_irq = c, \ +} + +/** + * struct abx500_gpio_irq_cluster - indicates GPIOs which are interrupt + * capable + * @start: The pin number of the first pin interrupt capable + * @end: The pin number of the last pin interrupt capable + * @to_irq: The ABx500 GPIO's associated IRQs are clustered + * together throughout the interrupt numbers at irregular + * intervals. To solve this quandary, we will place the + * read-in values into the cluster information table + */ + +struct abx500_gpio_irq_cluster { + int start; + int end; + int to_irq; +}; + +/** + * struct abx500_pinrange - map pin numbers to GPIO offsets + * @offset: offset into the GPIO local numberspace, incidentally + * identical to the offset into the local pin numberspace + * @npins: number of pins to map from both offsets + * @altfunc: altfunc setting to be used to enable GPIO on a pin in + * this range (may vary) + */ +struct abx500_pinrange { + unsigned int offset; + unsigned int npins; + int altfunc; +}; + +#define ABX500_PINRANGE(a, b, c) { .offset = a, .npins = b, .altfunc = c } + +/** + * struct abx500_pinctrl_soc_data - ABx500 pin controller per-SoC configuration + * @gpio_ranges: An array of GPIO ranges for this SoC + * @gpio_num_ranges: The number of GPIO ranges for this SoC + * @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: The functions supported on this SoC. + * @nfunction: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + * @alternate_functions: array describing pins which supports alternate and + * how to set it. + * @gpio_irq_cluster: An array of GPIO interrupt capable for this SoC + * @ngpio_irq_cluster: The number of GPIO inetrrupt capable for this SoC + * @irq_gpio_rising_offset: Interrupt offset used as base to compute specific + * setting strategy of the rising interrupt line + * @irq_gpio_falling_offset: Interrupt offset used as base to compute specific + * setting strategy of the falling interrupt line + * @irq_gpio_factor: Factor used to compute specific setting strategy of + * the interrupt line + */ + +struct abx500_pinctrl_soc_data { + const struct abx500_pinrange *gpio_ranges; + unsigned gpio_num_ranges; + const struct pinctrl_pin_desc *pins; + unsigned npins; + const struct abx500_function *functions; + unsigned nfunctions; + const struct abx500_pingroup *groups; + unsigned ngroups; + struct alternate_functions *alternate_functions; + struct abx500_gpio_irq_cluster *gpio_irq_cluster; + unsigned ngpio_irq_cluster; + int irq_gpio_rising_offset; + int irq_gpio_falling_offset; + int irq_gpio_factor; +}; + +#ifdef CONFIG_PINCTRL_AB8500 + +void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc); + +#else + +static inline void +abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc) +{ +} + +#endif + +#ifdef CONFIG_PINCTRL_AB8505 + +void abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc); + +#else + +static inline void +abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc) +{ +} + +#endif + +#endif /* PINCTRL_PINCTRL_ABx500_H */ diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c new file mode 100644 index 000000000..726c0b550 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c @@ -0,0 +1,1248 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/pinctrl/pinctrl.h> +#include "pinctrl-nomadik.h" + +/* All the pins that can be used for GPIO and some other functions */ +#define _GPIO(offset) (offset) + +#define DB8500_PIN_AJ5 _GPIO(0) +#define DB8500_PIN_AJ3 _GPIO(1) +#define DB8500_PIN_AH4 _GPIO(2) +#define DB8500_PIN_AH3 _GPIO(3) +#define DB8500_PIN_AH6 _GPIO(4) +#define DB8500_PIN_AG6 _GPIO(5) +#define DB8500_PIN_AF6 _GPIO(6) +#define DB8500_PIN_AG5 _GPIO(7) +#define DB8500_PIN_AD5 _GPIO(8) +#define DB8500_PIN_AE4 _GPIO(9) +#define DB8500_PIN_AF5 _GPIO(10) +#define DB8500_PIN_AG4 _GPIO(11) +#define DB8500_PIN_AC4 _GPIO(12) +#define DB8500_PIN_AF3 _GPIO(13) +#define DB8500_PIN_AE3 _GPIO(14) +#define DB8500_PIN_AC3 _GPIO(15) +#define DB8500_PIN_AD3 _GPIO(16) +#define DB8500_PIN_AD4 _GPIO(17) +#define DB8500_PIN_AC2 _GPIO(18) +#define DB8500_PIN_AC1 _GPIO(19) +#define DB8500_PIN_AB4 _GPIO(20) +#define DB8500_PIN_AB3 _GPIO(21) +#define DB8500_PIN_AA3 _GPIO(22) +#define DB8500_PIN_AA4 _GPIO(23) +#define DB8500_PIN_AB2 _GPIO(24) +#define DB8500_PIN_Y4 _GPIO(25) +#define DB8500_PIN_Y2 _GPIO(26) +#define DB8500_PIN_AA2 _GPIO(27) +#define DB8500_PIN_AA1 _GPIO(28) +#define DB8500_PIN_W2 _GPIO(29) +#define DB8500_PIN_W3 _GPIO(30) +#define DB8500_PIN_V3 _GPIO(31) +#define DB8500_PIN_V2 _GPIO(32) +#define DB8500_PIN_AF2 _GPIO(33) +#define DB8500_PIN_AE1 _GPIO(34) +#define DB8500_PIN_AE2 _GPIO(35) +#define DB8500_PIN_AG2 _GPIO(36) +/* Hole */ +#define DB8500_PIN_F3 _GPIO(64) +#define DB8500_PIN_F1 _GPIO(65) +#define DB8500_PIN_G3 _GPIO(66) +#define DB8500_PIN_G2 _GPIO(67) +#define DB8500_PIN_E1 _GPIO(68) +#define DB8500_PIN_E2 _GPIO(69) +#define DB8500_PIN_G5 _GPIO(70) +#define DB8500_PIN_G4 _GPIO(71) +#define DB8500_PIN_H4 _GPIO(72) +#define DB8500_PIN_H3 _GPIO(73) +#define DB8500_PIN_J3 _GPIO(74) +#define DB8500_PIN_H2 _GPIO(75) +#define DB8500_PIN_J2 _GPIO(76) +#define DB8500_PIN_H1 _GPIO(77) +#define DB8500_PIN_F4 _GPIO(78) +#define DB8500_PIN_E3 _GPIO(79) +#define DB8500_PIN_E4 _GPIO(80) +#define DB8500_PIN_D2 _GPIO(81) +#define DB8500_PIN_C1 _GPIO(82) +#define DB8500_PIN_D3 _GPIO(83) +#define DB8500_PIN_C2 _GPIO(84) +#define DB8500_PIN_D5 _GPIO(85) +#define DB8500_PIN_C6 _GPIO(86) +#define DB8500_PIN_B3 _GPIO(87) +#define DB8500_PIN_C4 _GPIO(88) +#define DB8500_PIN_E6 _GPIO(89) +#define DB8500_PIN_A3 _GPIO(90) +#define DB8500_PIN_B6 _GPIO(91) +#define DB8500_PIN_D6 _GPIO(92) +#define DB8500_PIN_B7 _GPIO(93) +#define DB8500_PIN_D7 _GPIO(94) +#define DB8500_PIN_E8 _GPIO(95) +#define DB8500_PIN_D8 _GPIO(96) +#define DB8500_PIN_D9 _GPIO(97) +/* Hole */ +#define DB8500_PIN_A5 _GPIO(128) +#define DB8500_PIN_B4 _GPIO(129) +#define DB8500_PIN_C8 _GPIO(130) +#define DB8500_PIN_A12 _GPIO(131) +#define DB8500_PIN_C10 _GPIO(132) +#define DB8500_PIN_B10 _GPIO(133) +#define DB8500_PIN_B9 _GPIO(134) +#define DB8500_PIN_A9 _GPIO(135) +#define DB8500_PIN_C7 _GPIO(136) +#define DB8500_PIN_A7 _GPIO(137) +#define DB8500_PIN_C5 _GPIO(138) +#define DB8500_PIN_C9 _GPIO(139) +#define DB8500_PIN_B11 _GPIO(140) +#define DB8500_PIN_C12 _GPIO(141) +#define DB8500_PIN_C11 _GPIO(142) +#define DB8500_PIN_D12 _GPIO(143) +#define DB8500_PIN_B13 _GPIO(144) +#define DB8500_PIN_C13 _GPIO(145) +#define DB8500_PIN_D13 _GPIO(146) +#define DB8500_PIN_C15 _GPIO(147) +#define DB8500_PIN_B16 _GPIO(148) +#define DB8500_PIN_B14 _GPIO(149) +#define DB8500_PIN_C14 _GPIO(150) +#define DB8500_PIN_D17 _GPIO(151) +#define DB8500_PIN_D16 _GPIO(152) +#define DB8500_PIN_B17 _GPIO(153) +#define DB8500_PIN_C16 _GPIO(154) +#define DB8500_PIN_C19 _GPIO(155) +#define DB8500_PIN_C17 _GPIO(156) +#define DB8500_PIN_A18 _GPIO(157) +#define DB8500_PIN_C18 _GPIO(158) +#define DB8500_PIN_B19 _GPIO(159) +#define DB8500_PIN_B20 _GPIO(160) +#define DB8500_PIN_D21 _GPIO(161) +#define DB8500_PIN_D20 _GPIO(162) +#define DB8500_PIN_C20 _GPIO(163) +#define DB8500_PIN_B21 _GPIO(164) +#define DB8500_PIN_C21 _GPIO(165) +#define DB8500_PIN_A22 _GPIO(166) +#define DB8500_PIN_B24 _GPIO(167) +#define DB8500_PIN_C22 _GPIO(168) +#define DB8500_PIN_D22 _GPIO(169) +#define DB8500_PIN_C23 _GPIO(170) +#define DB8500_PIN_D23 _GPIO(171) +/* Hole */ +#define DB8500_PIN_AJ27 _GPIO(192) +#define DB8500_PIN_AH27 _GPIO(193) +#define DB8500_PIN_AF27 _GPIO(194) +#define DB8500_PIN_AG28 _GPIO(195) +#define DB8500_PIN_AG26 _GPIO(196) +#define DB8500_PIN_AH24 _GPIO(197) +#define DB8500_PIN_AG25 _GPIO(198) +#define DB8500_PIN_AH23 _GPIO(199) +#define DB8500_PIN_AH26 _GPIO(200) +#define DB8500_PIN_AF24 _GPIO(201) +#define DB8500_PIN_AF25 _GPIO(202) +#define DB8500_PIN_AE23 _GPIO(203) +#define DB8500_PIN_AF23 _GPIO(204) +#define DB8500_PIN_AG23 _GPIO(205) +#define DB8500_PIN_AG24 _GPIO(206) +#define DB8500_PIN_AJ23 _GPIO(207) +#define DB8500_PIN_AH16 _GPIO(208) +#define DB8500_PIN_AG15 _GPIO(209) +#define DB8500_PIN_AJ15 _GPIO(210) +#define DB8500_PIN_AG14 _GPIO(211) +#define DB8500_PIN_AF13 _GPIO(212) +#define DB8500_PIN_AG13 _GPIO(213) +#define DB8500_PIN_AH15 _GPIO(214) +#define DB8500_PIN_AH13 _GPIO(215) +#define DB8500_PIN_AG12 _GPIO(216) +#define DB8500_PIN_AH12 _GPIO(217) +#define DB8500_PIN_AH11 _GPIO(218) +#define DB8500_PIN_AG10 _GPIO(219) +#define DB8500_PIN_AH10 _GPIO(220) +#define DB8500_PIN_AJ11 _GPIO(221) +#define DB8500_PIN_AJ9 _GPIO(222) +#define DB8500_PIN_AH9 _GPIO(223) +#define DB8500_PIN_AG9 _GPIO(224) +#define DB8500_PIN_AG8 _GPIO(225) +#define DB8500_PIN_AF8 _GPIO(226) +#define DB8500_PIN_AH7 _GPIO(227) +#define DB8500_PIN_AJ6 _GPIO(228) +#define DB8500_PIN_AG7 _GPIO(229) +#define DB8500_PIN_AF7 _GPIO(230) +/* Hole */ +#define DB8500_PIN_AF28 _GPIO(256) +#define DB8500_PIN_AE29 _GPIO(257) +#define DB8500_PIN_AD29 _GPIO(258) +#define DB8500_PIN_AC29 _GPIO(259) +#define DB8500_PIN_AD28 _GPIO(260) +#define DB8500_PIN_AD26 _GPIO(261) +#define DB8500_PIN_AE26 _GPIO(262) +#define DB8500_PIN_AG29 _GPIO(263) +#define DB8500_PIN_AE27 _GPIO(264) +#define DB8500_PIN_AD27 _GPIO(265) +#define DB8500_PIN_AC28 _GPIO(266) +#define DB8500_PIN_AC27 _GPIO(267) + +/* + * The names of the pins are denoted by GPIO number and ball name, even + * though they can be used for other things than GPIO, this is the first + * column in the table of the data sheet and often used on schematics and + * such. + */ +static const struct pinctrl_pin_desc nmk_db8500_pins[] = { + PINCTRL_PIN(DB8500_PIN_AJ5, "GPIO0_AJ5"), + PINCTRL_PIN(DB8500_PIN_AJ3, "GPIO1_AJ3"), + PINCTRL_PIN(DB8500_PIN_AH4, "GPIO2_AH4"), + PINCTRL_PIN(DB8500_PIN_AH3, "GPIO3_AH3"), + PINCTRL_PIN(DB8500_PIN_AH6, "GPIO4_AH6"), + PINCTRL_PIN(DB8500_PIN_AG6, "GPIO5_AG6"), + PINCTRL_PIN(DB8500_PIN_AF6, "GPIO6_AF6"), + PINCTRL_PIN(DB8500_PIN_AG5, "GPIO7_AG5"), + PINCTRL_PIN(DB8500_PIN_AD5, "GPIO8_AD5"), + PINCTRL_PIN(DB8500_PIN_AE4, "GPIO9_AE4"), + PINCTRL_PIN(DB8500_PIN_AF5, "GPIO10_AF5"), + PINCTRL_PIN(DB8500_PIN_AG4, "GPIO11_AG4"), + PINCTRL_PIN(DB8500_PIN_AC4, "GPIO12_AC4"), + PINCTRL_PIN(DB8500_PIN_AF3, "GPIO13_AF3"), + PINCTRL_PIN(DB8500_PIN_AE3, "GPIO14_AE3"), + PINCTRL_PIN(DB8500_PIN_AC3, "GPIO15_AC3"), + PINCTRL_PIN(DB8500_PIN_AD3, "GPIO16_AD3"), + PINCTRL_PIN(DB8500_PIN_AD4, "GPIO17_AD4"), + PINCTRL_PIN(DB8500_PIN_AC2, "GPIO18_AC2"), + PINCTRL_PIN(DB8500_PIN_AC1, "GPIO19_AC1"), + PINCTRL_PIN(DB8500_PIN_AB4, "GPIO20_AB4"), + PINCTRL_PIN(DB8500_PIN_AB3, "GPIO21_AB3"), + PINCTRL_PIN(DB8500_PIN_AA3, "GPIO22_AA3"), + PINCTRL_PIN(DB8500_PIN_AA4, "GPIO23_AA4"), + PINCTRL_PIN(DB8500_PIN_AB2, "GPIO24_AB2"), + PINCTRL_PIN(DB8500_PIN_Y4, "GPIO25_Y4"), + PINCTRL_PIN(DB8500_PIN_Y2, "GPIO26_Y2"), + PINCTRL_PIN(DB8500_PIN_AA2, "GPIO27_AA2"), + PINCTRL_PIN(DB8500_PIN_AA1, "GPIO28_AA1"), + PINCTRL_PIN(DB8500_PIN_W2, "GPIO29_W2"), + PINCTRL_PIN(DB8500_PIN_W3, "GPIO30_W3"), + PINCTRL_PIN(DB8500_PIN_V3, "GPIO31_V3"), + PINCTRL_PIN(DB8500_PIN_V2, "GPIO32_V2"), + PINCTRL_PIN(DB8500_PIN_AF2, "GPIO33_AF2"), + PINCTRL_PIN(DB8500_PIN_AE1, "GPIO34_AE1"), + PINCTRL_PIN(DB8500_PIN_AE2, "GPIO35_AE2"), + PINCTRL_PIN(DB8500_PIN_AG2, "GPIO36_AG2"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_F3, "GPIO64_F3"), + PINCTRL_PIN(DB8500_PIN_F1, "GPIO65_F1"), + PINCTRL_PIN(DB8500_PIN_G3, "GPIO66_G3"), + PINCTRL_PIN(DB8500_PIN_G2, "GPIO67_G2"), + PINCTRL_PIN(DB8500_PIN_E1, "GPIO68_E1"), + PINCTRL_PIN(DB8500_PIN_E2, "GPIO69_E2"), + PINCTRL_PIN(DB8500_PIN_G5, "GPIO70_G5"), + PINCTRL_PIN(DB8500_PIN_G4, "GPIO71_G4"), + PINCTRL_PIN(DB8500_PIN_H4, "GPIO72_H4"), + PINCTRL_PIN(DB8500_PIN_H3, "GPIO73_H3"), + PINCTRL_PIN(DB8500_PIN_J3, "GPIO74_J3"), + PINCTRL_PIN(DB8500_PIN_H2, "GPIO75_H2"), + PINCTRL_PIN(DB8500_PIN_J2, "GPIO76_J2"), + PINCTRL_PIN(DB8500_PIN_H1, "GPIO77_H1"), + PINCTRL_PIN(DB8500_PIN_F4, "GPIO78_F4"), + PINCTRL_PIN(DB8500_PIN_E3, "GPIO79_E3"), + PINCTRL_PIN(DB8500_PIN_E4, "GPIO80_E4"), + PINCTRL_PIN(DB8500_PIN_D2, "GPIO81_D2"), + PINCTRL_PIN(DB8500_PIN_C1, "GPIO82_C1"), + PINCTRL_PIN(DB8500_PIN_D3, "GPIO83_D3"), + PINCTRL_PIN(DB8500_PIN_C2, "GPIO84_C2"), + PINCTRL_PIN(DB8500_PIN_D5, "GPIO85_D5"), + PINCTRL_PIN(DB8500_PIN_C6, "GPIO86_C6"), + PINCTRL_PIN(DB8500_PIN_B3, "GPIO87_B3"), + PINCTRL_PIN(DB8500_PIN_C4, "GPIO88_C4"), + PINCTRL_PIN(DB8500_PIN_E6, "GPIO89_E6"), + PINCTRL_PIN(DB8500_PIN_A3, "GPIO90_A3"), + PINCTRL_PIN(DB8500_PIN_B6, "GPIO91_B6"), + PINCTRL_PIN(DB8500_PIN_D6, "GPIO92_D6"), + PINCTRL_PIN(DB8500_PIN_B7, "GPIO93_B7"), + PINCTRL_PIN(DB8500_PIN_D7, "GPIO94_D7"), + PINCTRL_PIN(DB8500_PIN_E8, "GPIO95_E8"), + PINCTRL_PIN(DB8500_PIN_D8, "GPIO96_D8"), + PINCTRL_PIN(DB8500_PIN_D9, "GPIO97_D9"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_A5, "GPIO128_A5"), + PINCTRL_PIN(DB8500_PIN_B4, "GPIO129_B4"), + PINCTRL_PIN(DB8500_PIN_C8, "GPIO130_C8"), + PINCTRL_PIN(DB8500_PIN_A12, "GPIO131_A12"), + PINCTRL_PIN(DB8500_PIN_C10, "GPIO132_C10"), + PINCTRL_PIN(DB8500_PIN_B10, "GPIO133_B10"), + PINCTRL_PIN(DB8500_PIN_B9, "GPIO134_B9"), + PINCTRL_PIN(DB8500_PIN_A9, "GPIO135_A9"), + PINCTRL_PIN(DB8500_PIN_C7, "GPIO136_C7"), + PINCTRL_PIN(DB8500_PIN_A7, "GPIO137_A7"), + PINCTRL_PIN(DB8500_PIN_C5, "GPIO138_C5"), + PINCTRL_PIN(DB8500_PIN_C9, "GPIO139_C9"), + PINCTRL_PIN(DB8500_PIN_B11, "GPIO140_B11"), + PINCTRL_PIN(DB8500_PIN_C12, "GPIO141_C12"), + PINCTRL_PIN(DB8500_PIN_C11, "GPIO142_C11"), + PINCTRL_PIN(DB8500_PIN_D12, "GPIO143_D12"), + PINCTRL_PIN(DB8500_PIN_B13, "GPIO144_B13"), + PINCTRL_PIN(DB8500_PIN_C13, "GPIO145_C13"), + PINCTRL_PIN(DB8500_PIN_D13, "GPIO146_D13"), + PINCTRL_PIN(DB8500_PIN_C15, "GPIO147_C15"), + PINCTRL_PIN(DB8500_PIN_B16, "GPIO148_B16"), + PINCTRL_PIN(DB8500_PIN_B14, "GPIO149_B14"), + PINCTRL_PIN(DB8500_PIN_C14, "GPIO150_C14"), + PINCTRL_PIN(DB8500_PIN_D17, "GPIO151_D17"), + PINCTRL_PIN(DB8500_PIN_D16, "GPIO152_D16"), + PINCTRL_PIN(DB8500_PIN_B17, "GPIO153_B17"), + PINCTRL_PIN(DB8500_PIN_C16, "GPIO154_C16"), + PINCTRL_PIN(DB8500_PIN_C19, "GPIO155_C19"), + PINCTRL_PIN(DB8500_PIN_C17, "GPIO156_C17"), + PINCTRL_PIN(DB8500_PIN_A18, "GPIO157_A18"), + PINCTRL_PIN(DB8500_PIN_C18, "GPIO158_C18"), + PINCTRL_PIN(DB8500_PIN_B19, "GPIO159_B19"), + PINCTRL_PIN(DB8500_PIN_B20, "GPIO160_B20"), + PINCTRL_PIN(DB8500_PIN_D21, "GPIO161_D21"), + PINCTRL_PIN(DB8500_PIN_D20, "GPIO162_D20"), + PINCTRL_PIN(DB8500_PIN_C20, "GPIO163_C20"), + PINCTRL_PIN(DB8500_PIN_B21, "GPIO164_B21"), + PINCTRL_PIN(DB8500_PIN_C21, "GPIO165_C21"), + PINCTRL_PIN(DB8500_PIN_A22, "GPIO166_A22"), + PINCTRL_PIN(DB8500_PIN_B24, "GPIO167_B24"), + PINCTRL_PIN(DB8500_PIN_C22, "GPIO168_C22"), + PINCTRL_PIN(DB8500_PIN_D22, "GPIO169_D22"), + PINCTRL_PIN(DB8500_PIN_C23, "GPIO170_C23"), + PINCTRL_PIN(DB8500_PIN_D23, "GPIO171_D23"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_AJ27, "GPIO192_AJ27"), + PINCTRL_PIN(DB8500_PIN_AH27, "GPIO193_AH27"), + PINCTRL_PIN(DB8500_PIN_AF27, "GPIO194_AF27"), + PINCTRL_PIN(DB8500_PIN_AG28, "GPIO195_AG28"), + PINCTRL_PIN(DB8500_PIN_AG26, "GPIO196_AG26"), + PINCTRL_PIN(DB8500_PIN_AH24, "GPIO197_AH24"), + PINCTRL_PIN(DB8500_PIN_AG25, "GPIO198_AG25"), + PINCTRL_PIN(DB8500_PIN_AH23, "GPIO199_AH23"), + PINCTRL_PIN(DB8500_PIN_AH26, "GPIO200_AH26"), + PINCTRL_PIN(DB8500_PIN_AF24, "GPIO201_AF24"), + PINCTRL_PIN(DB8500_PIN_AF25, "GPIO202_AF25"), + PINCTRL_PIN(DB8500_PIN_AE23, "GPIO203_AE23"), + PINCTRL_PIN(DB8500_PIN_AF23, "GPIO204_AF23"), + PINCTRL_PIN(DB8500_PIN_AG23, "GPIO205_AG23"), + PINCTRL_PIN(DB8500_PIN_AG24, "GPIO206_AG24"), + PINCTRL_PIN(DB8500_PIN_AJ23, "GPIO207_AJ23"), + PINCTRL_PIN(DB8500_PIN_AH16, "GPIO208_AH16"), + PINCTRL_PIN(DB8500_PIN_AG15, "GPIO209_AG15"), + PINCTRL_PIN(DB8500_PIN_AJ15, "GPIO210_AJ15"), + PINCTRL_PIN(DB8500_PIN_AG14, "GPIO211_AG14"), + PINCTRL_PIN(DB8500_PIN_AF13, "GPIO212_AF13"), + PINCTRL_PIN(DB8500_PIN_AG13, "GPIO213_AG13"), + PINCTRL_PIN(DB8500_PIN_AH15, "GPIO214_AH15"), + PINCTRL_PIN(DB8500_PIN_AH13, "GPIO215_AH13"), + PINCTRL_PIN(DB8500_PIN_AG12, "GPIO216_AG12"), + PINCTRL_PIN(DB8500_PIN_AH12, "GPIO217_AH12"), + PINCTRL_PIN(DB8500_PIN_AH11, "GPIO218_AH11"), + PINCTRL_PIN(DB8500_PIN_AG10, "GPIO219_AG10"), + PINCTRL_PIN(DB8500_PIN_AH10, "GPIO220_AH10"), + PINCTRL_PIN(DB8500_PIN_AJ11, "GPIO221_AJ11"), + PINCTRL_PIN(DB8500_PIN_AJ9, "GPIO222_AJ9"), + PINCTRL_PIN(DB8500_PIN_AH9, "GPIO223_AH9"), + PINCTRL_PIN(DB8500_PIN_AG9, "GPIO224_AG9"), + PINCTRL_PIN(DB8500_PIN_AG8, "GPIO225_AG8"), + PINCTRL_PIN(DB8500_PIN_AF8, "GPIO226_AF8"), + PINCTRL_PIN(DB8500_PIN_AH7, "GPIO227_AH7"), + PINCTRL_PIN(DB8500_PIN_AJ6, "GPIO228_AJ6"), + PINCTRL_PIN(DB8500_PIN_AG7, "GPIO229_AG7"), + PINCTRL_PIN(DB8500_PIN_AF7, "GPIO230_AF7"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_AF28, "GPIO256_AF28"), + PINCTRL_PIN(DB8500_PIN_AE29, "GPIO257_AE29"), + PINCTRL_PIN(DB8500_PIN_AD29, "GPIO258_AD29"), + PINCTRL_PIN(DB8500_PIN_AC29, "GPIO259_AC29"), + PINCTRL_PIN(DB8500_PIN_AD28, "GPIO260_AD28"), + PINCTRL_PIN(DB8500_PIN_AD26, "GPIO261_AD26"), + PINCTRL_PIN(DB8500_PIN_AE26, "GPIO262_AE26"), + PINCTRL_PIN(DB8500_PIN_AG29, "GPIO263_AG29"), + PINCTRL_PIN(DB8500_PIN_AE27, "GPIO264_AE27"), + PINCTRL_PIN(DB8500_PIN_AD27, "GPIO265_AD27"), + PINCTRL_PIN(DB8500_PIN_AC28, "GPIO266_AC28"), + PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"), +}; + +/* + * Read the pin group names like this: + * u0_a_1 = first groups of pins for uart0 on alt function a + * i2c2_b_2 = second group of pins for i2c2 on alt function b + * + * The groups are arranged as sets per altfunction column, so we can + * mux in one group at a time by selecting the same altfunction for them + * all. When functions require pins on different altfunctions, you need + * to combine several groups. + */ + +/* Altfunction A column */ +static const unsigned u0_a_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3, + DB8500_PIN_AH4, DB8500_PIN_AH3 }; +static const unsigned u1rxtx_a_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 }; +static const unsigned u1ctsrts_a_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 }; +/* Image processor I2C line, this is driven by image processor firmware */ +static const unsigned ipi2c_a_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 }; +static const unsigned ipi2c_a_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 }; +/* MSP0 can only be on these pins, but TXD and RXD can be flipped */ +static const unsigned msp0txrx_a_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 }; +static const unsigned msp0tfstck_a_1_pins[] = { DB8500_PIN_AF3, DB8500_PIN_AE3 }; +static const unsigned msp0rfsrck_a_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 }; +/* Basic pins of the MMC/SD card 0 interface */ +static const unsigned mc0_a_1_pins[] = { DB8500_PIN_AC2, /* MC0_CMDDIR */ + DB8500_PIN_AC1, /* MC0_DAT0DIR */ + DB8500_PIN_AB4, /* MC0_DAT2DIR */ + DB8500_PIN_AA3, /* MC0_FBCLK */ + DB8500_PIN_AA4, /* MC0_CLK */ + DB8500_PIN_AB2, /* MC0_CMD */ + DB8500_PIN_Y4, /* MC0_DAT0 */ + DB8500_PIN_Y2, /* MC0_DAT1 */ + DB8500_PIN_AA2, /* MC0_DAT2 */ + DB8500_PIN_AA1 /* MC0_DAT3 */ +}; +/* Often only 4 bits are used, then these are not needed (only used for MMC) */ +static const unsigned mc0_dat47_a_1_pins[] = { DB8500_PIN_W2, /* MC0_DAT4 */ + DB8500_PIN_W3, /* MC0_DAT5 */ + DB8500_PIN_V3, /* MC0_DAT6 */ + DB8500_PIN_V2 /* MC0_DAT7 */ +}; +static const unsigned mc0dat31dir_a_1_pins[] = { DB8500_PIN_AB3 }; /* MC0_DAT31DIR */ +/* MSP1 can only be on these pins, but TXD and RXD can be flipped */ +static const unsigned msp1txrx_a_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 }; +static const unsigned msp1_a_1_pins[] = { DB8500_PIN_AE1, DB8500_PIN_AE2 }; +/* LCD interface */ +static const unsigned lcdb_a_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1, + DB8500_PIN_G3, DB8500_PIN_G2 }; +static const unsigned lcdvsi0_a_1_pins[] = { DB8500_PIN_E1 }; +static const unsigned lcdvsi1_a_1_pins[] = { DB8500_PIN_E2 }; +static const unsigned lcd_d0_d7_a_1_pins[] = { + DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3, + DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1 }; +/* D8 thru D11 often used as TVOUT lines */ +static const unsigned lcd_d8_d11_a_1_pins[] = { DB8500_PIN_F4, + DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2 }; +static const unsigned lcd_d12_d23_a_1_pins[] = { + DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5, + DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6, + DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 }; +static const unsigned kp_a_1_pins[] = { DB8500_PIN_D7, DB8500_PIN_E8, + DB8500_PIN_D8, DB8500_PIN_D9 }; +static const unsigned kpskaskb_a_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16 }; +static const unsigned kp_a_2_pins[] = { + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; +/* MC2 has 8 data lines and no direction control, so only for (e)MMC */ +static const unsigned mc2_a_1_pins[] = { DB8500_PIN_A5, DB8500_PIN_B4, + DB8500_PIN_C8, DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, + DB8500_PIN_B9, DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, + DB8500_PIN_C5 }; +static const unsigned ssp1_a_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11, + DB8500_PIN_C12, DB8500_PIN_C11 }; +static const unsigned ssp0_a_1_pins[] = { DB8500_PIN_D12, DB8500_PIN_B13, + DB8500_PIN_C13, DB8500_PIN_D13 }; +static const unsigned i2c0_a_1_pins[] = { DB8500_PIN_C15, DB8500_PIN_B16 }; +/* + * Image processor GPIO pins are named "ipgpio" and have their own + * numberspace + */ +static const unsigned ipgpio0_a_1_pins[] = { DB8500_PIN_B14 }; +static const unsigned ipgpio1_a_1_pins[] = { DB8500_PIN_C14 }; +/* Three modem pins named RF_PURn, MODEM_STATE and MODEM_PWREN */ +static const unsigned modem_a_1_pins[] = { DB8500_PIN_D22, DB8500_PIN_C23, + DB8500_PIN_D23 }; +/* + * This MSP cannot switch RX and TX, SCK in a separate group since this + * seems to be optional. + */ +static const unsigned msp2sck_a_1_pins[] = { DB8500_PIN_AJ27 }; +static const unsigned msp2_a_1_pins[] = { DB8500_PIN_AH27, DB8500_PIN_AF27, + DB8500_PIN_AG28, DB8500_PIN_AG26 }; +static const unsigned mc4_a_1_pins[] = { DB8500_PIN_AH24, DB8500_PIN_AG25, + DB8500_PIN_AH23, DB8500_PIN_AH26, DB8500_PIN_AF24, DB8500_PIN_AF25, + DB8500_PIN_AE23, DB8500_PIN_AF23, DB8500_PIN_AG23, DB8500_PIN_AG24, + DB8500_PIN_AJ23 }; +/* MC1 has only 4 data pins, designed for SD or SDIO exclusively */ +static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15, + DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13, + DB8500_PIN_AH15 }; +static const unsigned mc1_a_2_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AJ15, + DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13, DB8500_PIN_AH15 }; +static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, + DB8500_PIN_AH12, DB8500_PIN_AH11 }; +static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10, + DB8500_PIN_AJ11 }; +static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, + DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 }; +static const unsigned hsit_a_2_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, + DB8500_PIN_AG9, DB8500_PIN_AG8 }; +static const unsigned clkout1_a_1_pins[] = { DB8500_PIN_AH7 }; +static const unsigned clkout1_a_2_pins[] = { DB8500_PIN_AG7 }; +static const unsigned clkout2_a_1_pins[] = { DB8500_PIN_AJ6 }; +static const unsigned clkout2_a_2_pins[] = { DB8500_PIN_AF7 }; +static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29, + DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26, + DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27, + DB8500_PIN_AC28, DB8500_PIN_AC27 }; + +/* Altfunction B column */ +static const unsigned trig_b_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3 }; +static const unsigned i2c4_b_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 }; +static const unsigned i2c1_b_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 }; +static const unsigned i2c2_b_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 }; +static const unsigned i2c2_b_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 }; +static const unsigned msp0txrx_b_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 }; +static const unsigned i2c1_b_2_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 }; +/* Just RX and TX for UART2 */ +static const unsigned u2rxtx_b_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1 }; +static const unsigned uartmodtx_b_1_pins[] = { DB8500_PIN_AB4 }; +static const unsigned msp0sck_b_1_pins[] = { DB8500_PIN_AB3 }; +static const unsigned uartmodrx_b_1_pins[] = { DB8500_PIN_AA3 }; +static const unsigned stmmod_b_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4, + DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned uartmodrx_b_2_pins[] = { DB8500_PIN_AB2 }; +static const unsigned spi3_b_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3, + DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned msp1txrx_b_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 }; +static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1, + DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_E1, DB8500_PIN_E2, + DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3, + DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1, + DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2, + DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 }; +static const unsigned kp_b_2_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1, + DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_F4, DB8500_PIN_E3}; +static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, + DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, + DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8, + DB8500_PIN_D9, DB8500_PIN_A5, DB8500_PIN_B4, DB8500_PIN_C8, + DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, DB8500_PIN_B9, + DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, DB8500_PIN_C5, + DB8500_PIN_C9 }; +/* This chip select pin can be "ps0" in alt C so have it separately */ +static const unsigned smcs0_b_1_pins[] = { DB8500_PIN_E8 }; +/* This chip select pin can be "ps1" in alt C so have it separately */ +static const unsigned smcs1_b_1_pins[] = { DB8500_PIN_B14 }; +static const unsigned ipgpio7_b_1_pins[] = { DB8500_PIN_B11 }; +static const unsigned ipgpio2_b_1_pins[] = { DB8500_PIN_C12 }; +static const unsigned ipgpio3_b_1_pins[] = { DB8500_PIN_C11 }; +static const unsigned lcdaclk_b_1_pins[] = { DB8500_PIN_C14 }; +static const unsigned lcda_b_1_pins[] = { DB8500_PIN_D22, + DB8500_PIN_C23, DB8500_PIN_D23 }; +static const unsigned lcd_b_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; +static const unsigned ddrtrig_b_1_pins[] = { DB8500_PIN_AJ27 }; +static const unsigned pwl_b_1_pins[] = { DB8500_PIN_AF25 }; +static const unsigned spi1_b_1_pins[] = { DB8500_PIN_AG15, DB8500_PIN_AF13, + DB8500_PIN_AG13, DB8500_PIN_AH15 }; +static const unsigned mc3_b_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, + DB8500_PIN_AH12, DB8500_PIN_AH11, DB8500_PIN_AG10, DB8500_PIN_AH10, + DB8500_PIN_AJ11, DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9, + DB8500_PIN_AG8 }; +static const unsigned pwl_b_2_pins[] = { DB8500_PIN_AF8 }; +static const unsigned pwl_b_3_pins[] = { DB8500_PIN_AG7 }; +static const unsigned pwl_b_4_pins[] = { DB8500_PIN_AF7 }; + +/* Altfunction C column */ +static const unsigned ipjtag_c_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3, + DB8500_PIN_AH4, DB8500_PIN_AH3, DB8500_PIN_AH6 }; +static const unsigned ipgpio6_c_1_pins[] = { DB8500_PIN_AG6 }; +static const unsigned ipgpio0_c_1_pins[] = { DB8500_PIN_AF6 }; +static const unsigned ipgpio1_c_1_pins[] = { DB8500_PIN_AG5 }; +static const unsigned ipgpio3_c_1_pins[] = { DB8500_PIN_AF5 }; +static const unsigned ipgpio2_c_1_pins[] = { DB8500_PIN_AG4 }; +static const unsigned slim0_c_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 }; +/* Optional 4-bit Memory Stick interface */ +static const unsigned ms_c_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1, + DB8500_PIN_AB3, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2, + DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned iptrigout_c_1_pins[] = { DB8500_PIN_AB4 }; +static const unsigned u2rxtx_c_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3 }; +static const unsigned u2ctsrts_c_1_pins[] = { DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned u0_c_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AE1, + DB8500_PIN_AE2, DB8500_PIN_AG2 }; +static const unsigned ipgpio4_c_1_pins[] = { DB8500_PIN_F3 }; +static const unsigned ipgpio5_c_1_pins[] = { DB8500_PIN_F1 }; +static const unsigned ipgpio6_c_2_pins[] = { DB8500_PIN_G3 }; +static const unsigned ipgpio7_c_1_pins[] = { DB8500_PIN_G2 }; +static const unsigned smcleale_c_1_pins[] = { DB8500_PIN_E1, DB8500_PIN_E2 }; +static const unsigned stmape_c_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 }; +static const unsigned u2rxtx_c_2_pins[] = { DB8500_PIN_H2, DB8500_PIN_J2 }; +static const unsigned ipgpio2_c_2_pins[] = { DB8500_PIN_F4 }; +static const unsigned ipgpio3_c_2_pins[] = { DB8500_PIN_E3 }; +static const unsigned ipgpio4_c_2_pins[] = { DB8500_PIN_E4 }; +static const unsigned ipgpio5_c_2_pins[] = { DB8500_PIN_D2 }; +static const unsigned mc5_c_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, + DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, + DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8, + DB8500_PIN_D9 }; +static const unsigned mc2rstn_c_1_pins[] = { DB8500_PIN_C8 }; +static const unsigned kp_c_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11, + DB8500_PIN_C12, DB8500_PIN_C11, DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_C23, DB8500_PIN_D23 }; +static const unsigned smps0_c_1_pins[] = { DB8500_PIN_E8 }; +static const unsigned smps1_c_1_pins[] = { DB8500_PIN_B14 }; +static const unsigned u2rxtx_c_3_pins[] = { DB8500_PIN_B17, DB8500_PIN_C16 }; +static const unsigned stmape_c_2_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 }; +static const unsigned uartmodrx_c_1_pins[] = { DB8500_PIN_D21 }; +static const unsigned uartmodtx_c_1_pins[] = { DB8500_PIN_D20 }; +static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 }; +static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 }; +static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 }; +static const unsigned clkout1_c_1_pins[] = { DB8500_PIN_AH13 }; +static const unsigned clkout2_c_1_pins[] = { DB8500_PIN_AH12 }; +static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 }; +static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9, + DB8500_PIN_AG9, DB8500_PIN_AG8 }; +static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 }; +static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; + +/* Other C1 column */ +static const unsigned u2rx_oc1_1_pins[] = { DB8500_PIN_AB2 }; +static const unsigned stmape_oc1_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4, + DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned remap0_oc1_1_pins[] = { DB8500_PIN_E1 }; +static const unsigned remap1_oc1_1_pins[] = { DB8500_PIN_E2 }; +static const unsigned ptma9_oc1_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2, + DB8500_PIN_J2, DB8500_PIN_H1 }; +static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, + DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, + DB8500_PIN_D6, DB8500_PIN_B7 }; +static const unsigned rf_oc1_1_pins[] = { DB8500_PIN_D8, DB8500_PIN_D9 }; +static const unsigned hxclk_oc1_1_pins[] = { DB8500_PIN_D16 }; +static const unsigned uartmodrx_oc1_1_pins[] = { DB8500_PIN_B17 }; +static const unsigned uartmodtx_oc1_1_pins[] = { DB8500_PIN_C16 }; +static const unsigned stmmod_oc1_1_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 }; +static const unsigned hxgpio_oc1_1_pins[] = { DB8500_PIN_D21, DB8500_PIN_D20, + DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22, + DB8500_PIN_B24, DB8500_PIN_C22 }; +static const unsigned rf_oc1_2_pins[] = { DB8500_PIN_C23, DB8500_PIN_D23 }; +static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, + DB8500_PIN_AH12, DB8500_PIN_AH11 }; +static const unsigned spi2_oc1_2_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12, + DB8500_PIN_AH11 }; + +/* Other C2 column */ +static const unsigned sbag_oc2_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_AB2, + DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned etmr4_oc2_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2, + DB8500_PIN_J2, DB8500_PIN_H1 }; +static const unsigned ptma9_oc2_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +/* Other C3 column */ +static const unsigned stmmod_oc3_1_pins[] = { DB8500_PIN_AB2, DB8500_PIN_W2, + DB8500_PIN_W3, DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned stmmod_oc3_2_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 }; +static const unsigned uartmodrx_oc3_1_pins[] = { DB8500_PIN_H2 }; +static const unsigned uartmodtx_oc3_1_pins[] = { DB8500_PIN_J2 }; +static const unsigned etmr4_oc3_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +/* Other C4 column */ +static const unsigned sbag_oc4_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H1 }; +static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +#define DB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \ + .npins = ARRAY_SIZE(a##_pins), .altsetting = b } + +static const struct nmk_pingroup nmk_db8500_groups[] = { + /* Altfunction A column */ + DB8500_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(u1rxtx_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(u1ctsrts_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipi2c_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipi2c_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp0txrx_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc0_dat47_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc0dat31dir_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcdvsi0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcdvsi1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcd_d0_d7_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcd_d8_d11_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcd_d12_d23_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(kp_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ssp1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ssp0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(kp_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc1_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), + /* Altfunction B column */ + DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c4_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c1_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c2_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c2_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(msp0txrx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c1_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(u2rxtx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(uartmodtx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(msp0sck_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(uartmodrx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(stmmod_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(uartmodrx_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(kp_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(smcs1_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(lcdaclk_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(lcda_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(lcd_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ddrtrig_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(spi1_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(mc3_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_3, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_4, NMK_GPIO_ALT_B), + /* Altfunction C column */ + DB8500_PIN_GROUP(ipjtag_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio3_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio2_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(slim0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ms_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(iptrigout_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2rxtx_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2ctsrts_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio4_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio5_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio7_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(smcleale_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(stmape_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2rxtx_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio2_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio3_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio4_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio5_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(smps0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2rxtx_c_3, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(stmape_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(uartmodrx_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(uartmodtx_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout2_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C), + /* Other alt C1 column */ + DB8500_PIN_GROUP(u2rx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(ptma9_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(rf_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(hxclk_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(uartmodrx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(uartmodtx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(stmmod_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(hxgpio_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(rf_oc1_2, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1), + /* Other alt C2 column */ + DB8500_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2), + DB8500_PIN_GROUP(etmr4_oc2_1, NMK_GPIO_ALT_C2), + DB8500_PIN_GROUP(ptma9_oc2_1, NMK_GPIO_ALT_C2), + /* Other alt C3 column */ + DB8500_PIN_GROUP(stmmod_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(stmmod_oc3_2, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(uartmodrx_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(uartmodtx_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(etmr4_oc3_1, NMK_GPIO_ALT_C3), + /* Other alt C4 column */ + DB8500_PIN_GROUP(sbag_oc4_1, NMK_GPIO_ALT_C4), + DB8500_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4), +}; + +/* We use this macro to define the groups applicable to a function */ +#define DB8500_FUNC_GROUPS(a, b...) \ +static const char * const a##_groups[] = { b }; + +DB8500_FUNC_GROUPS(u0, "u0_a_1", "u0_c_1"); +DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1"); +/* + * UART2 can be muxed out with just RX/TX in four places, CTS+RTS is however + * only available on two pins in alternative function C + */ +DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1", + "u2rxtx_c_2", "u2rxtx_c_3", "u2rx_oc1_1"); +DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2"); +/* + * MSP0 can only be on a certain set of pins, but the TX/RX pins can be + * switched around by selecting the altfunction A or B. The SCK pin is + * only available on the altfunction B. + */ +DB8500_FUNC_GROUPS(msp0, "msp0txrx_a_1", "msp0tfstck_a_1", "msp0rfstck_a_1", + "msp0txrx_b_1", "msp0sck_b_1"); +DB8500_FUNC_GROUPS(mc0, "mc0_a_1", "mc0_dat47_a_1", "mc0dat31dir_a_1"); +/* MSP0 can swap RX/TX like MSP0 but has no SCK pin available */ +DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1"); +DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1"); +DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1", + "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1"); +DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_a_2", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1"); +DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1"); +DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1"); +DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1"); +DB8500_FUNC_GROUPS(i2c0, "i2c0_a_1"); +/* The image processor has 8 GPIO pins that can be muxed out */ +DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1", + "ipgpio2_b_1", "ipgpio3_b_1", "ipgpio6_c_1", "ipgpio0_c_1", + "ipgpio1_c_1", "ipgpio3_c_1", "ipgpio2_c_1", "ipgpio4_c_1", + "ipgpio5_c_1", "ipgpio6_c_2", "ipgpio7_c_1", "ipgpio2_c_2", + "ipgpio3_c_2", "ipgpio4_c_2", "ipgpio5_c_2"); +/* MSP2 can not invert the RX/TX pins but has the optional SCK pin */ +DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1"); +DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1"); +DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1_a_2", "mc1dir_a_1"); +DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2"); +DB8500_FUNC_GROUPS(clkout, "clkout1_a_1", "clkout1_a_2", "clkout1_c_1", + "clkout2_a_1", "clkout2_a_2", "clkout2_c_1"); +DB8500_FUNC_GROUPS(usb, "usb_a_1"); +DB8500_FUNC_GROUPS(trig, "trig_b_1"); +DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1"); +DB8500_FUNC_GROUPS(i2c1, "i2c1_b_1", "i2c1_b_2"); +DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2"); +/* + * The modem UART can output its RX and TX pins in some different places, + * so select one of each. + */ +DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2", + "uartmodrx_c_1", "uartmod_tx_c_1", "uartmodrx_oc1_1", + "uartmodtx_oc1_1", "uartmodrx_oc3_1", "uartmodtx_oc3_1"); +DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1", "stmmod_oc1_1", + "stmmod_oc3_1", "stmmod_oc3_2"); +DB8500_FUNC_GROUPS(spi3, "spi3_b_1"); +/* Select between CS0 on alt B or PS1 on alt C */ +DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcs1_b_1", "smcleale_c_1", + "smps0_c_1", "smps1_c_1"); +DB8500_FUNC_GROUPS(lcda, "lcdaclk_b_1", "lcda_b_1"); +DB8500_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1"); +DB8500_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4"); +DB8500_FUNC_GROUPS(spi1, "spi1_b_1"); +DB8500_FUNC_GROUPS(mc3, "mc3_b_1"); +DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1"); +DB8500_FUNC_GROUPS(slim0, "slim0_c_1"); +DB8500_FUNC_GROUPS(ms, "ms_c_1"); +DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1"); +DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2", "stmape_oc1_1"); +DB8500_FUNC_GROUPS(mc5, "mc5_c_1"); +DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2"); +DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2"); +DB8500_FUNC_GROUPS(spi0, "spi0_c_1"); +DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1", "spi2_oc1_2"); +DB8500_FUNC_GROUPS(remap, "remap0_oc1_1", "remap1_oc1_1"); +DB8500_FUNC_GROUPS(sbag, "sbag_oc2_1", "sbag_oc4_1"); +DB8500_FUNC_GROUPS(ptm, "ptma9_oc1_1", "ptma9_oc2_1"); +DB8500_FUNC_GROUPS(rf, "rf_oc1_1", "rf_oc1_2"); +DB8500_FUNC_GROUPS(hx, "hxclk_oc1_1", "hxgpio_oc1_1"); +DB8500_FUNC_GROUPS(etm, "etmr4_oc2_1", "etmr4_oc3_1"); +DB8500_FUNC_GROUPS(hwobs, "hwobs_oc4_1"); +#define FUNCTION(fname) \ + { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct nmk_function nmk_db8500_functions[] = { + FUNCTION(u0), + FUNCTION(u1), + FUNCTION(u2), + FUNCTION(ipi2c), + FUNCTION(msp0), + FUNCTION(mc0), + FUNCTION(msp1), + FUNCTION(lcdb), + FUNCTION(lcd), + FUNCTION(kp), + FUNCTION(mc2), + FUNCTION(ssp1), + FUNCTION(ssp0), + FUNCTION(i2c0), + FUNCTION(ipgpio), + FUNCTION(msp2), + FUNCTION(mc4), + FUNCTION(mc1), + FUNCTION(hsi), + FUNCTION(clkout), + FUNCTION(usb), + FUNCTION(trig), + FUNCTION(i2c4), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(uartmod), + FUNCTION(stmmod), + FUNCTION(spi3), + FUNCTION(sm), + FUNCTION(lcda), + FUNCTION(ddrtrig), + FUNCTION(pwl), + FUNCTION(spi1), + FUNCTION(mc3), + FUNCTION(ipjtag), + FUNCTION(slim0), + FUNCTION(ms), + FUNCTION(iptrigout), + FUNCTION(stmape), + FUNCTION(mc5), + FUNCTION(usbsim), + FUNCTION(i2c3), + FUNCTION(spi0), + FUNCTION(spi2), + FUNCTION(remap), + FUNCTION(ptm), + FUNCTION(rf), + FUNCTION(hx), + FUNCTION(etm), + FUNCTION(hwobs), +}; + +static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = { + PRCM_GPIOCR_ALTCX(23, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_CLK_a */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_CLK_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(24, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE or U2_RXD ??? */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_VAL_a */ + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(25, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[0] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[0] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(26, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[1] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[1] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(27, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[2] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[2] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(28, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[3] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[3] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(29, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(30, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(31, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(32, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(68, true, PRCM_IDX_GPIOCR1, 18, /* REMAP_SELECT_ON */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(69, true, PRCM_IDX_GPIOCR1, 18, /* REMAP_SELECT_ON */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(70, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D23 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_CLK */ + ), + PRCM_GPIOCR_ALTCX(71, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D22 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D3 */ + ), + PRCM_GPIOCR_ALTCX(72, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D21 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D2 */ + ), + PRCM_GPIOCR_ALTCX(73, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D20 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D1 */ + ), + PRCM_GPIOCR_ALTCX(74, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D19 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D0 */ + ), + PRCM_GPIOCR_ALTCX(75, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D18 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 0, /* DBG_UARTMOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(76, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D17 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 0, /* DBG_UARTMOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(77, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D16 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_VAL */ + ), + PRCM_GPIOCR_ALTCX(86, true, PRCM_IDX_GPIOCR1, 12, /* KP_O3 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(87, true, PRCM_IDX_GPIOCR1, 12, /* KP_O2 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(88, true, PRCM_IDX_GPIOCR1, 12, /* KP_I3 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(89, true, PRCM_IDX_GPIOCR1, 12, /* KP_I2 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(90, true, PRCM_IDX_GPIOCR1, 12, /* KP_O1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(91, true, PRCM_IDX_GPIOCR1, 12, /* KP_O0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(92, true, PRCM_IDX_GPIOCR1, 12, /* KP_I1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(93, true, PRCM_IDX_GPIOCR1, 12, /* KP_I0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(96, true, PRCM_IDX_GPIOCR2, 3, /* RF_INT */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(97, true, PRCM_IDX_GPIOCR2, 1, /* RF_CTRL */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(151, false, 0, 0, + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_CTL */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS17 */ + ), + PRCM_GPIOCR_ALTCX(152, true, PRCM_IDX_GPIOCR1, 4, /* Hx_CLK */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_CLK */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS16 */ + ), + PRCM_GPIOCR_ALTCX(153, true, PRCM_IDX_GPIOCR1, 1, /* UARTMOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D15 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS15 */ + ), + PRCM_GPIOCR_ALTCX(154, true, PRCM_IDX_GPIOCR1, 1, /* UARTMOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D14 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS14 */ + ), + PRCM_GPIOCR_ALTCX(155, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D13 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS13 */ + ), + PRCM_GPIOCR_ALTCX(156, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D12 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS12 */ + ), + PRCM_GPIOCR_ALTCX(157, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D11 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS11 */ + ), + PRCM_GPIOCR_ALTCX(158, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D10 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS10 */ + ), + PRCM_GPIOCR_ALTCX(159, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D9 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS9 */ + ), + PRCM_GPIOCR_ALTCX(160, false, 0, 0, + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D8 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS8 */ + ), + PRCM_GPIOCR_ALTCX(161, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO7 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D7 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS7 */ + ), + PRCM_GPIOCR_ALTCX(162, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO6 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D6 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS6 */ + ), + PRCM_GPIOCR_ALTCX(163, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO5 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D5 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS5 */ + ), + PRCM_GPIOCR_ALTCX(164, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO4 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D4 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS4 */ + ), + PRCM_GPIOCR_ALTCX(165, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO3 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D3 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS3 */ + ), + PRCM_GPIOCR_ALTCX(166, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO2 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D2 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS2 */ + ), + PRCM_GPIOCR_ALTCX(167, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO1 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D1 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS1 */ + ), + PRCM_GPIOCR_ALTCX(168, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO0 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D0 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS0 */ + ), + PRCM_GPIOCR_ALTCX(170, true, PRCM_IDX_GPIOCR2, 2, /* RF_INT */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(171, true, PRCM_IDX_GPIOCR2, 0, /* RF_CTRL */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(215, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_TXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(216, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_FRM */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(217, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_CLK */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(218, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_RXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), +}; + +static const u16 db8500_prcm_gpiocr_regs[] = { + [PRCM_IDX_GPIOCR1] = 0x138, + [PRCM_IDX_GPIOCR2] = 0x574, +}; + +static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { + .pins = nmk_db8500_pins, + .npins = ARRAY_SIZE(nmk_db8500_pins), + .functions = nmk_db8500_functions, + .nfunctions = ARRAY_SIZE(nmk_db8500_functions), + .groups = nmk_db8500_groups, + .ngroups = ARRAY_SIZE(nmk_db8500_groups), + .altcx_pins = db8500_altcx_pins, + .npins_altcx = ARRAY_SIZE(db8500_altcx_pins), + .prcm_gpiocr_registers = db8500_prcm_gpiocr_regs, +}; + +void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc) +{ + *soc = &nmk_db8500_soc; +} diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c new file mode 100644 index 000000000..8d944bb3a --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/pinctrl/pinctrl.h> +#include "pinctrl-nomadik.h" + +/* All the pins that can be used for GPIO and some other functions */ +#define _GPIO(offset) (offset) + +#define STN8815_PIN_B4 _GPIO(0) +#define STN8815_PIN_D5 _GPIO(1) +#define STN8815_PIN_C5 _GPIO(2) +#define STN8815_PIN_A4 _GPIO(3) +#define STN8815_PIN_B5 _GPIO(4) +#define STN8815_PIN_D6 _GPIO(5) +#define STN8815_PIN_C6 _GPIO(6) +#define STN8815_PIN_B6 _GPIO(7) +#define STN8815_PIN_B10 _GPIO(8) +#define STN8815_PIN_A10 _GPIO(9) +#define STN8815_PIN_C11 _GPIO(10) +#define STN8815_PIN_B11 _GPIO(11) +#define STN8815_PIN_A11 _GPIO(12) +#define STN8815_PIN_C12 _GPIO(13) +#define STN8815_PIN_B12 _GPIO(14) +#define STN8815_PIN_A12 _GPIO(15) +#define STN8815_PIN_C13 _GPIO(16) +#define STN8815_PIN_B13 _GPIO(17) +#define STN8815_PIN_A13 _GPIO(18) +#define STN8815_PIN_D13 _GPIO(19) +#define STN8815_PIN_C14 _GPIO(20) +#define STN8815_PIN_B14 _GPIO(21) +#define STN8815_PIN_A14 _GPIO(22) +#define STN8815_PIN_D15 _GPIO(23) +#define STN8815_PIN_C15 _GPIO(24) +#define STN8815_PIN_B15 _GPIO(25) +#define STN8815_PIN_A15 _GPIO(26) +#define STN8815_PIN_C16 _GPIO(27) +#define STN8815_PIN_B16 _GPIO(28) +#define STN8815_PIN_A16 _GPIO(29) +#define STN8815_PIN_D17 _GPIO(30) +#define STN8815_PIN_C17 _GPIO(31) +#define STN8815_PIN_AB6 _GPIO(32) +#define STN8815_PIN_AA6 _GPIO(33) +#define STN8815_PIN_Y6 _GPIO(34) +#define STN8815_PIN_Y5 _GPIO(35) +#define STN8815_PIN_AA5 _GPIO(36) +#define STN8815_PIN_AB5 _GPIO(37) +#define STN8815_PIN_AB4 _GPIO(38) +#define STN8815_PIN_Y4 _GPIO(39) +#define STN8815_PIN_R1 _GPIO(40) +#define STN8815_PIN_R2 _GPIO(41) +#define STN8815_PIN_R3 _GPIO(42) +#define STN8815_PIN_P1 _GPIO(43) +#define STN8815_PIN_P2 _GPIO(44) +#define STN8815_PIN_P3 _GPIO(45) +#define STN8815_PIN_N1 _GPIO(46) +#define STN8815_PIN_N2 _GPIO(47) +#define STN8815_PIN_N3 _GPIO(48) +#define STN8815_PIN_M1 _GPIO(49) +#define STN8815_PIN_M3 _GPIO(50) +#define STN8815_PIN_M2 _GPIO(51) +#define STN8815_PIN_L1 _GPIO(52) +#define STN8815_PIN_L4 _GPIO(53) +#define STN8815_PIN_L3 _GPIO(54) +#define STN8815_PIN_L2 _GPIO(55) +#define STN8815_PIN_F3 _GPIO(56) +#define STN8815_PIN_F2 _GPIO(57) +#define STN8815_PIN_E1 _GPIO(58) +#define STN8815_PIN_E3 _GPIO(59) +#define STN8815_PIN_E2 _GPIO(60) +#define STN8815_PIN_E4 _GPIO(61) +#define STN8815_PIN_D3 _GPIO(62) +#define STN8815_PIN_D2 _GPIO(63) +#define STN8815_PIN_F21 _GPIO(64) +#define STN8815_PIN_F20 _GPIO(65) +#define STN8815_PIN_E22 _GPIO(66) +#define STN8815_PIN_D22 _GPIO(67) +#define STN8815_PIN_E21 _GPIO(68) +#define STN8815_PIN_E20 _GPIO(69) +#define STN8815_PIN_C22 _GPIO(70) +#define STN8815_PIN_D21 _GPIO(71) +#define STN8815_PIN_D20 _GPIO(72) +#define STN8815_PIN_C21 _GPIO(73) +#define STN8815_PIN_C20 _GPIO(74) +#define STN8815_PIN_C19 _GPIO(75) +#define STN8815_PIN_B20 _GPIO(76) +#define STN8815_PIN_B8 _GPIO(77) +#define STN8815_PIN_A8 _GPIO(78) +#define STN8815_PIN_C9 _GPIO(79) +#define STN8815_PIN_B9 _GPIO(80) +#define STN8815_PIN_A9 _GPIO(81) +#define STN8815_PIN_C10 _GPIO(82) +#define STN8815_PIN_K1 _GPIO(83) +#define STN8815_PIN_K3 _GPIO(84) +#define STN8815_PIN_K2 _GPIO(85) +#define STN8815_PIN_J1 _GPIO(86) +#define STN8815_PIN_J3 _GPIO(87) +#define STN8815_PIN_J2 _GPIO(88) +#define STN8815_PIN_H1 _GPIO(89) +#define STN8815_PIN_H3 _GPIO(90) +#define STN8815_PIN_H2 _GPIO(91) +#define STN8815_PIN_G1 _GPIO(92) +#define STN8815_PIN_G3 _GPIO(93) +#define STN8815_PIN_G2 _GPIO(94) +#define STN8815_PIN_F1 _GPIO(95) +#define STN8815_PIN_T20 _GPIO(96) +#define STN8815_PIN_R21 _GPIO(97) +#define STN8815_PIN_R20 _GPIO(98) +#define STN8815_PIN_U22 _GPIO(99) +#define STN8815_PIN_N21 _GPIO(100) +#define STN8815_PIN_N20 _GPIO(101) +#define STN8815_PIN_P22 _GPIO(102) +#define STN8815_PIN_N22 _GPIO(103) +#define STN8815_PIN_V22 _GPIO(104) +#define STN8815_PIN_V21 _GPIO(105) +#define STN8815_PIN_K22 _GPIO(106) +#define STN8815_PIN_K21 _GPIO(107) +#define STN8815_PIN_H20 _GPIO(108) +#define STN8815_PIN_G20 _GPIO(109) +#define STN8815_PIN_L21 _GPIO(110) +#define STN8815_PIN_H21 _GPIO(111) +#define STN8815_PIN_J21 _GPIO(112) +#define STN8815_PIN_H22 _GPIO(113) +#define STN8815_PIN_K20 _GPIO(114) +#define STN8815_PIN_L22 _GPIO(115) +#define STN8815_PIN_G21 _GPIO(116) +#define STN8815_PIN_J20 _GPIO(117) +#define STN8815_PIN_G22 _GPIO(118) +#define STN8815_PIN_U19 _GPIO(119) +#define STN8815_PIN_G19 _GPIO(120) +#define STN8815_PIN_M22 _GPIO(121) +#define STN8815_PIN_M19 _GPIO(122) +#define STN8815_PIN_J22 _GPIO(123) +/* GPIOs 124-127 not routed to pins */ + +/* + * The names of the pins are denoted by GPIO number and ball name, even + * though they can be used for other things than GPIO, this is the first + * column in the table of the data sheet and often used on schematics and + * such. + */ +static const struct pinctrl_pin_desc nmk_stn8815_pins[] = { + PINCTRL_PIN(STN8815_PIN_B4, "GPIO0_B4"), + PINCTRL_PIN(STN8815_PIN_D5, "GPIO1_D5"), + PINCTRL_PIN(STN8815_PIN_C5, "GPIO2_C5"), + PINCTRL_PIN(STN8815_PIN_A4, "GPIO3_A4"), + PINCTRL_PIN(STN8815_PIN_B5, "GPIO4_B5"), + PINCTRL_PIN(STN8815_PIN_D6, "GPIO5_D6"), + PINCTRL_PIN(STN8815_PIN_C6, "GPIO6_C6"), + PINCTRL_PIN(STN8815_PIN_B6, "GPIO7_B6"), + PINCTRL_PIN(STN8815_PIN_B10, "GPIO8_B10"), + PINCTRL_PIN(STN8815_PIN_A10, "GPIO9_A10"), + PINCTRL_PIN(STN8815_PIN_C11, "GPIO10_C11"), + PINCTRL_PIN(STN8815_PIN_B11, "GPIO11_B11"), + PINCTRL_PIN(STN8815_PIN_A11, "GPIO12_A11"), + PINCTRL_PIN(STN8815_PIN_C12, "GPIO13_C12"), + PINCTRL_PIN(STN8815_PIN_B12, "GPIO14_B12"), + PINCTRL_PIN(STN8815_PIN_A12, "GPIO15_A12"), + PINCTRL_PIN(STN8815_PIN_C13, "GPIO16_C13"), + PINCTRL_PIN(STN8815_PIN_B13, "GPIO17_B13"), + PINCTRL_PIN(STN8815_PIN_A13, "GPIO18_A13"), + PINCTRL_PIN(STN8815_PIN_D13, "GPIO19_D13"), + PINCTRL_PIN(STN8815_PIN_C14, "GPIO20_C14"), + PINCTRL_PIN(STN8815_PIN_B14, "GPIO21_B14"), + PINCTRL_PIN(STN8815_PIN_A14, "GPIO22_A14"), + PINCTRL_PIN(STN8815_PIN_D15, "GPIO23_D15"), + PINCTRL_PIN(STN8815_PIN_C15, "GPIO24_C15"), + PINCTRL_PIN(STN8815_PIN_B15, "GPIO25_B15"), + PINCTRL_PIN(STN8815_PIN_A15, "GPIO26_A15"), + PINCTRL_PIN(STN8815_PIN_C16, "GPIO27_C16"), + PINCTRL_PIN(STN8815_PIN_B16, "GPIO28_B16"), + PINCTRL_PIN(STN8815_PIN_A16, "GPIO29_A16"), + PINCTRL_PIN(STN8815_PIN_D17, "GPIO30_D17"), + PINCTRL_PIN(STN8815_PIN_C17, "GPIO31_C17"), + PINCTRL_PIN(STN8815_PIN_AB6, "GPIO32_AB6"), + PINCTRL_PIN(STN8815_PIN_AA6, "GPIO33_AA6"), + PINCTRL_PIN(STN8815_PIN_Y6, "GPIO34_Y6"), + PINCTRL_PIN(STN8815_PIN_Y5, "GPIO35_Y5"), + PINCTRL_PIN(STN8815_PIN_AA5, "GPIO36_AA5"), + PINCTRL_PIN(STN8815_PIN_AB5, "GPIO37_AB5"), + PINCTRL_PIN(STN8815_PIN_AB4, "GPIO38_AB4"), + PINCTRL_PIN(STN8815_PIN_Y4, "GPIO39_Y4"), + PINCTRL_PIN(STN8815_PIN_R1, "GPIO40_R1"), + PINCTRL_PIN(STN8815_PIN_R2, "GPIO41_R2"), + PINCTRL_PIN(STN8815_PIN_R3, "GPIO42_R3"), + PINCTRL_PIN(STN8815_PIN_P1, "GPIO43_P1"), + PINCTRL_PIN(STN8815_PIN_P2, "GPIO44_P2"), + PINCTRL_PIN(STN8815_PIN_P3, "GPIO45_P3"), + PINCTRL_PIN(STN8815_PIN_N1, "GPIO46_N1"), + PINCTRL_PIN(STN8815_PIN_N2, "GPIO47_N2"), + PINCTRL_PIN(STN8815_PIN_N3, "GPIO48_N3"), + PINCTRL_PIN(STN8815_PIN_M1, "GPIO49_M1"), + PINCTRL_PIN(STN8815_PIN_M3, "GPIO50_M3"), + PINCTRL_PIN(STN8815_PIN_M2, "GPIO51_M2"), + PINCTRL_PIN(STN8815_PIN_L1, "GPIO52_L1"), + PINCTRL_PIN(STN8815_PIN_L4, "GPIO53_L4"), + PINCTRL_PIN(STN8815_PIN_L3, "GPIO54_L3"), + PINCTRL_PIN(STN8815_PIN_L2, "GPIO55_L2"), + PINCTRL_PIN(STN8815_PIN_F3, "GPIO56_F3"), + PINCTRL_PIN(STN8815_PIN_F2, "GPIO57_F2"), + PINCTRL_PIN(STN8815_PIN_E1, "GPIO58_E1"), + PINCTRL_PIN(STN8815_PIN_E3, "GPIO59_E3"), + PINCTRL_PIN(STN8815_PIN_E2, "GPIO60_E2"), + PINCTRL_PIN(STN8815_PIN_E4, "GPIO61_E4"), + PINCTRL_PIN(STN8815_PIN_D3, "GPIO62_D3"), + PINCTRL_PIN(STN8815_PIN_D2, "GPIO63_D2"), + PINCTRL_PIN(STN8815_PIN_F21, "GPIO64_F21"), + PINCTRL_PIN(STN8815_PIN_F20, "GPIO65_F20"), + PINCTRL_PIN(STN8815_PIN_E22, "GPIO66_E22"), + PINCTRL_PIN(STN8815_PIN_D22, "GPIO67_D22"), + PINCTRL_PIN(STN8815_PIN_E21, "GPIO68_E21"), + PINCTRL_PIN(STN8815_PIN_E20, "GPIO69_E20"), + PINCTRL_PIN(STN8815_PIN_C22, "GPIO70_C22"), + PINCTRL_PIN(STN8815_PIN_D21, "GPIO71_D21"), + PINCTRL_PIN(STN8815_PIN_D20, "GPIO72_D20"), + PINCTRL_PIN(STN8815_PIN_C21, "GPIO73_C21"), + PINCTRL_PIN(STN8815_PIN_C20, "GPIO74_C20"), + PINCTRL_PIN(STN8815_PIN_C19, "GPIO75_C19"), + PINCTRL_PIN(STN8815_PIN_B20, "GPIO76_B20"), + PINCTRL_PIN(STN8815_PIN_B8, "GPIO77_B8"), + PINCTRL_PIN(STN8815_PIN_A8, "GPIO78_A8"), + PINCTRL_PIN(STN8815_PIN_C9, "GPIO79_C9"), + PINCTRL_PIN(STN8815_PIN_B9, "GPIO80_B9"), + PINCTRL_PIN(STN8815_PIN_A9, "GPIO81_A9"), + PINCTRL_PIN(STN8815_PIN_C10, "GPIO82_C10"), + PINCTRL_PIN(STN8815_PIN_K1, "GPIO83_K1"), + PINCTRL_PIN(STN8815_PIN_K3, "GPIO84_K3"), + PINCTRL_PIN(STN8815_PIN_K2, "GPIO85_K2"), + PINCTRL_PIN(STN8815_PIN_J1, "GPIO86_J1"), + PINCTRL_PIN(STN8815_PIN_J3, "GPIO87_J3"), + PINCTRL_PIN(STN8815_PIN_J2, "GPIO88_J2"), + PINCTRL_PIN(STN8815_PIN_H1, "GPIO89_H1"), + PINCTRL_PIN(STN8815_PIN_H3, "GPIO90_H3"), + PINCTRL_PIN(STN8815_PIN_H2, "GPIO91_H2"), + PINCTRL_PIN(STN8815_PIN_G1, "GPIO92_G1"), + PINCTRL_PIN(STN8815_PIN_G3, "GPIO93_G3"), + PINCTRL_PIN(STN8815_PIN_G2, "GPIO94_G2"), + PINCTRL_PIN(STN8815_PIN_F1, "GPIO95_F1"), + PINCTRL_PIN(STN8815_PIN_T20, "GPIO96_T20"), + PINCTRL_PIN(STN8815_PIN_R21, "GPIO97_R21"), + PINCTRL_PIN(STN8815_PIN_R20, "GPIO98_R20"), + PINCTRL_PIN(STN8815_PIN_U22, "GPIO99_U22"), + PINCTRL_PIN(STN8815_PIN_N21, "GPIO100_N21"), + PINCTRL_PIN(STN8815_PIN_N20, "GPIO101_N20"), + PINCTRL_PIN(STN8815_PIN_P22, "GPIO102_P22"), + PINCTRL_PIN(STN8815_PIN_N22, "GPIO103_N22"), + PINCTRL_PIN(STN8815_PIN_V22, "GPIO104_V22"), + PINCTRL_PIN(STN8815_PIN_V21, "GPIO105_V21"), + PINCTRL_PIN(STN8815_PIN_K22, "GPIO106_K22"), + PINCTRL_PIN(STN8815_PIN_K21, "GPIO107_K21"), + PINCTRL_PIN(STN8815_PIN_H20, "GPIO108_H20"), + PINCTRL_PIN(STN8815_PIN_G20, "GPIO109_G20"), + PINCTRL_PIN(STN8815_PIN_L21, "GPIO110_L21"), + PINCTRL_PIN(STN8815_PIN_H21, "GPIO111_H21"), + PINCTRL_PIN(STN8815_PIN_J21, "GPIO112_J21"), + PINCTRL_PIN(STN8815_PIN_H22, "GPIO113_H22"), + PINCTRL_PIN(STN8815_PIN_K20, "GPIO114_K20"), + PINCTRL_PIN(STN8815_PIN_L22, "GPIO115_L22"), + PINCTRL_PIN(STN8815_PIN_G21, "GPIO116_G21"), + PINCTRL_PIN(STN8815_PIN_J20, "GPIO117_J20"), + PINCTRL_PIN(STN8815_PIN_G22, "GPIO118_G22"), + PINCTRL_PIN(STN8815_PIN_U19, "GPIO119_U19"), + PINCTRL_PIN(STN8815_PIN_G19, "GPIO120_G19"), + PINCTRL_PIN(STN8815_PIN_M22, "GPIO121_M22"), + PINCTRL_PIN(STN8815_PIN_M19, "GPIO122_M19"), + PINCTRL_PIN(STN8815_PIN_J22, "GPIO123_J22"), +}; + +/* + * Read the pin group names like this: + * u0_a_1 = first groups of pins for uart0 on alt function a + * i2c2_b_2 = second group of pins for i2c2 on alt function b + */ + +/* Altfunction A */ +static const unsigned u0txrx_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5 }; +static const unsigned u0ctsrts_a_1_pins[] = { STN8815_PIN_C5, STN8815_PIN_B6 }; +/* Modem pins: DCD, DSR, RI, DTR */ +static const unsigned u0modem_a_1_pins[] = { STN8815_PIN_A4, STN8815_PIN_B5, + STN8815_PIN_D6, STN8815_PIN_C6 }; +static const unsigned mmcsd_a_1_pins[] = { STN8815_PIN_B10, STN8815_PIN_A10, + STN8815_PIN_C11, STN8815_PIN_B11, STN8815_PIN_A11, STN8815_PIN_C12, + STN8815_PIN_B12, STN8815_PIN_A12, STN8815_PIN_C13, STN8815_PIN_C15 }; +static const unsigned mmcsd_b_1_pins[] = { STN8815_PIN_D15 }; +static const unsigned u1_a_1_pins[] = { STN8815_PIN_M2, STN8815_PIN_L1, + STN8815_PIN_F3, STN8815_PIN_F2 }; +static const unsigned i2c1_a_1_pins[] = { STN8815_PIN_L4, STN8815_PIN_L3 }; +static const unsigned i2c0_a_1_pins[] = { STN8815_PIN_D3, STN8815_PIN_D2 }; +/* Altfunction B */ +static const unsigned u1_b_1_pins[] = { STN8815_PIN_B16, STN8815_PIN_A16 }; +static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 }; +static const unsigned clcd_16_23_b_1_pins[] = { STN8815_PIN_AB6, + STN8815_PIN_AA6, STN8815_PIN_Y6, STN8815_PIN_Y5, STN8815_PIN_AA5, + STN8815_PIN_AB5, STN8815_PIN_AB4, STN8815_PIN_Y4 }; +/* Full-speed and high-speed USB pins */ +static const unsigned usbfs_b_1_pins[] = { STN8815_PIN_E21, STN8815_PIN_E20, + STN8815_PIN_C22, STN8815_PIN_D21, + STN8815_PIN_D20, STN8815_PIN_C21, + STN8815_PIN_C20 }; +static const unsigned usbhs_c_1_pins[] = { STN8815_PIN_E21, STN8815_PIN_E20, + STN8815_PIN_C20, STN8815_PIN_C19, + STN8815_PIN_C22, STN8815_PIN_D21, + STN8815_PIN_D20, STN8815_PIN_C21, + STN8815_PIN_C16, STN8815_PIN_A15, + STN8815_PIN_D17, STN8815_PIN_C17 }; + +#define STN8815_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \ + .npins = ARRAY_SIZE(a##_pins), .altsetting = b } + +static const struct nmk_pingroup nmk_stn8815_groups[] = { + STN8815_PIN_GROUP(u0txrx_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0ctsrts_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0modem_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(mmcsd_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(mmcsd_b_1, NMK_GPIO_ALT_B), + STN8815_PIN_GROUP(u1_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(i2c1_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u1_b_1, NMK_GPIO_ALT_B), + STN8815_PIN_GROUP(i2cusb_b_1, NMK_GPIO_ALT_B), + STN8815_PIN_GROUP(clcd_16_23_b_1, NMK_GPIO_ALT_B), + STN8815_PIN_GROUP(usbfs_b_1, NMK_GPIO_ALT_B), + STN8815_PIN_GROUP(usbhs_c_1, NMK_GPIO_ALT_C), +}; + +/* We use this macro to define the groups applicable to a function */ +#define STN8815_FUNC_GROUPS(a, b...) \ +static const char * const a##_groups[] = { b }; + +STN8815_FUNC_GROUPS(u0, "u0txrx_a_1", "u0ctsrts_a_1", "u0modem_a_1"); +STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1", "mmcsd_b_1"); +STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1"); +STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1"); +STN8815_FUNC_GROUPS(i2c0, "i2c0_a_1"); +STN8815_FUNC_GROUPS(i2cusb, "i2cusb_b_1"); +STN8815_FUNC_GROUPS(clcd, "clcd_16_23_b_1"); +STN8815_FUNC_GROUPS(usb, "usbfs_b_1", "usbhs_c_1"); + +#define FUNCTION(fname) \ + { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct nmk_function nmk_stn8815_functions[] = { + FUNCTION(u0), + FUNCTION(mmcsd), + FUNCTION(u1), + FUNCTION(i2c1), + FUNCTION(i2c0), + FUNCTION(i2cusb), + FUNCTION(clcd), + FUNCTION(usb), +}; + +static const struct nmk_pinctrl_soc_data nmk_stn8815_soc = { + .pins = nmk_stn8815_pins, + .npins = ARRAY_SIZE(nmk_stn8815_pins), + .functions = nmk_stn8815_functions, + .nfunctions = ARRAY_SIZE(nmk_stn8815_functions), + .groups = nmk_stn8815_groups, + .ngroups = ARRAY_SIZE(nmk_stn8815_groups), +}; + +void nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc) +{ + *soc = &nmk_stn8815_soc; +} diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c new file mode 100644 index 000000000..415e91360 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -0,0 +1,1986 @@ +/* + * Generic GPIO driver for logic cells found in the Nomadik SoC + * + * Copyright (C) 2008,2009 STMicroelectronics + * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> + * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> + * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/bitops.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +/* Since we request GPIOs from ourself */ +#include <linux/pinctrl/consumer.h> +#include "pinctrl-nomadik.h" +#include "../core.h" +#include "../pinctrl-utils.h" + +/* + * The GPIO module in the Nomadik family of Systems-on-Chip is an + * AMBA device, managing 32 pins and alternate functions. The logic block + * is currently used in the Nomadik and ux500. + * + * Symbols in this file are called "nmk_gpio" for "nomadik gpio" + */ + +/* + * pin configurations are represented by 32-bit integers: + * + * bit 0.. 8 - Pin Number (512 Pins Maximum) + * bit 9..10 - Alternate Function Selection + * bit 11..12 - Pull up/down state + * bit 13 - Sleep mode behaviour + * bit 14 - Direction + * bit 15 - Value (if output) + * bit 16..18 - SLPM pull up/down state + * bit 19..20 - SLPM direction + * bit 21..22 - SLPM Value (if output) + * bit 23..25 - PDIS value (if input) + * bit 26 - Gpio mode + * bit 27 - Sleep mode + * + * to facilitate the definition, the following macros are provided + * + * PIN_CFG_DEFAULT - default config (0): + * pull up/down = disabled + * sleep mode = input/wakeup + * direction = input + * value = low + * SLPM direction = same as normal + * SLPM pull = same as normal + * SLPM value = same as normal + * + * PIN_CFG - default config with alternate function + */ + +typedef unsigned long pin_cfg_t; + +#define PIN_NUM_MASK 0x1ff +#define PIN_NUM(x) ((x) & PIN_NUM_MASK) + +#define PIN_ALT_SHIFT 9 +#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT) +#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT) +#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT) +#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT) +#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT) +#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT) + +#define PIN_PULL_SHIFT 11 +#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT) +#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT) +#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT) +#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT) +#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT) + +#define PIN_SLPM_SHIFT 13 +#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT) +#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT) +#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT) +#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT) +/* These two replace the above in DB8500v2+ */ +#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT) +#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT) +#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE + +#define PIN_SLPM_GPIO PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */ +#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */ + +#define PIN_DIR_SHIFT 14 +#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT) +#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT) +#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT) +#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT) + +#define PIN_VAL_SHIFT 15 +#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT) +#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT) +#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) +#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) + +#define PIN_SLPM_PULL_SHIFT 16 +#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL(x) \ + (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL_NONE \ + ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL_UP \ + ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL_DOWN \ + ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT) + +#define PIN_SLPM_DIR_SHIFT 19 +#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT) +#define PIN_SLPM_DIR(x) \ + (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT) +#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT) +#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT) + +#define PIN_SLPM_VAL_SHIFT 21 +#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT) +#define PIN_SLPM_VAL(x) \ + (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT) +#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT) +#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT) + +#define PIN_SLPM_PDIS_SHIFT 23 +#define PIN_SLPM_PDIS_MASK (0x3 << PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS(x) \ + (((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS_NO_CHANGE (0 << PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS_DISABLED (1 << PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS_ENABLED (2 << PIN_SLPM_PDIS_SHIFT) + +#define PIN_LOWEMI_SHIFT 25 +#define PIN_LOWEMI_MASK (0x1 << PIN_LOWEMI_SHIFT) +#define PIN_LOWEMI(x) (((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT) +#define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT) +#define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT) + +#define PIN_GPIOMODE_SHIFT 26 +#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT) + +#define PIN_SLEEPMODE_SHIFT 27 +#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT) + + +/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ +#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) +#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) +#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE) +#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) +#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) + +#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN) +#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP) +#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE) +#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW) +#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH) + +#define PIN_CFG_DEFAULT (0) + +#define PIN_CFG(num, alt) \ + (PIN_CFG_DEFAULT |\ + (PIN_NUM(num) | PIN_##alt)) + +#define PIN_CFG_INPUT(num, alt, pull) \ + (PIN_CFG_DEFAULT |\ + (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull)) + +#define PIN_CFG_OUTPUT(num, alt, val) \ + (PIN_CFG_DEFAULT |\ + (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val)) + +/* + * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving + * the "gpio" namespace for generic and cross-machine functions + */ + +#define GPIO_BLOCK_SHIFT 5 +#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) +#define NMK_MAX_BANKS DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP) + +/* Register in the logic block */ +#define NMK_GPIO_DAT 0x00 +#define NMK_GPIO_DATS 0x04 +#define NMK_GPIO_DATC 0x08 +#define NMK_GPIO_PDIS 0x0c +#define NMK_GPIO_DIR 0x10 +#define NMK_GPIO_DIRS 0x14 +#define NMK_GPIO_DIRC 0x18 +#define NMK_GPIO_SLPC 0x1c +#define NMK_GPIO_AFSLA 0x20 +#define NMK_GPIO_AFSLB 0x24 +#define NMK_GPIO_LOWEMI 0x28 + +#define NMK_GPIO_RIMSC 0x40 +#define NMK_GPIO_FIMSC 0x44 +#define NMK_GPIO_IS 0x48 +#define NMK_GPIO_IC 0x4c +#define NMK_GPIO_RWIMSC 0x50 +#define NMK_GPIO_FWIMSC 0x54 +#define NMK_GPIO_WKS 0x58 +/* These appear in DB8540 and later ASICs */ +#define NMK_GPIO_EDGELEVEL 0x5C +#define NMK_GPIO_LEVEL 0x60 + + +/* Pull up/down values */ +enum nmk_gpio_pull { + NMK_GPIO_PULL_NONE, + NMK_GPIO_PULL_UP, + NMK_GPIO_PULL_DOWN, +}; + +/* Sleep mode */ +enum nmk_gpio_slpm { + NMK_GPIO_SLPM_INPUT, + NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT, + NMK_GPIO_SLPM_NOCHANGE, + NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, +}; + +struct nmk_gpio_chip { + struct gpio_chip chip; + struct irq_chip irqchip; + void __iomem *addr; + struct clk *clk; + unsigned int bank; + unsigned int parent_irq; + int latent_parent_irq; + u32 (*get_latent_status)(unsigned int bank); + void (*set_ioforce)(bool enable); + spinlock_t lock; + bool sleepmode; + /* Keep track of configured edges */ + u32 edge_rising; + u32 edge_falling; + u32 real_wake; + u32 rwimsc; + u32 fwimsc; + u32 rimsc; + u32 fimsc; + u32 pull_up; + u32 lowemi; +}; + +/** + * struct nmk_pinctrl - state container for the Nomadik pin controller + * @dev: containing device pointer + * @pctl: corresponding pin controller device + * @soc: SoC data for this specific chip + * @prcm_base: PRCM register range virtual base + */ +struct nmk_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + const struct nmk_pinctrl_soc_data *soc; + void __iomem *prcm_base; +}; + +static struct nmk_gpio_chip *nmk_gpio_chips[NMK_MAX_BANKS]; + +static DEFINE_SPINLOCK(nmk_gpio_slpm_lock); + +#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips) + +static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int gpio_mode) +{ + u32 afunc, bfunc; + + afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~BIT(offset); + bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~BIT(offset); + if (gpio_mode & NMK_GPIO_ALT_A) + afunc |= BIT(offset); + if (gpio_mode & NMK_GPIO_ALT_B) + bfunc |= BIT(offset); + writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); + writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); +} + +static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, + unsigned offset, enum nmk_gpio_slpm mode) +{ + u32 slpm; + + slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC); + if (mode == NMK_GPIO_SLPM_NOCHANGE) + slpm |= BIT(offset); + else + slpm &= ~BIT(offset); + writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC); +} + +static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, + unsigned offset, enum nmk_gpio_pull pull) +{ + u32 pdis; + + pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS); + if (pull == NMK_GPIO_PULL_NONE) { + pdis |= BIT(offset); + nmk_chip->pull_up &= ~BIT(offset); + } else { + pdis &= ~BIT(offset); + } + + writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS); + + if (pull == NMK_GPIO_PULL_UP) { + nmk_chip->pull_up |= BIT(offset); + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATS); + } else if (pull == NMK_GPIO_PULL_DOWN) { + nmk_chip->pull_up &= ~BIT(offset); + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATC); + } +} + +static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip, + unsigned offset, bool lowemi) +{ + bool enabled = nmk_chip->lowemi & BIT(offset); + + if (lowemi == enabled) + return; + + if (lowemi) + nmk_chip->lowemi |= BIT(offset); + else + nmk_chip->lowemi &= ~BIT(offset); + + writel_relaxed(nmk_chip->lowemi, + nmk_chip->addr + NMK_GPIO_LOWEMI); +} + +static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, + unsigned offset) +{ + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRC); +} + +static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int val) +{ + if (val) + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATS); + else + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATC); +} + +static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int val) +{ + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRS); + __nmk_gpio_set_output(nmk_chip, offset, val); +} + +static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int gpio_mode, + bool glitch) +{ + u32 rwimsc = nmk_chip->rwimsc; + u32 fwimsc = nmk_chip->fwimsc; + + if (glitch && nmk_chip->set_ioforce) { + u32 bit = BIT(offset); + + /* Prevent spurious wakeups */ + writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC); + writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC); + + nmk_chip->set_ioforce(true); + } + + __nmk_gpio_set_mode(nmk_chip, offset, gpio_mode); + + if (glitch && nmk_chip->set_ioforce) { + nmk_chip->set_ioforce(false); + + writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC); + writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC); + } +} + +static void +nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) +{ + u32 falling = nmk_chip->fimsc & BIT(offset); + u32 rising = nmk_chip->rimsc & BIT(offset); + int gpio = nmk_chip->chip.base + offset; + int irq = irq_find_mapping(nmk_chip->chip.irq.domain, offset); + struct irq_data *d = irq_get_irq_data(irq); + + if (!rising && !falling) + return; + + if (!d || !irqd_irq_disabled(d)) + return; + + if (rising) { + nmk_chip->rimsc &= ~BIT(offset); + writel_relaxed(nmk_chip->rimsc, + nmk_chip->addr + NMK_GPIO_RIMSC); + } + + if (falling) { + nmk_chip->fimsc &= ~BIT(offset); + writel_relaxed(nmk_chip->fimsc, + nmk_chip->addr + NMK_GPIO_FIMSC); + } + + dev_dbg(nmk_chip->chip.parent, "%d: clearing interrupt mask\n", gpio); +} + +static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value) +{ + u32 val; + + val = readl(reg); + val = ((val & ~mask) | (value & mask)); + writel(val, reg); +} + +static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, + unsigned offset, unsigned alt_num) +{ + int i; + u16 reg; + u8 bit; + u8 alt_index; + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + if (!npct->prcm_base) + return; + + if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { + dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", + alt_num); + return; + } + + for (i = 0 ; i < npct->soc->npins_altcx ; i++) { + if (npct->soc->altcx_pins[i].pin == offset) + break; + } + if (i == npct->soc->npins_altcx) { + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", + offset); + return; + } + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + + /* + * If alt_num is NULL, just clear current ALTCx selection + * to make sure we come back to a pure ALTC selection + */ + if (!alt_num) { + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (readl(npct->prcm_base + reg) & BIT(bit)) { + nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + return; + } + + alt_index = alt_num - 1; + if (pin_desc->altcx[alt_index].used == false) { + dev_warn(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", + offset, alt_num); + return; + } + + /* + * Check if any other ALTCx functions are activated on this pin + * and disable it first. + */ + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (i == alt_index) + continue; + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (readl(npct->prcm_base + reg) & BIT(bit)) { + nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + + reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; + bit = pin_desc->altcx[alt_index].control_bit; + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", + offset, alt_index+1); + nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit)); +} + +/* + * Safe sequence used to switch IOs between GPIO and Alternate-C mode: + * - Save SLPM registers + * - Set SLPM=0 for the IOs you want to switch and others to 1 + * - Configure the GPIO registers for the IOs that are being switched + * - Set IOFORCE=1 + * - Modify the AFLSA/B registers for the IOs that are being switched + * - Set IOFORCE=0 + * - Restore SLPM registers + * - Any spurious wake up event during switch sequence to be ignored and + * cleared + */ +static void nmk_gpio_glitch_slpm_init(unsigned int *slpm) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + unsigned int temp = slpm[i]; + + if (!chip) + break; + + clk_enable(chip->clk); + + slpm[i] = readl(chip->addr + NMK_GPIO_SLPC); + writel(temp, chip->addr + NMK_GPIO_SLPC); + } +} + +static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + break; + + writel(slpm[i], chip->addr + NMK_GPIO_SLPC); + + clk_disable(chip->clk); + } +} + +static int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) +{ + int i; + u16 reg; + u8 bit; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + if (!npct->prcm_base) + return NMK_GPIO_ALT_C; + + for (i = 0; i < npct->soc->npins_altcx; i++) { + if (npct->soc->altcx_pins[i].pin == gpio) + break; + } + if (i == npct->soc->npins_altcx) + return NMK_GPIO_ALT_C; + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) { + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (readl(npct->prcm_base + reg) & BIT(bit)) + return NMK_GPIO_ALT_C+i+1; + } + } + return NMK_GPIO_ALT_C; +} + +/* IRQ functions */ + +static void nmk_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + + clk_enable(nmk_chip->clk); + writel(BIT(d->hwirq), nmk_chip->addr + NMK_GPIO_IC); + clk_disable(nmk_chip->clk); +} + +enum nmk_gpio_irq_type { + NORMAL, + WAKE, +}; + +static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, + int offset, enum nmk_gpio_irq_type which, + bool enable) +{ + u32 *rimscval; + u32 *fimscval; + u32 rimscreg; + u32 fimscreg; + + if (which == NORMAL) { + rimscreg = NMK_GPIO_RIMSC; + fimscreg = NMK_GPIO_FIMSC; + rimscval = &nmk_chip->rimsc; + fimscval = &nmk_chip->fimsc; + } else { + rimscreg = NMK_GPIO_RWIMSC; + fimscreg = NMK_GPIO_FWIMSC; + rimscval = &nmk_chip->rwimsc; + fimscval = &nmk_chip->fwimsc; + } + + /* we must individually set/clear the two edges */ + if (nmk_chip->edge_rising & BIT(offset)) { + if (enable) + *rimscval |= BIT(offset); + else + *rimscval &= ~BIT(offset); + writel(*rimscval, nmk_chip->addr + rimscreg); + } + if (nmk_chip->edge_falling & BIT(offset)) { + if (enable) + *fimscval |= BIT(offset); + else + *fimscval &= ~BIT(offset); + writel(*fimscval, nmk_chip->addr + fimscreg); + } +} + +static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, + int offset, bool on) +{ + /* + * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is + * disabled, since setting SLPM to 1 increases power consumption, and + * wakeup is anyhow controlled by the RIMSC and FIMSC registers. + */ + if (nmk_chip->sleepmode && on) { + __nmk_gpio_set_slpm(nmk_chip, offset, + NMK_GPIO_SLPM_WAKEUP_ENABLE); + } + + __nmk_gpio_irq_modify(nmk_chip, offset, WAKE, on); +} + +static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + + nmk_chip = irq_data_get_irq_chip_data(d); + if (!nmk_chip) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + spin_lock(&nmk_chip->lock); + + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable); + + if (!(nmk_chip->real_wake & BIT(d->hwirq))) + __nmk_gpio_set_wake(nmk_chip, d->hwirq, enable); + + spin_unlock(&nmk_chip->lock); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +static void nmk_gpio_irq_mask(struct irq_data *d) +{ + nmk_gpio_irq_maskunmask(d, false); +} + +static void nmk_gpio_irq_unmask(struct irq_data *d) +{ + nmk_gpio_irq_maskunmask(d, true); +} + +static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + + nmk_chip = irq_data_get_irq_chip_data(d); + if (!nmk_chip) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + spin_lock(&nmk_chip->lock); + + if (irqd_irq_disabled(d)) + __nmk_gpio_set_wake(nmk_chip, d->hwirq, on); + + if (on) + nmk_chip->real_wake |= BIT(d->hwirq); + else + nmk_chip->real_wake &= ~BIT(d->hwirq); + + spin_unlock(&nmk_chip->lock); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + bool enabled = !irqd_irq_disabled(d); + bool wake = irqd_is_wakeup_set(d); + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + + nmk_chip = irq_data_get_irq_chip_data(d); + if (!nmk_chip) + return -EINVAL; + if (type & IRQ_TYPE_LEVEL_HIGH) + return -EINVAL; + if (type & IRQ_TYPE_LEVEL_LOW) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_chip->lock, flags); + + if (enabled) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false); + + if (enabled || wake) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false); + + nmk_chip->edge_rising &= ~BIT(d->hwirq); + if (type & IRQ_TYPE_EDGE_RISING) + nmk_chip->edge_rising |= BIT(d->hwirq); + + nmk_chip->edge_falling &= ~BIT(d->hwirq); + if (type & IRQ_TYPE_EDGE_FALLING) + nmk_chip->edge_falling |= BIT(d->hwirq); + + if (enabled) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true); + + if (enabled || wake) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true); + + spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +static unsigned int nmk_gpio_irq_startup(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + clk_enable(nmk_chip->clk); + nmk_gpio_irq_unmask(d); + return 0; +} + +static void nmk_gpio_irq_shutdown(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + nmk_gpio_irq_mask(d); + clk_disable(nmk_chip->clk); +} + +static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status) +{ + struct irq_chip *host_chip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + + chained_irq_enter(host_chip, desc); + + while (status) { + int bit = __ffs(status); + + generic_handle_irq(irq_find_mapping(chip->irq.domain, bit)); + status &= ~BIT(bit); + } + + chained_irq_exit(host_chip, desc); +} + +static void nmk_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + u32 status; + + clk_enable(nmk_chip->clk); + status = readl(nmk_chip->addr + NMK_GPIO_IS); + clk_disable(nmk_chip->clk); + + __nmk_gpio_irq_handler(desc, status); +} + +static void nmk_gpio_latent_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + u32 status = nmk_chip->get_latent_status(nmk_chip->bank); + + __nmk_gpio_irq_handler(desc, status); +} + +/* I/O Functions */ + +static int nmk_gpio_get_dir(struct gpio_chip *chip, unsigned offset) +{ + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + int dir; + + clk_enable(nmk_chip->clk); + + dir = !(readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset)); + + clk_disable(nmk_chip->clk); + + return dir; +} + +static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) +{ + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + + clk_enable(nmk_chip->clk); + + writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRC); + + clk_disable(nmk_chip->clk); + + return 0; +} + +static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) +{ + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + int value; + + clk_enable(nmk_chip->clk); + + value = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & BIT(offset)); + + clk_disable(nmk_chip->clk); + + return value; +} + +static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + + clk_enable(nmk_chip->clk); + + __nmk_gpio_set_output(nmk_chip, offset, val); + + clk_disable(nmk_chip->clk); +} + +static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + + clk_enable(nmk_chip->clk); + + __nmk_gpio_make_output(nmk_chip, offset, val); + + clk_disable(nmk_chip->clk); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int nmk_gpio_get_mode(struct nmk_gpio_chip *nmk_chip, int offset) +{ + u32 afunc, bfunc; + + clk_enable(nmk_chip->clk); + + afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & BIT(offset); + bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & BIT(offset); + + clk_disable(nmk_chip->clk); + + return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); +} + +#include <linux/seq_file.h> + +static void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, struct gpio_chip *chip, + unsigned offset, unsigned gpio) +{ + const char *label = gpiochip_is_requested(chip, offset); + struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); + int mode; + bool is_out; + bool data_out; + bool pull; + const char *modes[] = { + [NMK_GPIO_ALT_GPIO] = "gpio", + [NMK_GPIO_ALT_A] = "altA", + [NMK_GPIO_ALT_B] = "altB", + [NMK_GPIO_ALT_C] = "altC", + [NMK_GPIO_ALT_C+1] = "altC1", + [NMK_GPIO_ALT_C+2] = "altC2", + [NMK_GPIO_ALT_C+3] = "altC3", + [NMK_GPIO_ALT_C+4] = "altC4", + }; + const char *pulls[] = { + "none ", + "pull down", + "pull up ", + }; + + clk_enable(nmk_chip->clk); + is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset)); + pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & BIT(offset)); + data_out = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & BIT(offset)); + mode = nmk_gpio_get_mode(nmk_chip, offset); + if ((mode == NMK_GPIO_ALT_C) && pctldev) + mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio); + + if (is_out) { + seq_printf(s, " gpio-%-3d (%-20.20s) out %s %s", + gpio, + label ?: "(none)", + data_out ? "hi" : "lo", + (mode < 0) ? "unknown" : modes[mode]); + } else { + int irq = gpio_to_irq(gpio); + struct irq_desc *desc = irq_to_desc(irq); + int pullidx = 0; + int val; + + if (pull) + pullidx = data_out ? 2 : 1; + + seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s", + gpio, + label ?: "(none)", + pulls[pullidx], + (mode < 0) ? "unknown" : modes[mode]); + + val = nmk_gpio_get_input(chip, offset); + seq_printf(s, " VAL %d", val); + + /* + * This races with request_irq(), set_irq_type(), + * and set_irq_wake() ... but those are "rare". + */ + if (irq > 0 && desc && desc->action) { + char *trigger; + + if (nmk_chip->edge_rising & BIT(offset)) + trigger = "edge-rising"; + else if (nmk_chip->edge_falling & BIT(offset)) + trigger = "edge-falling"; + else + trigger = "edge-undefined"; + + seq_printf(s, " irq-%d %s%s", + irq, trigger, + irqd_is_wakeup_set(&desc->irq_data) + ? " wakeup" : ""); + } + } + clk_disable(nmk_chip->clk); +} + +static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned i; + unsigned gpio = chip->base; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio); + seq_printf(s, "\n"); + } +} + +#else +static inline void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, unsigned gpio) +{ +} +#define nmk_gpio_dbg_show NULL +#endif + +/* + * We will allocate memory for the state container using devm* allocators + * binding to the first device reaching this point, it doesn't matter if + * it is the pin controller or GPIO driver. However we need to use the right + * platform device when looking up resources so pay attention to pdev. + */ +static struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np, + struct platform_device *pdev) +{ + struct nmk_gpio_chip *nmk_chip; + struct platform_device *gpio_pdev; + struct gpio_chip *chip; + struct resource *res; + struct clk *clk; + void __iomem *base; + u32 id; + + gpio_pdev = of_find_device_by_node(np); + if (!gpio_pdev) { + pr_err("populate \"%s\": device not found\n", np->name); + return ERR_PTR(-ENODEV); + } + if (of_property_read_u32(np, "gpio-bank", &id)) { + dev_err(&pdev->dev, "populate: gpio-bank property not found\n"); + return ERR_PTR(-EINVAL); + } + + /* Already populated? */ + nmk_chip = nmk_gpio_chips[id]; + if (nmk_chip) + return nmk_chip; + + nmk_chip = devm_kzalloc(&pdev->dev, sizeof(*nmk_chip), GFP_KERNEL); + if (!nmk_chip) + return ERR_PTR(-ENOMEM); + + nmk_chip->bank = id; + chip = &nmk_chip->chip; + chip->base = id * NMK_GPIO_PER_CHIP; + chip->ngpio = NMK_GPIO_PER_CHIP; + chip->label = dev_name(&gpio_pdev->dev); + chip->parent = &gpio_pdev->dev; + + res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return ERR_CAST(base); + nmk_chip->addr = base; + + clk = clk_get(&gpio_pdev->dev, NULL); + if (IS_ERR(clk)) + return (void *) clk; + clk_prepare(clk); + nmk_chip->clk = clk; + + BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); + nmk_gpio_chips[id] = nmk_chip; + return nmk_chip; +} + +static int nmk_gpio_probe(struct platform_device *dev) +{ + struct device_node *np = dev->dev.of_node; + struct nmk_gpio_chip *nmk_chip; + struct gpio_chip *chip; + struct irq_chip *irqchip; + int latent_irq; + bool supports_sleepmode; + int irq; + int ret; + + nmk_chip = nmk_gpio_populate_chip(np, dev); + if (IS_ERR(nmk_chip)) { + dev_err(&dev->dev, "could not populate nmk chip struct\n"); + return PTR_ERR(nmk_chip); + } + + supports_sleepmode = + of_property_read_bool(np, "st,supports-sleepmode"); + + /* Correct platform device ID */ + dev->id = nmk_chip->bank; + + irq = platform_get_irq(dev, 0); + if (irq < 0) + return irq; + + /* It's OK for this IRQ not to be present */ + latent_irq = platform_get_irq(dev, 1); + + /* + * The virt address in nmk_chip->addr is in the nomadik register space, + * so we can simply convert the resource address, without remapping + */ + nmk_chip->parent_irq = irq; + nmk_chip->latent_parent_irq = latent_irq; + nmk_chip->sleepmode = supports_sleepmode; + spin_lock_init(&nmk_chip->lock); + + chip = &nmk_chip->chip; + chip->request = gpiochip_generic_request; + chip->free = gpiochip_generic_free; + chip->get_direction = nmk_gpio_get_dir; + chip->direction_input = nmk_gpio_make_input; + chip->get = nmk_gpio_get_input; + chip->direction_output = nmk_gpio_make_output; + chip->set = nmk_gpio_set_output; + chip->dbg_show = nmk_gpio_dbg_show; + chip->can_sleep = false; + chip->owner = THIS_MODULE; + + irqchip = &nmk_chip->irqchip; + irqchip->irq_ack = nmk_gpio_irq_ack; + irqchip->irq_mask = nmk_gpio_irq_mask; + irqchip->irq_unmask = nmk_gpio_irq_unmask; + irqchip->irq_set_type = nmk_gpio_irq_set_type; + irqchip->irq_set_wake = nmk_gpio_irq_set_wake; + irqchip->irq_startup = nmk_gpio_irq_startup; + irqchip->irq_shutdown = nmk_gpio_irq_shutdown; + irqchip->flags = IRQCHIP_MASK_ON_SUSPEND; + irqchip->name = kasprintf(GFP_KERNEL, "nmk%u-%u-%u", + dev->id, + chip->base, + chip->base + chip->ngpio - 1); + + clk_enable(nmk_chip->clk); + nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI); + clk_disable(nmk_chip->clk); + chip->of_node = np; + + ret = gpiochip_add_data(chip, nmk_chip); + if (ret) + return ret; + + platform_set_drvdata(dev, nmk_chip); + + /* + * Let the generic code handle this edge IRQ, the the chained + * handler will perform the actual work of handling the parent + * interrupt. + */ + ret = gpiochip_irqchip_add(chip, + irqchip, + 0, + handle_edge_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&dev->dev, "could not add irqchip\n"); + gpiochip_remove(&nmk_chip->chip); + return -ENODEV; + } + /* Then register the chain on the parent IRQ */ + gpiochip_set_chained_irqchip(chip, + irqchip, + nmk_chip->parent_irq, + nmk_gpio_irq_handler); + if (nmk_chip->latent_parent_irq > 0) + gpiochip_set_chained_irqchip(chip, + irqchip, + nmk_chip->latent_parent_irq, + nmk_gpio_latent_irq_handler); + + dev_info(&dev->dev, "at address %p\n", nmk_chip->addr); + + return 0; +} + +static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->ngroups; +} + +static const char *nmk_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->groups[selector].name; +} + +static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + *pins = npct->soc->groups[selector].pins; + *num_pins = npct->soc->groups[selector].npins; + return 0; +} + +static struct nmk_gpio_chip *find_nmk_gpio_from_pin(unsigned pin) +{ + int i; + struct nmk_gpio_chip *nmk_gpio; + + for(i = 0; i < NMK_MAX_BANKS; i++) { + nmk_gpio = nmk_gpio_chips[i]; + if (!nmk_gpio) + continue; + if (pin >= nmk_gpio->chip.base && + pin < nmk_gpio->chip.base + nmk_gpio->chip.ngpio) + return nmk_gpio; + } + return NULL; +} + +static struct gpio_chip *find_gc_from_pin(unsigned pin) +{ + struct nmk_gpio_chip *nmk_gpio = find_nmk_gpio_from_pin(pin); + + if (nmk_gpio) + return &nmk_gpio->chip; + return NULL; +} + +static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + struct gpio_chip *chip = find_gc_from_pin(offset); + + if (!chip) { + seq_printf(s, "invalid pin offset"); + return; + } + nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); +} + +static int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function) +{ + if (*num_maps == *reserved_maps) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +static int nmk_dt_add_map_configs(struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps, const char *group, + unsigned long *configs, unsigned num_configs) +{ + unsigned long *dup_configs; + + if (*num_maps == *reserved_maps) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) + return -ENOMEM; + + (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN; + + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +#define NMK_CONFIG_PIN(x, y) { .property = x, .config = y, } +#define NMK_CONFIG_PIN_ARRAY(x, y) { .property = x, .choice = y, \ + .size = ARRAY_SIZE(y), } + +static const unsigned long nmk_pin_input_modes[] = { + PIN_INPUT_NOPULL, + PIN_INPUT_PULLUP, + PIN_INPUT_PULLDOWN, +}; + +static const unsigned long nmk_pin_output_modes[] = { + PIN_OUTPUT_LOW, + PIN_OUTPUT_HIGH, + PIN_DIR_OUTPUT, +}; + +static const unsigned long nmk_pin_sleep_modes[] = { + PIN_SLEEPMODE_DISABLED, + PIN_SLEEPMODE_ENABLED, +}; + +static const unsigned long nmk_pin_sleep_input_modes[] = { + PIN_SLPM_INPUT_NOPULL, + PIN_SLPM_INPUT_PULLUP, + PIN_SLPM_INPUT_PULLDOWN, + PIN_SLPM_DIR_INPUT, +}; + +static const unsigned long nmk_pin_sleep_output_modes[] = { + PIN_SLPM_OUTPUT_LOW, + PIN_SLPM_OUTPUT_HIGH, + PIN_SLPM_DIR_OUTPUT, +}; + +static const unsigned long nmk_pin_sleep_wakeup_modes[] = { + PIN_SLPM_WAKEUP_DISABLE, + PIN_SLPM_WAKEUP_ENABLE, +}; + +static const unsigned long nmk_pin_gpio_modes[] = { + PIN_GPIOMODE_DISABLED, + PIN_GPIOMODE_ENABLED, +}; + +static const unsigned long nmk_pin_sleep_pdis_modes[] = { + PIN_SLPM_PDIS_DISABLED, + PIN_SLPM_PDIS_ENABLED, +}; + +struct nmk_cfg_param { + const char *property; + unsigned long config; + const unsigned long *choice; + int size; +}; + +static const struct nmk_cfg_param nmk_cfg_params[] = { + NMK_CONFIG_PIN_ARRAY("ste,input", nmk_pin_input_modes), + NMK_CONFIG_PIN_ARRAY("ste,output", nmk_pin_output_modes), + NMK_CONFIG_PIN_ARRAY("ste,sleep", nmk_pin_sleep_modes), + NMK_CONFIG_PIN_ARRAY("ste,sleep-input", nmk_pin_sleep_input_modes), + NMK_CONFIG_PIN_ARRAY("ste,sleep-output", nmk_pin_sleep_output_modes), + NMK_CONFIG_PIN_ARRAY("ste,sleep-wakeup", nmk_pin_sleep_wakeup_modes), + NMK_CONFIG_PIN_ARRAY("ste,gpio", nmk_pin_gpio_modes), + NMK_CONFIG_PIN_ARRAY("ste,sleep-pull-disable", nmk_pin_sleep_pdis_modes), +}; + +static int nmk_dt_pin_config(int index, int val, unsigned long *config) +{ + int ret = 0; + + if (nmk_cfg_params[index].choice == NULL) + *config = nmk_cfg_params[index].config; + else { + /* test if out of range */ + if (val < nmk_cfg_params[index].size) { + *config = nmk_cfg_params[index].config | + nmk_cfg_params[index].choice[val]; + } + } + return ret; +} + +static const char *nmk_find_pin_name(struct pinctrl_dev *pctldev, const char *pin_name) +{ + int i, pin_number; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1) + for (i = 0; i < npct->soc->npins; i++) + if (npct->soc->pins[i].number == pin_number) + return npct->soc->pins[i].name; + return NULL; +} + +static bool nmk_pinctrl_dt_get_config(struct device_node *np, + unsigned long *configs) +{ + bool has_config = 0; + unsigned long cfg = 0; + int i, val, ret; + + for (i = 0; i < ARRAY_SIZE(nmk_cfg_params); i++) { + ret = of_property_read_u32(np, + nmk_cfg_params[i].property, &val); + if (ret != -EINVAL) { + if (nmk_dt_pin_config(i, val, &cfg) == 0) { + *configs |= cfg; + has_config = 1; + } + } + } + + return has_config; +} + +static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + int ret; + const char *function = NULL; + unsigned long configs = 0; + bool has_config = 0; + struct property *prop; + struct device_node *np_config; + + ret = of_property_read_string(np, "function", &function); + if (ret >= 0) { + const char *group; + + ret = of_property_count_strings(np, "groups"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "groups", prop, group) { + ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps, + group, function); + if (ret < 0) + goto exit; + } + } + + has_config = nmk_pinctrl_dt_get_config(np, &configs); + np_config = of_parse_phandle(np, "ste,config", 0); + if (np_config) + has_config |= nmk_pinctrl_dt_get_config(np_config, &configs); + if (has_config) { + const char *gpio_name; + const char *pin; + + ret = of_property_count_strings(np, "pins"); + if (ret < 0) + goto exit; + ret = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "pins", prop, pin) { + gpio_name = nmk_find_pin_name(pctldev, pin); + + ret = nmk_dt_add_map_configs(map, reserved_maps, + num_maps, + gpio_name, &configs, 1); + if (ret < 0) + goto exit; + } + } + +exit: + return ret; +} + +static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + unsigned reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) { + pinctrl_utils_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; +} + +static const struct pinctrl_ops nmk_pinctrl_ops = { + .get_groups_count = nmk_get_groups_cnt, + .get_group_name = nmk_get_group_name, + .get_group_pins = nmk_get_group_pins, + .pin_dbg_show = nmk_pin_dbg_show, + .dt_node_to_map = nmk_pinctrl_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->nfunctions; +} + +static const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->functions[function].name; +} + +static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + *groups = npct->soc->functions[function].groups; + *num_groups = npct->soc->functions[function].ngroups; + + return 0; +} + +static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + const struct nmk_pingroup *g; + static unsigned int slpm[NUM_BANKS]; + unsigned long flags = 0; + bool glitch; + int ret = -EINVAL; + int i; + + g = &npct->soc->groups[group]; + + if (g->altsetting < 0) + return -EINVAL; + + dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins); + + /* + * If we're setting altfunc C by setting both AFSLA and AFSLB to 1, + * we may pass through an undesired state. In this case we take + * some extra care. + * + * Safe sequence used to switch IOs between GPIO and Alternate-C mode: + * - Save SLPM registers (since we have a shadow register in the + * nmk_chip we're using that as backup) + * - Set SLPM=0 for the IOs you want to switch and others to 1 + * - Configure the GPIO registers for the IOs that are being switched + * - Set IOFORCE=1 + * - Modify the AFLSA/B registers for the IOs that are being switched + * - Set IOFORCE=0 + * - Restore SLPM registers + * - Any spurious wake up event during switch sequence to be ignored + * and cleared + * + * We REALLY need to save ALL slpm registers, because the external + * IOFORCE will switch *all* ports to their sleepmode setting to as + * to avoid glitches. (Not just one port!) + */ + glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); + + if (glitch) { + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + + /* Initially don't put any pins to sleep when switching */ + memset(slpm, 0xff, sizeof(slpm)); + + /* + * Then mask the pins that need to be sleeping now when we're + * switching to the ALT C function. + */ + for (i = 0; i < g->npins; i++) + slpm[g->pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->pins[i]); + nmk_gpio_glitch_slpm_init(slpm); + } + + for (i = 0; i < g->npins; i++) { + struct nmk_gpio_chip *nmk_chip; + unsigned bit; + + nmk_chip = find_nmk_gpio_from_pin(g->pins[i]); + if (!nmk_chip) { + dev_err(npct->dev, + "invalid pin offset %d in group %s at index %d\n", + g->pins[i], g->name, i); + goto out_glitch; + } + dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting); + + clk_enable(nmk_chip->clk); + bit = g->pins[i] % NMK_GPIO_PER_CHIP; + /* + * If the pin is switching to altfunc, and there was an + * interrupt installed on it which has been lazy disabled, + * actually mask the interrupt to prevent spurious interrupts + * that would occur while the pin is under control of the + * peripheral. Only SKE does this. + */ + nmk_gpio_disable_lazy_irq(nmk_chip, bit); + + __nmk_gpio_set_mode_safe(nmk_chip, bit, + (g->altsetting & NMK_GPIO_ALT_C), glitch); + clk_disable(nmk_chip->clk); + + /* + * Call PRCM GPIOCR config function in case ALTC + * has been selected: + * - If selection is a ALTCx, some bits in PRCM GPIOCR registers + * must be set. + * - If selection is pure ALTC and previous selection was ALTCx, + * then some bits in PRCM GPIOCR registers must be cleared. + */ + if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) + nmk_prcm_altcx_set_mode(npct, g->pins[i], + g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); + } + + /* When all pins are successfully reconfigured we get here */ + ret = 0; + +out_glitch: + if (glitch) { + nmk_gpio_glitch_slpm_restore(slpm); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + } + + return ret; +} + +static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct nmk_gpio_chip *nmk_chip; + struct gpio_chip *chip; + unsigned bit; + + if (!range) { + dev_err(npct->dev, "invalid range\n"); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "missing GPIO chip in range\n"); + return -EINVAL; + } + chip = range->gc; + nmk_chip = gpiochip_get_data(chip); + + dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); + + clk_enable(nmk_chip->clk); + bit = offset % NMK_GPIO_PER_CHIP; + /* There is no glitch when converting any pin to GPIO */ + __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); + clk_disable(nmk_chip->clk); + + return 0; +} + +static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); + /* Set the pin to some default state, GPIO is usually default */ +} + +static const struct pinmux_ops nmk_pinmux_ops = { + .get_functions_count = nmk_pmx_get_funcs_cnt, + .get_function_name = nmk_pmx_get_func_name, + .get_function_groups = nmk_pmx_get_func_groups, + .set_mux = nmk_pmx_set, + .gpio_request_enable = nmk_gpio_request_enable, + .gpio_disable_free = nmk_gpio_disable_free, + .strict = true, +}; + +static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) +{ + /* Not implemented */ + return -EINVAL; +} + +static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *configs, unsigned num_configs) +{ + static const char *pullnames[] = { + [NMK_GPIO_PULL_NONE] = "none", + [NMK_GPIO_PULL_UP] = "up", + [NMK_GPIO_PULL_DOWN] = "down", + [3] /* illegal */ = "??" + }; + static const char *slpmnames[] = { + [NMK_GPIO_SLPM_INPUT] = "input/wakeup", + [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", + }; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct nmk_gpio_chip *nmk_chip; + unsigned bit; + pin_cfg_t cfg; + int pull, slpm, output, val, i; + bool lowemi, gpiomode, sleep; + + nmk_chip = find_nmk_gpio_from_pin(pin); + if (!nmk_chip) { + dev_err(npct->dev, + "invalid pin offset %d\n", pin); + return -EINVAL; + } + + for (i = 0; i < num_configs; i++) { + /* + * The pin config contains pin number and altfunction fields, + * here we just ignore that part. It's being handled by the + * framework and pinmux callback respectively. + */ + cfg = (pin_cfg_t) configs[i]; + pull = PIN_PULL(cfg); + slpm = PIN_SLPM(cfg); + output = PIN_DIR(cfg); + val = PIN_VAL(cfg); + lowemi = PIN_LOWEMI(cfg); + gpiomode = PIN_GPIOMODE(cfg); + sleep = PIN_SLEEPMODE(cfg); + + if (sleep) { + int slpm_pull = PIN_SLPM_PULL(cfg); + int slpm_output = PIN_SLPM_DIR(cfg); + int slpm_val = PIN_SLPM_VAL(cfg); + + /* All pins go into GPIO mode at sleep */ + gpiomode = true; + + /* + * The SLPM_* values are normal values + 1 to allow zero + * to mean "same as normal". + */ + if (slpm_pull) + pull = slpm_pull - 1; + if (slpm_output) + output = slpm_output - 1; + if (slpm_val) + val = slpm_val - 1; + + dev_dbg(nmk_chip->chip.parent, + "pin %d: sleep pull %s, dir %s, val %s\n", + pin, + slpm_pull ? pullnames[pull] : "same", + slpm_output ? (output ? "output" : "input") + : "same", + slpm_val ? (val ? "high" : "low") : "same"); + } + + dev_dbg(nmk_chip->chip.parent, + "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n", + pin, cfg, pullnames[pull], slpmnames[slpm], + output ? "output " : "input", + output ? (val ? "high" : "low") : "", + lowemi ? "on" : "off"); + + clk_enable(nmk_chip->clk); + bit = pin % NMK_GPIO_PER_CHIP; + if (gpiomode) + /* No glitch when going to GPIO mode */ + __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); + if (output) + __nmk_gpio_make_output(nmk_chip, bit, val); + else { + __nmk_gpio_make_input(nmk_chip, bit); + __nmk_gpio_set_pull(nmk_chip, bit, pull); + } + /* TODO: isn't this only applicable on output pins? */ + __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi); + + __nmk_gpio_set_slpm(nmk_chip, bit, slpm); + clk_disable(nmk_chip->clk); + } /* for each config */ + + return 0; +} + +static const struct pinconf_ops nmk_pinconf_ops = { + .pin_config_get = nmk_pin_config_get, + .pin_config_set = nmk_pin_config_set, +}; + +static struct pinctrl_desc nmk_pinctrl_desc = { + .name = "pinctrl-nomadik", + .pctlops = &nmk_pinctrl_ops, + .pmxops = &nmk_pinmux_ops, + .confops = &nmk_pinconf_ops, + .owner = THIS_MODULE, +}; + +static const struct of_device_id nmk_pinctrl_match[] = { + { + .compatible = "stericsson,stn8815-pinctrl", + .data = (void *)PINCTRL_NMK_STN8815, + }, + { + .compatible = "stericsson,db8500-pinctrl", + .data = (void *)PINCTRL_NMK_DB8500, + }, + { + .compatible = "stericsson,db8540-pinctrl", + .data = (void *)PINCTRL_NMK_DB8540, + }, + {}, +}; + +#ifdef CONFIG_PM_SLEEP +static int nmk_pinctrl_suspend(struct device *dev) +{ + struct nmk_pinctrl *npct; + + npct = dev_get_drvdata(dev); + if (!npct) + return -EINVAL; + + return pinctrl_force_sleep(npct->pctl); +} + +static int nmk_pinctrl_resume(struct device *dev) +{ + struct nmk_pinctrl *npct; + + npct = dev_get_drvdata(dev); + if (!npct) + return -EINVAL; + + return pinctrl_force_default(npct->pctl); +} +#endif + +static int nmk_pinctrl_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device_node *np = pdev->dev.of_node; + struct device_node *prcm_np; + struct nmk_pinctrl *npct; + unsigned int version = 0; + int i; + + npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); + if (!npct) + return -ENOMEM; + + match = of_match_device(nmk_pinctrl_match, &pdev->dev); + if (!match) + return -ENODEV; + version = (unsigned int) match->data; + + /* Poke in other ASIC variants here */ + if (version == PINCTRL_NMK_STN8815) + nmk_pinctrl_stn8815_init(&npct->soc); + if (version == PINCTRL_NMK_DB8500) + nmk_pinctrl_db8500_init(&npct->soc); + if (version == PINCTRL_NMK_DB8540) + nmk_pinctrl_db8540_init(&npct->soc); + + /* + * Since we depend on the GPIO chips to provide clock and register base + * for the pin control operations, make sure that we have these + * populated before we continue. Follow the phandles to instantiate + * them. The GPIO portion of the actual hardware may be probed before + * or after this point: it shouldn't matter as the APIs are orthogonal. + */ + for (i = 0; i < NMK_MAX_BANKS; i++) { + struct device_node *gpio_np; + struct nmk_gpio_chip *nmk_chip; + + gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i); + if (gpio_np) { + dev_info(&pdev->dev, + "populate NMK GPIO %d \"%s\"\n", + i, gpio_np->name); + nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev); + if (IS_ERR(nmk_chip)) + dev_err(&pdev->dev, + "could not populate nmk chip struct " + "- continue anyway\n"); + of_node_put(gpio_np); + } + } + + prcm_np = of_parse_phandle(np, "prcm", 0); + if (prcm_np) { + npct->prcm_base = of_iomap(prcm_np, 0); + of_node_put(prcm_np); + } + if (!npct->prcm_base) { + if (version == PINCTRL_NMK_STN8815) { + dev_info(&pdev->dev, + "No PRCM base, " + "assuming no ALT-Cx control is available\n"); + } else { + dev_err(&pdev->dev, "missing PRCM base address\n"); + return -EINVAL; + } + } + + nmk_pinctrl_desc.pins = npct->soc->pins; + nmk_pinctrl_desc.npins = npct->soc->npins; + npct->dev = &pdev->dev; + + npct->pctl = devm_pinctrl_register(&pdev->dev, &nmk_pinctrl_desc, npct); + if (IS_ERR(npct->pctl)) { + dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n"); + return PTR_ERR(npct->pctl); + } + + platform_set_drvdata(pdev, npct); + dev_info(&pdev->dev, "initialized Nomadik pin control driver\n"); + + return 0; +} + +static const struct of_device_id nmk_gpio_match[] = { + { .compatible = "st,nomadik-gpio", }, + {} +}; + +static struct platform_driver nmk_gpio_driver = { + .driver = { + .name = "gpio", + .of_match_table = nmk_gpio_match, + }, + .probe = nmk_gpio_probe, +}; + +static SIMPLE_DEV_PM_OPS(nmk_pinctrl_pm_ops, + nmk_pinctrl_suspend, + nmk_pinctrl_resume); + +static struct platform_driver nmk_pinctrl_driver = { + .driver = { + .name = "pinctrl-nomadik", + .of_match_table = nmk_pinctrl_match, + .pm = &nmk_pinctrl_pm_ops, + }, + .probe = nmk_pinctrl_probe, +}; + +static int __init nmk_gpio_init(void) +{ + return platform_driver_register(&nmk_gpio_driver); +} +subsys_initcall(nmk_gpio_init); + +static int __init nmk_pinctrl_init(void) +{ + return platform_driver_register(&nmk_pinctrl_driver); +} +core_initcall(nmk_pinctrl_init); diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.h b/drivers/pinctrl/nomadik/pinctrl-nomadik.h new file mode 100644 index 000000000..ae0bac066 --- /dev/null +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef PINCTRL_PINCTRL_NOMADIK_H +#define PINCTRL_PINCTRL_NOMADIK_H + +/* Package definitions */ +#define PINCTRL_NMK_STN8815 0 +#define PINCTRL_NMK_DB8500 1 +#define PINCTRL_NMK_DB8540 2 + +/* Alternate functions: function C is set in hw by setting both A and B */ +#define NMK_GPIO_ALT_GPIO 0 +#define NMK_GPIO_ALT_A 1 +#define NMK_GPIO_ALT_B 2 +#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) + +#define NMK_GPIO_ALT_CX_SHIFT 2 +#define NMK_GPIO_ALT_C1 ((1<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C2 ((2<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C3 ((3<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C4 ((4<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) + +#define PRCM_GPIOCR_ALTCX(pin_num,\ + altc1_used, altc1_ri, altc1_cb,\ + altc2_used, altc2_ri, altc2_cb,\ + altc3_used, altc3_ri, altc3_cb,\ + altc4_used, altc4_ri, altc4_cb)\ +{\ + .pin = pin_num,\ + .altcx[PRCM_IDX_GPIOCR_ALTC1] = {\ + .used = altc1_used,\ + .reg_index = altc1_ri,\ + .control_bit = altc1_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC2] = {\ + .used = altc2_used,\ + .reg_index = altc2_ri,\ + .control_bit = altc2_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC3] = {\ + .used = altc3_used,\ + .reg_index = altc3_ri,\ + .control_bit = altc3_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC4] = {\ + .used = altc4_used,\ + .reg_index = altc4_ri,\ + .control_bit = altc4_cb\ + },\ +} + +/** + * enum prcm_gpiocr_reg_index + * Used to reference an PRCM GPIOCR register address. + */ +enum prcm_gpiocr_reg_index { + PRCM_IDX_GPIOCR1, + PRCM_IDX_GPIOCR2, + PRCM_IDX_GPIOCR3 +}; +/** + * enum prcm_gpiocr_altcx_index + * Used to reference an Other alternate-C function. + */ +enum prcm_gpiocr_altcx_index { + PRCM_IDX_GPIOCR_ALTC1, + PRCM_IDX_GPIOCR_ALTC2, + PRCM_IDX_GPIOCR_ALTC3, + PRCM_IDX_GPIOCR_ALTC4, + PRCM_IDX_GPIOCR_ALTC_MAX, +}; + +/** + * struct prcm_gpio_altcx - Other alternate-C function + * @used: other alternate-C function availability + * @reg_index: PRCM GPIOCR register index used to control the function + * @control_bit: PRCM GPIOCR bit used to control the function + */ +struct prcm_gpiocr_altcx { + bool used:1; + u8 reg_index:2; + u8 control_bit:5; +} __packed; + +/** + * struct prcm_gpio_altcx_pin_desc - Other alternate-C pin + * @pin: The pin number + * @altcx: array of other alternate-C[1-4] functions + */ +struct prcm_gpiocr_altcx_pin_desc { + unsigned short pin; + struct prcm_gpiocr_altcx altcx[PRCM_IDX_GPIOCR_ALTC_MAX]; +}; + +/** + * struct nmk_function - Nomadik pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct nmk_function { + const char *name; + const char * const *groups; + unsigned ngroups; +}; + +/** + * struct nmk_pingroup - describes a Nomadik pin group + * @name: the name of this specific pin group + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @num_pins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + * @altsetting: the altsetting to apply to all pins in this group to + * configure them to be used by a function + */ +struct nmk_pingroup { + const char *name; + const unsigned int *pins; + const unsigned npins; + int altsetting; +}; + +/** + * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration + * @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: The functions supported on this SoC. + * @nfunction: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + * @altcx_pins: The pins that support Other alternate-C function on this SoC + * @npins_altcx: The number of Other alternate-C pins + * @prcm_gpiocr_registers: The array of PRCM GPIOCR registers on this SoC + */ +struct nmk_pinctrl_soc_data { + const struct pinctrl_pin_desc *pins; + unsigned npins; + const struct nmk_function *functions; + unsigned nfunctions; + const struct nmk_pingroup *groups; + unsigned ngroups; + const struct prcm_gpiocr_altcx_pin_desc *altcx_pins; + unsigned npins_altcx; + const u16 *prcm_gpiocr_registers; +}; + +#ifdef CONFIG_PINCTRL_STN8815 + +void nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +#ifdef CONFIG_PINCTRL_DB8500 + +void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +#ifdef CONFIG_PINCTRL_DB8540 + +void nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +#endif /* PINCTRL_PINCTRL_NOMADIK_H */ |