Add pinctrl/pinmux support for the Aspeed AST2400 SoC. Configuration of the SoC is somewhat involved: Enabling functions can involve writes of multiple bits to multiple registers, and signals provided by a pin are determined on a priority basis. That is, without care, it's possible to configure a function in the mux and to not gain expected functionality. Signed-off-by: Andrew Jeffery <andrew@xxxxxxxx> --- drivers/pinctrl/pinctrl-ast2400.c | 1488 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1488 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-ast2400.c diff --git a/drivers/pinctrl/pinctrl-ast2400.c b/drivers/pinctrl/pinctrl-ast2400.c new file mode 100644 index 000000000000..0f0c19005046 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ast2400.c @@ -0,0 +1,1488 @@ +/* + * Copyright (C) 2016 IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/string.h> +#include <linux/types.h> + +#include "core.h" +#include "pinctrl-utils.h" + +/* Challenges in the AST2400 Multifunction Pin Design + * -------------------------------------------------- + * + * * Reasonable number of pins (216) + * + * * The SoC function enabled on a pin is determined on a priority basis + * + * * Using the priority system, pins can provide up to 3 different signals + * types + * + * * The signal active on a pin is often described by compound logical + * expressions involving multiple operators, registers and bits + * + * * The high and low priority functions' bit masks are frequently not the + * same + * (i.e. cannot just flip a bit to change from high to low), or even in the + * same register. + * + * * Not all functions are disabled by unsetting bits, some require setting + * bits + * + * * Not all signals can be deactivated as some expressions depend on values + * in the hardware strapping register, which is treated as read-only. + * + * SoC Multi-function Pin Expression Examples + * ------------------------------------------ + * + * Here are some sample mux configurations from the datasheet to illustrate the + * corner cases, roughly in order of least to most corner. In the table, HP and + * LP are high- and low- priority respectively. + * + * D6 is a pin with a single (i.e. aside from GPIO), high priority signal + * that participates in one function: + * + * Ball | Default | HP Signal | HP Expression | LP Signal | LP Expression | GPIO Name + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * D6 GPIOA0 MAC1LINK SCU80[0]=1 GPIOA0 + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * + * C5 is a multi-signal pin (both high and low priority signals). Here we touch + * different registers for the different functions that enable each signal: + * + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * C5 GPIOA4 SCL9 SCU90[22]=1 TIMER5 SCU80[4]=1 GPIOA4 + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * + * E19 is a single-signal pin with two functions that influence the active + * signal. In this case both bits have the same meaning - enable a dedicated + * LPC reset pin. However it's not always the case that the bits in the + * OR-relationship have the same meaning. + * + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * E19 GPIOB4 LPCRST# SCU80[12]=1 | Strap[14]=1 GPIOB4 + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * + * For example, pin B19 has a low-priority signal that's enabled by two + * distinct SoC functions: A specific SIOPBI bit in SCUA4, and an ACPI bit + * in the STRAP register. The ACPI bit configures signals on pins in addition + * to B19. Both of the low priority functions as well as the high priority + * function must be disabled for GPIOF1 to be used. + * + * Ball | Default | HP Signal | HP Expression | LP Signal | LP Expression | GPIO Name + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * B19 GPIOF1 NDCD4 SCU80[25]=1 SIOPBI# SCUA4[12]=1 | Strap[19]=0 GPIOF1 + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * + * For pin E18, the SoC ANDs the expected state of three bits to determine the + * pin's active signal: + * + * * SCU3C[3]: Enable external SOC reset function + * * SCU80[15]: Enable SPICS1# or EXTRST# function pin + * * SCU90[31]: Select SPI interface CS# output + * + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * E18 GPIOB7 EXTRST# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0 SPICS1# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1 GPIOB7 + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * + * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for + * selecting the signals on pin E18) + * + * Pin T5 is a multi-signal pin with a more complex configuration: + * + * Ball | Default | HP Signal | HP Expression | LP Signal | LP Expression | GPIO Name + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * T5 GPIOL1 VPIDE SCU90[5:4]!=0 & SCU84[17]=1 NDCD1 SCU84[17]=1 GPIOL1 + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * + * The high priority signal configuration is best thought of in terms of its + * exploded form, with reference to the SCU90[5:4] bits: + * + * * SCU90[5:4]=00: disable + * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode. + * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode. + * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode. + * + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * T5 GPIOL1 VPIDE (SCU90[5:4]=1 & SCU84[17]=1) NDCD1 SCU84[17]=1 GPIOL1 + * | (SCU90[5:4]=2 & SCU84[17]=1) + * | (SCU90[5:4]=3 & SCU84[17]=1) + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * + * For reference the SCU84[17] bit enables the "UART1 NDCD1 or Video VPIDE + * function pin", where the signal itself is determined by whether SCU94[5:4] + * is disabled or in one of the 18, 24 or 30bit video modes. + * + * Other video-input-related pins require an explicit state in SCU90[5:4]: + * + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * W1 GPIOL6 VPIB0 SCU90[5:4]=3 & SCU84[22]=1 TXD1 SCU84[22]=1 GPIOL6 + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * + * The examples of T5 and W1 are particularly fertile, as they also demonstrate + * that despite operating as part of the video input bus each signal needs to + * be enabled individually via it's own SCU84 (in the cases of T5 and W1) + * register bit. This is a little crazy if the bus doesn't have optional + * signals, but is used to decent effect with some of the UARTs where not all + * signals are required. However, this isn't done consistently - UART1 is + * enabled on a per-pin basis, and by contrast, all signals for UART6 are + * enabled by a single bit. + * + * Ultimately the requirement to control pins like T5 drive the design: + * + * * Pins provide signals according to functions activated in the mux + * configuration + * + * * Pins provide two to three signals in a priority order + * + * * For priorities levels defined on a pin, each priority provides one signal + * + * * Enabling lower priority signals requires higher priority signals be + * disabled + * + * * A function represents a set of signals; functions are distinct if their + * sets of signals are not equal + * + * * Signals participate in one or more functions + * + * * A function is described by an expression of one or more function + * descriptors, which compare bit values in a register + * + * * A function expression is the smallest set of function descriptors whose + * comparisons must evaluate 'true' for a function to be enabled. + * + * * A function is active if evaluating every function descriptor in the + * function expression yields a 'true' result + * + * * A signal at a given priority on a given pin is active if any of the + * functions in which the signal participates are active, and no higher + * priority signal on the pin is active + * + * * GPIO is configured per-pin + * + * And so: + * + * * To disable a signal, any function(s) activating the signal must be + * disabled + * + * * Each pin must know the expressions of functions in which it participates, + * for the purpose of enabling GPIO. This is done by deactivating all + * functions that activate higher priority signals on the pin (except in the + * case of GPIO[TUV], where GPIO is the high priority function). + * + * As a concrete example: + * + * * T5 provides three signals types: VPIDE, NDCD1 and GPIO + * + * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30 + * + * * The NDCD1 signal participates in just its own NDCD1 function + * + * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least + * prioritised + * + * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24 + * and VPI30 functions all be disabled + * + * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled + * to provide GPIOL6 + * + * Considerations + * -------------- + * + * * If pinctrl allows us to allocate a pin we can configure a function without + * concern for the function of already allocated pins, if pin groups are + * created with respect to the SoC functions in which they participate (I felt + * this was worth mentioning as it didn't seem obvious from the bit/pin + * relationships; I've done some network analysis on the problem). + * + * * Conversely, failing to allocate all pins in a group indicates some + * bits (as well as pins) required for the group's configuration will + * already be in use, likely in a way that's inconsistent with the + * requirements of the failed group. + * + * * Implement data structures such that we can lean on the compiler to avoid + * or catch errors + * + * * Define symbols for structures so they can be referenced by name + * + * * Compiler enforces unique symbol names, detecting copy/paste errors + * * Compiler errors on undefined symbol names, detecting typos or missing + * information + * + * * Compiler can calculate array sizes for us + * + * * Implement macros such that we can lean on the CPP to + * + * * Avoid duplicate specification of information where possible + * * Reduce line noise of type declaration and assignment + */ + + /** + * A function descriptor, which describes the register, bits and the + * enable/disable values that should be compared or written. + * + * @reg: The register offset from base in bytes + * @mask: The mask to apply to the register. The lowest set bit of the mask is + * used to derive the shift value. + * @enable: The value that enables the function. Value should be in the LSBs, + * not at the position of the mask. + * @disable: The value that disables the function. Value should be in the + * LSBs, not at the position of the mask. + */ +struct func_desc { + unsigned reg; + u32 mask; + u32 enable; + u32 disable; +}; + +/** + * Describes a function expression. The expression is evaluated by ANDing the + * evaluation of the descriptors. + * + * @name: The function name + * @ndescs: The number of function descriptors in the expression + * @descs: Pointer to an array of function descriptors that comprise the + * function expression + */ +struct func_expr { + const char *name; + int ndescs; + const struct func_desc *descs; +}; + +/** + * A struct capturing the function expressions enabling signals at each + * priority for a given pin. A high or low priority signal configuration is + * evaluated by ORing the evaluation of the function expressions in the + * respective priority's list. + * + * @high: A NULL-terminated list of function expressions that enable the + * high-priority signal + * @low: A NULL-terminated list of function expressions that enable the + * low-priority signal + * @other: The name of the "other" function, enabled by disabling the high and + * low priority signals + */ +struct pin_prio { + const struct func_expr **high; + const struct func_expr **low; + const char *other; +}; + +/* Macro hell */ + +/** + * Short-hand macro describing a mux function enabled by the state of one bit. + * The disable value is derived. + * + * @reg: The function's associated register, offset from base + * @idx: The function's bit index in the register + * @val: The value (0 or 1) that enables the function + */ +#define FUNC_DESC_BIT(reg, idx, val) \ + { reg, BIT_MASK(idx), val, ((val + 1) & 1) } + +/** + * A further short-hand macro describing a mux function enabled with a set bit. + * + * @reg: The function's associated register, offset from base + * @idx: The function's bit index in the register + */ +#define FUNC_DESC_SET(reg, idx) FUNC_DESC_BIT(reg, idx, 1) + +#define FUNC_DESC_LIST_SYM(func) func_descs_ ## func +#define FUNC_DESC_LIST_DECL(func, ...) \ + static const struct func_desc FUNC_DESC_LIST_SYM(func)[] = \ + { __VA_ARGS__ } + +#define FUNC_EXPR_SYM(func) func_expr_ ## func +#define FUNC_EXPR_DECL_(func) \ + static const struct func_expr FUNC_EXPR_SYM(func) = \ + { \ + .name = #func, \ + .ndescs = ARRAY_SIZE(FUNC_DESC_LIST_SYM(func)), \ + .descs = &(FUNC_DESC_LIST_SYM(func))[0], \ + } + +/** + * Declare a function expression. + * + * @func: A macro symbol name for the function (is subjected to stringification + * and token pasting) + * @...: Function descriptors that define the function expression + * + * For example, the following declares the ACPI function: + * + * FUNC_EXPR_DECL(ACPI, FUNC_DESC_BIT(STRAP, 19, 0)); + * + * And (with a few defines left out for brevity) the following declares the + * 8-signal ROM function: + * + * FUNC_EXPR_DECL(ROM8, + * VPOOFF0_DESC, + * ROMEN_0_DESC, + * ROMEN_1_DESC, + * ROMEN_2_DESC); + */ +#define FUNC_EXPR_DECL(func, ...) \ + FUNC_DESC_LIST_DECL(func, __VA_ARGS__); \ + FUNC_EXPR_DECL_(func) + +/** + * Declare a pointer to a function expression + * + * @func: The macro symbol name for the function (subjected to token pasting) + */ +#define FUNC_EXPR_PTR(func) (&FUNC_EXPR_SYM(func)) + +#define FUNC_EXPR_LIST_SYM(func) func_exprs_ ## func + +/** + * Declare a function list for reference in a struct pin_prio. + * + * @func: A macro symbol name for the function (is subjected to token pasting) + * @...: Function expression structure pointers (use FUNC_EXPR_POINTER()) + */ +#define FUNC_EXPR_LIST_DECL(func, ...) \ + const struct func_expr *FUNC_EXPR_LIST_SYM(func)[] = { __VA_ARGS__ } + +/** + * A short-hand macro for declaring an expression list consisting of a single + * function. + * + * @func: A macro symbol name for the function (is subjected to token pasting) + */ +#define FUNC_EXPR_LIST_DECL_SINGLE(func) \ + FUNC_EXPR_LIST_DECL(func, FUNC_EXPR_PTR(func), NULL) + +#define FUNC_EXPR_LIST_PTR(func) (&FUNC_EXPR_LIST_SYM(func)[0]) + +/** + * A short-hand macro for declaring a function expression and an expression + * list with a single function. + * + * @func: A macro symbol name for the function (is subjected to token pasting) + * @...: Function descriptors that define the function expression + */ +#define FUNC_EXPR_DECL_SINGLE(func, ...) \ + FUNC_DESC_LIST_DECL(func, __VA_ARGS__); \ + FUNC_EXPR_DECL_(func); \ + FUNC_EXPR_LIST_DECL(func, FUNC_EXPR_PTR(func), NULL) + +#define PIN_SYM(pin) pin_ ## pin + +#define MS_PIN_DECL_(pin, other, high, low) \ + static const struct pin_prio PIN_SYM(pin) = { high, low, #other } + +/** + * Declare a multi-signal pin + * + * @pin: The pin number + * @other: Macro name for "other" functionality (subjected to stringification) + * @high: Macro name for the high signal functions + * @low: Macro name for the low signal functions + * + * For example: + * + * FUNC_EXPR_DECL_SINGLE(SD1, FUNC_DESC_SET(SCU90, 0)); + * FUNC_EXPR_DECL_SINGLE(I2C10, FUNC_DESC_SET(SCU90, 23)); + * + * #define C4 16 + * MS_PIN_DECL(C4, GPIOC0, SD1, I2C10); + * #define B3 17 + * MS_PIN_DECL(B3, GPIOC1, SD1, I2C10); + */ +#define MS_PIN_DECL(pin, other, high, low) \ + MS_PIN_DECL_(pin, other, \ + FUNC_EXPR_LIST_PTR(high), \ + FUNC_EXPR_LIST_PTR(low)) + +#define PIN_GROUP_SYM(func) pins_ ## func +#define FUNC_GROUP_SYM(func) groups_ ## func +#define FUNC_GROUP_DECL(func, ...) \ + static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \ + static const char *const FUNC_GROUP_SYM(func)[] = { #func } + +/** + * Declare a single signal pin + * + * @pin: The pin number + * @other: Macro name for "other" functionality (subjected to stringification) + * @func: Macro name for the function + * + * For example: + * + * FUNC_EXPR_DECL_SINGLE(I2C5, FUNC_DESC_SET(SCU90, 18)); + * + * #define E3 80 + * SS_PIN_DECL(E3, GPIOK0, I2C5); + * + * #define D2 81 + * SS_PIN_DECL(D2, GPIOK1, I2C5); + */ +#define SS_PIN_DECL(pin, other, func) \ + MS_PIN_DECL_(pin, other, FUNC_EXPR_LIST_PTR(func), NULL) + +/** + * Single signal, single function pin declaration + * + * @pin: The pin number + * @other: Macro name for "other" functionality (subjected to stringification) + * @func: Macro name for the function + * @...: Function descriptors that define the function expression + * + * For example: + * + * SSSF_PIN_DECL(A4, GPIOA2, TIMER3, FUNC_DESC_SET(SCU80, 2)); + */ +#define SSSF_PIN_DECL(pin, other, func, ...) \ + FUNC_EXPR_DECL(func, __VA_ARGS__); \ + FUNC_EXPR_LIST_DECL(func, FUNC_EXPR_PTR(func), NULL); \ + MS_PIN_DECL_(pin, other, FUNC_EXPR_LIST_PTR(func), NULL); \ + FUNC_GROUP_DECL(func, pin) + +#define SCU3C 0x3C +#define STRAP 0x70 +#define SCU80 0x80 +#define SCU84 0x84 +#define SCU88 0x88 +#define SCU8C 0x8C +#define SCU90 0x90 +#define SCU94 0x94 +#define SCUA4 0xA4 + +/* Use undefined macros for symbol naming and references, eg GPIOA0, MAC1LINK, + * TIMER3 etc. + */ + +/* Pins are defined in GPIO bank order: + * + * GPIOA0: 0 + * ... + * GPIOA7: 7 + * ... + * GPIOB0: 8 + * ... + * GPIOZ7: 207 + * GPIOAA0: 208 + * ... + * GPIOAB3: 219 + * + * Not all pins have their signals defined. + */ + +#define A4 2 +SSSF_PIN_DECL(A4, GPIOA2, TIMER3, FUNC_DESC_SET(SCU80, 2)); + +FUNC_EXPR_DECL_SINGLE(SD1, FUNC_DESC_SET(SCU90, 0)); + +FUNC_EXPR_DECL_SINGLE(I2C10, FUNC_DESC_SET(SCU90, 23)); + +#define C4 16 +MS_PIN_DECL(C4, GPIOC0, SD1, I2C10); +#define B3 17 +MS_PIN_DECL(B3, GPIOC1, SD1, I2C10); + +FUNC_GROUP_DECL(I2C10, C4, B3); + +FUNC_EXPR_DECL_SINGLE(I2C11, FUNC_DESC_SET(SCU90, 24)); + +#define A2 18 +MS_PIN_DECL(A2, GPIOC2, SD1, I2C11); +#define E5 19 +MS_PIN_DECL(E5, GPIOC3, SD1, I2C11); + +FUNC_GROUP_DECL(I2C11, A2, E5); + +FUNC_EXPR_DECL_SINGLE(I2C12, FUNC_DESC_SET(SCU90, 25)); + +#define D4 20 +MS_PIN_DECL(D4, GPIOC4, SD1, I2C12); +#define C3 21 +MS_PIN_DECL(C3, GPIOC5, SD1, I2C12); + +FUNC_GROUP_DECL(I2C12, D4, C3); + +FUNC_EXPR_DECL_SINGLE(I2C13, FUNC_DESC_SET(SCU90, 26)); + +#define B2 22 +MS_PIN_DECL(B2, GPIOC6, SD1, I2C13); +#define A1 23 +MS_PIN_DECL(A1, GPIOC7, SD1, I2C13); + +FUNC_GROUP_DECL(I2C13, B2, A1); +FUNC_GROUP_DECL(SD1, C4, B3, A2, E5, D4, C3, B2, A1); + +#define D18 40 +SSSF_PIN_DECL(D18, GPIOF0, NCTS4, FUNC_DESC_SET(SCU80, 24)); + +FUNC_EXPR_DECL(ACPI, FUNC_DESC_BIT(STRAP, 19, 0)); + +#define B19 41 +FUNC_EXPR_DECL(NDCD4, FUNC_DESC_SET(SCU80, 25)); +FUNC_EXPR_LIST_DECL_SINGLE(NDCD4); +FUNC_EXPR_DECL(SIOPBI, FUNC_DESC_SET(SCUA4, 12)); +FUNC_EXPR_LIST_DECL(SIOPBI, FUNC_EXPR_PTR(SIOPBI), FUNC_EXPR_PTR(ACPI), NULL); +MS_PIN_DECL(B19, GPIOF1, NDCD4, SIOPBI); +FUNC_GROUP_DECL(NDCD4, B19); +FUNC_GROUP_DECL(SIOPBI, B19); + +#define D17 43 +FUNC_EXPR_DECL(NRI4, FUNC_DESC_SET(SCU80, 27)); +FUNC_EXPR_LIST_DECL_SINGLE(NRI4); +FUNC_EXPR_DECL(SIOPBO, FUNC_DESC_SET(SCUA4, 14)); +FUNC_EXPR_LIST_DECL(SIOPBO, FUNC_EXPR_PTR(SIOPBO), FUNC_EXPR_PTR(ACPI), NULL); +MS_PIN_DECL(D17, GPIOF3, NRI4, SIOPBO); +FUNC_GROUP_DECL(NRI4, D17); +FUNC_GROUP_DECL(SIOPBO, D17); + +FUNC_GROUP_DECL(ACPI, B19, D17); + +#define E16 46 +SSSF_PIN_DECL(E16, GPIOF6, TXD4, FUNC_DESC_SET(SCU80, 30)); + +#define C17 47 +SSSF_PIN_DECL(C17, GPIOF7, RXD4, FUNC_DESC_SET(SCU80, 31)); + +#define AA22 54 +SSSF_PIN_DECL(AA22, GPIOG6, FLBUSY, FUNC_DESC_SET(SCU84, 6)); + +#define U18 55 +SSSF_PIN_DECL(U18, GPIOG7, FLWP, FUNC_DESC_SET(SCU84, 7)); + +/* The following descriptors describe incomplete list of signals for VPO/ROM, + * enough to cover the pins which we need to configure in the OpenPOWER + * Palmetto BMC. Some functions require separate functions be disabled, so + * we're describing masks for those separate functions and setting the enabled + * value to the disabled value. Also, GENMASK() is used to require a range of + * set bits, where each signal has its own activation bit rather than all being + * activated by a single bit. + */ +#define VPOOFF0_DESC { SCU94, GENMASK(1, 0), 0, 0 } +#define ROMEN_0_DESC \ + { SCU88, GENMASK(29, 24), GENMASK(5, 0), 0 } +#define ROMEN_1_DESC \ + { SCU8C, GENMASK(7, 0), GENMASK(7, 0), 0 } +#define ROMEN_2_DESC { SCU94, BIT_MASK(1), 0, 0 } +#define ROMEN_3_DESC \ + { STRAP, GENMASK(1, 0), 0, 0 } + +FUNC_EXPR_DECL(ROM8, + VPOOFF0_DESC, + ROMEN_0_DESC, + ROMEN_1_DESC, + ROMEN_2_DESC); + +/* ROM16 enabled by SCU90 */ +FUNC_EXPR_DECL(ROM16, + VPOOFF0_DESC, + ROMEN_0_DESC, + ROMEN_1_DESC, + ROMEN_2_DESC, + FUNC_DESC_SET(SCU90, 6)); + +/* ROM16 enabled by strapping register */ +FUNC_EXPR_DECL(ROM16S, + VPOOFF0_DESC, + ROMEN_0_DESC, + ROMEN_1_DESC, + ROMEN_2_DESC, + FUNC_DESC_SET(STRAP, 4), + ROMEN_3_DESC); + +FUNC_EXPR_LIST_DECL(ROM16, + FUNC_EXPR_PTR(ROM16), + FUNC_EXPR_PTR(ROM16S), + NULL); + +FUNC_EXPR_DECL_SINGLE(UART6, FUNC_DESC_SET(SCU90, 7)); + +#define A8 56 +MS_PIN_DECL(A8, GPIOH0, ROM16, UART6); + +#define C7 57 +MS_PIN_DECL(C7, GPIOH1, ROM16, UART6); + +#define B7 58 +MS_PIN_DECL(B7, GPIOH2, ROM16, UART6); + +#define A7 59 +MS_PIN_DECL(A7, GPIOH3, ROM16, UART6); + +#define D7 60 +MS_PIN_DECL(D7, GPIOH4, ROM16, UART6); + +#define B6 61 +MS_PIN_DECL(B6, GPIOH5, ROM16, UART6); + +#define A6 62 +MS_PIN_DECL(A6, GPIOH6, ROM16, UART6); + +#define E7 63 +MS_PIN_DECL(E7, GPIOH7, ROM16, UART6); + +FUNC_GROUP_DECL(UART6, A8, C7, B7, A7, D7, B6, A6, E7); + +#define T4 76 +SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, FUNC_DESC_SET(SCU84, 12)); + +#define U2 77 +SSSF_PIN_DECL(U2, GPIOJ5, VGAVS, FUNC_DESC_SET(SCU84, 13)); + +#define T2 78 +SSSF_PIN_DECL(T2, GPIOJ6, DDCCLK, FUNC_DESC_SET(SCU84, 14)); + +#define T1 79 +SSSF_PIN_DECL(T1, GPIOJ7, DDCDAT, FUNC_DESC_SET(SCU84, 15)); + +FUNC_EXPR_DECL_SINGLE(I2C5, FUNC_DESC_SET(SCU90, 18)); + +#define E3 80 +SS_PIN_DECL(E3, GPIOK0, I2C5); + +#define D2 81 +SS_PIN_DECL(D2, GPIOK1, I2C5); + +FUNC_GROUP_DECL(I2C5, E3, D2); + +FUNC_EXPR_DECL_SINGLE(I2C6, FUNC_DESC_SET(SCU90, 19)); + +#define C1 82 +SS_PIN_DECL(C1, GPIOK2, I2C6); + +#define F4 83 +SS_PIN_DECL(F4, GPIOK3, I2C6); + +FUNC_GROUP_DECL(I2C6, C1, F4); + +FUNC_EXPR_DECL_SINGLE(I2C7, FUNC_DESC_SET(SCU90, 20)); + +#define E2 84 +SS_PIN_DECL(E2, GPIOK4, I2C7); + +#define D1 85 +SS_PIN_DECL(D1, GPIOK5, I2C7); + +FUNC_GROUP_DECL(I2C7, E2, D1); + +FUNC_EXPR_DECL_SINGLE(I2C8, FUNC_DESC_SET(SCU90, 21)); + +#define G5 86 +SS_PIN_DECL(G5, GPIOK6, I2C8); + +#define F3 87 +SS_PIN_DECL(F3, GPIOK7, I2C8); + +FUNC_GROUP_DECL(I2C8, G5, F3); + +#define U1 88 +SSSF_PIN_DECL(U1, GPIOL0, NCTS1, FUNC_DESC_SET(SCU84, 16)); + +#define VPI18_DESC { SCU84, GENMASK(5, 4), 1, 0 } +#define VPI24_DESC { SCU84, GENMASK(5, 4), 2, 0 } +#define VPI30_DESC { SCU84, GENMASK(5, 4), 3, 0 } + +#define VPIEN_0_DESC \ + { SCU84, GENMASK(21, 17), GENMASK(4, 0), 0 } +#define VPIEN_1_DESC \ + { SCU84, GENMASK(23, 22), GENMASK(1, 0), 0 } +#define VPIEN_2_DESC \ + { SCU88, GENMASK(1, 0), GENMASK(1, 0), 0 } +#define VPIEN_3_DESC \ + { SCU88, GENMASK(5, 2), GENMASK(3, 0), 0 } +#define VPIEN_4_DESC \ + { SCU88, GENMASK(7, 6), GENMASK(1, 0), 0 } + +FUNC_EXPR_DECL(VPI18, + VPI18_DESC, + VPIEN_0_DESC, + VPIEN_3_DESC); + +FUNC_EXPR_DECL(VPI24, + VPI24_DESC, + VPIEN_0_DESC, + VPIEN_3_DESC, + VPIEN_4_DESC); + +FUNC_EXPR_DECL(VPI30, + VPI30_DESC, + VPIEN_0_DESC, + VPIEN_1_DESC, + VPIEN_2_DESC, + VPIEN_3_DESC); + +FUNC_EXPR_LIST_DECL(VPI, + FUNC_EXPR_PTR(VPI18), + FUNC_EXPR_PTR(VPI24), + FUNC_EXPR_PTR(VPI30), + NULL); + +#define T5 89 +FUNC_EXPR_DECL_SINGLE(NDCD1, FUNC_DESC_SET(SCU84, 17)); +MS_PIN_DECL(T5, GPIOL1, VPI, NDCD1); +FUNC_GROUP_DECL(NDCD1, T5); + +#define U3 90 +FUNC_EXPR_DECL_SINGLE(NDSR1, FUNC_DESC_SET(SCU84, 18)); +MS_PIN_DECL(U3, GPIOL2, VPI, NDSR1); +FUNC_GROUP_DECL(NDSR1, U3); + +#define V1 91 +FUNC_EXPR_DECL_SINGLE(NRI1, FUNC_DESC_SET(SCU84, 19)); +MS_PIN_DECL(V1, GPIOL3, VPI, NRI1); +FUNC_GROUP_DECL(NRI1, V1); + +#define U4 92 +FUNC_EXPR_DECL_SINGLE(NDTR1, FUNC_DESC_SET(SCU84, 20)); +MS_PIN_DECL(U4, GPIOL4, VPI, NDTR1); +FUNC_GROUP_DECL(NDTR1, U4); + +#define V2 93 +FUNC_EXPR_DECL_SINGLE(NRTS1, FUNC_DESC_SET(SCU84, 21)); +MS_PIN_DECL(V2, GPIOL5, VPI, NRTS1); +FUNC_GROUP_DECL(NRTS1, V2); + +#define W1 94 +FUNC_EXPR_DECL_SINGLE(TXD1, FUNC_DESC_SET(SCU84, 22)); +MS_PIN_DECL(W1, GPIOL6, VPI, TXD1); +FUNC_GROUP_DECL(TXD1, W1); + +#define U5 95 +FUNC_EXPR_DECL_SINGLE(RXD1, FUNC_DESC_SET(SCU84, 23)); +MS_PIN_DECL(U5, GPIOL7, VPI, RXD1); +FUNC_GROUP_DECL(RXD1, U5); + +#define W4 104 +FUNC_EXPR_DECL_SINGLE(PWM0, FUNC_DESC_SET(SCU88, 0)); +MS_PIN_DECL(W4, GPION0, VPI, PWM0); +FUNC_GROUP_DECL(PWM0, W4); + +#define Y3 105 +FUNC_EXPR_DECL_SINGLE(PWM1, FUNC_DESC_SET(SCU88, 1)); +MS_PIN_DECL(Y3, GPION1, VPI, PWM1); +FUNC_GROUP_DECL(PWM1, Y3); + +#define AA2 106 +FUNC_EXPR_DECL_SINGLE(PWM2, FUNC_DESC_SET(SCU88, 2)); +MS_PIN_DECL(AA2, GPION2, VPI, PWM2); +FUNC_GROUP_DECL(PWM2, AA2); + +#define AB1 107 +FUNC_EXPR_DECL_SINGLE(PWM3, FUNC_DESC_SET(SCU88, 3)); +MS_PIN_DECL(AB1, GPION3, VPI, PWM3); +FUNC_GROUP_DECL(PWM3, AB1); + +#define W5 108 +FUNC_EXPR_DECL_SINGLE(PWM4, FUNC_DESC_SET(SCU88, 4)); +MS_PIN_DECL(W5, GPION4, VPI, PWM4); +FUNC_GROUP_DECL(PWM4, W5); + +#define Y4 109 +FUNC_EXPR_DECL_SINGLE(PWM5, FUNC_DESC_SET(SCU88, 5)); +MS_PIN_DECL(Y4, GPION5, VPI, PWM5); +FUNC_GROUP_DECL(PWM5, Y4); + +#define AA3 110 +FUNC_EXPR_DECL_SINGLE(PWM6, FUNC_DESC_SET(SCU88, 6)); +MS_PIN_DECL(AA3, GPION6, VPI, PWM6); +FUNC_GROUP_DECL(PWM6, AA3); + +#define AB2 111 +FUNC_EXPR_DECL_SINGLE(PWM7, FUNC_DESC_SET(SCU88, 7)); +MS_PIN_DECL(AB2, GPION7, VPI, PWM7); +FUNC_GROUP_DECL(PWM7, AB2); + +FUNC_GROUP_DECL(VPI18, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2); +FUNC_GROUP_DECL(VPI24, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2); +FUNC_GROUP_DECL(VPI30, T5, U3, V1, U4, V2, W1, U5, W4, Y3, AA22, W5, Y4, AA3, + AB2); + +#define AA7 126 +SSSF_PIN_DECL(AA7, GPIOP6, BMCINT, FUNC_DESC_SET(SCU88, 22)); + +#define AB7 127 +SSSF_PIN_DECL(AB7, GPIOP7, FLACK, FUNC_DESC_SET(SCU88, 23)); + +FUNC_EXPR_DECL(I2C3, FUNC_DESC_SET(SCU90, 16)); +FUNC_EXPR_LIST_DECL_SINGLE(I2C3); + +#define D3 128 +SS_PIN_DECL(D3, GPIOQ0, I2C3); + +#define C2 129 +SS_PIN_DECL(C2, GPIOQ1, I2C3); + +FUNC_GROUP_DECL(I2C3, D3, C2); + +FUNC_EXPR_DECL_SINGLE(I2C4, FUNC_DESC_SET(SCU90, 17)); + +#define B1 130 +SS_PIN_DECL(B1, GPIOQ2, I2C4); + +#define F5 131 +SS_PIN_DECL(F5, GPIOQ3, I2C4); + +FUNC_GROUP_DECL(I2C4, B1, F5); + +#define VPOOFF1_DESC { SCU94, GENMASK(1, 0), 3, 0 } +#define VPO12_DESC { SCU94, GENMASK(1, 0), 1, 0 } +#define VPO24_DESC { SCU94, GENMASK(1, 0), 2, 0 } + +/* Enables an incomplete list of signals, only enough to cover the pins that we + * need to describe at the moment + */ +#define VPOEN_0_DESC \ + { SCU88, GENMASK(29, 28), GENMASK(1, 0), 0 } +#define VPOEN_1_DESC \ + { SCU8C, GENMASK(3, 0), GENMASK(3, 0), 0 } +#define VPOEN_2_DESC \ + { SCU8C, GENMASK(7, 6), GENMASK(1, 0), 0 } + +FUNC_EXPR_LIST_DECL(ROM, + FUNC_EXPR_PTR(ROM8), + FUNC_EXPR_PTR(ROM16), + FUNC_EXPR_PTR(ROM16S), + NULL); + +#define V20 136 +MS_PIN_DECL_(V20, GPIOR0, FUNC_EXPR_LIST_PTR(ROM), NULL); + +FUNC_EXPR_DECL(VPO12, + VPO12_DESC, + VPOEN_0_DESC, + VPOEN_1_DESC, + VPOEN_2_DESC); + +FUNC_EXPR_DECL(VPO24, + VPO24_DESC, + VPOEN_0_DESC, + VPOEN_1_DESC, + VPOEN_2_DESC); + +FUNC_EXPR_DECL(VPOOFF1, + VPOOFF1_DESC, + VPOEN_0_DESC, + VPOEN_1_DESC, + VPOEN_2_DESC); + +FUNC_EXPR_LIST_DECL(VPO, + FUNC_EXPR_PTR(VPO12), + FUNC_EXPR_PTR(VPO24), + FUNC_EXPR_PTR(VPOOFF1), + NULL); + +#define U21 144 +MS_PIN_DECL(U21, GPIOS0, ROM, VPO); + +#define T19 145 +MS_PIN_DECL(T19, GPIOS1, ROM, VPO); + +#define V22 146 +MS_PIN_DECL(V22, GPIOS2, ROM, VPO); + +#define U20 147 +MS_PIN_DECL(U20, GPIOS3, ROM, VPO); + +#define R18 148 +MS_PIN_DECL_(R18, GPIOS4, FUNC_EXPR_LIST_PTR(ROM), NULL); + +#define N21 149 +MS_PIN_DECL_(N21, GPIOS5, FUNC_EXPR_LIST_PTR(ROM), NULL); + +#define L22 150 +MS_PIN_DECL(L22, GPIOS6, ROM, VPO); + +#define K18 151 +MS_PIN_DECL(K18, GPIOS7, ROM, VPO); + +FUNC_GROUP_DECL(ROM8, V20, U21, T19, V22, U20, R18, N21, L22, K18); +FUNC_GROUP_DECL(ROM16, V20, U21, T19, V22, U20, R18, N21, L22, K18, + A8, C7, B7, A7, D7, B6, A6, E7); +FUNC_GROUP_DECL(VPO12, U21, T19, V22, U20); +FUNC_GROUP_DECL(VPO24, U21, T19, V22, U20, L22, K18); + +#define AST_PINCTRL_PIN(name_) \ + [name_] = { \ + .number = name_, \ + .name = #name_, \ + .drv_data = (void *) &(PIN_SYM(name_)) \ + } + +/* Note we account for GPIOY4-GPIOY7 even though they're not valid, thus 216 + * pins becomes 220. + */ +#define AST2400_NR_GPIOS 220 + +static struct pinctrl_pin_desc ast2400_pins[AST2400_NR_GPIOS] = { + AST_PINCTRL_PIN(A4), + AST_PINCTRL_PIN(C4), + AST_PINCTRL_PIN(B3), + AST_PINCTRL_PIN(A2), + AST_PINCTRL_PIN(E5), + AST_PINCTRL_PIN(D4), + AST_PINCTRL_PIN(C3), + AST_PINCTRL_PIN(B2), + AST_PINCTRL_PIN(A1), + AST_PINCTRL_PIN(D18), + AST_PINCTRL_PIN(B19), + AST_PINCTRL_PIN(D17), + AST_PINCTRL_PIN(E16), + AST_PINCTRL_PIN(C17), + AST_PINCTRL_PIN(AA22), + AST_PINCTRL_PIN(U18), + AST_PINCTRL_PIN(A8), + AST_PINCTRL_PIN(C7), + AST_PINCTRL_PIN(B7), + AST_PINCTRL_PIN(A7), + AST_PINCTRL_PIN(D7), + AST_PINCTRL_PIN(B6), + AST_PINCTRL_PIN(A6), + AST_PINCTRL_PIN(E7), + AST_PINCTRL_PIN(T4), + AST_PINCTRL_PIN(U2), + AST_PINCTRL_PIN(T2), + AST_PINCTRL_PIN(T1), + AST_PINCTRL_PIN(E3), + AST_PINCTRL_PIN(D2), + AST_PINCTRL_PIN(C1), + AST_PINCTRL_PIN(F4), + AST_PINCTRL_PIN(E2), + AST_PINCTRL_PIN(D1), + AST_PINCTRL_PIN(G5), + AST_PINCTRL_PIN(F3), + AST_PINCTRL_PIN(U1), + AST_PINCTRL_PIN(T5), + AST_PINCTRL_PIN(U3), + AST_PINCTRL_PIN(V1), + AST_PINCTRL_PIN(U4), + AST_PINCTRL_PIN(V2), + AST_PINCTRL_PIN(W1), + AST_PINCTRL_PIN(U5), + AST_PINCTRL_PIN(W4), + AST_PINCTRL_PIN(Y3), + AST_PINCTRL_PIN(AA2), + AST_PINCTRL_PIN(AB1), + AST_PINCTRL_PIN(W5), + AST_PINCTRL_PIN(Y4), + AST_PINCTRL_PIN(AA3), + AST_PINCTRL_PIN(AB2), + AST_PINCTRL_PIN(AA7), + AST_PINCTRL_PIN(AB7), + AST_PINCTRL_PIN(D3), + AST_PINCTRL_PIN(C2), + AST_PINCTRL_PIN(B1), + AST_PINCTRL_PIN(F5), + AST_PINCTRL_PIN(V20), + AST_PINCTRL_PIN(U21), + AST_PINCTRL_PIN(T19), + AST_PINCTRL_PIN(V22), + AST_PINCTRL_PIN(U20), + AST_PINCTRL_PIN(R18), + AST_PINCTRL_PIN(N21), + AST_PINCTRL_PIN(L22), + AST_PINCTRL_PIN(K18), +}; + +struct ast2400_pin_group { + const char *name; + const unsigned int *pins; + const unsigned npins; +}; + +#define AST_PINCTRL_GROUP(name_) { \ + .name = #name_, \ + .pins = &(PIN_GROUP_SYM(name_))[0], \ + .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \ +} + +static const struct ast2400_pin_group ast2400_groups[] = { + AST_PINCTRL_GROUP(TIMER3), + AST_PINCTRL_GROUP(SD1), + AST_PINCTRL_GROUP(I2C10), + AST_PINCTRL_GROUP(I2C11), + AST_PINCTRL_GROUP(I2C12), + AST_PINCTRL_GROUP(I2C13), + AST_PINCTRL_GROUP(NCTS4), + AST_PINCTRL_GROUP(ACPI), + AST_PINCTRL_GROUP(NDCD4), + AST_PINCTRL_GROUP(SIOPBI), + AST_PINCTRL_GROUP(NRI4), + AST_PINCTRL_GROUP(SIOPBO), + AST_PINCTRL_GROUP(TXD4), + AST_PINCTRL_GROUP(RXD4), + AST_PINCTRL_GROUP(FLBUSY), + AST_PINCTRL_GROUP(FLWP), + AST_PINCTRL_GROUP(UART6), + AST_PINCTRL_GROUP(VGAHS), + AST_PINCTRL_GROUP(VGAVS), + AST_PINCTRL_GROUP(DDCCLK), + AST_PINCTRL_GROUP(DDCDAT), + AST_PINCTRL_GROUP(I2C5), + AST_PINCTRL_GROUP(I2C6), + AST_PINCTRL_GROUP(I2C7), + AST_PINCTRL_GROUP(I2C8), + AST_PINCTRL_GROUP(NCTS1), + AST_PINCTRL_GROUP(NDCD1), + AST_PINCTRL_GROUP(NDSR1), + AST_PINCTRL_GROUP(NRI1), + AST_PINCTRL_GROUP(NDTR1), + AST_PINCTRL_GROUP(NRTS1), + AST_PINCTRL_GROUP(TXD1), + AST_PINCTRL_GROUP(RXD1), + AST_PINCTRL_GROUP(PWM0), + AST_PINCTRL_GROUP(PWM1), + AST_PINCTRL_GROUP(PWM2), + AST_PINCTRL_GROUP(PWM3), + AST_PINCTRL_GROUP(PWM4), + AST_PINCTRL_GROUP(PWM5), + AST_PINCTRL_GROUP(PWM6), + AST_PINCTRL_GROUP(PWM7), + AST_PINCTRL_GROUP(VPI18), + AST_PINCTRL_GROUP(VPI24), + AST_PINCTRL_GROUP(VPI30), + AST_PINCTRL_GROUP(BMCINT), + AST_PINCTRL_GROUP(FLACK), + AST_PINCTRL_GROUP(I2C3), + AST_PINCTRL_GROUP(I2C4), + AST_PINCTRL_GROUP(ROM8), + AST_PINCTRL_GROUP(ROM16), + AST_PINCTRL_GROUP(VPO12), + AST_PINCTRL_GROUP(VPO24), +}; + +struct ast2400_pin_function { + const char *name; + const char *const *groups; + unsigned ngroups; + const struct func_expr *expr; +}; + +#define AST_PINCTRL_FUNC(name_, ...) { \ + .name = #name_, \ + .groups = &FUNC_GROUP_SYM(name_)[0], \ + .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \ + .expr = FUNC_EXPR_PTR(name_), \ +} + +static const struct ast2400_pin_function ast2400_functions[] = { + AST_PINCTRL_FUNC(TIMER3), + AST_PINCTRL_FUNC(SD1), + AST_PINCTRL_FUNC(I2C10), + AST_PINCTRL_FUNC(I2C11), + AST_PINCTRL_FUNC(I2C12), + AST_PINCTRL_FUNC(I2C13), + AST_PINCTRL_FUNC(NCTS4), + AST_PINCTRL_FUNC(ACPI), + AST_PINCTRL_FUNC(NDCD4), + AST_PINCTRL_FUNC(SIOPBI), + AST_PINCTRL_FUNC(NRI4), + AST_PINCTRL_FUNC(SIOPBO), + AST_PINCTRL_FUNC(TXD4), + AST_PINCTRL_FUNC(RXD4), + AST_PINCTRL_FUNC(FLBUSY), + AST_PINCTRL_FUNC(FLWP), + AST_PINCTRL_FUNC(UART6), + AST_PINCTRL_FUNC(VGAHS), + AST_PINCTRL_FUNC(VGAVS), + AST_PINCTRL_FUNC(DDCCLK), + AST_PINCTRL_FUNC(DDCDAT), + AST_PINCTRL_FUNC(I2C5), + AST_PINCTRL_FUNC(I2C6), + AST_PINCTRL_FUNC(I2C7), + AST_PINCTRL_FUNC(I2C8), + AST_PINCTRL_FUNC(NCTS1), + AST_PINCTRL_FUNC(NDCD1), + AST_PINCTRL_FUNC(NDSR1), + AST_PINCTRL_FUNC(NRI1), + AST_PINCTRL_FUNC(NDTR1), + AST_PINCTRL_FUNC(NRTS1), + AST_PINCTRL_FUNC(TXD1), + AST_PINCTRL_FUNC(RXD1), + AST_PINCTRL_FUNC(PWM0), + AST_PINCTRL_FUNC(PWM1), + AST_PINCTRL_FUNC(PWM2), + AST_PINCTRL_FUNC(PWM3), + AST_PINCTRL_FUNC(PWM4), + AST_PINCTRL_FUNC(PWM5), + AST_PINCTRL_FUNC(PWM6), + AST_PINCTRL_FUNC(PWM7), + AST_PINCTRL_FUNC(VPI18), + AST_PINCTRL_FUNC(VPI24), + AST_PINCTRL_FUNC(VPI30), + AST_PINCTRL_FUNC(BMCINT), + AST_PINCTRL_FUNC(FLACK), + AST_PINCTRL_FUNC(I2C3), + AST_PINCTRL_FUNC(I2C4), + AST_PINCTRL_FUNC(ROM8), + AST_PINCTRL_FUNC(ROM16), + AST_PINCTRL_FUNC(VPO12), + AST_PINCTRL_FUNC(VPO24), +}; + +struct ast2400_pinctrl_data { + void __iomem *reg_base; + + const struct pinctrl_pin_desc *pins; + const unsigned npins; + + const struct ast2400_pin_group *groups; + const unsigned ngroups; + + const struct ast2400_pin_function *functions; + const unsigned nfunctions; +}; + +static struct ast2400_pinctrl_data ast2400_pinctrl = { + .pins = ast2400_pins, + .npins = ARRAY_SIZE(ast2400_pins), + .groups = ast2400_groups, + .ngroups = ARRAY_SIZE(ast2400_groups), + .functions = ast2400_functions, + .nfunctions = ARRAY_SIZE(ast2400_functions), +}; + +static int ast2400_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->ngroups; +} + +static const char *ast2400_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->groups[group].name; +} + +static int ast2400_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, unsigned *npins) +{ + struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pdata->groups[group].pins[0]; + *npins = pdata->groups[group].npins; + + return 0; +} + +static void ast2400_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) +{ + seq_printf(s, " %s", dev_name(pctldev->dev)); +} + +static struct pinctrl_ops ast2400_pinctrl_ops = { + .get_groups_count = ast2400_pinctrl_get_groups_count, + .get_group_name = ast2400_pinctrl_get_group_name, + .get_group_pins = ast2400_pinctrl_get_group_pins, + .pin_dbg_show = ast2400_pinctrl_pin_dbg_show, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int ast2400_pinmux_get_fn_count(struct pinctrl_dev *pctldev) +{ + struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->nfunctions; +} + +static const char *ast2400_pinmux_get_fn_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->functions[function].name; +} + +static int ast2400_pinmux_get_fn_groups(struct pinctrl_dev *pctldev, + unsigned function, const char * const **groups, + unsigned * const num_groups) +{ + struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + *groups = pdata->functions[function].groups; + *num_groups = pdata->functions[function].ngroups; + + return 0; +} + +static bool func_desc_eval(const struct func_desc *desc, void __iomem *base) +{ + u32 raw = ioread32(base + desc->reg); + + return ((raw & desc->mask) >> __ffs(desc->mask)) == desc->enable; +} + +static bool func_expr_eval(const struct func_expr *expr, void __iomem *base) +{ + bool ret = true; + int i; + + for (i = 0; i < expr->ndescs; i++) { + const struct func_desc *desc = &expr->descs[i]; + + ret = ret && func_desc_eval(desc, base); + } + + return ret; +} + +static bool func_expr_enable(const struct func_expr *expr, void __iomem *base) +{ + int i; + int ret; + + ret = func_expr_eval(expr, base); + if (ret) + return ret; + + for (i = 0; i < expr->ndescs; i++) { + const struct func_desc *desc = &expr->descs[i]; + u32 val; + + if (desc->reg == STRAP) + continue; + + val = ioread32(base + desc->reg); + val &= ~desc->mask; + val |= desc->enable << __ffs(desc->mask); + iowrite32(val, base + desc->reg); + } + + ret = func_expr_eval(expr, base); + return ret; +} + +static bool func_expr_disable(const struct func_expr *expr, void __iomem *base) +{ + int i; + bool ret; + + /* Ensure that we change any unsupported state to disabled */ + for (i = 0; i < expr->ndescs; i++) { + const struct func_desc *desc = &expr->descs[i]; + u32 val; + + if (desc->reg == STRAP) + continue; + + val = ioread32(base + desc->reg); + val &= ~desc->mask; + val |= (desc->disable << __ffs(desc->mask)); + iowrite32(val, base + desc->reg); + } + + ret = !func_expr_eval(expr, base); + return ret; +} + +static inline bool maybe_disable(const struct func_expr **expr, + void __iomem *base) +{ + bool ret; + + if (!expr) + return true; + + while (*expr) { + ret |= func_expr_disable(*expr, base); + expr++; + } + return ret; +} + +static bool sig_in_exprs(const struct func_expr **exprs, + const struct func_expr *sig) +{ + if (!exprs) + return false; + + while (*exprs) { + if (sig == *exprs) + return true; + exprs++; + } + return false; +} + +static int ast2400_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, unsigned group) +{ + int i; + const struct ast2400_pinctrl_data *pdata = + pinctrl_dev_get_drvdata(pctldev); + const struct ast2400_pin_group *pgroup = &pdata->groups[group]; + const struct ast2400_pin_function *pfunc = + &pdata->functions[function]; + + for (i = 0; i < pgroup->npins; i++) { + int pin = pgroup->pins[i]; + const struct pin_prio *pprio = pdata->pins[pin].drv_data; + const struct func_expr *func = pfunc->expr; + + if (!pprio) + return -1; + + /* If low priority is requested, ensure high is disabled */ + if (sig_in_exprs(pprio->low, func)) { + if (!maybe_disable(pprio->high, pdata->reg_base)) { + pr_err("Failed to disable high priority function on pin %d\n", + pin); + return -1; + } + } + + /* Nothing to do if we're already enabled */ + if (func_expr_eval(func, pdata->reg_base)) + continue; + + /* Configure the pin */ + if (!func_expr_enable(func, pdata->reg_base)) + return -1; + } + + return 0; +} + +static int ast2400_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + unsigned pin = range->base + offset; + const struct ast2400_pinctrl_data *pdata = + pinctrl_dev_get_drvdata(pctldev); + const struct pin_prio *pprio = + pdata->pins[pin].drv_data; + + if (!pprio) + return 0; + + if (!maybe_disable(pprio->high, pdata->reg_base)) + return -1; + + if (!maybe_disable(pprio->low, pdata->reg_base)) + return -1; + + return 0; +} + +static struct pinmux_ops ast2400_pinmux_ops = { + .get_functions_count = ast2400_pinmux_get_fn_count, + .get_function_name = ast2400_pinmux_get_fn_name, + .get_function_groups = ast2400_pinmux_get_fn_groups, + .set_mux = ast2400_pinmux_set_mux, + .gpio_request_enable = ast2400_gpio_request_enable, + .strict = true, +}; + +static int ast2400_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + return 0; +} + +static int ast2400_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + return 0; +} + +static struct pinconf_ops ast2400_pinconf_ops = { + .pin_config_get = ast2400_pin_config_get, + .pin_config_set = ast2400_pin_config_set, +}; + +static struct pinctrl_desc ast2400_pinctrl_desc = { + .name = "pinctrl-ast2400", + .pins = ast2400_pins, + .npins = ARRAY_SIZE(ast2400_pins), + .pctlops = &ast2400_pinctrl_ops, + .pmxops = &ast2400_pinmux_ops, + .confops = &ast2400_pinconf_ops, + .owner = THIS_MODULE, +}; + +static struct pinctrl_gpio_range ast2400_gpios = { + .name = "ast2400-pctrl-gpio-range", + .npins = ARRAY_SIZE(ast2400_pins), +}; + +static int __init ast2400_pinctrl_probe(struct platform_device *pdev) +{ + struct ast2400_pinctrl_data *pdata = &ast2400_pinctrl; + struct resource *res; + struct pinctrl_dev *pctl; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->reg_base)) + return PTR_ERR(pdata->reg_base); + + /* We allocated space for all pins, make sure we initialise all pin + * numbers. Those pins we haven't defined won't yet have had their + * number initialised, and it's effectively a no-op for those which + * have. + */ + for (i = 0; i < ARRAY_SIZE(ast2400_pins); i++) + ast2400_pins[i].number = i; + + pctl = pinctrl_register(&ast2400_pinctrl_desc, &pdev->dev, pdata); + + if (IS_ERR(pctl)) { + dev_err(&pdev->dev, "Failed to register pinctrl\n"); + return PTR_ERR(pctl); + } + + platform_set_drvdata(pdev, pdata); + + /* grange.name = "exynos5440-pctrl-gpio-range"; */ + pinctrl_add_gpio_range(pctl, &ast2400_gpios); + + return 0; +} + +static const struct of_device_id ast2400_pinctrl_of_match[] = { + { .compatible = "aspeed,ast2400-pinctrl", }, + { }, +}; + +static struct platform_driver ast2400_pinctrl_driver = { + .driver = { + .name = "pinctrl-ast2400", + .of_match_table = ast2400_pinctrl_of_match, + }, +}; + +module_platform_driver_probe(ast2400_pinctrl_driver, ast2400_pinctrl_probe); + +MODULE_AUTHOR("Andrew Jeffery <andrew@xxxxxxxx>"); +MODULE_DESCRIPTION("ASPEED AST2400 pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html