// SPDX-License-Identifier: GPL-2.0-only /* * Core driver for the generic pin config portions of the pin control subsystem * * Copyright (C) 2011 ST-Ericsson SA * Written on behalf of Linaro for ST-Ericsson * * Author: Linus Walleij <linus.walleij@linaro.org>
*/
staticvoid pinconf_generic_dump_one(struct pinctrl_dev *pctldev, struct seq_file *s, constchar *gname, unsignedint pin, conststruct pin_config_item *items, int nitems, int *print_sep)
{ int i;
for (i = 0; i < nitems; i++) { unsignedlong config; int ret;
/* We want to check out this parameter */
config = pinconf_to_config_packed(items[i].param, 0); if (gname)
ret = pin_config_group_get(dev_name(pctldev->dev),
gname, &config); else
ret = pin_config_get_for_pin(pctldev, pin, &config); /* These are legal errors */ if (ret == -EINVAL || ret == -ENOTSUPP) continue; if (ret) {
seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); continue;
} /* comma between multiple configs */ if (*print_sep)
seq_puts(s, ", ");
*print_sep = 1;
seq_puts(s, items[i].display); /* Print unit if available */ if (items[i].has_arg) {
u32 val = pinconf_to_config_argument(config);
/** * pinconf_generic_dump_pins - Print information about pin or group of pins * @pctldev: Pincontrol device * @s: File to print to * @gname: Group name specifying pins * @pin: Pin number specyfying pin * * Print the pinconf configuration for the requested pin(s) to @s. Pins can be * specified either by pin using @pin or by group using @gname. Only one needs * to be specified the other can be NULL/0.
*/ void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s, constchar *gname, unsignedint pin)
{ conststruct pinconf_ops *ops = pctldev->desc->confops; int print_sep = 0;
for (i = 0; i < ARRAY_SIZE(conf_items); i++) { if (pinconf_to_config_param(config) != conf_items[i].param) continue;
seq_printf(s, "%s: 0x%x", conf_items[i].display,
pinconf_to_config_argument(config));
}
if (!pctldev->desc->num_custom_params ||
!pctldev->desc->custom_conf_items) return;
for (i = 0; i < pctldev->desc->num_custom_params; i++) { if (pinconf_to_config_param(config) !=
pctldev->desc->custom_conf_items[i].param) continue;
seq_printf(s, "%s: 0x%x",
pctldev->desc->custom_conf_items[i].display,
pinconf_to_config_argument(config));
}
}
EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); #endif
/** * parse_dt_cfg() - Parse DT pinconf parameters * @np: DT node * @params: Array of describing generic parameters * @count: Number of entries in @params * @cfg: Array of parsed config options * @ncfg: Number of entries in @cfg * * Parse the config options described in @params from @np and puts the result * in @cfg. @cfg does not need to be empty, entries are added beginning at * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg * needs to have enough memory allocated to hold all possible entries.
*/ staticvoid parse_dt_cfg(struct device_node *np, conststruct pinconf_generic_params *params, unsignedint count, unsignedlong *cfg, unsignedint *ncfg)
{ int i;
for (i = 0; i < count; i++) {
u32 val; int ret; conststruct pinconf_generic_params *par = ¶ms[i];
ret = of_property_read_u32(np, par->property, &val);
/* property not found */ if (ret == -EINVAL) continue;
/* use default value, when no value is specified */ if (ret)
val = par->default_value;
pr_debug("found %s with value %u\n", par->property, val);
cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
(*ncfg)++;
}
}
/** * pinconf_generic_parse_dt_pinmux() * parse the pinmux properties into generic pin mux values. * @np: node containing the pinmux properties * @dev: pincontrol core device * @pid: array with pin identity entries * @pmux: array with pin mux value entries * @npins: number of pins * * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits.
*/ int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, unsignedint **pid, unsignedint **pmux, unsignedint *npins)
{ unsignedint *pid_t; unsignedint *pmux_t; struct property *prop; unsignedint npins_t, i;
u32 value; int ret;
/** * pinconf_generic_parse_dt_config() * parse the config properties into generic pinconfig values. * @np: node containing the pinconfig properties * @pctldev: pincontrol device * @configs: array with nconfigs entries containing the generic pinconf values * must be freed when no longer necessary. * @nconfigs: number of configurations
*/ int pinconf_generic_parse_dt_config(struct device_node *np, struct pinctrl_dev *pctldev, unsignedlong **configs, unsignedint *nconfigs)
{ unsignedlong *cfg; unsignedint max_cfg, ncfg = 0; int ret;
if (!np) return -EINVAL;
/* allocate a temporary array big enough to hold one of each option */
max_cfg = ARRAY_SIZE(dt_params); if (pctldev)
max_cfg += pctldev->desc->num_custom_params;
cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM;
/* no configs found at all */ if (ncfg == 0) {
*configs = NULL;
*nconfigs = 0; goto out;
}
/* * Now limit the number of configs to the real number of * found properties.
*/
*configs = kmemdup(cfg, ncfg * sizeof(unsignedlong), GFP_KERNEL); if (!*configs) {
ret = -ENOMEM; goto out;
}
ret = of_property_count_strings(np, "pins"); if (ret < 0) {
ret = of_property_count_strings(np, "groups"); if (ret < 0) /* skip this node; may contain config child nodes */ return 0; if (type == PIN_MAP_TYPE_INVALID)
type = PIN_MAP_TYPE_CONFIGS_GROUP;
subnode_target_type = "groups";
} else { if (type == PIN_MAP_TYPE_INVALID)
type = PIN_MAP_TYPE_CONFIGS_PIN;
}
strings_count = ret;
ret = of_property_read_string(np, "function", &function); if (ret < 0) { /* EINVAL=missing, which is fine since it's optional */ if (ret != -EINVAL)
dev_err(dev, "%pOF: could not parse property function\n",
np);
function = NULL;
}
ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
&num_configs); if (ret < 0) {
dev_err(dev, "%pOF: could not parse node property\n", np); return ret;
}
reserve = 0; if (function != NULL)
reserve++; if (num_configs)
reserve++;
reserve *= strings_count;
ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
num_maps, reserve); if (ret < 0) gotoexit;
of_property_for_each_string(np, subnode_target_type, prop, group) { if (function) {
ret = pinctrl_utils_add_map_mux(pctldev, map,
reserved_maps, num_maps, group,
function); if (ret < 0) gotoexit;
}
if (num_configs) {
ret = pinctrl_utils_add_map_configs(pctldev, map,
reserved_maps, num_maps, group, configs,
num_configs, type); if (ret < 0) gotoexit;
}
}
ret = 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.