18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 IBM Corp. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 78c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci#include "../core.h" 118c2ecf20Sopenharmony_ci#include "pinctrl-aspeed.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciint aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci return pdata->pinmux.ngroups; 188c2ecf20Sopenharmony_ci} 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciconst char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev, 218c2ecf20Sopenharmony_ci unsigned int group) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return pdata->pinmux.groups[group].name; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciint aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, 298c2ecf20Sopenharmony_ci unsigned int group, const unsigned int **pins, 308c2ecf20Sopenharmony_ci unsigned int *npins) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci *pins = &pdata->pinmux.groups[group].pins[0]; 358c2ecf20Sopenharmony_ci *npins = pdata->pinmux.groups[group].npins; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_civoid aspeed_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, 418c2ecf20Sopenharmony_ci struct seq_file *s, unsigned int offset) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci seq_printf(s, " %s", dev_name(pctldev->dev)); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint aspeed_pinmux_get_fn_count(struct pinctrl_dev *pctldev) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return pdata->pinmux.nfunctions; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciconst char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev, 548c2ecf20Sopenharmony_ci unsigned int function) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return pdata->pinmux.functions[function].name; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciint aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev, 628c2ecf20Sopenharmony_ci unsigned int function, 638c2ecf20Sopenharmony_ci const char * const **groups, 648c2ecf20Sopenharmony_ci unsigned int * const num_groups) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci *groups = pdata->pinmux.functions[function].groups; 698c2ecf20Sopenharmony_ci *num_groups = pdata->pinmux.functions[function].ngroups; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int aspeed_sig_expr_enable(struct aspeed_pinmux_data *ctx, 758c2ecf20Sopenharmony_ci const struct aspeed_sig_expr *expr) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int ret; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci pr_debug("Enabling signal %s for %s\n", expr->signal, 808c2ecf20Sopenharmony_ci expr->function); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = aspeed_sig_expr_eval(ctx, expr, true); 838c2ecf20Sopenharmony_ci if (ret < 0) 848c2ecf20Sopenharmony_ci return ret; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!ret) 878c2ecf20Sopenharmony_ci return aspeed_sig_expr_set(ctx, expr, true); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int aspeed_sig_expr_disable(struct aspeed_pinmux_data *ctx, 938c2ecf20Sopenharmony_ci const struct aspeed_sig_expr *expr) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int ret; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci pr_debug("Disabling signal %s for %s\n", expr->signal, 988c2ecf20Sopenharmony_ci expr->function); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ret = aspeed_sig_expr_eval(ctx, expr, true); 1018c2ecf20Sopenharmony_ci if (ret < 0) 1028c2ecf20Sopenharmony_ci return ret; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (ret) 1058c2ecf20Sopenharmony_ci return aspeed_sig_expr_set(ctx, expr, false); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/** 1118c2ecf20Sopenharmony_ci * Disable a signal on a pin by disabling all provided signal expressions. 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * @ctx: The pinmux context 1148c2ecf20Sopenharmony_ci * @exprs: The list of signal expressions (from a priority level on a pin) 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * Return: 0 if all expressions are disabled, otherwise a negative error code 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic int aspeed_disable_sig(struct aspeed_pinmux_data *ctx, 1198c2ecf20Sopenharmony_ci const struct aspeed_sig_expr **exprs) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci int ret = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!exprs) 1248c2ecf20Sopenharmony_ci return -EINVAL; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci while (*exprs && !ret) { 1278c2ecf20Sopenharmony_ci ret = aspeed_sig_expr_disable(ctx, *exprs); 1288c2ecf20Sopenharmony_ci exprs++; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/** 1358c2ecf20Sopenharmony_ci * Search for the signal expression needed to enable the pin's signal for the 1368c2ecf20Sopenharmony_ci * requested function. 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * @exprs: List of signal expressions (haystack) 1398c2ecf20Sopenharmony_ci * @name: The name of the requested function (needle) 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Return: A pointer to the signal expression whose function tag matches the 1428c2ecf20Sopenharmony_ci * provided name, otherwise NULL. 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic const struct aspeed_sig_expr *aspeed_find_expr_by_name( 1468c2ecf20Sopenharmony_ci const struct aspeed_sig_expr **exprs, const char *name) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci while (*exprs) { 1498c2ecf20Sopenharmony_ci if (strcmp((*exprs)->function, name) == 0) 1508c2ecf20Sopenharmony_ci return *exprs; 1518c2ecf20Sopenharmony_ci exprs++; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return NULL; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic char *get_defined_attribute(const struct aspeed_pin_desc *pdesc, 1588c2ecf20Sopenharmony_ci const char *(*get)( 1598c2ecf20Sopenharmony_ci const struct aspeed_sig_expr *)) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci char *found = NULL; 1628c2ecf20Sopenharmony_ci size_t len = 0; 1638c2ecf20Sopenharmony_ci const struct aspeed_sig_expr ***prios, **funcs, *expr; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci prios = pdesc->prios; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci while ((funcs = *prios)) { 1688c2ecf20Sopenharmony_ci while ((expr = *funcs)) { 1698c2ecf20Sopenharmony_ci const char *str = get(expr); 1708c2ecf20Sopenharmony_ci size_t delta = strlen(str) + 2; 1718c2ecf20Sopenharmony_ci char *expanded; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci expanded = krealloc(found, len + delta + 1, GFP_KERNEL); 1748c2ecf20Sopenharmony_ci if (!expanded) { 1758c2ecf20Sopenharmony_ci kfree(found); 1768c2ecf20Sopenharmony_ci return expanded; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci found = expanded; 1808c2ecf20Sopenharmony_ci found[len] = '\0'; 1818c2ecf20Sopenharmony_ci len += delta; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci strcat(found, str); 1848c2ecf20Sopenharmony_ci strcat(found, ", "); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci funcs++; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci prios++; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (len < 2) { 1928c2ecf20Sopenharmony_ci kfree(found); 1938c2ecf20Sopenharmony_ci return NULL; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci found[len - 2] = '\0'; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return found; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic const char *aspeed_sig_expr_function(const struct aspeed_sig_expr *expr) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci return expr->function; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic char *get_defined_functions(const struct aspeed_pin_desc *pdesc) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci return get_defined_attribute(pdesc, aspeed_sig_expr_function); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic const char *aspeed_sig_expr_signal(const struct aspeed_sig_expr *expr) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci return expr->signal; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic char *get_defined_signals(const struct aspeed_pin_desc *pdesc) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci return get_defined_attribute(pdesc, aspeed_sig_expr_signal); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciint aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, 2228c2ecf20Sopenharmony_ci unsigned int group) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int i; 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 2278c2ecf20Sopenharmony_ci const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group]; 2288c2ecf20Sopenharmony_ci const struct aspeed_pin_function *pfunc = 2298c2ecf20Sopenharmony_ci &pdata->pinmux.functions[function]; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci for (i = 0; i < pgroup->npins; i++) { 2328c2ecf20Sopenharmony_ci int pin = pgroup->pins[i]; 2338c2ecf20Sopenharmony_ci const struct aspeed_pin_desc *pdesc = pdata->pins[pin].drv_data; 2348c2ecf20Sopenharmony_ci const struct aspeed_sig_expr *expr = NULL; 2358c2ecf20Sopenharmony_ci const struct aspeed_sig_expr **funcs; 2368c2ecf20Sopenharmony_ci const struct aspeed_sig_expr ***prios; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!pdesc) 2398c2ecf20Sopenharmony_ci return -EINVAL; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci prios = pdesc->prios; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!prios) 2468c2ecf20Sopenharmony_ci continue; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Disable functions at a higher priority than that requested */ 2498c2ecf20Sopenharmony_ci while ((funcs = *prios)) { 2508c2ecf20Sopenharmony_ci expr = aspeed_find_expr_by_name(funcs, pfunc->name); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (expr) 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ret = aspeed_disable_sig(&pdata->pinmux, funcs); 2568c2ecf20Sopenharmony_ci if (ret) 2578c2ecf20Sopenharmony_ci return ret; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci prios++; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!expr) { 2638c2ecf20Sopenharmony_ci char *functions = get_defined_functions(pdesc); 2648c2ecf20Sopenharmony_ci char *signals = get_defined_signals(pdesc); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci pr_warn("No function %s found on pin %s (%d). Found signal(s) %s for function(s) %s\n", 2678c2ecf20Sopenharmony_ci pfunc->name, pdesc->name, pin, signals, 2688c2ecf20Sopenharmony_ci functions); 2698c2ecf20Sopenharmony_ci kfree(signals); 2708c2ecf20Sopenharmony_ci kfree(functions); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return -ENXIO; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret = aspeed_sig_expr_enable(&pdata->pinmux, expr); 2768c2ecf20Sopenharmony_ci if (ret) 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci pr_debug("Muxed pin %s as %s for %s\n", pdesc->name, expr->signal, 2808c2ecf20Sopenharmony_ci expr->function); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic bool aspeed_expr_is_gpio(const struct aspeed_sig_expr *expr) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci * We need to differentiate between GPIO and non-GPIO signals to 2908c2ecf20Sopenharmony_ci * implement the gpio_request_enable() interface. For better or worse 2918c2ecf20Sopenharmony_ci * the ASPEED pinctrl driver uses the expression names to determine 2928c2ecf20Sopenharmony_ci * whether an expression will mux a pin for GPIO. 2938c2ecf20Sopenharmony_ci * 2948c2ecf20Sopenharmony_ci * Generally we have the following - A GPIO such as B1 has: 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * - expr->signal set to "GPIOB1" 2978c2ecf20Sopenharmony_ci * - expr->function set to "GPIOB1" 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Using this fact we can determine whether the provided expression is 3008c2ecf20Sopenharmony_ci * a GPIO expression by testing the signal name for the string prefix 3018c2ecf20Sopenharmony_ci * "GPIO". 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * However, some GPIOs are input-only, and the ASPEED datasheets name 3048c2ecf20Sopenharmony_ci * them differently. An input-only GPIO such as T0 has: 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * - expr->signal set to "GPIT0" 3078c2ecf20Sopenharmony_ci * - expr->function set to "GPIT0" 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * It's tempting to generalise the prefix test from "GPIO" to "GPI" to 3108c2ecf20Sopenharmony_ci * account for both GPIOs and GPIs, but in doing so we run aground on 3118c2ecf20Sopenharmony_ci * another feature: 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Some pins in the ASPEED BMC SoCs have a "pass-through" GPIO 3148c2ecf20Sopenharmony_ci * function where the input state of one pin is replicated as the 3158c2ecf20Sopenharmony_ci * output state of another (as if they were shorted together - a mux 3168c2ecf20Sopenharmony_ci * configuration that is typically enabled by hardware strapping). 3178c2ecf20Sopenharmony_ci * This feature allows the BMC to pass e.g. power button state through 3188c2ecf20Sopenharmony_ci * to the host while the BMC is yet to boot, but take control of the 3198c2ecf20Sopenharmony_ci * button state once the BMC has booted by muxing each pin as a 3208c2ecf20Sopenharmony_ci * separate, pin-specific GPIO. 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * Conceptually this pass-through mode is a form of GPIO and is named 3238c2ecf20Sopenharmony_ci * as such in the datasheets, e.g. "GPID0". This naming similarity 3248c2ecf20Sopenharmony_ci * trips us up with the simple GPI-prefixed-signal-name scheme 3258c2ecf20Sopenharmony_ci * discussed above, as the pass-through configuration is not what we 3268c2ecf20Sopenharmony_ci * want when muxing a pin as GPIO for the GPIO subsystem. 3278c2ecf20Sopenharmony_ci * 3288c2ecf20Sopenharmony_ci * On e.g. the AST2400, a pass-through function "GPID0" is grouped on 3298c2ecf20Sopenharmony_ci * balls A18 and D16, where we have: 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * For ball A18: 3328c2ecf20Sopenharmony_ci * - expr->signal set to "GPID0IN" 3338c2ecf20Sopenharmony_ci * - expr->function set to "GPID0" 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * For ball D16: 3368c2ecf20Sopenharmony_ci * - expr->signal set to "GPID0OUT" 3378c2ecf20Sopenharmony_ci * - expr->function set to "GPID0" 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * By contrast, the pin-specific GPIO expressions for the same pins are 3408c2ecf20Sopenharmony_ci * as follows: 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * For ball A18: 3438c2ecf20Sopenharmony_ci * - expr->signal looks like "GPIOD0" 3448c2ecf20Sopenharmony_ci * - expr->function looks like "GPIOD0" 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * For ball D16: 3478c2ecf20Sopenharmony_ci * - expr->signal looks like "GPIOD1" 3488c2ecf20Sopenharmony_ci * - expr->function looks like "GPIOD1" 3498c2ecf20Sopenharmony_ci * 3508c2ecf20Sopenharmony_ci * Testing both the signal _and_ function names gives us the means 3518c2ecf20Sopenharmony_ci * differentiate the pass-through GPIO pinmux configuration from the 3528c2ecf20Sopenharmony_ci * pin-specific configuration that the GPIO subsystem is after: An 3538c2ecf20Sopenharmony_ci * expression is a pin-specific (non-pass-through) GPIO configuration 3548c2ecf20Sopenharmony_ci * if the signal prefix is "GPI" and the signal name matches the 3558c2ecf20Sopenharmony_ci * function name. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci return !strncmp(expr->signal, "GPI", 3) && 3588c2ecf20Sopenharmony_ci !strcmp(expr->signal, expr->function); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic bool aspeed_gpio_in_exprs(const struct aspeed_sig_expr **exprs) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci if (!exprs) 3648c2ecf20Sopenharmony_ci return false; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci while (*exprs) { 3678c2ecf20Sopenharmony_ci if (aspeed_expr_is_gpio(*exprs)) 3688c2ecf20Sopenharmony_ci return true; 3698c2ecf20Sopenharmony_ci exprs++; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return false; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciint aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, 3768c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 3778c2ecf20Sopenharmony_ci unsigned int offset) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int ret; 3808c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 3818c2ecf20Sopenharmony_ci const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; 3828c2ecf20Sopenharmony_ci const struct aspeed_sig_expr ***prios, **funcs, *expr; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!pdesc) 3858c2ecf20Sopenharmony_ci return -EINVAL; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci prios = pdesc->prios; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (!prios) 3908c2ecf20Sopenharmony_ci return -ENXIO; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci pr_debug("Muxing pin %s for GPIO\n", pdesc->name); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* Disable any functions of higher priority than GPIO */ 3958c2ecf20Sopenharmony_ci while ((funcs = *prios)) { 3968c2ecf20Sopenharmony_ci if (aspeed_gpio_in_exprs(funcs)) 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = aspeed_disable_sig(&pdata->pinmux, funcs); 4008c2ecf20Sopenharmony_ci if (ret) 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci prios++; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (!funcs) { 4078c2ecf20Sopenharmony_ci char *signals = get_defined_signals(pdesc); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n", 4108c2ecf20Sopenharmony_ci pdesc->name, offset, signals); 4118c2ecf20Sopenharmony_ci kfree(signals); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return -ENXIO; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci expr = *funcs; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* 4198c2ecf20Sopenharmony_ci * Disabling all higher-priority expressions is enough to enable the 4208c2ecf20Sopenharmony_ci * lowest-priority signal type. As such it has no associated 4218c2ecf20Sopenharmony_ci * expression. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci if (!expr) { 4248c2ecf20Sopenharmony_ci pr_debug("Muxed pin %s as GPIO\n", pdesc->name); 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * If GPIO is not the lowest priority signal type, assume there is only 4308c2ecf20Sopenharmony_ci * one expression defined to enable the GPIO function 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci ret = aspeed_sig_expr_enable(&pdata->pinmux, expr); 4338c2ecf20Sopenharmony_ci if (ret) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci pr_debug("Muxed pin %s as %s\n", pdesc->name, expr->signal); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciint aspeed_pinctrl_probe(struct platform_device *pdev, 4428c2ecf20Sopenharmony_ci struct pinctrl_desc *pdesc, 4438c2ecf20Sopenharmony_ci struct aspeed_pinctrl_data *pdata) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct device *parent; 4468c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci parent = pdev->dev.parent; 4498c2ecf20Sopenharmony_ci if (!parent) { 4508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No parent for syscon pincontroller\n"); 4518c2ecf20Sopenharmony_ci return -ENODEV; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci pdata->scu = syscon_node_to_regmap(parent->of_node); 4558c2ecf20Sopenharmony_ci if (IS_ERR(pdata->scu)) { 4568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n"); 4578c2ecf20Sopenharmony_ci return PTR_ERR(pdata->scu); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci pdata->pinmux.maps[ASPEED_IP_SCU] = pdata->scu; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci pctl = pinctrl_register(pdesc, &pdev->dev, pdata); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (IS_ERR(pctl)) { 4658c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register pinctrl\n"); 4668c2ecf20Sopenharmony_ci return PTR_ERR(pctl); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pdata); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic inline bool pin_in_config_range(unsigned int offset, 4758c2ecf20Sopenharmony_ci const struct aspeed_pin_config *config) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci return offset >= config->pins[0] && offset <= config->pins[1]; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic inline const struct aspeed_pin_config *find_pinconf_config( 4818c2ecf20Sopenharmony_ci const struct aspeed_pinctrl_data *pdata, 4828c2ecf20Sopenharmony_ci unsigned int offset, 4838c2ecf20Sopenharmony_ci enum pin_config_param param) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci unsigned int i; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci for (i = 0; i < pdata->nconfigs; i++) { 4888c2ecf20Sopenharmony_ci if (param == pdata->configs[i].param && 4898c2ecf20Sopenharmony_ci pin_in_config_range(offset, &pdata->configs[i])) 4908c2ecf20Sopenharmony_ci return &pdata->configs[i]; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return NULL; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cienum aspeed_pin_config_map_type { MAP_TYPE_ARG, MAP_TYPE_VAL }; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic const struct aspeed_pin_config_map *find_pinconf_map( 4998c2ecf20Sopenharmony_ci const struct aspeed_pinctrl_data *pdata, 5008c2ecf20Sopenharmony_ci enum pin_config_param param, 5018c2ecf20Sopenharmony_ci enum aspeed_pin_config_map_type type, 5028c2ecf20Sopenharmony_ci s64 value) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int i; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci for (i = 0; i < pdata->nconfmaps; i++) { 5078c2ecf20Sopenharmony_ci const struct aspeed_pin_config_map *elem; 5088c2ecf20Sopenharmony_ci bool match; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci elem = &pdata->confmaps[i]; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci switch (type) { 5138c2ecf20Sopenharmony_ci case MAP_TYPE_ARG: 5148c2ecf20Sopenharmony_ci match = (elem->arg == -1 || elem->arg == value); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci case MAP_TYPE_VAL: 5178c2ecf20Sopenharmony_ci match = (elem->val == value); 5188c2ecf20Sopenharmony_ci break; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (param == elem->param && match) 5228c2ecf20Sopenharmony_ci return elem; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return NULL; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ciint aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset, 5298c2ecf20Sopenharmony_ci unsigned long *config) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci const enum pin_config_param param = pinconf_to_config_param(*config); 5328c2ecf20Sopenharmony_ci const struct aspeed_pin_config_map *pmap; 5338c2ecf20Sopenharmony_ci const struct aspeed_pinctrl_data *pdata; 5348c2ecf20Sopenharmony_ci const struct aspeed_pin_config *pconf; 5358c2ecf20Sopenharmony_ci unsigned int val; 5368c2ecf20Sopenharmony_ci int rc = 0; 5378c2ecf20Sopenharmony_ci u32 arg; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci pdata = pinctrl_dev_get_drvdata(pctldev); 5408c2ecf20Sopenharmony_ci pconf = find_pinconf_config(pdata, offset, param); 5418c2ecf20Sopenharmony_ci if (!pconf) 5428c2ecf20Sopenharmony_ci return -ENOTSUPP; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci rc = regmap_read(pdata->scu, pconf->reg, &val); 5458c2ecf20Sopenharmony_ci if (rc < 0) 5468c2ecf20Sopenharmony_ci return rc; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci pmap = find_pinconf_map(pdata, param, MAP_TYPE_VAL, 5498c2ecf20Sopenharmony_ci (val & pconf->mask) >> __ffs(pconf->mask)); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (!pmap) 5528c2ecf20Sopenharmony_ci return -EINVAL; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (param == PIN_CONFIG_DRIVE_STRENGTH) 5558c2ecf20Sopenharmony_ci arg = (u32) pmap->arg; 5568c2ecf20Sopenharmony_ci else if (param == PIN_CONFIG_BIAS_PULL_DOWN) 5578c2ecf20Sopenharmony_ci arg = !!pmap->arg; 5588c2ecf20Sopenharmony_ci else 5598c2ecf20Sopenharmony_ci arg = 1; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!arg) 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ciint aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset, 5708c2ecf20Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci const struct aspeed_pinctrl_data *pdata; 5738c2ecf20Sopenharmony_ci unsigned int i; 5748c2ecf20Sopenharmony_ci int rc = 0; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci pdata = pinctrl_dev_get_drvdata(pctldev); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 5798c2ecf20Sopenharmony_ci const struct aspeed_pin_config_map *pmap; 5808c2ecf20Sopenharmony_ci const struct aspeed_pin_config *pconf; 5818c2ecf20Sopenharmony_ci enum pin_config_param param; 5828c2ecf20Sopenharmony_ci unsigned int val; 5838c2ecf20Sopenharmony_ci u32 arg; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 5868c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci pconf = find_pinconf_config(pdata, offset, param); 5898c2ecf20Sopenharmony_ci if (!pconf) 5908c2ecf20Sopenharmony_ci return -ENOTSUPP; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci pmap = find_pinconf_map(pdata, param, MAP_TYPE_ARG, arg); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (WARN_ON(!pmap)) 5958c2ecf20Sopenharmony_ci return -EINVAL; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci val = pmap->val << __ffs(pconf->mask); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci rc = regmap_update_bits(pdata->scu, pconf->reg, 6008c2ecf20Sopenharmony_ci pconf->mask, val); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (rc < 0) 6038c2ecf20Sopenharmony_ci return rc; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci pr_debug("%s: Set SCU%02X[0x%08X]=0x%X for param %d(=%d) on pin %d\n", 6068c2ecf20Sopenharmony_ci __func__, pconf->reg, pconf->mask, 6078c2ecf20Sopenharmony_ci val, param, arg, offset); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ciint aspeed_pin_config_group_get(struct pinctrl_dev *pctldev, 6148c2ecf20Sopenharmony_ci unsigned int selector, 6158c2ecf20Sopenharmony_ci unsigned long *config) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci const unsigned int *pins; 6188c2ecf20Sopenharmony_ci unsigned int npins; 6198c2ecf20Sopenharmony_ci int rc; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci rc = aspeed_pinctrl_get_group_pins(pctldev, selector, &pins, &npins); 6228c2ecf20Sopenharmony_ci if (rc < 0) 6238c2ecf20Sopenharmony_ci return rc; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!npins) 6268c2ecf20Sopenharmony_ci return -ENODEV; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci rc = aspeed_pin_config_get(pctldev, pins[0], config); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return rc; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ciint aspeed_pin_config_group_set(struct pinctrl_dev *pctldev, 6348c2ecf20Sopenharmony_ci unsigned int selector, 6358c2ecf20Sopenharmony_ci unsigned long *configs, 6368c2ecf20Sopenharmony_ci unsigned int num_configs) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci const unsigned int *pins; 6398c2ecf20Sopenharmony_ci unsigned int npins; 6408c2ecf20Sopenharmony_ci int rc; 6418c2ecf20Sopenharmony_ci int i; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci pr_debug("%s: Fetching pins for group selector %d\n", 6448c2ecf20Sopenharmony_ci __func__, selector); 6458c2ecf20Sopenharmony_ci rc = aspeed_pinctrl_get_group_pins(pctldev, selector, &pins, &npins); 6468c2ecf20Sopenharmony_ci if (rc < 0) 6478c2ecf20Sopenharmony_ci return rc; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci for (i = 0; i < npins; i++) { 6508c2ecf20Sopenharmony_ci rc = aspeed_pin_config_set(pctldev, pins[i], configs, 6518c2ecf20Sopenharmony_ci num_configs); 6528c2ecf20Sopenharmony_ci if (rc < 0) 6538c2ecf20Sopenharmony_ci return rc; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return 0; 6578c2ecf20Sopenharmony_ci} 658