162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Core driver for the pin muxing portions of the pin control subsystem 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011-2012 ST-Ericsson SA 662306a36Sopenharmony_ci * Written on behalf of Linaro for ST-Ericsson 762306a36Sopenharmony_ci * Based on bits of regulator core, gpio core and clk core 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Linus Walleij <linus.walleij@linaro.org> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#define pr_fmt(fmt) "pinmux core: " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/ctype.h> 1662306a36Sopenharmony_ci#include <linux/debugfs.h> 1762306a36Sopenharmony_ci#include <linux/device.h> 1862306a36Sopenharmony_ci#include <linux/err.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/list.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/radix-tree.h> 2462306a36Sopenharmony_ci#include <linux/seq_file.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/string.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/pinctrl/machine.h> 2962306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 3062306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "core.h" 3362306a36Sopenharmony_ci#include "pinmux.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint pinmux_check_ops(struct pinctrl_dev *pctldev) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 3862306a36Sopenharmony_ci unsigned nfuncs; 3962306a36Sopenharmony_ci unsigned selector = 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* Check that we implement required operations */ 4262306a36Sopenharmony_ci if (!ops || 4362306a36Sopenharmony_ci !ops->get_functions_count || 4462306a36Sopenharmony_ci !ops->get_function_name || 4562306a36Sopenharmony_ci !ops->get_function_groups || 4662306a36Sopenharmony_ci !ops->set_mux) { 4762306a36Sopenharmony_ci dev_err(pctldev->dev, "pinmux ops lacks necessary functions\n"); 4862306a36Sopenharmony_ci return -EINVAL; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci /* Check that all functions registered have names */ 5162306a36Sopenharmony_ci nfuncs = ops->get_functions_count(pctldev); 5262306a36Sopenharmony_ci while (selector < nfuncs) { 5362306a36Sopenharmony_ci const char *fname = ops->get_function_name(pctldev, 5462306a36Sopenharmony_ci selector); 5562306a36Sopenharmony_ci if (!fname) { 5662306a36Sopenharmony_ci dev_err(pctldev->dev, "pinmux ops has no name for function%u\n", 5762306a36Sopenharmony_ci selector); 5862306a36Sopenharmony_ci return -EINVAL; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci selector++; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciint pinmux_validate_map(const struct pinctrl_map *map, int i) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci if (!map->data.mux.function) { 6962306a36Sopenharmony_ci pr_err("failed to register map %s (%d): no function given\n", 7062306a36Sopenharmony_ci map->name, i); 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * pinmux_can_be_used_for_gpio() - check if a specific pin 7962306a36Sopenharmony_ci * is either muxed to a different function or used as gpio. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * @pctldev: the associated pin controller device 8262306a36Sopenharmony_ci * @pin: the pin number in the global pin space 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Controllers not defined as strict will always return true, 8562306a36Sopenharmony_ci * menaning that the gpio can be used. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cibool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct pin_desc *desc = pin_desc_get(pctldev, pin); 9062306a36Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Can't inspect pin, assume it can be used */ 9362306a36Sopenharmony_ci if (!desc || !ops) 9462306a36Sopenharmony_ci return true; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (ops->strict && desc->mux_usecount) 9762306a36Sopenharmony_ci return false; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return !(ops->strict && !!desc->gpio_owner); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/** 10362306a36Sopenharmony_ci * pin_request() - request a single pin to be muxed in, typically for GPIO 10462306a36Sopenharmony_ci * @pctldev: the associated pin controller device 10562306a36Sopenharmony_ci * @pin: the pin number in the global pin space 10662306a36Sopenharmony_ci * @owner: a representation of the owner of this pin; typically the device 10762306a36Sopenharmony_ci * name that controls its mux function, or the requested GPIO name 10862306a36Sopenharmony_ci * @gpio_range: the range matching the GPIO pin if this is a request for a 10962306a36Sopenharmony_ci * single GPIO pin 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_cistatic int pin_request(struct pinctrl_dev *pctldev, 11262306a36Sopenharmony_ci int pin, const char *owner, 11362306a36Sopenharmony_ci struct pinctrl_gpio_range *gpio_range) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct pin_desc *desc; 11662306a36Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 11762306a36Sopenharmony_ci int status = -EINVAL; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pin); 12062306a36Sopenharmony_ci if (desc == NULL) { 12162306a36Sopenharmony_ci dev_err(pctldev->dev, 12262306a36Sopenharmony_ci "pin %d is not registered so it cannot be requested\n", 12362306a36Sopenharmony_ci pin); 12462306a36Sopenharmony_ci goto out; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", 12862306a36Sopenharmony_ci pin, desc->name, owner); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if ((!gpio_range || ops->strict) && 13162306a36Sopenharmony_ci desc->mux_usecount && strcmp(desc->mux_owner, owner)) { 13262306a36Sopenharmony_ci dev_err(pctldev->dev, 13362306a36Sopenharmony_ci "pin %s already requested by %s; cannot claim for %s\n", 13462306a36Sopenharmony_ci desc->name, desc->mux_owner, owner); 13562306a36Sopenharmony_ci goto out; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if ((gpio_range || ops->strict) && desc->gpio_owner) { 13962306a36Sopenharmony_ci dev_err(pctldev->dev, 14062306a36Sopenharmony_ci "pin %s already requested by %s; cannot claim for %s\n", 14162306a36Sopenharmony_ci desc->name, desc->gpio_owner, owner); 14262306a36Sopenharmony_ci goto out; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (gpio_range) { 14662306a36Sopenharmony_ci desc->gpio_owner = owner; 14762306a36Sopenharmony_ci } else { 14862306a36Sopenharmony_ci desc->mux_usecount++; 14962306a36Sopenharmony_ci if (desc->mux_usecount > 1) 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci desc->mux_owner = owner; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Let each pin increase references to this module */ 15662306a36Sopenharmony_ci if (!try_module_get(pctldev->owner)) { 15762306a36Sopenharmony_ci dev_err(pctldev->dev, 15862306a36Sopenharmony_ci "could not increase module refcount for pin %d\n", 15962306a36Sopenharmony_ci pin); 16062306a36Sopenharmony_ci status = -EINVAL; 16162306a36Sopenharmony_ci goto out_free_pin; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * If there is no kind of request function for the pin we just assume 16662306a36Sopenharmony_ci * we got it by default and proceed. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci if (gpio_range && ops->gpio_request_enable) 16962306a36Sopenharmony_ci /* This requests and enables a single GPIO pin */ 17062306a36Sopenharmony_ci status = ops->gpio_request_enable(pctldev, gpio_range, pin); 17162306a36Sopenharmony_ci else if (ops->request) 17262306a36Sopenharmony_ci status = ops->request(pctldev, pin); 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci status = 0; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (status) { 17762306a36Sopenharmony_ci dev_err(pctldev->dev, "request() failed for pin %d\n", pin); 17862306a36Sopenharmony_ci module_put(pctldev->owner); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciout_free_pin: 18262306a36Sopenharmony_ci if (status) { 18362306a36Sopenharmony_ci if (gpio_range) { 18462306a36Sopenharmony_ci desc->gpio_owner = NULL; 18562306a36Sopenharmony_ci } else { 18662306a36Sopenharmony_ci desc->mux_usecount--; 18762306a36Sopenharmony_ci if (!desc->mux_usecount) 18862306a36Sopenharmony_ci desc->mux_owner = NULL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ciout: 19262306a36Sopenharmony_ci if (status) 19362306a36Sopenharmony_ci dev_err(pctldev->dev, "pin-%d (%s) status %d\n", 19462306a36Sopenharmony_ci pin, owner, status); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return status; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/** 20062306a36Sopenharmony_ci * pin_free() - release a single muxed in pin so something else can be muxed 20162306a36Sopenharmony_ci * @pctldev: pin controller device handling this pin 20262306a36Sopenharmony_ci * @pin: the pin to free 20362306a36Sopenharmony_ci * @gpio_range: the range matching the GPIO pin if this is a request for a 20462306a36Sopenharmony_ci * single GPIO pin 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * This function returns a pointer to the previous owner. This is used 20762306a36Sopenharmony_ci * for callers that dynamically allocate an owner name so it can be freed 20862306a36Sopenharmony_ci * once the pin is free. This is done for GPIO request functions. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_cistatic const char *pin_free(struct pinctrl_dev *pctldev, int pin, 21162306a36Sopenharmony_ci struct pinctrl_gpio_range *gpio_range) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 21462306a36Sopenharmony_ci struct pin_desc *desc; 21562306a36Sopenharmony_ci const char *owner; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pin); 21862306a36Sopenharmony_ci if (desc == NULL) { 21962306a36Sopenharmony_ci dev_err(pctldev->dev, 22062306a36Sopenharmony_ci "pin is not registered so it cannot be freed\n"); 22162306a36Sopenharmony_ci return NULL; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!gpio_range) { 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * A pin should not be freed more times than allocated. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci if (WARN_ON(!desc->mux_usecount)) 22962306a36Sopenharmony_ci return NULL; 23062306a36Sopenharmony_ci desc->mux_usecount--; 23162306a36Sopenharmony_ci if (desc->mux_usecount) 23262306a36Sopenharmony_ci return NULL; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * If there is no kind of request function for the pin we just assume 23762306a36Sopenharmony_ci * we got it by default and proceed. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci if (gpio_range && ops->gpio_disable_free) 24062306a36Sopenharmony_ci ops->gpio_disable_free(pctldev, gpio_range, pin); 24162306a36Sopenharmony_ci else if (ops->free) 24262306a36Sopenharmony_ci ops->free(pctldev, pin); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (gpio_range) { 24562306a36Sopenharmony_ci owner = desc->gpio_owner; 24662306a36Sopenharmony_ci desc->gpio_owner = NULL; 24762306a36Sopenharmony_ci } else { 24862306a36Sopenharmony_ci owner = desc->mux_owner; 24962306a36Sopenharmony_ci desc->mux_owner = NULL; 25062306a36Sopenharmony_ci desc->mux_setting = NULL; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci module_put(pctldev->owner); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return owner; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * pinmux_request_gpio() - request pinmuxing for a GPIO pin 26062306a36Sopenharmony_ci * @pctldev: pin controller device affected 26162306a36Sopenharmony_ci * @pin: the pin to mux in for GPIO 26262306a36Sopenharmony_ci * @range: the applicable GPIO range 26362306a36Sopenharmony_ci * @gpio: number of requested GPIO 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ciint pinmux_request_gpio(struct pinctrl_dev *pctldev, 26662306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 26762306a36Sopenharmony_ci unsigned pin, unsigned gpio) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci const char *owner; 27062306a36Sopenharmony_ci int ret; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Conjure some name stating what chip and pin this is taken by */ 27362306a36Sopenharmony_ci owner = kasprintf(GFP_KERNEL, "%s:%d", range->name, gpio); 27462306a36Sopenharmony_ci if (!owner) 27562306a36Sopenharmony_ci return -ENOMEM; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ret = pin_request(pctldev, pin, owner, range); 27862306a36Sopenharmony_ci if (ret < 0) 27962306a36Sopenharmony_ci kfree(owner); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return ret; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * pinmux_free_gpio() - release a pin from GPIO muxing 28662306a36Sopenharmony_ci * @pctldev: the pin controller device for the pin 28762306a36Sopenharmony_ci * @pin: the affected currently GPIO-muxed in pin 28862306a36Sopenharmony_ci * @range: applicable GPIO range 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_civoid pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin, 29162306a36Sopenharmony_ci struct pinctrl_gpio_range *range) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci const char *owner; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci owner = pin_free(pctldev, pin, range); 29662306a36Sopenharmony_ci kfree(owner); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/** 30062306a36Sopenharmony_ci * pinmux_gpio_direction() - set the direction of a single muxed-in GPIO pin 30162306a36Sopenharmony_ci * @pctldev: the pin controller handling this pin 30262306a36Sopenharmony_ci * @range: applicable GPIO range 30362306a36Sopenharmony_ci * @pin: the affected GPIO pin in this controller 30462306a36Sopenharmony_ci * @input: true if we set the pin as input, false for output 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ciint pinmux_gpio_direction(struct pinctrl_dev *pctldev, 30762306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 30862306a36Sopenharmony_ci unsigned pin, bool input) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci const struct pinmux_ops *ops; 31162306a36Sopenharmony_ci int ret; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ops = pctldev->desc->pmxops; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (ops->gpio_set_direction) 31662306a36Sopenharmony_ci ret = ops->gpio_set_direction(pctldev, range, pin, input); 31762306a36Sopenharmony_ci else 31862306a36Sopenharmony_ci ret = 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return ret; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, 32462306a36Sopenharmony_ci const char *function) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 32762306a36Sopenharmony_ci unsigned nfuncs = ops->get_functions_count(pctldev); 32862306a36Sopenharmony_ci unsigned selector = 0; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* See if this pctldev has this function */ 33162306a36Sopenharmony_ci while (selector < nfuncs) { 33262306a36Sopenharmony_ci const char *fname = ops->get_function_name(pctldev, selector); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!strcmp(function, fname)) 33562306a36Sopenharmony_ci return selector; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci selector++; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciint pinmux_map_to_setting(const struct pinctrl_map *map, 34462306a36Sopenharmony_ci struct pinctrl_setting *setting) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 34762306a36Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 34862306a36Sopenharmony_ci char const * const *groups; 34962306a36Sopenharmony_ci unsigned num_groups; 35062306a36Sopenharmony_ci int ret; 35162306a36Sopenharmony_ci const char *group; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (!pmxops) { 35462306a36Sopenharmony_ci dev_err(pctldev->dev, "does not support mux function\n"); 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function); 35962306a36Sopenharmony_ci if (ret < 0) { 36062306a36Sopenharmony_ci dev_err(pctldev->dev, "invalid function %s in map table\n", 36162306a36Sopenharmony_ci map->data.mux.function); 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci setting->data.mux.func = ret; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ret = pmxops->get_function_groups(pctldev, setting->data.mux.func, 36762306a36Sopenharmony_ci &groups, &num_groups); 36862306a36Sopenharmony_ci if (ret < 0) { 36962306a36Sopenharmony_ci dev_err(pctldev->dev, "can't query groups for function %s\n", 37062306a36Sopenharmony_ci map->data.mux.function); 37162306a36Sopenharmony_ci return ret; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci if (!num_groups) { 37462306a36Sopenharmony_ci dev_err(pctldev->dev, 37562306a36Sopenharmony_ci "function %s can't be selected on any group\n", 37662306a36Sopenharmony_ci map->data.mux.function); 37762306a36Sopenharmony_ci return -EINVAL; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci if (map->data.mux.group) { 38062306a36Sopenharmony_ci group = map->data.mux.group; 38162306a36Sopenharmony_ci ret = match_string(groups, num_groups, group); 38262306a36Sopenharmony_ci if (ret < 0) { 38362306a36Sopenharmony_ci dev_err(pctldev->dev, 38462306a36Sopenharmony_ci "invalid group \"%s\" for function \"%s\"\n", 38562306a36Sopenharmony_ci group, map->data.mux.function); 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } else { 38962306a36Sopenharmony_ci group = groups[0]; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci ret = pinctrl_get_group_selector(pctldev, group); 39362306a36Sopenharmony_ci if (ret < 0) { 39462306a36Sopenharmony_ci dev_err(pctldev->dev, "invalid group %s in map table\n", 39562306a36Sopenharmony_ci map->data.mux.group); 39662306a36Sopenharmony_ci return ret; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci setting->data.mux.group = ret; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_civoid pinmux_free_setting(const struct pinctrl_setting *setting) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci /* This function is currently unused */ 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciint pinmux_enable_setting(const struct pinctrl_setting *setting) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 41162306a36Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 41262306a36Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 41362306a36Sopenharmony_ci int ret = 0; 41462306a36Sopenharmony_ci const unsigned *pins = NULL; 41562306a36Sopenharmony_ci unsigned num_pins = 0; 41662306a36Sopenharmony_ci int i; 41762306a36Sopenharmony_ci struct pin_desc *desc; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (pctlops->get_group_pins) 42062306a36Sopenharmony_ci ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, 42162306a36Sopenharmony_ci &pins, &num_pins); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (ret) { 42462306a36Sopenharmony_ci const char *gname; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* errors only affect debug data, so just warn */ 42762306a36Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 42862306a36Sopenharmony_ci setting->data.mux.group); 42962306a36Sopenharmony_ci dev_warn(pctldev->dev, 43062306a36Sopenharmony_ci "could not get pins for group %s\n", 43162306a36Sopenharmony_ci gname); 43262306a36Sopenharmony_ci num_pins = 0; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Try to allocate all pins in this group, one by one */ 43662306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) { 43762306a36Sopenharmony_ci ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); 43862306a36Sopenharmony_ci if (ret) { 43962306a36Sopenharmony_ci const char *gname; 44062306a36Sopenharmony_ci const char *pname; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 44362306a36Sopenharmony_ci pname = desc ? desc->name : "non-existing"; 44462306a36Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 44562306a36Sopenharmony_ci setting->data.mux.group); 44662306a36Sopenharmony_ci dev_err(pctldev->dev, 44762306a36Sopenharmony_ci "could not request pin %d (%s) from group %s " 44862306a36Sopenharmony_ci " on device %s\n", 44962306a36Sopenharmony_ci pins[i], pname, gname, 45062306a36Sopenharmony_ci pinctrl_dev_get_name(pctldev)); 45162306a36Sopenharmony_ci goto err_pin_request; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Now that we have acquired the pins, encode the mux setting */ 45662306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) { 45762306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 45862306a36Sopenharmony_ci if (desc == NULL) { 45962306a36Sopenharmony_ci dev_warn(pctldev->dev, 46062306a36Sopenharmony_ci "could not get pin desc for pin %d\n", 46162306a36Sopenharmony_ci pins[i]); 46262306a36Sopenharmony_ci continue; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci desc->mux_setting = &(setting->data.mux); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ret = ops->set_mux(pctldev, setting->data.mux.func, 46862306a36Sopenharmony_ci setting->data.mux.group); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (ret) 47162306a36Sopenharmony_ci goto err_set_mux; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cierr_set_mux: 47662306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) { 47762306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 47862306a36Sopenharmony_ci if (desc) 47962306a36Sopenharmony_ci desc->mux_setting = NULL; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_cierr_pin_request: 48262306a36Sopenharmony_ci /* On error release all taken pins */ 48362306a36Sopenharmony_ci while (--i >= 0) 48462306a36Sopenharmony_ci pin_free(pctldev, pins[i], NULL); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_civoid pinmux_disable_setting(const struct pinctrl_setting *setting) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 49262306a36Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 49362306a36Sopenharmony_ci int ret = 0; 49462306a36Sopenharmony_ci const unsigned *pins = NULL; 49562306a36Sopenharmony_ci unsigned num_pins = 0; 49662306a36Sopenharmony_ci int i; 49762306a36Sopenharmony_ci struct pin_desc *desc; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (pctlops->get_group_pins) 50062306a36Sopenharmony_ci ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, 50162306a36Sopenharmony_ci &pins, &num_pins); 50262306a36Sopenharmony_ci if (ret) { 50362306a36Sopenharmony_ci const char *gname; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* errors only affect debug data, so just warn */ 50662306a36Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 50762306a36Sopenharmony_ci setting->data.mux.group); 50862306a36Sopenharmony_ci dev_warn(pctldev->dev, 50962306a36Sopenharmony_ci "could not get pins for group %s\n", 51062306a36Sopenharmony_ci gname); 51162306a36Sopenharmony_ci num_pins = 0; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Flag the descs that no setting is active */ 51562306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) { 51662306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 51762306a36Sopenharmony_ci if (desc == NULL) { 51862306a36Sopenharmony_ci dev_warn(pctldev->dev, 51962306a36Sopenharmony_ci "could not get pin desc for pin %d\n", 52062306a36Sopenharmony_ci pins[i]); 52162306a36Sopenharmony_ci continue; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci if (desc->mux_setting == &(setting->data.mux)) { 52462306a36Sopenharmony_ci pin_free(pctldev, pins[i], NULL); 52562306a36Sopenharmony_ci } else { 52662306a36Sopenharmony_ci const char *gname; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 52962306a36Sopenharmony_ci setting->data.mux.group); 53062306a36Sopenharmony_ci dev_warn(pctldev->dev, 53162306a36Sopenharmony_ci "not freeing pin %d (%s) as part of " 53262306a36Sopenharmony_ci "deactivating group %s - it is already " 53362306a36Sopenharmony_ci "used for some other setting", 53462306a36Sopenharmony_ci pins[i], desc->name, gname); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/* Called from pincontrol core */ 54262306a36Sopenharmony_cistatic int pinmux_functions_show(struct seq_file *s, void *what) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct pinctrl_dev *pctldev = s->private; 54562306a36Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 54662306a36Sopenharmony_ci unsigned nfuncs; 54762306a36Sopenharmony_ci unsigned func_selector = 0; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (!pmxops) 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci mutex_lock(&pctldev->mutex); 55362306a36Sopenharmony_ci nfuncs = pmxops->get_functions_count(pctldev); 55462306a36Sopenharmony_ci while (func_selector < nfuncs) { 55562306a36Sopenharmony_ci const char *func = pmxops->get_function_name(pctldev, 55662306a36Sopenharmony_ci func_selector); 55762306a36Sopenharmony_ci const char * const *groups; 55862306a36Sopenharmony_ci unsigned num_groups; 55962306a36Sopenharmony_ci int ret; 56062306a36Sopenharmony_ci int i; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ret = pmxops->get_function_groups(pctldev, func_selector, 56362306a36Sopenharmony_ci &groups, &num_groups); 56462306a36Sopenharmony_ci if (ret) { 56562306a36Sopenharmony_ci seq_printf(s, "function %s: COULD NOT GET GROUPS\n", 56662306a36Sopenharmony_ci func); 56762306a36Sopenharmony_ci func_selector++; 56862306a36Sopenharmony_ci continue; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci seq_printf(s, "function %d: %s, groups = [ ", func_selector, func); 57262306a36Sopenharmony_ci for (i = 0; i < num_groups; i++) 57362306a36Sopenharmony_ci seq_printf(s, "%s ", groups[i]); 57462306a36Sopenharmony_ci seq_puts(s, "]\n"); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci func_selector++; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci mutex_unlock(&pctldev->mutex); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int pinmux_pins_show(struct seq_file *s, void *what) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct pinctrl_dev *pctldev = s->private; 58762306a36Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 58862306a36Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 58962306a36Sopenharmony_ci unsigned i, pin; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!pmxops) 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci seq_puts(s, "Pinmux settings per pin\n"); 59562306a36Sopenharmony_ci if (pmxops->strict) 59662306a36Sopenharmony_ci seq_puts(s, 59762306a36Sopenharmony_ci "Format: pin (name): mux_owner|gpio_owner (strict) hog?\n"); 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci seq_puts(s, 60062306a36Sopenharmony_ci "Format: pin (name): mux_owner gpio_owner hog?\n"); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci mutex_lock(&pctldev->mutex); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* The pin number can be retrived from the pin controller descriptor */ 60562306a36Sopenharmony_ci for (i = 0; i < pctldev->desc->npins; i++) { 60662306a36Sopenharmony_ci struct pin_desc *desc; 60762306a36Sopenharmony_ci bool is_hog = false; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci pin = pctldev->desc->pins[i].number; 61062306a36Sopenharmony_ci desc = pin_desc_get(pctldev, pin); 61162306a36Sopenharmony_ci /* Skip if we cannot search the pin */ 61262306a36Sopenharmony_ci if (desc == NULL) 61362306a36Sopenharmony_ci continue; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (desc->mux_owner && 61662306a36Sopenharmony_ci !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) 61762306a36Sopenharmony_ci is_hog = true; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (pmxops->strict) { 62062306a36Sopenharmony_ci if (desc->mux_owner) 62162306a36Sopenharmony_ci seq_printf(s, "pin %d (%s): device %s%s", 62262306a36Sopenharmony_ci pin, desc->name, desc->mux_owner, 62362306a36Sopenharmony_ci is_hog ? " (HOG)" : ""); 62462306a36Sopenharmony_ci else if (desc->gpio_owner) 62562306a36Sopenharmony_ci seq_printf(s, "pin %d (%s): GPIO %s", 62662306a36Sopenharmony_ci pin, desc->name, desc->gpio_owner); 62762306a36Sopenharmony_ci else 62862306a36Sopenharmony_ci seq_printf(s, "pin %d (%s): UNCLAIMED", 62962306a36Sopenharmony_ci pin, desc->name); 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci /* For non-strict controllers */ 63262306a36Sopenharmony_ci seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name, 63362306a36Sopenharmony_ci desc->mux_owner ? desc->mux_owner 63462306a36Sopenharmony_ci : "(MUX UNCLAIMED)", 63562306a36Sopenharmony_ci desc->gpio_owner ? desc->gpio_owner 63662306a36Sopenharmony_ci : "(GPIO UNCLAIMED)", 63762306a36Sopenharmony_ci is_hog ? " (HOG)" : ""); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* If mux: print function+group claiming the pin */ 64162306a36Sopenharmony_ci if (desc->mux_setting) 64262306a36Sopenharmony_ci seq_printf(s, " function %s group %s\n", 64362306a36Sopenharmony_ci pmxops->get_function_name(pctldev, 64462306a36Sopenharmony_ci desc->mux_setting->func), 64562306a36Sopenharmony_ci pctlops->get_group_name(pctldev, 64662306a36Sopenharmony_ci desc->mux_setting->group)); 64762306a36Sopenharmony_ci else 64862306a36Sopenharmony_ci seq_putc(s, '\n'); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci mutex_unlock(&pctldev->mutex); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_civoid pinmux_show_map(struct seq_file *s, const struct pinctrl_map *map) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci seq_printf(s, "group %s\nfunction %s\n", 65962306a36Sopenharmony_ci map->data.mux.group ? map->data.mux.group : "(default)", 66062306a36Sopenharmony_ci map->data.mux.function); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_civoid pinmux_show_setting(struct seq_file *s, 66462306a36Sopenharmony_ci const struct pinctrl_setting *setting) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 66762306a36Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 66862306a36Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci seq_printf(s, "group: %s (%u) function: %s (%u)\n", 67162306a36Sopenharmony_ci pctlops->get_group_name(pctldev, setting->data.mux.group), 67262306a36Sopenharmony_ci setting->data.mux.group, 67362306a36Sopenharmony_ci pmxops->get_function_name(pctldev, setting->data.mux.func), 67462306a36Sopenharmony_ci setting->data.mux.func); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pinmux_functions); 67862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pinmux_pins); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic ssize_t pinmux_select(struct file *file, const char __user *user_buf, 68162306a36Sopenharmony_ci size_t len, loff_t *ppos) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct seq_file *sfile = file->private_data; 68462306a36Sopenharmony_ci struct pinctrl_dev *pctldev = sfile->private; 68562306a36Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 68662306a36Sopenharmony_ci const char *const *groups; 68762306a36Sopenharmony_ci char *buf, *gname, *fname; 68862306a36Sopenharmony_ci unsigned int num_groups; 68962306a36Sopenharmony_ci int fsel, gsel, ret; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci buf = memdup_user_nul(user_buf, len); 69262306a36Sopenharmony_ci if (IS_ERR(buf)) 69362306a36Sopenharmony_ci return PTR_ERR(buf); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* remove leading and trailing spaces of input buffer */ 69662306a36Sopenharmony_ci gname = strstrip(buf); 69762306a36Sopenharmony_ci if (*gname == '\0') { 69862306a36Sopenharmony_ci ret = -EINVAL; 69962306a36Sopenharmony_ci goto exit_free_buf; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* find a separator which is a spacelike character */ 70362306a36Sopenharmony_ci for (fname = gname; !isspace(*fname); fname++) { 70462306a36Sopenharmony_ci if (*fname == '\0') { 70562306a36Sopenharmony_ci ret = -EINVAL; 70662306a36Sopenharmony_ci goto exit_free_buf; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci *fname = '\0'; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* drop extra spaces between function and group names */ 71262306a36Sopenharmony_ci fname = skip_spaces(fname + 1); 71362306a36Sopenharmony_ci if (*fname == '\0') { 71462306a36Sopenharmony_ci ret = -EINVAL; 71562306a36Sopenharmony_ci goto exit_free_buf; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ret = pinmux_func_name_to_selector(pctldev, fname); 71962306a36Sopenharmony_ci if (ret < 0) { 72062306a36Sopenharmony_ci dev_err(pctldev->dev, "invalid function %s in map table\n", fname); 72162306a36Sopenharmony_ci goto exit_free_buf; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci fsel = ret; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ret = pmxops->get_function_groups(pctldev, fsel, &groups, &num_groups); 72662306a36Sopenharmony_ci if (ret) { 72762306a36Sopenharmony_ci dev_err(pctldev->dev, "no groups for function %d (%s)", fsel, fname); 72862306a36Sopenharmony_ci goto exit_free_buf; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci ret = match_string(groups, num_groups, gname); 73262306a36Sopenharmony_ci if (ret < 0) { 73362306a36Sopenharmony_ci dev_err(pctldev->dev, "invalid group %s", gname); 73462306a36Sopenharmony_ci goto exit_free_buf; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ret = pinctrl_get_group_selector(pctldev, gname); 73862306a36Sopenharmony_ci if (ret < 0) 73962306a36Sopenharmony_ci goto exit_free_buf; 74062306a36Sopenharmony_ci gsel = ret; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci ret = pmxops->set_mux(pctldev, fsel, gsel); 74362306a36Sopenharmony_ci if (ret) { 74462306a36Sopenharmony_ci dev_err(pctldev->dev, "set_mux() failed: %d", ret); 74562306a36Sopenharmony_ci goto exit_free_buf; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci ret = len; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ciexit_free_buf: 75062306a36Sopenharmony_ci kfree(buf); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return ret; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int pinmux_select_open(struct inode *inode, struct file *file) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci return single_open(file, NULL, inode->i_private); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic const struct file_operations pinmux_select_ops = { 76162306a36Sopenharmony_ci .owner = THIS_MODULE, 76262306a36Sopenharmony_ci .open = pinmux_select_open, 76362306a36Sopenharmony_ci .write = pinmux_select, 76462306a36Sopenharmony_ci .llseek = no_llseek, 76562306a36Sopenharmony_ci .release = single_release, 76662306a36Sopenharmony_ci}; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_civoid pinmux_init_device_debugfs(struct dentry *devroot, 76962306a36Sopenharmony_ci struct pinctrl_dev *pctldev) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci debugfs_create_file("pinmux-functions", 0444, 77262306a36Sopenharmony_ci devroot, pctldev, &pinmux_functions_fops); 77362306a36Sopenharmony_ci debugfs_create_file("pinmux-pins", 0444, 77462306a36Sopenharmony_ci devroot, pctldev, &pinmux_pins_fops); 77562306a36Sopenharmony_ci debugfs_create_file("pinmux-select", 0200, 77662306a36Sopenharmony_ci devroot, pctldev, &pinmux_select_ops); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/** 78462306a36Sopenharmony_ci * pinmux_generic_get_function_count() - returns number of functions 78562306a36Sopenharmony_ci * @pctldev: pin controller device 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ciint pinmux_generic_get_function_count(struct pinctrl_dev *pctldev) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci return pctldev->num_functions; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function_count); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/** 79462306a36Sopenharmony_ci * pinmux_generic_get_function_name() - returns the function name 79562306a36Sopenharmony_ci * @pctldev: pin controller device 79662306a36Sopenharmony_ci * @selector: function number 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ciconst char * 79962306a36Sopenharmony_cipinmux_generic_get_function_name(struct pinctrl_dev *pctldev, 80062306a36Sopenharmony_ci unsigned int selector) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct function_desc *function; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 80562306a36Sopenharmony_ci selector); 80662306a36Sopenharmony_ci if (!function) 80762306a36Sopenharmony_ci return NULL; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci return function->name; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function_name); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci/** 81462306a36Sopenharmony_ci * pinmux_generic_get_function_groups() - gets the function groups 81562306a36Sopenharmony_ci * @pctldev: pin controller device 81662306a36Sopenharmony_ci * @selector: function number 81762306a36Sopenharmony_ci * @groups: array of pin groups 81862306a36Sopenharmony_ci * @num_groups: number of pin groups 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ciint pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, 82162306a36Sopenharmony_ci unsigned int selector, 82262306a36Sopenharmony_ci const char * const **groups, 82362306a36Sopenharmony_ci unsigned * const num_groups) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct function_desc *function; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 82862306a36Sopenharmony_ci selector); 82962306a36Sopenharmony_ci if (!function) { 83062306a36Sopenharmony_ci dev_err(pctldev->dev, "%s could not find function%i\n", 83162306a36Sopenharmony_ci __func__, selector); 83262306a36Sopenharmony_ci return -EINVAL; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci *groups = function->group_names; 83562306a36Sopenharmony_ci *num_groups = function->num_group_names; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function_groups); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci/** 84262306a36Sopenharmony_ci * pinmux_generic_get_function() - returns a function based on the number 84362306a36Sopenharmony_ci * @pctldev: pin controller device 84462306a36Sopenharmony_ci * @selector: function number 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_cistruct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev, 84762306a36Sopenharmony_ci unsigned int selector) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct function_desc *function; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 85262306a36Sopenharmony_ci selector); 85362306a36Sopenharmony_ci if (!function) 85462306a36Sopenharmony_ci return NULL; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return function; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/** 86162306a36Sopenharmony_ci * pinmux_generic_add_function() - adds a function group 86262306a36Sopenharmony_ci * @pctldev: pin controller device 86362306a36Sopenharmony_ci * @name: name of the function 86462306a36Sopenharmony_ci * @groups: array of pin groups 86562306a36Sopenharmony_ci * @num_groups: number of pin groups 86662306a36Sopenharmony_ci * @data: pin controller driver specific data 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ciint pinmux_generic_add_function(struct pinctrl_dev *pctldev, 86962306a36Sopenharmony_ci const char *name, 87062306a36Sopenharmony_ci const char * const *groups, 87162306a36Sopenharmony_ci const unsigned int num_groups, 87262306a36Sopenharmony_ci void *data) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct function_desc *function; 87562306a36Sopenharmony_ci int selector, error; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (!name) 87862306a36Sopenharmony_ci return -EINVAL; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci selector = pinmux_func_name_to_selector(pctldev, name); 88162306a36Sopenharmony_ci if (selector >= 0) 88262306a36Sopenharmony_ci return selector; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci selector = pctldev->num_functions; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL); 88762306a36Sopenharmony_ci if (!function) 88862306a36Sopenharmony_ci return -ENOMEM; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci function->name = name; 89162306a36Sopenharmony_ci function->group_names = groups; 89262306a36Sopenharmony_ci function->num_group_names = num_groups; 89362306a36Sopenharmony_ci function->data = data; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci error = radix_tree_insert(&pctldev->pin_function_tree, selector, function); 89662306a36Sopenharmony_ci if (error) 89762306a36Sopenharmony_ci return error; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci pctldev->num_functions++; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci return selector; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_add_function); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/** 90662306a36Sopenharmony_ci * pinmux_generic_remove_function() - removes a numbered function 90762306a36Sopenharmony_ci * @pctldev: pin controller device 90862306a36Sopenharmony_ci * @selector: function number 90962306a36Sopenharmony_ci * 91062306a36Sopenharmony_ci * Note that the caller must take care of locking. 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_ciint pinmux_generic_remove_function(struct pinctrl_dev *pctldev, 91362306a36Sopenharmony_ci unsigned int selector) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct function_desc *function; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 91862306a36Sopenharmony_ci selector); 91962306a36Sopenharmony_ci if (!function) 92062306a36Sopenharmony_ci return -ENOENT; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci radix_tree_delete(&pctldev->pin_function_tree, selector); 92362306a36Sopenharmony_ci devm_kfree(pctldev->dev, function); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci pctldev->num_functions--; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_remove_function); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci/** 93262306a36Sopenharmony_ci * pinmux_generic_free_functions() - removes all functions 93362306a36Sopenharmony_ci * @pctldev: pin controller device 93462306a36Sopenharmony_ci * 93562306a36Sopenharmony_ci * Note that the caller must take care of locking. The pinctrl 93662306a36Sopenharmony_ci * functions are allocated with devm_kzalloc() so no need to free 93762306a36Sopenharmony_ci * them here. 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_civoid pinmux_generic_free_functions(struct pinctrl_dev *pctldev) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct radix_tree_iter iter; 94262306a36Sopenharmony_ci void __rcu **slot; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci radix_tree_for_each_slot(slot, &pctldev->pin_function_tree, &iter, 0) 94562306a36Sopenharmony_ci radix_tree_delete(&pctldev->pin_function_tree, iter.index); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci pctldev->num_functions = 0; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */ 951