Re: [PATCH RFC v2 3/3] pinctrl: add support for ACPI pin function and config resources

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 15, 2022 at 05:54:15PM +0000, Niyas Sait wrote:
> Add support for following ACPI pin resources
> 
> - PinFunction
> - PinConfig
> - PinGroupFunction
> - PinGroupConfig
> 
> Pinctrl-acpi parses the ACPI table and generates list of pin
> descriptors that can be used by pin controller to set and config pin.
> 
> Descriptors are grouped by pin number or group name and contains list
> of functions or configs to apply.
> 
> Pin config types from ACPI are converted to generic pin config types
> and passed through the descriptor.
> 
> Signed-off-by: Niyas Sait <niyas.sait@xxxxxxxxxx>
> ---
>  drivers/pinctrl/core.c          |  18 +-
>  drivers/pinctrl/core.h          |   3 +
>  drivers/pinctrl/pinctrl-acpi.c  | 443 ++++++++++++++++++++++++++++++++
>  drivers/pinctrl/pinctrl-acpi.h  |  44 ++++
>  include/linux/pinctrl/pinctrl.h |  15 ++
>  5 files changed, 519 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
> index 9e57f4c62e60..00e5066c1087 100644
> --- a/drivers/pinctrl/core.c
> +++ b/drivers/pinctrl/core.c
> @@ -25,6 +25,7 @@
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/pinctrl/pinctrl.h>
>  #include <linux/pinctrl/machine.h>
> +#include <linux/acpi.h>
>  
>  #ifdef CONFIG_GPIOLIB
>  #include "../gpio/gpiolib.h"
> @@ -35,7 +36,7 @@
>  #include "devicetree.h"
>  #include "pinmux.h"
>  #include "pinconf.h"
> -
> +#include "pinctrl-acpi.h"
>  
>  static bool pinctrl_dummy_state;
>  
> @@ -1042,9 +1043,15 @@ static struct pinctrl *create_pinctrl(struct device *dev,
>  		return ERR_PTR(-ENOMEM);
>  	p->dev = dev;
>  	INIT_LIST_HEAD(&p->states);
> -	INIT_LIST_HEAD(&p->dt_maps);
>  
> -	ret = pinctrl_dt_to_map(p, pctldev);
> +	if (!ACPI_COMPANION(dev)) {

It looks better of you reverse the branches (and use
has_acpi_companion()):

if (has_acpi_companion(dev)) {
	INIT_LIST_HEAD(&p->acpi_maps);
	ret = pinctrl_acpi_to_map(p);
} else {
	INIT_LIST_HEAD(&p->dt_maps);
	ret = pinctrl_dt_to_map(p, pctldev);
}

> +		INIT_LIST_HEAD(&p->dt_maps);
> +		ret = pinctrl_dt_to_map(p, pctldev);
> +	} else {
> +		INIT_LIST_HEAD(&p->acpi_maps);
> +		ret = pinctrl_acpi_to_map(p);
> +	}
> +
>  	if (ret < 0) {
>  		kfree(p);
>  		return ERR_PTR(ret);
> @@ -1168,7 +1175,10 @@ static void pinctrl_free(struct pinctrl *p, bool inlist)
>  		kfree(state);
>  	}
>  
> -	pinctrl_dt_free_maps(p);
> +	if (!ACPI_COMPANION(p->dev))
> +		pinctrl_dt_free_maps(p);
> +	else
> +		pinctrl_acpi_free_maps(p);

DItto here.

>  
>  	if (inlist)
>  		list_del(&p->node);
> diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
> index 840103c40c14..603e36e175c7 100644
> --- a/drivers/pinctrl/core.h
> +++ b/drivers/pinctrl/core.h
> @@ -72,6 +72,8 @@ struct pinctrl_dev {
>   * @state: the current state
>   * @dt_maps: the mapping table chunks dynamically parsed from device tree for
>   *	this device, if any
> + * @acpi_maps: the mapping table chunks dynamically parsed from ACPI for this
> + *  device, if any
>   * @users: reference count
>   */
>  struct pinctrl {
> @@ -80,6 +82,7 @@ struct pinctrl {
>  	struct list_head states;
>  	struct pinctrl_state *state;
>  	struct list_head dt_maps;
> +	struct list_head acpi_maps;
>  	struct kref users;
>  };
>  
> diff --git a/drivers/pinctrl/pinctrl-acpi.c b/drivers/pinctrl/pinctrl-acpi.c
> index cd0d4b2d8868..e337f83e6879 100644
> --- a/drivers/pinctrl/pinctrl-acpi.c
> +++ b/drivers/pinctrl/pinctrl-acpi.c
> @@ -13,6 +13,449 @@
>  #include <linux/list.h>
>  
>  #include "pinctrl-acpi.h"
> +#include "core.h"
> +
> +/**
> + * struct pinctrl_acpi_map - mapping table chunk parsed from ACPI
> + * @node: list node for struct pinctrl's @acpi_maps field
> + * @pctldev: the pin controller that allocated this struct, and will free it
> + * @map: the mapping table entries
> + * @num_maps: number of mapping table entries
> + */
> +struct pinctrl_acpi_map {
> +	struct list_head node;
> +	struct pinctrl_dev *pctldev;
> +	struct pinctrl_map *map;
> +	size_t num_maps;

Perhaps nmaps consistent with npins in the previous patch?

> +};
> +
> +static void acpi_free_map(struct pinctrl_dev *pctldev,
> +			 struct pinctrl_map *map, unsigned int num_maps)
> +{
> +	int i;
> +
> +	for (i = 0; i < num_maps; ++i) {
> +		kfree_const(map[i].dev_name);
> +		map[i].dev_name = NULL;
> +	}
> +
> +	if (pctldev) {
> +		const struct pinctrl_ops *ops = pctldev->desc->pctlops;
> +
> +		if (ops->acpi_free_map)
> +			ops->acpi_free_map(pctldev, map, num_maps);
> +

Drop this empty line

> +	} else {
> +		kfree(map);
> +	}
> +}
> +

Kernel-doc?

> +void pinctrl_acpi_free_maps(struct pinctrl *p)
> +{
> +	struct pinctrl_acpi_map *acpi_map, *tmp;
> +
> +	list_for_each_entry_safe(acpi_map, tmp, &p->acpi_maps, node) {
> +		pinctrl_unregister_mappings(acpi_map->map);
> +		list_del(&acpi_map->node);
> +		acpi_free_map(acpi_map->pctldev, acpi_map->map,
> +				acpi_map->num_maps);
> +		kfree(acpi_map);
> +	}
> +}
> +
> +static int acpi_remember_or_free_map(struct pinctrl *p, const char *statename,
> +				   struct pinctrl_dev *pctldev,
> +				   struct pinctrl_map *map, unsigned int num_maps)
> +{
> +	int i;
> +	struct pinctrl_acpi_map *acpi_map;

"reverse christmas tree" looks better but up to you:

	struct pinctrl_acpi_map *acpi_map;
	int i;

Ditto everywhere

> +
> +	for (i = 0; i < num_maps; i++) {
> +		const char *devname;
> +
> +		devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL);
> +		if (!devname)
> +			goto err_free_map;
> +
> +		map[i].dev_name = devname;
> +		map[i].name = statename;
> +		if (pctldev)
> +			map[i].ctrl_dev_name = dev_name(pctldev->dev);
> +	}
> +
> +	acpi_map = kzalloc(sizeof(*acpi_map), GFP_KERNEL);
> +	if (!acpi_map)
> +		goto err_free_map;
> +
> +	acpi_map->pctldev = pctldev;
> +	acpi_map->map = map;
> +	acpi_map->num_maps = num_maps;
> +	list_add_tail(&acpi_map->node, &p->acpi_maps);
> +
> +	return pinctrl_register_mappings(map, num_maps);
> +
> +err_free_map:
> +	acpi_free_map(pctldev, map, num_maps);

Empty line

> +	return -ENOMEM;
> +}
> +
> +static const char *acpi_node_to_device_name(char *acpi_node)
> +{
> +	acpi_status status;
> +	acpi_handle handle;
> +	struct acpi_device *controller_device;
> +
> +	status = acpi_get_handle(NULL, acpi_node, &handle);
> +	if (ACPI_FAILURE(status))
> +		return NULL;
> +
> +	controller_device = acpi_get_acpi_dev(handle);
> +	if (!controller_device)
> +		return NULL;
> +
> +	return acpi_dev_name(controller_device);
> +}
> +
> +static int map_acpi_conf_to_general_conf(unsigned int acpi_param,
> +			unsigned int acpi_value, unsigned int *pin_config)
> +{
> +	enum pin_config_param genconf_param;
> +
> +	switch (acpi_param) {
> +	case ACPI_PIN_CONFIG_BIAS_PULL_UP:
> +		genconf_param = PIN_CONFIG_BIAS_PULL_UP;
> +		break;
> +	case ACPI_PIN_CONFIG_BIAS_PULL_DOWN:
> +		genconf_param = PIN_CONFIG_BIAS_PULL_DOWN;
> +		break;
> +	case ACPI_PIN_CONFIG_BIAS_DEFAULT:
> +		genconf_param = PIN_CONFIG_BIAS_PULL_PIN_DEFAULT;
> +		break;
> +	case ACPI_PIN_CONFIG_BIAS_DISABLE:
> +		genconf_param = PIN_CONFIG_BIAS_DISABLE;
> +		break;
> +	case ACPI_PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
> +		genconf_param = PIN_CONFIG_BIAS_HIGH_IMPEDANCE;
> +		break;
> +	case ACPI_PIN_CONFIG_BIAS_BUS_HOLD:
> +		genconf_param = PIN_CONFIG_BIAS_BUS_HOLD;
> +		break;
> +	case ACPI_PIN_CONFIG_DRIVE_OPEN_DRAIN:
> +		genconf_param = PIN_CONFIG_DRIVE_OPEN_DRAIN;
> +		break;
> +	case ACPI_PIN_CONFIG_DRIVE_OPEN_SOURCE:
> +		genconf_param = PIN_CONFIG_DRIVE_OPEN_SOURCE;
> +		break;
> +	case ACPI_PIN_CONFIG_DRIVE_PUSH_PULL:
> +		genconf_param = PIN_CONFIG_DRIVE_PUSH_PULL;
> +		break;
> +	case ACPI_PIN_CONFIG_DRIVE_STRENGTH:
> +		genconf_param = PIN_CONFIG_DRIVE_STRENGTH;
> +		break;
> +	case ACPI_PIN_CONFIG_SLEW_RATE:
> +		genconf_param = PIN_CONFIG_SLEW_RATE;
> +		break;
> +	case ACPI_PIN_CONFIG_INPUT_DEBOUNCE:
> +		genconf_param = PIN_CONFIG_INPUT_DEBOUNCE;
> +		break;
> +	case ACPI_PIN_CONFIG_INPUT_SCHMITT_TRIGGER:
> +		genconf_param = PIN_CONFIG_INPUT_SCHMITT_ENABLE;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	*pin_config = pinconf_to_config_packed(genconf_param, acpi_value);
> +
> +	return 0;
> +}
> +
> +/**
> + * struct pinctrl_acpi_controller_map - internal structure to group pin resources
> + * @pinctrl_dev: pin controller ACPI name
> + * @list: list head for the map
> + * @pin_group_maps: list head for the pin/group maps
> + */
> +struct pinctrl_acpi_controller_map {
> +	char *pinctrl_dev;
> +	struct list_head list;
> +	struct list_head pin_group_maps;
> +};
> +
> +static int add_pin_group_node(struct list_head *acpi_map_head,
> +							char *pinctrl_dev,
> +							char *group,
> +							unsigned int pin,
> +							bool is_config,
> +							unsigned int config_func,
> +							void *vendor_data,
> +							unsigned int vendor_length)

This takes quite many parameters, perhaps you can use a structure or
helper functions to make it look nicer? Also consider formatting:

static int add_pin_group_node(struct list_head *acpi_map_head, char *pinctrl_dev,
			      char *group, unsigned int pin, bool is_config,
			      unsigned int config_func, void *vendor_data,
			      unsigned int vendor_length)

> +{
> +	struct pinctrl_acpi_controller_map *acpi_controller_map = NULL;
> +	struct pinctrl_acpi_controller_map *acpi_controller_map_iter;
> +	struct pinctrl_acpi_pin_group_map *pin_group_map = NULL;
> +	struct pinctrl_acpi_pin_group_map *pin_group_map_iter;
> +	struct pinctrl_acpi_pin_group_info *info;
> +	bool group_pin_match;
> +
> +	list_for_each_entry(acpi_controller_map_iter, acpi_map_head, list) {
> +		if (!strcmp(acpi_controller_map_iter->pinctrl_dev, pinctrl_dev)) {
> +			acpi_controller_map = acpi_controller_map_iter;
> +			break;
> +		}
> +	}
> +
> +	if (!acpi_controller_map) {
> +		acpi_controller_map = kzalloc(sizeof(*acpi_controller_map), GFP_KERNEL);
> +		if (!acpi_controller_map)
> +			return -ENOMEM;
> +
> +		acpi_controller_map->pinctrl_dev = pinctrl_dev;
> +		INIT_LIST_HEAD(&acpi_controller_map->list);
> +		INIT_LIST_HEAD(&acpi_controller_map->pin_group_maps);
> +		list_add(&acpi_controller_map->list, acpi_map_head);
> +	}
> +
> +	list_for_each_entry(pin_group_map_iter, &acpi_controller_map->pin_group_maps, list) {
> +		if (group)
> +			group_pin_match = pin_group_map_iter->group &&
> +					!strcmp(pin_group_map_iter->group, group);
> +		else
> +			group_pin_match = (pin == pin_group_map_iter->pin);
> +
> +		if (pin_group_map_iter->is_config == is_config && group_pin_match) {
> +			pin_group_map = pin_group_map_iter;
> +			break;
> +		}
> +	}
> +
> +	if (!pin_group_map) {
> +		pin_group_map = kzalloc(sizeof(struct pinctrl_acpi_pin_group_map), GFP_KERNEL);
> +		if (!pin_group_map)

Did you just leak acpi_controller_map?

> +			return -ENOMEM;
> +
> +		pin_group_map->group = group;
> +		pin_group_map->pin = pin;
> +		pin_group_map->is_config = is_config;
> +		INIT_LIST_HEAD(&pin_group_map->list);
> +		INIT_LIST_HEAD(&pin_group_map->info_list);
> +		list_add(&pin_group_map->list, &acpi_controller_map->pin_group_maps);
> +	}
> +
> +	info = kzalloc(sizeof(struct pinctrl_acpi_pin_group_info), GFP_KERNEL);
> +	if (!info)

Does this leak acpi_controller_map and pin_group_map?

> +		return -ENOMEM;
> +
> +	info->config_func = config_func;
> +	info->vendor_data = vendor_data;
> +	info->vendor_length = vendor_length;
> +	INIT_LIST_HEAD(&info->list);
> +	list_add(&info->list, &pin_group_map->info_list);
> +
> +	return 0;
> +}
> +
> +static int populate_pin_function(struct list_head *acpi_map_head,
> +		struct acpi_resource_pin_function *ares_pin_function)
> +{
> +	int i;
> +	int ret;
> +	unsigned int config;
> +
> +	ret = map_acpi_conf_to_general_conf(ares_pin_function->pin_config, 1, &config);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; i < ares_pin_function->pin_table_length; i++) {
> +		ret = add_pin_group_node(acpi_map_head,
> +				ares_pin_function->resource_source.string_ptr,
> +				NULL,
> +				ares_pin_function->pin_table[i],
> +				false,
> +				ares_pin_function->function_number,
> +				ares_pin_function->vendor_data,
> +				ares_pin_function->vendor_length);

If you pass here:

		ret = add_pin_group_node(acpi_map_head, ares_pin_function, NULL, false);

looks much nicer. I mean can't you pass "ares_pin_function" as is?


> +		if (ret < 0)
> +			return ret;
> +
> +		ret = add_pin_group_node(acpi_map_head,
> +				ares_pin_function->resource_source.string_ptr,
> +				NULL,
> +				ares_pin_function->pin_table[i],
> +				true,
> +				config,
> +				ares_pin_function->vendor_data,
> +				ares_pin_function->vendor_length);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 1;
> +}
> +
> +static int populate_pin_config(struct list_head *acpi_map_head,
> +						struct acpi_resource_pin_config *ares_pin_config)
> +{
> +	int i;
> +	int ret;
> +	unsigned int config;
> +
> +	ret = map_acpi_conf_to_general_conf(ares_pin_config->pin_config_type,
> +					ares_pin_config->pin_config_value, &config);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; i < ares_pin_config->pin_table_length; i++) {
> +		ret = add_pin_group_node(acpi_map_head,
> +				ares_pin_config->resource_source.string_ptr,
> +				NULL,
> +				ares_pin_config->pin_table[i],
> +				true,
> +				config,
> +				ares_pin_config->vendor_data,
> +				ares_pin_config->vendor_length);

Same here

> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 1;
> +}
> +
> +static int populate_pin_group_function(struct list_head *acpi_map_head,
> +		struct acpi_resource_pin_group_function *ares_pin_group_function)
> +{
> +	int ret;
> +
> +	ret = add_pin_group_node(acpi_map_head,
> +			ares_pin_group_function->resource_source.string_ptr,
> +			ares_pin_group_function->resource_source_label.string_ptr,
> +			0,
> +			false,
> +			ares_pin_group_function->function_number,
> +			ares_pin_group_function->vendor_data,
> +			ares_pin_group_function->vendor_length);

And here. Okay the type is different but since they all have the same
common "header" it should be OK, I think.

> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int populate_pin_group_config(struct list_head *acpi_map_head,
> +		struct acpi_resource_pin_group_config *ares_pin_group_config)
> +{
> +	unsigned int config;
> +	int ret;
> +
> +	ret = map_acpi_conf_to_general_conf(
> +			ares_pin_group_config->pin_config_type,
> +			ares_pin_group_config->pin_config_value,
> +			&config);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = add_pin_group_node(acpi_map_head,
> +			ares_pin_group_config->resource_source.string_ptr,
> +			ares_pin_group_config->resource_source_label.string_ptr,
> +			0,
> +			true,
> +			config,
> +			ares_pin_group_config->vendor_data,
> +			ares_pin_group_config->vendor_length);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int pinctrl_acpi_populate_pin_group_map(struct acpi_resource *ares, void *data)
> +{
> +	struct list_head *acpi_map_head = data;
> +
> +	switch (ares->type) {
> +	case ACPI_RESOURCE_TYPE_PIN_FUNCTION:
> +		return populate_pin_function(acpi_map_head, &ares->data.pin_function);
> +	case ACPI_RESOURCE_TYPE_PIN_CONFIG:
> +		return populate_pin_config(acpi_map_head, &ares->data.pin_config);
> +	case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION:
> +		return populate_pin_group_function(acpi_map_head, &ares->data.pin_group_function);
> +	case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG:
> +		return populate_pin_group_config(acpi_map_head, &ares->data.pin_group_config);
> +	default:
> +		return 1;
> +	}
> +}
> +
> +static int pinctrl_acpi_get_pin_group_map(struct acpi_device *adev,
> +		struct list_head *pin_group_root)
> +{
> +	struct list_head res_list;
> +	int ret;
> +
> +	INIT_LIST_HEAD(&res_list);
> +	ret = acpi_dev_get_resources(adev, &res_list,
> +								pinctrl_acpi_populate_pin_group_map,
> +								pin_group_root);

Still weird formatting. Didn't checkpatch.pl complain about this?

> +	acpi_dev_free_resource_list(&res_list);
> +
> +	return ret;
> +}
> +
> +/**
> + * pinctrl_acpi_to_map() - pinctrl map from ACPI pin resources for device
> + * @p: pinctrl descriptor for the device
> + *
> + * This will parse the ACPI pin resources for the device and creates
> + * pinctrl map. This functions handles PinFunction, PinFunctionConfig,
> + * PinGroupFunction and PinGroupConfig resources.
> + */
> +int pinctrl_acpi_to_map(struct pinctrl *p)
> +{
> +	int num_maps;
> +	int ret;
> +	struct acpi_device *adev;
> +	struct list_head pin_group_list;
> +	struct pinctrl_map *new_map;
> +	struct pinctrl_dev *pctldev;
> +	const struct pinctrl_ops *ops;
> +	struct pinctrl_acpi_controller_map *controller_map;
> +
> +	adev = ACPI_COMPANION(p->dev);
> +	if (!adev)
> +		return -ENODEV;
> +
> +	INIT_LIST_HEAD(&pin_group_list);
> +	ret = pinctrl_acpi_get_pin_group_map(adev, &pin_group_list);
> +	if (ret < 0)
> +		return ret;
> +
> +	list_for_each_entry(controller_map, &pin_group_list, list) {
> +		const char *pctldev_name = acpi_node_to_device_name(controller_map->pinctrl_dev);
> +
> +		pctldev = get_pinctrl_dev_from_devname(pctldev_name);
> +		ops = pctldev->desc->pctlops;
> +		if (!ops->acpi_node_to_map) {
> +			dev_err(p->dev, "pctldev %s doesn't support ACPI\n",
> +				dev_name(pctldev->dev));
> +			return -ENODEV;
> +		}
> +		ret = ops->acpi_node_to_map(pctldev,
> +			&controller_map->pin_group_maps, &new_map, &num_maps);
> +		if (ret < 0) {
> +			return ret;
> +		} else if (num_maps == 0) {

!num_maps

> +			dev_info(p->dev, "there is not valid maps for pin controller %s\n",
> +				pctldev_name);
> +			return 0;
> +		}
> +
> +		ret = acpi_remember_or_free_map(p, "default", pctldev, new_map, num_maps);
> +		if (ret < 0) {
> +			dev_info(p->dev, "Failed to register maps\n");
> +			return ret;
> +		}
> +	}
> +	return 0;
> +}
>  
>  static int pinctrl_acpi_populate_group_desc(struct acpi_resource *ares, void *data)
>  {
> diff --git a/drivers/pinctrl/pinctrl-acpi.h b/drivers/pinctrl/pinctrl-acpi.h
> index e3a6b61bea90..1b097edb43a8 100644
> --- a/drivers/pinctrl/pinctrl-acpi.h
> +++ b/drivers/pinctrl/pinctrl-acpi.h
> @@ -23,12 +23,56 @@ struct pinctrl_acpi_group_desc {
>  	struct list_head list;
>  };
>  
> +/**
> + * struct pinctrl_acpi_pin_group_map - pin/group to config/functions map
> + * @group: name of the pin group. @group is NULL for pin types
> + * @pin: pin number. @pin is valid only if @group is NULL
> + * @is_config: set if @info contains config values
> + * @info_list: list of config or function for the pin/group
> + * @list: list head for the map
> + */
> +struct pinctrl_acpi_pin_group_map {
> +	const char *group;
> +	unsigned int pin;
> +	bool is_config;
> +	struct list_head info_list;
> +	struct list_head list;
> +};
> +
> +/**
> + * struct pinctrl_acpi_pin_group_info - config or function to apply
> + * @config_func: packed config value or function number
> + * @vendor_data: vendor data from ACPI resource
> + * @vendor_length: length of vendor data
> + * @list: list head for the descriptor
> + */
> +struct pinctrl_acpi_pin_group_info {
> +	unsigned int config_func;
> +	u8 *vendor_data;
> +	unsigned int vendor_length;
> +	struct list_head list;
> +};
> +
>  #ifdef CONFIG_ACPI
>  int pinctrl_acpi_get_pin_groups(struct acpi_device *adev, struct list_head *group_desc_list);
> +

Drop the empty line

> +int pinctrl_acpi_to_map(struct pinctrl *p);
> +

Ditto

> +void pinctrl_acpi_free_maps(struct pinctrl *p);
>  #else
>  static inline int pinctrl_acpi_get_pin_groups(struct acpi_device *adev,
>  			struct list_head *group_desc_list)
>  {
>  	return -ENXIO;
>  }
> +
> +static inline int pinctrl_acpi_to_map(struct pinctrl *p)
> +{
> +	return -ENXIO;
> +}
> +
> +static inline void pinctrl_acpi_free_maps(struct pinctrl *p)
> +{
> +
> +}
>  #endif
> diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
> index 487117ccb1bc..13d43a186df9 100644
> --- a/include/linux/pinctrl/pinctrl.h
> +++ b/include/linux/pinctrl/pinctrl.h
> @@ -104,6 +104,15 @@ struct pinctrl_gpio_range {
>   *	allocated members of the mapping table entries themselves. This
>   *	function is optional, and may be omitted for pinctrl drivers that do
>   *	not support device tree.
> + * @acpi_node_to_map: process ACPI pin related properties, and create
> + *	mapping table entries for it. These are returned through the @map and
> + *	@num_maps output parameters. This function is optional, and may be
> + *	omitted for pinctrl drivers that do not support ACPI.
> + * @acpi_free_map: free mapping table entries created via @acpi_node_to_map. The
> + *	top-level @map pointer must be freed, along with any dynamically
> + *	allocated members of the mapping table entries themselves. This
> + *	function is optional, and may be omitted for pinctrl drivers that do
> + *	not support ACPI.
>   */
>  struct pinctrl_ops {
>  	int (*get_groups_count) (struct pinctrl_dev *pctldev);
> @@ -120,6 +129,12 @@ struct pinctrl_ops {
>  			       struct pinctrl_map **map, unsigned *num_maps);
>  	void (*dt_free_map) (struct pinctrl_dev *pctldev,
>  			     struct pinctrl_map *map, unsigned num_maps);
> +	int (*acpi_node_to_map) (struct pinctrl_dev *pctldev,
> +			       struct list_head *info_list,
> +			       struct pinctrl_map **map, unsigned *num_maps);
> +	void (*acpi_free_map) (struct pinctrl_dev *pctldev,
> +				   struct pinctrl_map *map, unsigned num_maps);
> +
>  };
>  
>  /**
> -- 
> 2.25.1



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux