162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 IBM Corp. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 762306a36Sopenharmony_ci#include <linux/platform_device.h> 862306a36Sopenharmony_ci#include <linux/seq_file.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/string.h> 1162306a36Sopenharmony_ci#include "../core.h" 1262306a36Sopenharmony_ci#include "pinctrl-aspeed.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciint aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci return pdata->pinmux.ngroups; 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciconst char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev, 2262306a36Sopenharmony_ci unsigned int group) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci return pdata->pinmux.groups[group].name; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciint aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, 3062306a36Sopenharmony_ci unsigned int group, const unsigned int **pins, 3162306a36Sopenharmony_ci unsigned int *npins) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci *pins = &pdata->pinmux.groups[group].pins[0]; 3662306a36Sopenharmony_ci *npins = pdata->pinmux.groups[group].npins; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_civoid aspeed_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, 4262306a36Sopenharmony_ci struct seq_file *s, unsigned int offset) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci seq_printf(s, " %s", dev_name(pctldev->dev)); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint aspeed_pinmux_get_fn_count(struct pinctrl_dev *pctldev) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return pdata->pinmux.nfunctions; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciconst char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev, 5562306a36Sopenharmony_ci unsigned int function) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return pdata->pinmux.functions[function].name; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciint aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev, 6362306a36Sopenharmony_ci unsigned int function, 6462306a36Sopenharmony_ci const char * const **groups, 6562306a36Sopenharmony_ci unsigned int * const num_groups) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci *groups = pdata->pinmux.functions[function].groups; 7062306a36Sopenharmony_ci *num_groups = pdata->pinmux.functions[function].ngroups; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int aspeed_sig_expr_enable(struct aspeed_pinmux_data *ctx, 7662306a36Sopenharmony_ci const struct aspeed_sig_expr *expr) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci int ret; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci pr_debug("Enabling signal %s for %s\n", expr->signal, 8162306a36Sopenharmony_ci expr->function); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ret = aspeed_sig_expr_eval(ctx, expr, true); 8462306a36Sopenharmony_ci if (ret < 0) 8562306a36Sopenharmony_ci return ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!ret) 8862306a36Sopenharmony_ci return aspeed_sig_expr_set(ctx, expr, true); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int aspeed_sig_expr_disable(struct aspeed_pinmux_data *ctx, 9462306a36Sopenharmony_ci const struct aspeed_sig_expr *expr) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci int ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci pr_debug("Disabling signal %s for %s\n", expr->signal, 9962306a36Sopenharmony_ci expr->function); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ret = aspeed_sig_expr_eval(ctx, expr, true); 10262306a36Sopenharmony_ci if (ret < 0) 10362306a36Sopenharmony_ci return ret; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (ret) 10662306a36Sopenharmony_ci return aspeed_sig_expr_set(ctx, expr, false); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/** 11262306a36Sopenharmony_ci * aspeed_disable_sig() - Disable a signal on a pin by disabling all provided 11362306a36Sopenharmony_ci * signal expressions. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * @ctx: The pinmux context 11662306a36Sopenharmony_ci * @exprs: The list of signal expressions (from a priority level on a pin) 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * Return: 0 if all expressions are disabled, otherwise a negative error code 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic int aspeed_disable_sig(struct aspeed_pinmux_data *ctx, 12162306a36Sopenharmony_ci const struct aspeed_sig_expr **exprs) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int ret = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!exprs) 12662306a36Sopenharmony_ci return -EINVAL; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci while (*exprs && !ret) { 12962306a36Sopenharmony_ci ret = aspeed_sig_expr_disable(ctx, *exprs); 13062306a36Sopenharmony_ci exprs++; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return ret; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * aspeed_find_expr_by_name - Search for the signal expression needed to 13862306a36Sopenharmony_ci * enable the pin's signal for the requested function. 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * @exprs: List of signal expressions (haystack) 14162306a36Sopenharmony_ci * @name: The name of the requested function (needle) 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * Return: A pointer to the signal expression whose function tag matches the 14462306a36Sopenharmony_ci * provided name, otherwise NULL. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cistatic const struct aspeed_sig_expr *aspeed_find_expr_by_name( 14862306a36Sopenharmony_ci const struct aspeed_sig_expr **exprs, const char *name) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci while (*exprs) { 15162306a36Sopenharmony_ci if (strcmp((*exprs)->function, name) == 0) 15262306a36Sopenharmony_ci return *exprs; 15362306a36Sopenharmony_ci exprs++; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic char *get_defined_attribute(const struct aspeed_pin_desc *pdesc, 16062306a36Sopenharmony_ci const char *(*get)( 16162306a36Sopenharmony_ci const struct aspeed_sig_expr *)) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci char *found = NULL; 16462306a36Sopenharmony_ci size_t len = 0; 16562306a36Sopenharmony_ci const struct aspeed_sig_expr ***prios, **funcs, *expr; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci prios = pdesc->prios; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci while ((funcs = *prios)) { 17062306a36Sopenharmony_ci while ((expr = *funcs)) { 17162306a36Sopenharmony_ci const char *str = get(expr); 17262306a36Sopenharmony_ci size_t delta = strlen(str) + 2; 17362306a36Sopenharmony_ci char *expanded; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci expanded = krealloc(found, len + delta + 1, GFP_KERNEL); 17662306a36Sopenharmony_ci if (!expanded) { 17762306a36Sopenharmony_ci kfree(found); 17862306a36Sopenharmony_ci return expanded; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci found = expanded; 18262306a36Sopenharmony_ci found[len] = '\0'; 18362306a36Sopenharmony_ci len += delta; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci strcat(found, str); 18662306a36Sopenharmony_ci strcat(found, ", "); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci funcs++; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci prios++; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (len < 2) { 19462306a36Sopenharmony_ci kfree(found); 19562306a36Sopenharmony_ci return NULL; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci found[len - 2] = '\0'; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return found; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic const char *aspeed_sig_expr_function(const struct aspeed_sig_expr *expr) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci return expr->function; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic char *get_defined_functions(const struct aspeed_pin_desc *pdesc) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return get_defined_attribute(pdesc, aspeed_sig_expr_function); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic const char *aspeed_sig_expr_signal(const struct aspeed_sig_expr *expr) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return expr->signal; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic char *get_defined_signals(const struct aspeed_pin_desc *pdesc) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return get_defined_attribute(pdesc, aspeed_sig_expr_signal); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciint aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, 22462306a36Sopenharmony_ci unsigned int group) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int i; 22762306a36Sopenharmony_ci int ret; 22862306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 22962306a36Sopenharmony_ci const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group]; 23062306a36Sopenharmony_ci const struct aspeed_pin_function *pfunc = 23162306a36Sopenharmony_ci &pdata->pinmux.functions[function]; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci for (i = 0; i < pgroup->npins; i++) { 23462306a36Sopenharmony_ci int pin = pgroup->pins[i]; 23562306a36Sopenharmony_ci const struct aspeed_pin_desc *pdesc = pdata->pins[pin].drv_data; 23662306a36Sopenharmony_ci const struct aspeed_sig_expr *expr = NULL; 23762306a36Sopenharmony_ci const struct aspeed_sig_expr **funcs; 23862306a36Sopenharmony_ci const struct aspeed_sig_expr ***prios; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!pdesc) 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci prios = pdesc->prios; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (!prios) 24862306a36Sopenharmony_ci continue; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Disable functions at a higher priority than that requested */ 25162306a36Sopenharmony_ci while ((funcs = *prios)) { 25262306a36Sopenharmony_ci expr = aspeed_find_expr_by_name(funcs, pfunc->name); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (expr) 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = aspeed_disable_sig(&pdata->pinmux, funcs); 25862306a36Sopenharmony_ci if (ret) 25962306a36Sopenharmony_ci return ret; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci prios++; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!expr) { 26562306a36Sopenharmony_ci char *functions = get_defined_functions(pdesc); 26662306a36Sopenharmony_ci char *signals = get_defined_signals(pdesc); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci pr_warn("No function %s found on pin %s (%d). Found signal(s) %s for function(s) %s\n", 26962306a36Sopenharmony_ci pfunc->name, pdesc->name, pin, signals, 27062306a36Sopenharmony_ci functions); 27162306a36Sopenharmony_ci kfree(signals); 27262306a36Sopenharmony_ci kfree(functions); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return -ENXIO; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ret = aspeed_sig_expr_enable(&pdata->pinmux, expr); 27862306a36Sopenharmony_ci if (ret) 27962306a36Sopenharmony_ci return ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci pr_debug("Muxed pin %s as %s for %s\n", pdesc->name, expr->signal, 28262306a36Sopenharmony_ci expr->function); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic bool aspeed_expr_is_gpio(const struct aspeed_sig_expr *expr) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * We need to differentiate between GPIO and non-GPIO signals to 29262306a36Sopenharmony_ci * implement the gpio_request_enable() interface. For better or worse 29362306a36Sopenharmony_ci * the ASPEED pinctrl driver uses the expression names to determine 29462306a36Sopenharmony_ci * whether an expression will mux a pin for GPIO. 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * Generally we have the following - A GPIO such as B1 has: 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * - expr->signal set to "GPIOB1" 29962306a36Sopenharmony_ci * - expr->function set to "GPIOB1" 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * Using this fact we can determine whether the provided expression is 30262306a36Sopenharmony_ci * a GPIO expression by testing the signal name for the string prefix 30362306a36Sopenharmony_ci * "GPIO". 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * However, some GPIOs are input-only, and the ASPEED datasheets name 30662306a36Sopenharmony_ci * them differently. An input-only GPIO such as T0 has: 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * - expr->signal set to "GPIT0" 30962306a36Sopenharmony_ci * - expr->function set to "GPIT0" 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * It's tempting to generalise the prefix test from "GPIO" to "GPI" to 31262306a36Sopenharmony_ci * account for both GPIOs and GPIs, but in doing so we run aground on 31362306a36Sopenharmony_ci * another feature: 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * Some pins in the ASPEED BMC SoCs have a "pass-through" GPIO 31662306a36Sopenharmony_ci * function where the input state of one pin is replicated as the 31762306a36Sopenharmony_ci * output state of another (as if they were shorted together - a mux 31862306a36Sopenharmony_ci * configuration that is typically enabled by hardware strapping). 31962306a36Sopenharmony_ci * This feature allows the BMC to pass e.g. power button state through 32062306a36Sopenharmony_ci * to the host while the BMC is yet to boot, but take control of the 32162306a36Sopenharmony_ci * button state once the BMC has booted by muxing each pin as a 32262306a36Sopenharmony_ci * separate, pin-specific GPIO. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * Conceptually this pass-through mode is a form of GPIO and is named 32562306a36Sopenharmony_ci * as such in the datasheets, e.g. "GPID0". This naming similarity 32662306a36Sopenharmony_ci * trips us up with the simple GPI-prefixed-signal-name scheme 32762306a36Sopenharmony_ci * discussed above, as the pass-through configuration is not what we 32862306a36Sopenharmony_ci * want when muxing a pin as GPIO for the GPIO subsystem. 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * On e.g. the AST2400, a pass-through function "GPID0" is grouped on 33162306a36Sopenharmony_ci * balls A18 and D16, where we have: 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * For ball A18: 33462306a36Sopenharmony_ci * - expr->signal set to "GPID0IN" 33562306a36Sopenharmony_ci * - expr->function set to "GPID0" 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * For ball D16: 33862306a36Sopenharmony_ci * - expr->signal set to "GPID0OUT" 33962306a36Sopenharmony_ci * - expr->function set to "GPID0" 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * By contrast, the pin-specific GPIO expressions for the same pins are 34262306a36Sopenharmony_ci * as follows: 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * For ball A18: 34562306a36Sopenharmony_ci * - expr->signal looks like "GPIOD0" 34662306a36Sopenharmony_ci * - expr->function looks like "GPIOD0" 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * For ball D16: 34962306a36Sopenharmony_ci * - expr->signal looks like "GPIOD1" 35062306a36Sopenharmony_ci * - expr->function looks like "GPIOD1" 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * Testing both the signal _and_ function names gives us the means 35362306a36Sopenharmony_ci * differentiate the pass-through GPIO pinmux configuration from the 35462306a36Sopenharmony_ci * pin-specific configuration that the GPIO subsystem is after: An 35562306a36Sopenharmony_ci * expression is a pin-specific (non-pass-through) GPIO configuration 35662306a36Sopenharmony_ci * if the signal prefix is "GPI" and the signal name matches the 35762306a36Sopenharmony_ci * function name. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci return !strncmp(expr->signal, "GPI", 3) && 36062306a36Sopenharmony_ci !strcmp(expr->signal, expr->function); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic bool aspeed_gpio_in_exprs(const struct aspeed_sig_expr **exprs) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci if (!exprs) 36662306a36Sopenharmony_ci return false; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci while (*exprs) { 36962306a36Sopenharmony_ci if (aspeed_expr_is_gpio(*exprs)) 37062306a36Sopenharmony_ci return true; 37162306a36Sopenharmony_ci exprs++; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return false; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciint aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, 37862306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 37962306a36Sopenharmony_ci unsigned int offset) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci int ret; 38262306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); 38362306a36Sopenharmony_ci const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; 38462306a36Sopenharmony_ci const struct aspeed_sig_expr ***prios, **funcs, *expr; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (!pdesc) 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci prios = pdesc->prios; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (!prios) 39262306a36Sopenharmony_ci return -ENXIO; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci pr_debug("Muxing pin %s for GPIO\n", pdesc->name); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Disable any functions of higher priority than GPIO */ 39762306a36Sopenharmony_ci while ((funcs = *prios)) { 39862306a36Sopenharmony_ci if (aspeed_gpio_in_exprs(funcs)) 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ret = aspeed_disable_sig(&pdata->pinmux, funcs); 40262306a36Sopenharmony_ci if (ret) 40362306a36Sopenharmony_ci return ret; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci prios++; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (!funcs) { 40962306a36Sopenharmony_ci char *signals = get_defined_signals(pdesc); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n", 41262306a36Sopenharmony_ci pdesc->name, offset, signals); 41362306a36Sopenharmony_ci kfree(signals); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return -ENXIO; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci expr = *funcs; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* 42162306a36Sopenharmony_ci * Disabling all higher-priority expressions is enough to enable the 42262306a36Sopenharmony_ci * lowest-priority signal type. As such it has no associated 42362306a36Sopenharmony_ci * expression. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci if (!expr) { 42662306a36Sopenharmony_ci pr_debug("Muxed pin %s as GPIO\n", pdesc->name); 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* 43162306a36Sopenharmony_ci * If GPIO is not the lowest priority signal type, assume there is only 43262306a36Sopenharmony_ci * one expression defined to enable the GPIO function 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci ret = aspeed_sig_expr_enable(&pdata->pinmux, expr); 43562306a36Sopenharmony_ci if (ret) 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci pr_debug("Muxed pin %s as %s\n", pdesc->name, expr->signal); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciint aspeed_pinctrl_probe(struct platform_device *pdev, 44462306a36Sopenharmony_ci struct pinctrl_desc *pdesc, 44562306a36Sopenharmony_ci struct aspeed_pinctrl_data *pdata) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct device *parent; 44862306a36Sopenharmony_ci struct pinctrl_dev *pctl; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci parent = pdev->dev.parent; 45162306a36Sopenharmony_ci if (!parent) { 45262306a36Sopenharmony_ci dev_err(&pdev->dev, "No parent for syscon pincontroller\n"); 45362306a36Sopenharmony_ci return -ENODEV; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci pdata->scu = syscon_node_to_regmap(parent->of_node); 45762306a36Sopenharmony_ci if (IS_ERR(pdata->scu)) { 45862306a36Sopenharmony_ci dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n"); 45962306a36Sopenharmony_ci return PTR_ERR(pdata->scu); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci pdata->pinmux.maps[ASPEED_IP_SCU] = pdata->scu; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci pctl = pinctrl_register(pdesc, &pdev->dev, pdata); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (IS_ERR(pctl)) { 46762306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register pinctrl\n"); 46862306a36Sopenharmony_ci return PTR_ERR(pctl); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci platform_set_drvdata(pdev, pdata); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic inline bool pin_in_config_range(unsigned int offset, 47762306a36Sopenharmony_ci const struct aspeed_pin_config *config) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci return offset >= config->pins[0] && offset <= config->pins[1]; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic inline const struct aspeed_pin_config *find_pinconf_config( 48362306a36Sopenharmony_ci const struct aspeed_pinctrl_data *pdata, 48462306a36Sopenharmony_ci unsigned int offset, 48562306a36Sopenharmony_ci enum pin_config_param param) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci unsigned int i; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (i = 0; i < pdata->nconfigs; i++) { 49062306a36Sopenharmony_ci if (param == pdata->configs[i].param && 49162306a36Sopenharmony_ci pin_in_config_range(offset, &pdata->configs[i])) 49262306a36Sopenharmony_ci return &pdata->configs[i]; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return NULL; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cienum aspeed_pin_config_map_type { MAP_TYPE_ARG, MAP_TYPE_VAL }; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic const struct aspeed_pin_config_map *find_pinconf_map( 50162306a36Sopenharmony_ci const struct aspeed_pinctrl_data *pdata, 50262306a36Sopenharmony_ci enum pin_config_param param, 50362306a36Sopenharmony_ci enum aspeed_pin_config_map_type type, 50462306a36Sopenharmony_ci s64 value) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int i; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci for (i = 0; i < pdata->nconfmaps; i++) { 50962306a36Sopenharmony_ci const struct aspeed_pin_config_map *elem; 51062306a36Sopenharmony_ci bool match; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci elem = &pdata->confmaps[i]; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci switch (type) { 51562306a36Sopenharmony_ci case MAP_TYPE_ARG: 51662306a36Sopenharmony_ci match = (elem->arg == -1 || elem->arg == value); 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci case MAP_TYPE_VAL: 51962306a36Sopenharmony_ci match = (elem->val == value); 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (param == elem->param && match) 52462306a36Sopenharmony_ci return elem; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return NULL; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciint aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset, 53162306a36Sopenharmony_ci unsigned long *config) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci const enum pin_config_param param = pinconf_to_config_param(*config); 53462306a36Sopenharmony_ci const struct aspeed_pin_config_map *pmap; 53562306a36Sopenharmony_ci const struct aspeed_pinctrl_data *pdata; 53662306a36Sopenharmony_ci const struct aspeed_pin_config *pconf; 53762306a36Sopenharmony_ci unsigned int val; 53862306a36Sopenharmony_ci int rc = 0; 53962306a36Sopenharmony_ci u32 arg; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci pdata = pinctrl_dev_get_drvdata(pctldev); 54262306a36Sopenharmony_ci pconf = find_pinconf_config(pdata, offset, param); 54362306a36Sopenharmony_ci if (!pconf) 54462306a36Sopenharmony_ci return -ENOTSUPP; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci rc = regmap_read(pdata->scu, pconf->reg, &val); 54762306a36Sopenharmony_ci if (rc < 0) 54862306a36Sopenharmony_ci return rc; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci pmap = find_pinconf_map(pdata, param, MAP_TYPE_VAL, 55162306a36Sopenharmony_ci (val & pconf->mask) >> __ffs(pconf->mask)); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (!pmap) 55462306a36Sopenharmony_ci return -EINVAL; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (param == PIN_CONFIG_DRIVE_STRENGTH) 55762306a36Sopenharmony_ci arg = (u32) pmap->arg; 55862306a36Sopenharmony_ci else if (param == PIN_CONFIG_BIAS_PULL_DOWN) 55962306a36Sopenharmony_ci arg = !!pmap->arg; 56062306a36Sopenharmony_ci else 56162306a36Sopenharmony_ci arg = 1; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (!arg) 56462306a36Sopenharmony_ci return -EINVAL; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ciint aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset, 57262306a36Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci const struct aspeed_pinctrl_data *pdata; 57562306a36Sopenharmony_ci unsigned int i; 57662306a36Sopenharmony_ci int rc = 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci pdata = pinctrl_dev_get_drvdata(pctldev); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 58162306a36Sopenharmony_ci const struct aspeed_pin_config_map *pmap; 58262306a36Sopenharmony_ci const struct aspeed_pin_config *pconf; 58362306a36Sopenharmony_ci enum pin_config_param param; 58462306a36Sopenharmony_ci unsigned int val; 58562306a36Sopenharmony_ci u32 arg; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 58862306a36Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci pconf = find_pinconf_config(pdata, offset, param); 59162306a36Sopenharmony_ci if (!pconf) 59262306a36Sopenharmony_ci return -ENOTSUPP; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci pmap = find_pinconf_map(pdata, param, MAP_TYPE_ARG, arg); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (WARN_ON(!pmap)) 59762306a36Sopenharmony_ci return -EINVAL; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci val = pmap->val << __ffs(pconf->mask); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci rc = regmap_update_bits(pdata->scu, pconf->reg, 60262306a36Sopenharmony_ci pconf->mask, val); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (rc < 0) 60562306a36Sopenharmony_ci return rc; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci pr_debug("%s: Set SCU%02X[0x%08X]=0x%X for param %d(=%d) on pin %d\n", 60862306a36Sopenharmony_ci __func__, pconf->reg, pconf->mask, 60962306a36Sopenharmony_ci val, param, arg, offset); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ciint aspeed_pin_config_group_get(struct pinctrl_dev *pctldev, 61662306a36Sopenharmony_ci unsigned int selector, 61762306a36Sopenharmony_ci unsigned long *config) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci const unsigned int *pins; 62062306a36Sopenharmony_ci unsigned int npins; 62162306a36Sopenharmony_ci int rc; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci rc = aspeed_pinctrl_get_group_pins(pctldev, selector, &pins, &npins); 62462306a36Sopenharmony_ci if (rc < 0) 62562306a36Sopenharmony_ci return rc; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!npins) 62862306a36Sopenharmony_ci return -ENODEV; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci rc = aspeed_pin_config_get(pctldev, pins[0], config); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return rc; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ciint aspeed_pin_config_group_set(struct pinctrl_dev *pctldev, 63662306a36Sopenharmony_ci unsigned int selector, 63762306a36Sopenharmony_ci unsigned long *configs, 63862306a36Sopenharmony_ci unsigned int num_configs) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci const unsigned int *pins; 64162306a36Sopenharmony_ci unsigned int npins; 64262306a36Sopenharmony_ci int rc; 64362306a36Sopenharmony_ci int i; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci pr_debug("%s: Fetching pins for group selector %d\n", 64662306a36Sopenharmony_ci __func__, selector); 64762306a36Sopenharmony_ci rc = aspeed_pinctrl_get_group_pins(pctldev, selector, &pins, &npins); 64862306a36Sopenharmony_ci if (rc < 0) 64962306a36Sopenharmony_ci return rc; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 65262306a36Sopenharmony_ci rc = aspeed_pin_config_set(pctldev, pins[i], configs, 65362306a36Sopenharmony_ci num_configs); 65462306a36Sopenharmony_ci if (rc < 0) 65562306a36Sopenharmony_ci return rc; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 660