Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 190 lines 5.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Software Node helpers for the GPIO API 4 * 5 * Copyright 2022 Google LLC 6 */ 7 8#define pr_fmt(fmt) "gpiolib: swnode: " fmt 9 10#include <linux/err.h> 11#include <linux/errno.h> 12#include <linux/export.h> 13#include <linux/init.h> 14#include <linux/kernel.h> 15#include <linux/printk.h> 16#include <linux/property.h> 17#include <linux/string.h> 18 19#include <linux/gpio/consumer.h> 20#include <linux/gpio/driver.h> 21#include <linux/gpio/property.h> 22 23#include "gpiolib.h" 24#include "gpiolib-swnode.h" 25 26static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) 27{ 28 const struct software_node *gdev_node; 29 struct gpio_device *gdev; 30 31 gdev_node = to_software_node(fwnode); 32 if (!gdev_node) 33 goto fwnode_lookup; 34 35 /* 36 * Check for a special node that identifies undefined GPIOs, this is 37 * primarily used as a key for internal chip selects in SPI bindings. 38 */ 39 if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) && 40 gdev_node == &swnode_gpio_undefined) 41 return ERR_PTR(-ENOENT); 42 43fwnode_lookup: 44 gdev = gpio_device_find_by_fwnode(fwnode); 45 if (!gdev && gdev_node && gdev_node->name) 46 /* 47 * FIXME: We shouldn't need to compare the GPIO controller's 48 * label against the software node that is supposedly attached 49 * to it. However there are currently GPIO users that - knowing 50 * the expected label of the GPIO chip whose pins they want to 51 * control - set up dummy software nodes named after those GPIO 52 * controllers, which aren't actually attached to them. In this 53 * case gpio_device_find_by_fwnode() will fail as no device on 54 * the GPIO bus is actually associated with the fwnode we're 55 * looking for. 56 * 57 * As a fallback: continue checking the label if we have no 58 * match. However, the situation described above is an abuse 59 * of the software node API and should be phased out and the 60 * following line - eventually removed. 61 */ 62 gdev = gpio_device_find_by_label(gdev_node->name); 63 64 return gdev ?: ERR_PTR(-EPROBE_DEFER); 65} 66 67static int swnode_gpio_get_reference(const struct fwnode_handle *fwnode, 68 const char *propname, unsigned int idx, 69 struct fwnode_reference_args *args) 70{ 71 /* 72 * We expect all swnode-described GPIOs have GPIO number and 73 * polarity arguments, hence nargs is set to 2. 74 */ 75 return fwnode_property_get_reference_args(fwnode, propname, NULL, 2, idx, args); 76} 77 78struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode, 79 const char *con_id, unsigned int idx, 80 unsigned long *flags) 81{ 82 const struct software_node *swnode; 83 struct fwnode_reference_args args; 84 struct gpio_desc *desc; 85 char propname[32]; /* 32 is max size of property name */ 86 int ret = 0; 87 88 swnode = to_software_node(fwnode); 89 if (!swnode) 90 return ERR_PTR(-EINVAL); 91 92 for_each_gpio_property_name(propname, con_id) { 93 ret = swnode_gpio_get_reference(fwnode, propname, idx, &args); 94 if (ret == 0) 95 break; 96 if (ret == -ENOTCONN) 97 /* 98 * -ENOTCONN for a software node reference lookup means 99 * that a remote struct software_node exists but has 100 * not yet been registered as a firmware node. Defer 101 * until this happens. 102 */ 103 return ERR_PTR(-EPROBE_DEFER); 104 } 105 if (ret) { 106 pr_debug("%s: can't parse '%s' property of node '%pfwP[%d]'\n", 107 __func__, propname, fwnode, idx); 108 return ERR_PTR(ret); 109 } 110 111 struct gpio_device *gdev __free(gpio_device_put) = 112 swnode_get_gpio_device(args.fwnode); 113 fwnode_handle_put(args.fwnode); 114 if (IS_ERR(gdev)) 115 return ERR_CAST(gdev); 116 117 /* 118 * FIXME: The GPIO device reference is put at return but the descriptor 119 * is passed on. Find a proper solution. 120 */ 121 desc = gpio_device_get_desc(gdev, args.args[0]); 122 *flags = args.args[1]; /* We expect native GPIO flags */ 123 124 pr_debug("%s: parsed '%s' property of node '%pfwP[%d]' - status (%d)\n", 125 __func__, propname, fwnode, idx, PTR_ERR_OR_ZERO(desc)); 126 127 return desc; 128} 129 130/** 131 * swnode_gpio_count - count the GPIOs associated with a device / function 132 * @fwnode: firmware node of the GPIO consumer, can be %NULL for 133 * system-global GPIOs 134 * @con_id: function within the GPIO consumer 135 * 136 * Returns: 137 * The number of GPIOs associated with a device / function or %-ENOENT, 138 * if no GPIO has been assigned to the requested function. 139 */ 140int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id) 141{ 142 struct fwnode_reference_args args; 143 char propname[32]; 144 int count; 145 146 /* 147 * This is not very efficient, but GPIO lists usually have only 148 * 1 or 2 entries. 149 */ 150 for_each_gpio_property_name(propname, con_id) { 151 count = 0; 152 while (swnode_gpio_get_reference(fwnode, propname, count, &args) == 0) { 153 fwnode_handle_put(args.fwnode); 154 count++; 155 } 156 if (count) 157 return count; 158 } 159 160 return -ENOENT; 161} 162 163#if IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) 164/* 165 * A special node that identifies undefined GPIOs, this is primarily used as 166 * a key for internal chip selects in SPI bindings. 167 */ 168const struct software_node swnode_gpio_undefined = { 169 .name = "swnode-gpio-undefined", 170}; 171EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, "GPIO_SWNODE"); 172 173static int __init swnode_gpio_init(void) 174{ 175 int ret; 176 177 ret = software_node_register(&swnode_gpio_undefined); 178 if (ret < 0) 179 pr_err("failed to register swnode: %d\n", ret); 180 181 return ret; 182} 183subsys_initcall(swnode_gpio_init); 184 185static void __exit swnode_gpio_cleanup(void) 186{ 187 software_node_unregister(&swnode_gpio_undefined); 188} 189__exitcall(swnode_gpio_cleanup); 190#endif