18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Core driver for the pin muxing portions of the pin control subsystem 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011-2012 ST-Ericsson SA 68c2ecf20Sopenharmony_ci * Written on behalf of Linaro for ST-Ericsson 78c2ecf20Sopenharmony_ci * Based on bits of regulator core, gpio core and clk core 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Author: Linus Walleij <linus.walleij@linaro.org> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "pinmux core: " fmt 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/device.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/radix-tree.h> 218c2ecf20Sopenharmony_ci#include <linux/err.h> 228c2ecf20Sopenharmony_ci#include <linux/list.h> 238c2ecf20Sopenharmony_ci#include <linux/string.h> 248c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 258c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 268c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 278c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 288c2ecf20Sopenharmony_ci#include "core.h" 298c2ecf20Sopenharmony_ci#include "pinmux.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciint pinmux_check_ops(struct pinctrl_dev *pctldev) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 348c2ecf20Sopenharmony_ci unsigned nfuncs; 358c2ecf20Sopenharmony_ci unsigned selector = 0; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* Check that we implement required operations */ 388c2ecf20Sopenharmony_ci if (!ops || 398c2ecf20Sopenharmony_ci !ops->get_functions_count || 408c2ecf20Sopenharmony_ci !ops->get_function_name || 418c2ecf20Sopenharmony_ci !ops->get_function_groups || 428c2ecf20Sopenharmony_ci !ops->set_mux) { 438c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "pinmux ops lacks necessary functions\n"); 448c2ecf20Sopenharmony_ci return -EINVAL; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci /* Check that all functions registered have names */ 478c2ecf20Sopenharmony_ci nfuncs = ops->get_functions_count(pctldev); 488c2ecf20Sopenharmony_ci while (selector < nfuncs) { 498c2ecf20Sopenharmony_ci const char *fname = ops->get_function_name(pctldev, 508c2ecf20Sopenharmony_ci selector); 518c2ecf20Sopenharmony_ci if (!fname) { 528c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "pinmux ops has no name for function%u\n", 538c2ecf20Sopenharmony_ci selector); 548c2ecf20Sopenharmony_ci return -EINVAL; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci selector++; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciint pinmux_validate_map(const struct pinctrl_map *map, int i) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (!map->data.mux.function) { 658c2ecf20Sopenharmony_ci pr_err("failed to register map %s (%d): no function given\n", 668c2ecf20Sopenharmony_ci map->name, i); 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * pinmux_can_be_used_for_gpio() - check if a specific pin 758c2ecf20Sopenharmony_ci * is either muxed to a different function or used as gpio. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * @pctldev: the associated pin controller device 788c2ecf20Sopenharmony_ci * @pin: the pin number in the global pin space 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * Controllers not defined as strict will always return true, 818c2ecf20Sopenharmony_ci * menaning that the gpio can be used. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cibool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct pin_desc *desc = pin_desc_get(pctldev, pin); 868c2ecf20Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Can't inspect pin, assume it can be used */ 898c2ecf20Sopenharmony_ci if (!desc || !ops) 908c2ecf20Sopenharmony_ci return true; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (ops->strict && desc->mux_usecount) 938c2ecf20Sopenharmony_ci return false; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return !(ops->strict && !!desc->gpio_owner); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * pin_request() - request a single pin to be muxed in, typically for GPIO 1008c2ecf20Sopenharmony_ci * @pctldev: the associated pin controller device 1018c2ecf20Sopenharmony_ci * @pin: the pin number in the global pin space 1028c2ecf20Sopenharmony_ci * @owner: a representation of the owner of this pin; typically the device 1038c2ecf20Sopenharmony_ci * name that controls its mux function, or the requested GPIO name 1048c2ecf20Sopenharmony_ci * @gpio_range: the range matching the GPIO pin if this is a request for a 1058c2ecf20Sopenharmony_ci * single GPIO pin 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistatic int pin_request(struct pinctrl_dev *pctldev, 1088c2ecf20Sopenharmony_ci int pin, const char *owner, 1098c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *gpio_range) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct pin_desc *desc; 1128c2ecf20Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 1138c2ecf20Sopenharmony_ci int status = -EINVAL; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pin); 1168c2ecf20Sopenharmony_ci if (desc == NULL) { 1178c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 1188c2ecf20Sopenharmony_ci "pin %d is not registered so it cannot be requested\n", 1198c2ecf20Sopenharmony_ci pin); 1208c2ecf20Sopenharmony_ci goto out; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", 1248c2ecf20Sopenharmony_ci pin, desc->name, owner); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if ((!gpio_range || ops->strict) && 1278c2ecf20Sopenharmony_ci desc->mux_usecount && strcmp(desc->mux_owner, owner)) { 1288c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 1298c2ecf20Sopenharmony_ci "pin %s already requested by %s; cannot claim for %s\n", 1308c2ecf20Sopenharmony_ci desc->name, desc->mux_owner, owner); 1318c2ecf20Sopenharmony_ci goto out; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if ((gpio_range || ops->strict) && desc->gpio_owner) { 1358c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 1368c2ecf20Sopenharmony_ci "pin %s already requested by %s; cannot claim for %s\n", 1378c2ecf20Sopenharmony_ci desc->name, desc->gpio_owner, owner); 1388c2ecf20Sopenharmony_ci goto out; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (gpio_range) { 1428c2ecf20Sopenharmony_ci desc->gpio_owner = owner; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci desc->mux_usecount++; 1458c2ecf20Sopenharmony_ci if (desc->mux_usecount > 1) 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci desc->mux_owner = owner; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Let each pin increase references to this module */ 1528c2ecf20Sopenharmony_ci if (!try_module_get(pctldev->owner)) { 1538c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 1548c2ecf20Sopenharmony_ci "could not increase module refcount for pin %d\n", 1558c2ecf20Sopenharmony_ci pin); 1568c2ecf20Sopenharmony_ci status = -EINVAL; 1578c2ecf20Sopenharmony_ci goto out_free_pin; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * If there is no kind of request function for the pin we just assume 1628c2ecf20Sopenharmony_ci * we got it by default and proceed. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci if (gpio_range && ops->gpio_request_enable) 1658c2ecf20Sopenharmony_ci /* This requests and enables a single GPIO pin */ 1668c2ecf20Sopenharmony_ci status = ops->gpio_request_enable(pctldev, gpio_range, pin); 1678c2ecf20Sopenharmony_ci else if (ops->request) 1688c2ecf20Sopenharmony_ci status = ops->request(pctldev, pin); 1698c2ecf20Sopenharmony_ci else 1708c2ecf20Sopenharmony_ci status = 0; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (status) { 1738c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "request() failed for pin %d\n", pin); 1748c2ecf20Sopenharmony_ci module_put(pctldev->owner); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciout_free_pin: 1788c2ecf20Sopenharmony_ci if (status) { 1798c2ecf20Sopenharmony_ci if (gpio_range) { 1808c2ecf20Sopenharmony_ci desc->gpio_owner = NULL; 1818c2ecf20Sopenharmony_ci } else { 1828c2ecf20Sopenharmony_ci desc->mux_usecount--; 1838c2ecf20Sopenharmony_ci if (!desc->mux_usecount) 1848c2ecf20Sopenharmony_ci desc->mux_owner = NULL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ciout: 1888c2ecf20Sopenharmony_ci if (status) 1898c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "pin-%d (%s) status %d\n", 1908c2ecf20Sopenharmony_ci pin, owner, status); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return status; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/** 1968c2ecf20Sopenharmony_ci * pin_free() - release a single muxed in pin so something else can be muxed 1978c2ecf20Sopenharmony_ci * @pctldev: pin controller device handling this pin 1988c2ecf20Sopenharmony_ci * @pin: the pin to free 1998c2ecf20Sopenharmony_ci * @gpio_range: the range matching the GPIO pin if this is a request for a 2008c2ecf20Sopenharmony_ci * single GPIO pin 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * This function returns a pointer to the previous owner. This is used 2038c2ecf20Sopenharmony_ci * for callers that dynamically allocate an owner name so it can be freed 2048c2ecf20Sopenharmony_ci * once the pin is free. This is done for GPIO request functions. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistatic const char *pin_free(struct pinctrl_dev *pctldev, int pin, 2078c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *gpio_range) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 2108c2ecf20Sopenharmony_ci struct pin_desc *desc; 2118c2ecf20Sopenharmony_ci const char *owner; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pin); 2148c2ecf20Sopenharmony_ci if (desc == NULL) { 2158c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 2168c2ecf20Sopenharmony_ci "pin is not registered so it cannot be freed\n"); 2178c2ecf20Sopenharmony_ci return NULL; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!gpio_range) { 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * A pin should not be freed more times than allocated. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci if (WARN_ON(!desc->mux_usecount)) 2258c2ecf20Sopenharmony_ci return NULL; 2268c2ecf20Sopenharmony_ci desc->mux_usecount--; 2278c2ecf20Sopenharmony_ci if (desc->mux_usecount) 2288c2ecf20Sopenharmony_ci return NULL; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * If there is no kind of request function for the pin we just assume 2338c2ecf20Sopenharmony_ci * we got it by default and proceed. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci if (gpio_range && ops->gpio_disable_free) 2368c2ecf20Sopenharmony_ci ops->gpio_disable_free(pctldev, gpio_range, pin); 2378c2ecf20Sopenharmony_ci else if (ops->free) 2388c2ecf20Sopenharmony_ci ops->free(pctldev, pin); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (gpio_range) { 2418c2ecf20Sopenharmony_ci owner = desc->gpio_owner; 2428c2ecf20Sopenharmony_ci desc->gpio_owner = NULL; 2438c2ecf20Sopenharmony_ci } else { 2448c2ecf20Sopenharmony_ci owner = desc->mux_owner; 2458c2ecf20Sopenharmony_ci desc->mux_owner = NULL; 2468c2ecf20Sopenharmony_ci desc->mux_setting = NULL; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci module_put(pctldev->owner); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return owner; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/** 2558c2ecf20Sopenharmony_ci * pinmux_request_gpio() - request pinmuxing for a GPIO pin 2568c2ecf20Sopenharmony_ci * @pctldev: pin controller device affected 2578c2ecf20Sopenharmony_ci * @pin: the pin to mux in for GPIO 2588c2ecf20Sopenharmony_ci * @range: the applicable GPIO range 2598c2ecf20Sopenharmony_ci * @gpio: number of requested GPIO 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ciint pinmux_request_gpio(struct pinctrl_dev *pctldev, 2628c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 2638c2ecf20Sopenharmony_ci unsigned pin, unsigned gpio) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci const char *owner; 2668c2ecf20Sopenharmony_ci int ret; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Conjure some name stating what chip and pin this is taken by */ 2698c2ecf20Sopenharmony_ci owner = kasprintf(GFP_KERNEL, "%s:%d", range->name, gpio); 2708c2ecf20Sopenharmony_ci if (!owner) 2718c2ecf20Sopenharmony_ci return -ENOMEM; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ret = pin_request(pctldev, pin, owner, range); 2748c2ecf20Sopenharmony_ci if (ret < 0) 2758c2ecf20Sopenharmony_ci kfree(owner); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/** 2818c2ecf20Sopenharmony_ci * pinmux_free_gpio() - release a pin from GPIO muxing 2828c2ecf20Sopenharmony_ci * @pctldev: the pin controller device for the pin 2838c2ecf20Sopenharmony_ci * @pin: the affected currently GPIO-muxed in pin 2848c2ecf20Sopenharmony_ci * @range: applicable GPIO range 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_civoid pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin, 2878c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci const char *owner; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci owner = pin_free(pctldev, pin, range); 2928c2ecf20Sopenharmony_ci kfree(owner); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/** 2968c2ecf20Sopenharmony_ci * pinmux_gpio_direction() - set the direction of a single muxed-in GPIO pin 2978c2ecf20Sopenharmony_ci * @pctldev: the pin controller handling this pin 2988c2ecf20Sopenharmony_ci * @range: applicable GPIO range 2998c2ecf20Sopenharmony_ci * @pin: the affected GPIO pin in this controller 3008c2ecf20Sopenharmony_ci * @input: true if we set the pin as input, false for output 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ciint pinmux_gpio_direction(struct pinctrl_dev *pctldev, 3038c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 3048c2ecf20Sopenharmony_ci unsigned pin, bool input) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci const struct pinmux_ops *ops; 3078c2ecf20Sopenharmony_ci int ret; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci ops = pctldev->desc->pmxops; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (ops->gpio_set_direction) 3128c2ecf20Sopenharmony_ci ret = ops->gpio_set_direction(pctldev, range, pin, input); 3138c2ecf20Sopenharmony_ci else 3148c2ecf20Sopenharmony_ci ret = 0; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, 3208c2ecf20Sopenharmony_ci const char *function) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 3238c2ecf20Sopenharmony_ci unsigned nfuncs = ops->get_functions_count(pctldev); 3248c2ecf20Sopenharmony_ci unsigned selector = 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* See if this pctldev has this function */ 3278c2ecf20Sopenharmony_ci while (selector < nfuncs) { 3288c2ecf20Sopenharmony_ci const char *fname = ops->get_function_name(pctldev, selector); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (!strcmp(function, fname)) 3318c2ecf20Sopenharmony_ci return selector; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci selector++; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return -EINVAL; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciint pinmux_map_to_setting(const struct pinctrl_map *map, 3408c2ecf20Sopenharmony_ci struct pinctrl_setting *setting) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 3438c2ecf20Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 3448c2ecf20Sopenharmony_ci char const * const *groups; 3458c2ecf20Sopenharmony_ci unsigned num_groups; 3468c2ecf20Sopenharmony_ci int ret; 3478c2ecf20Sopenharmony_ci const char *group; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!pmxops) { 3508c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "does not support mux function\n"); 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function); 3558c2ecf20Sopenharmony_ci if (ret < 0) { 3568c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "invalid function %s in map table\n", 3578c2ecf20Sopenharmony_ci map->data.mux.function); 3588c2ecf20Sopenharmony_ci return ret; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci setting->data.mux.func = ret; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ret = pmxops->get_function_groups(pctldev, setting->data.mux.func, 3638c2ecf20Sopenharmony_ci &groups, &num_groups); 3648c2ecf20Sopenharmony_ci if (ret < 0) { 3658c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "can't query groups for function %s\n", 3668c2ecf20Sopenharmony_ci map->data.mux.function); 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci if (!num_groups) { 3708c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 3718c2ecf20Sopenharmony_ci "function %s can't be selected on any group\n", 3728c2ecf20Sopenharmony_ci map->data.mux.function); 3738c2ecf20Sopenharmony_ci return -EINVAL; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci if (map->data.mux.group) { 3768c2ecf20Sopenharmony_ci group = map->data.mux.group; 3778c2ecf20Sopenharmony_ci ret = match_string(groups, num_groups, group); 3788c2ecf20Sopenharmony_ci if (ret < 0) { 3798c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 3808c2ecf20Sopenharmony_ci "invalid group \"%s\" for function \"%s\"\n", 3818c2ecf20Sopenharmony_ci group, map->data.mux.function); 3828c2ecf20Sopenharmony_ci return ret; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci group = groups[0]; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ret = pinctrl_get_group_selector(pctldev, group); 3898c2ecf20Sopenharmony_ci if (ret < 0) { 3908c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "invalid group %s in map table\n", 3918c2ecf20Sopenharmony_ci map->data.mux.group); 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci setting->data.mux.group = ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_civoid pinmux_free_setting(const struct pinctrl_setting *setting) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci /* This function is currently unused */ 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciint pinmux_enable_setting(const struct pinctrl_setting *setting) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 4078c2ecf20Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 4088c2ecf20Sopenharmony_ci const struct pinmux_ops *ops = pctldev->desc->pmxops; 4098c2ecf20Sopenharmony_ci int ret = 0; 4108c2ecf20Sopenharmony_ci const unsigned *pins = NULL; 4118c2ecf20Sopenharmony_ci unsigned num_pins = 0; 4128c2ecf20Sopenharmony_ci int i; 4138c2ecf20Sopenharmony_ci struct pin_desc *desc; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (pctlops->get_group_pins) 4168c2ecf20Sopenharmony_ci ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, 4178c2ecf20Sopenharmony_ci &pins, &num_pins); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (ret) { 4208c2ecf20Sopenharmony_ci const char *gname; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* errors only affect debug data, so just warn */ 4238c2ecf20Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 4248c2ecf20Sopenharmony_ci setting->data.mux.group); 4258c2ecf20Sopenharmony_ci dev_warn(pctldev->dev, 4268c2ecf20Sopenharmony_ci "could not get pins for group %s\n", 4278c2ecf20Sopenharmony_ci gname); 4288c2ecf20Sopenharmony_ci num_pins = 0; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* Try to allocate all pins in this group, one by one */ 4328c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 4338c2ecf20Sopenharmony_ci ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); 4348c2ecf20Sopenharmony_ci if (ret) { 4358c2ecf20Sopenharmony_ci const char *gname; 4368c2ecf20Sopenharmony_ci const char *pname; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 4398c2ecf20Sopenharmony_ci pname = desc ? desc->name : "non-existing"; 4408c2ecf20Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 4418c2ecf20Sopenharmony_ci setting->data.mux.group); 4428c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 4438c2ecf20Sopenharmony_ci "could not request pin %d (%s) from group %s " 4448c2ecf20Sopenharmony_ci " on device %s\n", 4458c2ecf20Sopenharmony_ci pins[i], pname, gname, 4468c2ecf20Sopenharmony_ci pinctrl_dev_get_name(pctldev)); 4478c2ecf20Sopenharmony_ci goto err_pin_request; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Now that we have acquired the pins, encode the mux setting */ 4528c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 4538c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 4548c2ecf20Sopenharmony_ci if (desc == NULL) { 4558c2ecf20Sopenharmony_ci dev_warn(pctldev->dev, 4568c2ecf20Sopenharmony_ci "could not get pin desc for pin %d\n", 4578c2ecf20Sopenharmony_ci pins[i]); 4588c2ecf20Sopenharmony_ci continue; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci desc->mux_setting = &(setting->data.mux); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ret = ops->set_mux(pctldev, setting->data.mux.func, 4648c2ecf20Sopenharmony_ci setting->data.mux.group); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (ret) 4678c2ecf20Sopenharmony_ci goto err_set_mux; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cierr_set_mux: 4728c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 4738c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 4748c2ecf20Sopenharmony_ci if (desc) 4758c2ecf20Sopenharmony_ci desc->mux_setting = NULL; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_cierr_pin_request: 4788c2ecf20Sopenharmony_ci /* On error release all taken pins */ 4798c2ecf20Sopenharmony_ci while (--i >= 0) 4808c2ecf20Sopenharmony_ci pin_free(pctldev, pins[i], NULL); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return ret; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_civoid pinmux_disable_setting(const struct pinctrl_setting *setting) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 4888c2ecf20Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 4898c2ecf20Sopenharmony_ci int ret = 0; 4908c2ecf20Sopenharmony_ci const unsigned *pins = NULL; 4918c2ecf20Sopenharmony_ci unsigned num_pins = 0; 4928c2ecf20Sopenharmony_ci int i; 4938c2ecf20Sopenharmony_ci struct pin_desc *desc; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (pctlops->get_group_pins) 4968c2ecf20Sopenharmony_ci ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, 4978c2ecf20Sopenharmony_ci &pins, &num_pins); 4988c2ecf20Sopenharmony_ci if (ret) { 4998c2ecf20Sopenharmony_ci const char *gname; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* errors only affect debug data, so just warn */ 5028c2ecf20Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 5038c2ecf20Sopenharmony_ci setting->data.mux.group); 5048c2ecf20Sopenharmony_ci dev_warn(pctldev->dev, 5058c2ecf20Sopenharmony_ci "could not get pins for group %s\n", 5068c2ecf20Sopenharmony_ci gname); 5078c2ecf20Sopenharmony_ci num_pins = 0; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* Flag the descs that no setting is active */ 5118c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 5128c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pins[i]); 5138c2ecf20Sopenharmony_ci if (desc == NULL) { 5148c2ecf20Sopenharmony_ci dev_warn(pctldev->dev, 5158c2ecf20Sopenharmony_ci "could not get pin desc for pin %d\n", 5168c2ecf20Sopenharmony_ci pins[i]); 5178c2ecf20Sopenharmony_ci continue; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci if (desc->mux_setting == &(setting->data.mux)) { 5208c2ecf20Sopenharmony_ci pin_free(pctldev, pins[i], NULL); 5218c2ecf20Sopenharmony_ci } else { 5228c2ecf20Sopenharmony_ci const char *gname; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci gname = pctlops->get_group_name(pctldev, 5258c2ecf20Sopenharmony_ci setting->data.mux.group); 5268c2ecf20Sopenharmony_ci dev_warn(pctldev->dev, 5278c2ecf20Sopenharmony_ci "not freeing pin %d (%s) as part of " 5288c2ecf20Sopenharmony_ci "deactivating group %s - it is already " 5298c2ecf20Sopenharmony_ci "used for some other setting", 5308c2ecf20Sopenharmony_ci pins[i], desc->name, gname); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci/* Called from pincontrol core */ 5388c2ecf20Sopenharmony_cistatic int pinmux_functions_show(struct seq_file *s, void *what) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = s->private; 5418c2ecf20Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 5428c2ecf20Sopenharmony_ci unsigned nfuncs; 5438c2ecf20Sopenharmony_ci unsigned func_selector = 0; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!pmxops) 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci mutex_lock(&pctldev->mutex); 5498c2ecf20Sopenharmony_ci nfuncs = pmxops->get_functions_count(pctldev); 5508c2ecf20Sopenharmony_ci while (func_selector < nfuncs) { 5518c2ecf20Sopenharmony_ci const char *func = pmxops->get_function_name(pctldev, 5528c2ecf20Sopenharmony_ci func_selector); 5538c2ecf20Sopenharmony_ci const char * const *groups; 5548c2ecf20Sopenharmony_ci unsigned num_groups; 5558c2ecf20Sopenharmony_ci int ret; 5568c2ecf20Sopenharmony_ci int i; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = pmxops->get_function_groups(pctldev, func_selector, 5598c2ecf20Sopenharmony_ci &groups, &num_groups); 5608c2ecf20Sopenharmony_ci if (ret) { 5618c2ecf20Sopenharmony_ci seq_printf(s, "function %s: COULD NOT GET GROUPS\n", 5628c2ecf20Sopenharmony_ci func); 5638c2ecf20Sopenharmony_ci func_selector++; 5648c2ecf20Sopenharmony_ci continue; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci seq_printf(s, "function: %s, groups = [ ", func); 5688c2ecf20Sopenharmony_ci for (i = 0; i < num_groups; i++) 5698c2ecf20Sopenharmony_ci seq_printf(s, "%s ", groups[i]); 5708c2ecf20Sopenharmony_ci seq_puts(s, "]\n"); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci func_selector++; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci mutex_unlock(&pctldev->mutex); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int pinmux_pins_show(struct seq_file *s, void *what) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = s->private; 5838c2ecf20Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 5848c2ecf20Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 5858c2ecf20Sopenharmony_ci unsigned i, pin; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (!pmxops) 5888c2ecf20Sopenharmony_ci return 0; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci seq_puts(s, "Pinmux settings per pin\n"); 5918c2ecf20Sopenharmony_ci if (pmxops->strict) 5928c2ecf20Sopenharmony_ci seq_puts(s, 5938c2ecf20Sopenharmony_ci "Format: pin (name): mux_owner|gpio_owner (strict) hog?\n"); 5948c2ecf20Sopenharmony_ci else 5958c2ecf20Sopenharmony_ci seq_puts(s, 5968c2ecf20Sopenharmony_ci "Format: pin (name): mux_owner gpio_owner hog?\n"); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci mutex_lock(&pctldev->mutex); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* The pin number can be retrived from the pin controller descriptor */ 6018c2ecf20Sopenharmony_ci for (i = 0; i < pctldev->desc->npins; i++) { 6028c2ecf20Sopenharmony_ci struct pin_desc *desc; 6038c2ecf20Sopenharmony_ci bool is_hog = false; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci pin = pctldev->desc->pins[i].number; 6068c2ecf20Sopenharmony_ci desc = pin_desc_get(pctldev, pin); 6078c2ecf20Sopenharmony_ci /* Skip if we cannot search the pin */ 6088c2ecf20Sopenharmony_ci if (desc == NULL) 6098c2ecf20Sopenharmony_ci continue; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (desc->mux_owner && 6128c2ecf20Sopenharmony_ci !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) 6138c2ecf20Sopenharmony_ci is_hog = true; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (pmxops->strict) { 6168c2ecf20Sopenharmony_ci if (desc->mux_owner) 6178c2ecf20Sopenharmony_ci seq_printf(s, "pin %d (%s): device %s%s", 6188c2ecf20Sopenharmony_ci pin, desc->name, desc->mux_owner, 6198c2ecf20Sopenharmony_ci is_hog ? " (HOG)" : ""); 6208c2ecf20Sopenharmony_ci else if (desc->gpio_owner) 6218c2ecf20Sopenharmony_ci seq_printf(s, "pin %d (%s): GPIO %s", 6228c2ecf20Sopenharmony_ci pin, desc->name, desc->gpio_owner); 6238c2ecf20Sopenharmony_ci else 6248c2ecf20Sopenharmony_ci seq_printf(s, "pin %d (%s): UNCLAIMED", 6258c2ecf20Sopenharmony_ci pin, desc->name); 6268c2ecf20Sopenharmony_ci } else { 6278c2ecf20Sopenharmony_ci /* For non-strict controllers */ 6288c2ecf20Sopenharmony_ci seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name, 6298c2ecf20Sopenharmony_ci desc->mux_owner ? desc->mux_owner 6308c2ecf20Sopenharmony_ci : "(MUX UNCLAIMED)", 6318c2ecf20Sopenharmony_ci desc->gpio_owner ? desc->gpio_owner 6328c2ecf20Sopenharmony_ci : "(GPIO UNCLAIMED)", 6338c2ecf20Sopenharmony_ci is_hog ? " (HOG)" : ""); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* If mux: print function+group claiming the pin */ 6378c2ecf20Sopenharmony_ci if (desc->mux_setting) 6388c2ecf20Sopenharmony_ci seq_printf(s, " function %s group %s\n", 6398c2ecf20Sopenharmony_ci pmxops->get_function_name(pctldev, 6408c2ecf20Sopenharmony_ci desc->mux_setting->func), 6418c2ecf20Sopenharmony_ci pctlops->get_group_name(pctldev, 6428c2ecf20Sopenharmony_ci desc->mux_setting->group)); 6438c2ecf20Sopenharmony_ci else 6448c2ecf20Sopenharmony_ci seq_putc(s, '\n'); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci mutex_unlock(&pctldev->mutex); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_civoid pinmux_show_map(struct seq_file *s, const struct pinctrl_map *map) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci seq_printf(s, "group %s\nfunction %s\n", 6558c2ecf20Sopenharmony_ci map->data.mux.group ? map->data.mux.group : "(default)", 6568c2ecf20Sopenharmony_ci map->data.mux.function); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_civoid pinmux_show_setting(struct seq_file *s, 6608c2ecf20Sopenharmony_ci const struct pinctrl_setting *setting) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = setting->pctldev; 6638c2ecf20Sopenharmony_ci const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 6648c2ecf20Sopenharmony_ci const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci seq_printf(s, "group: %s (%u) function: %s (%u)\n", 6678c2ecf20Sopenharmony_ci pctlops->get_group_name(pctldev, setting->data.mux.group), 6688c2ecf20Sopenharmony_ci setting->data.mux.group, 6698c2ecf20Sopenharmony_ci pmxops->get_function_name(pctldev, setting->data.mux.func), 6708c2ecf20Sopenharmony_ci setting->data.mux.func); 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pinmux_functions); 6748c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pinmux_pins); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_civoid pinmux_init_device_debugfs(struct dentry *devroot, 6778c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci debugfs_create_file("pinmux-functions", S_IFREG | S_IRUGO, 6808c2ecf20Sopenharmony_ci devroot, pctldev, &pinmux_functions_fops); 6818c2ecf20Sopenharmony_ci debugfs_create_file("pinmux-pins", S_IFREG | S_IRUGO, 6828c2ecf20Sopenharmony_ci devroot, pctldev, &pinmux_pins_fops); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/** 6908c2ecf20Sopenharmony_ci * pinmux_generic_get_function_count() - returns number of functions 6918c2ecf20Sopenharmony_ci * @pctldev: pin controller device 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ciint pinmux_generic_get_function_count(struct pinctrl_dev *pctldev) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci return pctldev->num_functions; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function_count); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/** 7008c2ecf20Sopenharmony_ci * pinmux_generic_get_function_name() - returns the function name 7018c2ecf20Sopenharmony_ci * @pctldev: pin controller device 7028c2ecf20Sopenharmony_ci * @selector: function number 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_ciconst char * 7058c2ecf20Sopenharmony_cipinmux_generic_get_function_name(struct pinctrl_dev *pctldev, 7068c2ecf20Sopenharmony_ci unsigned int selector) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct function_desc *function; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 7118c2ecf20Sopenharmony_ci selector); 7128c2ecf20Sopenharmony_ci if (!function) 7138c2ecf20Sopenharmony_ci return NULL; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return function->name; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function_name); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/** 7208c2ecf20Sopenharmony_ci * pinmux_generic_get_function_groups() - gets the function groups 7218c2ecf20Sopenharmony_ci * @pctldev: pin controller device 7228c2ecf20Sopenharmony_ci * @selector: function number 7238c2ecf20Sopenharmony_ci * @groups: array of pin groups 7248c2ecf20Sopenharmony_ci * @num_groups: number of pin groups 7258c2ecf20Sopenharmony_ci */ 7268c2ecf20Sopenharmony_ciint pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, 7278c2ecf20Sopenharmony_ci unsigned int selector, 7288c2ecf20Sopenharmony_ci const char * const **groups, 7298c2ecf20Sopenharmony_ci unsigned * const num_groups) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct function_desc *function; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 7348c2ecf20Sopenharmony_ci selector); 7358c2ecf20Sopenharmony_ci if (!function) { 7368c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "%s could not find function%i\n", 7378c2ecf20Sopenharmony_ci __func__, selector); 7388c2ecf20Sopenharmony_ci return -EINVAL; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci *groups = function->group_names; 7418c2ecf20Sopenharmony_ci *num_groups = function->num_group_names; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function_groups); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci/** 7488c2ecf20Sopenharmony_ci * pinmux_generic_get_function() - returns a function based on the number 7498c2ecf20Sopenharmony_ci * @pctldev: pin controller device 7508c2ecf20Sopenharmony_ci * @selector: function number 7518c2ecf20Sopenharmony_ci */ 7528c2ecf20Sopenharmony_cistruct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev, 7538c2ecf20Sopenharmony_ci unsigned int selector) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct function_desc *function; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 7588c2ecf20Sopenharmony_ci selector); 7598c2ecf20Sopenharmony_ci if (!function) 7608c2ecf20Sopenharmony_ci return NULL; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci return function; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_get_function); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/** 7678c2ecf20Sopenharmony_ci * pinmux_generic_add_function() - adds a function group 7688c2ecf20Sopenharmony_ci * @pctldev: pin controller device 7698c2ecf20Sopenharmony_ci * @name: name of the function 7708c2ecf20Sopenharmony_ci * @groups: array of pin groups 7718c2ecf20Sopenharmony_ci * @num_groups: number of pin groups 7728c2ecf20Sopenharmony_ci * @data: pin controller driver specific data 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ciint pinmux_generic_add_function(struct pinctrl_dev *pctldev, 7758c2ecf20Sopenharmony_ci const char *name, 7768c2ecf20Sopenharmony_ci const char **groups, 7778c2ecf20Sopenharmony_ci const unsigned int num_groups, 7788c2ecf20Sopenharmony_ci void *data) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct function_desc *function; 7818c2ecf20Sopenharmony_ci int selector; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (!name) 7848c2ecf20Sopenharmony_ci return -EINVAL; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci selector = pinmux_func_name_to_selector(pctldev, name); 7878c2ecf20Sopenharmony_ci if (selector >= 0) 7888c2ecf20Sopenharmony_ci return selector; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci selector = pctldev->num_functions; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL); 7938c2ecf20Sopenharmony_ci if (!function) 7948c2ecf20Sopenharmony_ci return -ENOMEM; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci function->name = name; 7978c2ecf20Sopenharmony_ci function->group_names = groups; 7988c2ecf20Sopenharmony_ci function->num_group_names = num_groups; 7998c2ecf20Sopenharmony_ci function->data = data; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci radix_tree_insert(&pctldev->pin_function_tree, selector, function); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci pctldev->num_functions++; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return selector; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_add_function); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/** 8108c2ecf20Sopenharmony_ci * pinmux_generic_remove_function() - removes a numbered function 8118c2ecf20Sopenharmony_ci * @pctldev: pin controller device 8128c2ecf20Sopenharmony_ci * @selector: function number 8138c2ecf20Sopenharmony_ci * 8148c2ecf20Sopenharmony_ci * Note that the caller must take care of locking. 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ciint pinmux_generic_remove_function(struct pinctrl_dev *pctldev, 8178c2ecf20Sopenharmony_ci unsigned int selector) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct function_desc *function; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci function = radix_tree_lookup(&pctldev->pin_function_tree, 8228c2ecf20Sopenharmony_ci selector); 8238c2ecf20Sopenharmony_ci if (!function) 8248c2ecf20Sopenharmony_ci return -ENOENT; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci radix_tree_delete(&pctldev->pin_function_tree, selector); 8278c2ecf20Sopenharmony_ci devm_kfree(pctldev->dev, function); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci pctldev->num_functions--; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinmux_generic_remove_function); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/** 8368c2ecf20Sopenharmony_ci * pinmux_generic_free_functions() - removes all functions 8378c2ecf20Sopenharmony_ci * @pctldev: pin controller device 8388c2ecf20Sopenharmony_ci * 8398c2ecf20Sopenharmony_ci * Note that the caller must take care of locking. The pinctrl 8408c2ecf20Sopenharmony_ci * functions are allocated with devm_kzalloc() so no need to free 8418c2ecf20Sopenharmony_ci * them here. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_civoid pinmux_generic_free_functions(struct pinctrl_dev *pctldev) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct radix_tree_iter iter; 8468c2ecf20Sopenharmony_ci void __rcu **slot; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci radix_tree_for_each_slot(slot, &pctldev->pin_function_tree, &iter, 0) 8498c2ecf20Sopenharmony_ci radix_tree_delete(&pctldev->pin_function_tree, iter.index); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci pctldev->num_functions = 0; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */ 855