brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 51d2475 Raw
164 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Software Node helpers for the GPIO API4 *5 * Copyright 2022 Google LLC6 */7 8#define pr_fmt(fmt) "gpiolib: swnode: " fmt9 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 22#include "gpiolib.h"23#include "gpiolib-swnode.h"24 25#define GPIOLIB_SWNODE_UNDEFINED_NAME "swnode-gpio-undefined"26 27static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)28{29	const struct software_node *gdev_node;30	struct gpio_device *gdev;31 32	gdev_node = to_software_node(fwnode);33	if (!gdev_node || !gdev_node->name)34		return ERR_PTR(-EINVAL);35 36	/*37	 * Check for a special node that identifies undefined GPIOs, this is38	 * primarily used as a key for internal chip selects in SPI bindings.39	 */40	if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) &&41	    !strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME))42		return ERR_PTR(-ENOENT);43 44	gdev = gpio_device_find_by_label(gdev_node->name);45	return gdev ?: ERR_PTR(-EPROBE_DEFER);46}47 48static int swnode_gpio_get_reference(const struct fwnode_handle *fwnode,49				     const char *propname, unsigned int idx,50				     struct fwnode_reference_args *args)51{52	/*53	 * We expect all swnode-described GPIOs have GPIO number and54	 * polarity arguments, hence nargs is set to 2.55	 */56	return fwnode_property_get_reference_args(fwnode, propname, NULL, 2, idx, args);57}58 59struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,60				   const char *con_id, unsigned int idx,61				   unsigned long *flags)62{63	const struct software_node *swnode;64	struct fwnode_reference_args args;65	struct gpio_desc *desc;66	char propname[32]; /* 32 is max size of property name */67	int ret = 0;68 69	swnode = to_software_node(fwnode);70	if (!swnode)71		return ERR_PTR(-EINVAL);72 73	for_each_gpio_property_name(propname, con_id) {74		ret = swnode_gpio_get_reference(fwnode, propname, idx, &args);75		if (ret == 0)76			break;77	}78	if (ret) {79		pr_debug("%s: can't parse '%s' property of node '%pfwP[%d]'\n",80			__func__, propname, fwnode, idx);81		return ERR_PTR(ret);82	}83 84	struct gpio_device *gdev __free(gpio_device_put) =85					swnode_get_gpio_device(args.fwnode);86	fwnode_handle_put(args.fwnode);87	if (IS_ERR(gdev))88		return ERR_CAST(gdev);89 90	/*91	 * FIXME: The GPIO device reference is put at return but the descriptor92	 * is passed on. Find a proper solution.93	 */94	desc = gpio_device_get_desc(gdev, args.args[0]);95	*flags = args.args[1]; /* We expect native GPIO flags */96 97	pr_debug("%s: parsed '%s' property of node '%pfwP[%d]' - status (%d)\n",98		 __func__, propname, fwnode, idx, PTR_ERR_OR_ZERO(desc));99 100	return desc;101}102 103/**104 * swnode_gpio_count - count the GPIOs associated with a device / function105 * @fwnode:	firmware node of the GPIO consumer, can be %NULL for106 *		system-global GPIOs107 * @con_id:	function within the GPIO consumer108 *109 * Returns:110 * The number of GPIOs associated with a device / function or %-ENOENT,111 * if no GPIO has been assigned to the requested function.112 */113int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)114{115	struct fwnode_reference_args args;116	char propname[32];117	int count;118 119	/*120	 * This is not very efficient, but GPIO lists usually have only121	 * 1 or 2 entries.122	 */123	for_each_gpio_property_name(propname, con_id) {124		count = 0;125		while (swnode_gpio_get_reference(fwnode, propname, count, &args) == 0) {126			fwnode_handle_put(args.fwnode);127			count++;128		}129		if (count)130			return count;131	}132 133	return -ENOENT;134}135 136#if IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED)137/*138 * A special node that identifies undefined GPIOs, this is primarily used as139 * a key for internal chip selects in SPI bindings.140 */141const struct software_node swnode_gpio_undefined = {142	.name = GPIOLIB_SWNODE_UNDEFINED_NAME,143};144EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, GPIO_SWNODE);145 146static int __init swnode_gpio_init(void)147{148	int ret;149 150	ret = software_node_register(&swnode_gpio_undefined);151	if (ret < 0)152		pr_err("failed to register swnode: %d\n", ret);153 154	return ret;155}156subsys_initcall(swnode_gpio_init);157 158static void __exit swnode_gpio_cleanup(void)159{160	software_node_unregister(&swnode_gpio_undefined);161}162__exitcall(swnode_gpio_cleanup);163#endif164