brintos

brintos / linux-shallow public Read only

0
0
Text · 21.2 KiB · 3855c98 Raw
918 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * System Control and Management Interface (SCMI) Pinctrl Protocol4 *5 * Copyright (C) 2024 EPAM6 * Copyright 2024 NXP7 */8 9#include <asm/byteorder.h>10#include <linux/bits.h>11#include <linux/bitfield.h>12#include <linux/device.h>13#include <linux/module.h>14#include <linux/scmi_protocol.h>15#include <linux/slab.h>16#include <linux/string.h>17#include <linux/types.h>18 19#include "common.h"20#include "protocols.h"21 22/* Updated only after ALL the mandatory features for that version are merged */23#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x1000024 25#define GET_GROUPS_NR(x)	le32_get_bits((x), GENMASK(31, 16))26#define GET_PINS_NR(x)		le32_get_bits((x), GENMASK(15, 0))27#define GET_FUNCTIONS_NR(x)	le32_get_bits((x), GENMASK(15, 0))28 29#define EXT_NAME_FLAG(x)	le32_get_bits((x), BIT(31))30#define NUM_ELEMS(x)		le32_get_bits((x), GENMASK(15, 0))31 32#define REMAINING(x)		le32_get_bits((x), GENMASK(31, 16))33#define RETURNED(x)		le32_get_bits((x), GENMASK(11, 0))34 35#define CONFIG_FLAG_MASK	GENMASK(19, 18)36#define SELECTOR_MASK		GENMASK(17, 16)37#define SKIP_CONFIGS_MASK	GENMASK(15, 8)38#define CONFIG_TYPE_MASK	GENMASK(7, 0)39 40enum scmi_pinctrl_protocol_cmd {41	PINCTRL_ATTRIBUTES = 0x3,42	PINCTRL_LIST_ASSOCIATIONS = 0x4,43	PINCTRL_SETTINGS_GET = 0x5,44	PINCTRL_SETTINGS_CONFIGURE = 0x6,45	PINCTRL_REQUEST = 0x7,46	PINCTRL_RELEASE = 0x8,47	PINCTRL_NAME_GET = 0x9,48	PINCTRL_SET_PERMISSIONS = 0xa,49};50 51struct scmi_msg_settings_conf {52	__le32 identifier;53	__le32 function_id;54	__le32 attributes;55	__le32 configs[];56};57 58struct scmi_msg_settings_get {59	__le32 identifier;60	__le32 attributes;61};62 63struct scmi_resp_settings_get {64	__le32 function_selected;65	__le32 num_configs;66	__le32 configs[];67};68 69struct scmi_msg_pinctrl_protocol_attributes {70	__le32 attributes_low;71	__le32 attributes_high;72};73 74struct scmi_msg_pinctrl_attributes {75	__le32 identifier;76	__le32 flags;77};78 79struct scmi_resp_pinctrl_attributes {80	__le32 attributes;81	u8 name[SCMI_SHORT_NAME_MAX_SIZE];82};83 84struct scmi_msg_pinctrl_list_assoc {85	__le32 identifier;86	__le32 flags;87	__le32 index;88};89 90struct scmi_resp_pinctrl_list_assoc {91	__le32 flags;92	__le16 array[];93};94 95struct scmi_msg_request {96	__le32 identifier;97	__le32 flags;98};99 100struct scmi_group_info {101	char name[SCMI_MAX_STR_SIZE];102	bool present;103	u32 *group_pins;104	u32 nr_pins;105};106 107struct scmi_function_info {108	char name[SCMI_MAX_STR_SIZE];109	bool present;110	u32 *groups;111	u32 nr_groups;112};113 114struct scmi_pin_info {115	char name[SCMI_MAX_STR_SIZE];116	bool present;117};118 119struct scmi_pinctrl_info {120	u32 version;121	int nr_groups;122	int nr_functions;123	int nr_pins;124	struct scmi_group_info *groups;125	struct scmi_function_info *functions;126	struct scmi_pin_info *pins;127};128 129static int scmi_pinctrl_attributes_get(const struct scmi_protocol_handle *ph,130				       struct scmi_pinctrl_info *pi)131{132	int ret;133	struct scmi_xfer *t;134	struct scmi_msg_pinctrl_protocol_attributes *attr;135 136	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);137	if (ret)138		return ret;139 140	attr = t->rx.buf;141 142	ret = ph->xops->do_xfer(ph, t);143	if (!ret) {144		pi->nr_functions = GET_FUNCTIONS_NR(attr->attributes_high);145		pi->nr_groups = GET_GROUPS_NR(attr->attributes_low);146		pi->nr_pins = GET_PINS_NR(attr->attributes_low);147		if (pi->nr_pins == 0) {148			dev_warn(ph->dev, "returned zero pins\n");149			ret = -EINVAL;150		}151	}152 153	ph->xops->xfer_put(ph, t);154	return ret;155}156 157static int scmi_pinctrl_count_get(const struct scmi_protocol_handle *ph,158				  enum scmi_pinctrl_selector_type type)159{160	struct scmi_pinctrl_info *pi = ph->get_priv(ph);161 162	switch (type) {163	case PIN_TYPE:164		return pi->nr_pins;165	case GROUP_TYPE:166		return pi->nr_groups;167	case FUNCTION_TYPE:168		return pi->nr_functions;169	default:170		return -EINVAL;171	}172}173 174static int scmi_pinctrl_validate_id(const struct scmi_protocol_handle *ph,175				    u32 selector,176				    enum scmi_pinctrl_selector_type type)177{178	int value;179 180	value = scmi_pinctrl_count_get(ph, type);181	if (value < 0)182		return value;183 184	if (selector >= value || value == 0)185		return -EINVAL;186 187	return 0;188}189 190static int scmi_pinctrl_attributes(const struct scmi_protocol_handle *ph,191				   enum scmi_pinctrl_selector_type type,192				   u32 selector, char *name,193				   u32 *n_elems)194{195	int ret;196	struct scmi_xfer *t;197	struct scmi_msg_pinctrl_attributes *tx;198	struct scmi_resp_pinctrl_attributes *rx;199	bool ext_name_flag;200 201	if (!name)202		return -EINVAL;203 204	ret = scmi_pinctrl_validate_id(ph, selector, type);205	if (ret)206		return ret;207 208	ret = ph->xops->xfer_get_init(ph, PINCTRL_ATTRIBUTES, sizeof(*tx),209				      sizeof(*rx), &t);210	if (ret)211		return ret;212 213	tx = t->tx.buf;214	rx = t->rx.buf;215	tx->identifier = cpu_to_le32(selector);216	tx->flags = cpu_to_le32(type);217 218	ret = ph->xops->do_xfer(ph, t);219	if (!ret) {220		if (n_elems)221			*n_elems = NUM_ELEMS(rx->attributes);222 223		strscpy(name, rx->name, SCMI_SHORT_NAME_MAX_SIZE);224 225		ext_name_flag = !!EXT_NAME_FLAG(rx->attributes);226	}227 228	ph->xops->xfer_put(ph, t);229 230	if (ret)231		return ret;232	/*233	 * If supported overwrite short name with the extended one;234	 * on error just carry on and use already provided short name.235	 */236	if (ext_name_flag)237		ret = ph->hops->extended_name_get(ph, PINCTRL_NAME_GET,238						  selector, (u32 *)&type, name,239						  SCMI_MAX_STR_SIZE);240	return ret;241}242 243struct scmi_pinctrl_ipriv {244	u32 selector;245	enum scmi_pinctrl_selector_type type;246	u32 *array;247};248 249static void iter_pinctrl_assoc_prepare_message(void *message,250					       u32 desc_index,251					       const void *priv)252{253	struct scmi_msg_pinctrl_list_assoc *msg = message;254	const struct scmi_pinctrl_ipriv *p = priv;255 256	msg->identifier = cpu_to_le32(p->selector);257	msg->flags = cpu_to_le32(p->type);258	msg->index = cpu_to_le32(desc_index);259}260 261static int iter_pinctrl_assoc_update_state(struct scmi_iterator_state *st,262					   const void *response, void *priv)263{264	const struct scmi_resp_pinctrl_list_assoc *r = response;265 266	st->num_returned = RETURNED(r->flags);267	st->num_remaining = REMAINING(r->flags);268 269	return 0;270}271 272static int273iter_pinctrl_assoc_process_response(const struct scmi_protocol_handle *ph,274				    const void *response,275				    struct scmi_iterator_state *st, void *priv)276{277	const struct scmi_resp_pinctrl_list_assoc *r = response;278	struct scmi_pinctrl_ipriv *p = priv;279 280	p->array[st->desc_index + st->loop_idx] =281		le16_to_cpu(r->array[st->loop_idx]);282 283	return 0;284}285 286static int scmi_pinctrl_list_associations(const struct scmi_protocol_handle *ph,287					  u32 selector,288					  enum scmi_pinctrl_selector_type type,289					  u16 size, u32 *array)290{291	int ret;292	void *iter;293	struct scmi_iterator_ops ops = {294		.prepare_message = iter_pinctrl_assoc_prepare_message,295		.update_state = iter_pinctrl_assoc_update_state,296		.process_response = iter_pinctrl_assoc_process_response,297	};298	struct scmi_pinctrl_ipriv ipriv = {299		.selector = selector,300		.type = type,301		.array = array,302	};303 304	if (!array || !size || type == PIN_TYPE)305		return -EINVAL;306 307	ret = scmi_pinctrl_validate_id(ph, selector, type);308	if (ret)309		return ret;310 311	iter = ph->hops->iter_response_init(ph, &ops, size,312					    PINCTRL_LIST_ASSOCIATIONS,313					    sizeof(struct scmi_msg_pinctrl_list_assoc),314					    &ipriv);315	if (IS_ERR(iter))316		return PTR_ERR(iter);317 318	return ph->hops->iter_response_run(iter);319}320 321struct scmi_settings_get_ipriv {322	u32 selector;323	enum scmi_pinctrl_selector_type type;324	bool get_all;325	unsigned int *nr_configs;326	enum scmi_pinctrl_conf_type *config_types;327	u32 *config_values;328};329 330static void331iter_pinctrl_settings_get_prepare_message(void *message, u32 desc_index,332					  const void *priv)333{334	struct scmi_msg_settings_get *msg = message;335	const struct scmi_settings_get_ipriv *p = priv;336	u32 attributes;337 338	attributes = FIELD_PREP(SELECTOR_MASK, p->type);339 340	if (p->get_all) {341		attributes |= FIELD_PREP(CONFIG_FLAG_MASK, 1) |342			FIELD_PREP(SKIP_CONFIGS_MASK, desc_index);343	} else {344		attributes |= FIELD_PREP(CONFIG_TYPE_MASK, p->config_types[0]);345	}346 347	msg->attributes = cpu_to_le32(attributes);348	msg->identifier = cpu_to_le32(p->selector);349}350 351static int352iter_pinctrl_settings_get_update_state(struct scmi_iterator_state *st,353				       const void *response, void *priv)354{355	const struct scmi_resp_settings_get *r = response;356	struct scmi_settings_get_ipriv *p = priv;357 358	if (p->get_all) {359		st->num_returned = le32_get_bits(r->num_configs, GENMASK(7, 0));360		st->num_remaining = le32_get_bits(r->num_configs, GENMASK(31, 24));361	} else {362		st->num_returned = 1;363		st->num_remaining = 0;364	}365 366	return 0;367}368 369static int370iter_pinctrl_settings_get_process_response(const struct scmi_protocol_handle *ph,371					   const void *response,372					   struct scmi_iterator_state *st,373					   void *priv)374{375	const struct scmi_resp_settings_get *r = response;376	struct scmi_settings_get_ipriv *p = priv;377	u32 type = le32_get_bits(r->configs[st->loop_idx * 2], GENMASK(7, 0));378	u32 val = le32_to_cpu(r->configs[st->loop_idx * 2 + 1]);379 380	if (p->get_all) {381		p->config_types[st->desc_index + st->loop_idx] = type;382	} else {383		if (p->config_types[0] != type)384			return -EINVAL;385	}386 387	p->config_values[st->desc_index + st->loop_idx] = val;388	++*p->nr_configs;389 390	return 0;391}392 393static int394scmi_pinctrl_settings_get(const struct scmi_protocol_handle *ph, u32 selector,395			  enum scmi_pinctrl_selector_type type,396			  unsigned int *nr_configs,397			  enum scmi_pinctrl_conf_type *config_types,398			  u32 *config_values)399{400	int ret;401	void *iter;402	unsigned int max_configs = *nr_configs;403	struct scmi_iterator_ops ops = {404		.prepare_message = iter_pinctrl_settings_get_prepare_message,405		.update_state = iter_pinctrl_settings_get_update_state,406		.process_response = iter_pinctrl_settings_get_process_response,407	};408	struct scmi_settings_get_ipriv ipriv = {409		.selector = selector,410		.type = type,411		.get_all = (max_configs > 1),412		.nr_configs = nr_configs,413		.config_types = config_types,414		.config_values = config_values,415	};416 417	if (!config_types || !config_values || type == FUNCTION_TYPE)418		return -EINVAL;419 420	ret = scmi_pinctrl_validate_id(ph, selector, type);421	if (ret)422		return ret;423 424	/* Prepare to count returned configs */425	*nr_configs = 0;426	iter = ph->hops->iter_response_init(ph, &ops, max_configs,427					    PINCTRL_SETTINGS_GET,428					    sizeof(struct scmi_msg_settings_get),429					    &ipriv);430	if (IS_ERR(iter))431		return PTR_ERR(iter);432 433	return ph->hops->iter_response_run(iter);434}435 436static int scmi_pinctrl_settings_get_one(const struct scmi_protocol_handle *ph,437					 u32 selector,438					 enum scmi_pinctrl_selector_type type,439					 enum scmi_pinctrl_conf_type config_type,440					 u32 *config_value)441{442	unsigned int nr_configs = 1;443 444	return scmi_pinctrl_settings_get(ph, selector, type, &nr_configs,445					 &config_type, config_value);446}447 448static int scmi_pinctrl_settings_get_all(const struct scmi_protocol_handle *ph,449					 u32 selector,450					 enum scmi_pinctrl_selector_type type,451					 unsigned int *nr_configs,452					 enum scmi_pinctrl_conf_type *config_types,453					 u32 *config_values)454{455	if (!nr_configs || *nr_configs == 0)456		return -EINVAL;457 458	return scmi_pinctrl_settings_get(ph, selector, type, nr_configs,459					 config_types, config_values);460}461 462static int463scmi_pinctrl_settings_conf(const struct scmi_protocol_handle *ph,464			   u32 selector,465			   enum scmi_pinctrl_selector_type type,466			   u32 nr_configs,467			   enum scmi_pinctrl_conf_type *config_type,468			   u32 *config_value)469{470	struct scmi_xfer *t;471	struct scmi_msg_settings_conf *tx;472	u32 attributes;473	int ret, i;474	u32 configs_in_chunk, conf_num = 0;475	u32 chunk;476	int max_msg_size = ph->hops->get_max_msg_size(ph);477 478	if (!config_type || !config_value || type == FUNCTION_TYPE)479		return -EINVAL;480 481	ret = scmi_pinctrl_validate_id(ph, selector, type);482	if (ret)483		return ret;484 485	configs_in_chunk = (max_msg_size - sizeof(*tx)) / (sizeof(__le32) * 2);486	while (conf_num < nr_configs) {487		chunk = (nr_configs - conf_num > configs_in_chunk) ?488			configs_in_chunk : nr_configs - conf_num;489 490		ret = ph->xops->xfer_get_init(ph, PINCTRL_SETTINGS_CONFIGURE,491					      sizeof(*tx) +492					      chunk * 2 * sizeof(__le32), 0, &t);493		if (ret)494			break;495 496		tx = t->tx.buf;497		tx->identifier = cpu_to_le32(selector);498		tx->function_id = cpu_to_le32(0xFFFFFFFF);499		attributes = FIELD_PREP(GENMASK(1, 0), type) |500			FIELD_PREP(GENMASK(9, 2), chunk);501		tx->attributes = cpu_to_le32(attributes);502 503		for (i = 0; i < chunk; i++) {504			tx->configs[i * 2] =505				cpu_to_le32(config_type[conf_num + i]);506			tx->configs[i * 2 + 1] =507				cpu_to_le32(config_value[conf_num + i]);508		}509 510		ret = ph->xops->do_xfer(ph, t);511 512		ph->xops->xfer_put(ph, t);513 514		if (ret)515			break;516 517		conf_num += chunk;518	}519 520	return ret;521}522 523static int scmi_pinctrl_function_select(const struct scmi_protocol_handle *ph,524					u32 group,525					enum scmi_pinctrl_selector_type type,526					u32 function_id)527{528	int ret;529	struct scmi_xfer *t;530	struct scmi_msg_settings_conf *tx;531	u32 attributes;532 533	ret = scmi_pinctrl_validate_id(ph, group, type);534	if (ret)535		return ret;536 537	ret = ph->xops->xfer_get_init(ph, PINCTRL_SETTINGS_CONFIGURE,538				      sizeof(*tx), 0, &t);539	if (ret)540		return ret;541 542	tx = t->tx.buf;543	tx->identifier = cpu_to_le32(group);544	tx->function_id = cpu_to_le32(function_id);545	attributes = FIELD_PREP(GENMASK(1, 0), type) | BIT(10);546	tx->attributes = cpu_to_le32(attributes);547 548	ret = ph->xops->do_xfer(ph, t);549	ph->xops->xfer_put(ph, t);550 551	return ret;552}553 554static int scmi_pinctrl_request_free(const struct scmi_protocol_handle *ph,555				     u32 identifier,556				     enum scmi_pinctrl_selector_type type,557				     enum scmi_pinctrl_protocol_cmd cmd)558{559	int ret;560	struct scmi_xfer *t;561	struct scmi_msg_request *tx;562 563	if (type == FUNCTION_TYPE)564		return -EINVAL;565 566	if (cmd != PINCTRL_REQUEST && cmd != PINCTRL_RELEASE)567		return -EINVAL;568 569	ret = scmi_pinctrl_validate_id(ph, identifier, type);570	if (ret)571		return ret;572 573	ret = ph->xops->xfer_get_init(ph, cmd, sizeof(*tx), 0, &t);574	if (ret)575		return ret;576 577	tx = t->tx.buf;578	tx->identifier = cpu_to_le32(identifier);579	tx->flags = cpu_to_le32(type);580 581	ret = ph->xops->do_xfer(ph, t);582	ph->xops->xfer_put(ph, t);583 584	return ret;585}586 587static int scmi_pinctrl_pin_request(const struct scmi_protocol_handle *ph,588				    u32 pin)589{590	return scmi_pinctrl_request_free(ph, pin, PIN_TYPE, PINCTRL_REQUEST);591}592 593static int scmi_pinctrl_pin_free(const struct scmi_protocol_handle *ph, u32 pin)594{595	return scmi_pinctrl_request_free(ph, pin, PIN_TYPE, PINCTRL_RELEASE);596}597 598static int scmi_pinctrl_get_group_info(const struct scmi_protocol_handle *ph,599				       u32 selector,600				       struct scmi_group_info *group)601{602	int ret;603 604	ret = scmi_pinctrl_attributes(ph, GROUP_TYPE, selector, group->name,605				      &group->nr_pins);606	if (ret)607		return ret;608 609	if (!group->nr_pins) {610		dev_err(ph->dev, "Group %d has 0 elements", selector);611		return -ENODATA;612	}613 614	group->group_pins = kmalloc_array(group->nr_pins,615					  sizeof(*group->group_pins),616					  GFP_KERNEL);617	if (!group->group_pins)618		return -ENOMEM;619 620	ret = scmi_pinctrl_list_associations(ph, selector, GROUP_TYPE,621					     group->nr_pins, group->group_pins);622	if (ret) {623		kfree(group->group_pins);624		return ret;625	}626 627	group->present = true;628	return 0;629}630 631static int scmi_pinctrl_get_group_name(const struct scmi_protocol_handle *ph,632				       u32 selector, const char **name)633{634	struct scmi_pinctrl_info *pi = ph->get_priv(ph);635 636	if (!name)637		return -EINVAL;638 639	if (selector >= pi->nr_groups || pi->nr_groups == 0)640		return -EINVAL;641 642	if (!pi->groups[selector].present) {643		int ret;644 645		ret = scmi_pinctrl_get_group_info(ph, selector,646						  &pi->groups[selector]);647		if (ret)648			return ret;649	}650 651	*name = pi->groups[selector].name;652 653	return 0;654}655 656static int scmi_pinctrl_group_pins_get(const struct scmi_protocol_handle *ph,657				       u32 selector, const u32 **pins,658				       u32 *nr_pins)659{660	struct scmi_pinctrl_info *pi = ph->get_priv(ph);661 662	if (!pins || !nr_pins)663		return -EINVAL;664 665	if (selector >= pi->nr_groups || pi->nr_groups == 0)666		return -EINVAL;667 668	if (!pi->groups[selector].present) {669		int ret;670 671		ret = scmi_pinctrl_get_group_info(ph, selector,672						  &pi->groups[selector]);673		if (ret)674			return ret;675	}676 677	*pins = pi->groups[selector].group_pins;678	*nr_pins = pi->groups[selector].nr_pins;679 680	return 0;681}682 683static int scmi_pinctrl_get_function_info(const struct scmi_protocol_handle *ph,684					  u32 selector,685					  struct scmi_function_info *func)686{687	int ret;688 689	ret = scmi_pinctrl_attributes(ph, FUNCTION_TYPE, selector, func->name,690				      &func->nr_groups);691	if (ret)692		return ret;693 694	if (!func->nr_groups) {695		dev_err(ph->dev, "Function %d has 0 elements", selector);696		return -ENODATA;697	}698 699	func->groups = kmalloc_array(func->nr_groups, sizeof(*func->groups),700				     GFP_KERNEL);701	if (!func->groups)702		return -ENOMEM;703 704	ret = scmi_pinctrl_list_associations(ph, selector, FUNCTION_TYPE,705					     func->nr_groups, func->groups);706	if (ret) {707		kfree(func->groups);708		return ret;709	}710 711	func->present = true;712	return 0;713}714 715static int scmi_pinctrl_get_function_name(const struct scmi_protocol_handle *ph,716					  u32 selector, const char **name)717{718	struct scmi_pinctrl_info *pi = ph->get_priv(ph);719 720	if (!name)721		return -EINVAL;722 723	if (selector >= pi->nr_functions || pi->nr_functions == 0)724		return -EINVAL;725 726	if (!pi->functions[selector].present) {727		int ret;728 729		ret = scmi_pinctrl_get_function_info(ph, selector,730						     &pi->functions[selector]);731		if (ret)732			return ret;733	}734 735	*name = pi->functions[selector].name;736	return 0;737}738 739static int740scmi_pinctrl_function_groups_get(const struct scmi_protocol_handle *ph,741				 u32 selector, u32 *nr_groups,742				 const u32 **groups)743{744	struct scmi_pinctrl_info *pi = ph->get_priv(ph);745 746	if (!groups || !nr_groups)747		return -EINVAL;748 749	if (selector >= pi->nr_functions || pi->nr_functions == 0)750		return -EINVAL;751 752	if (!pi->functions[selector].present) {753		int ret;754 755		ret = scmi_pinctrl_get_function_info(ph, selector,756						     &pi->functions[selector]);757		if (ret)758			return ret;759	}760 761	*groups = pi->functions[selector].groups;762	*nr_groups = pi->functions[selector].nr_groups;763 764	return 0;765}766 767static int scmi_pinctrl_mux_set(const struct scmi_protocol_handle *ph,768				u32 selector, u32 group)769{770	return scmi_pinctrl_function_select(ph, group, GROUP_TYPE, selector);771}772 773static int scmi_pinctrl_get_pin_info(const struct scmi_protocol_handle *ph,774				     u32 selector, struct scmi_pin_info *pin)775{776	int ret;777 778	if (!pin)779		return -EINVAL;780 781	ret = scmi_pinctrl_attributes(ph, PIN_TYPE, selector, pin->name, NULL);782	if (ret)783		return ret;784 785	pin->present = true;786	return 0;787}788 789static int scmi_pinctrl_get_pin_name(const struct scmi_protocol_handle *ph,790				     u32 selector, const char **name)791{792	struct scmi_pinctrl_info *pi = ph->get_priv(ph);793 794	if (!name)795		return -EINVAL;796 797	if (selector >= pi->nr_pins)798		return -EINVAL;799 800	if (!pi->pins[selector].present) {801		int ret;802 803		ret = scmi_pinctrl_get_pin_info(ph, selector, &pi->pins[selector]);804		if (ret)805			return ret;806	}807 808	*name = pi->pins[selector].name;809 810	return 0;811}812 813static int scmi_pinctrl_name_get(const struct scmi_protocol_handle *ph,814				 u32 selector,815				 enum scmi_pinctrl_selector_type type,816				 const char **name)817{818	switch (type) {819	case PIN_TYPE:820		return scmi_pinctrl_get_pin_name(ph, selector, name);821	case GROUP_TYPE:822		return scmi_pinctrl_get_group_name(ph, selector, name);823	case FUNCTION_TYPE:824		return scmi_pinctrl_get_function_name(ph, selector, name);825	default:826		return -EINVAL;827	}828}829 830static const struct scmi_pinctrl_proto_ops pinctrl_proto_ops = {831	.count_get = scmi_pinctrl_count_get,832	.name_get = scmi_pinctrl_name_get,833	.group_pins_get = scmi_pinctrl_group_pins_get,834	.function_groups_get = scmi_pinctrl_function_groups_get,835	.mux_set = scmi_pinctrl_mux_set,836	.settings_get_one = scmi_pinctrl_settings_get_one,837	.settings_get_all = scmi_pinctrl_settings_get_all,838	.settings_conf = scmi_pinctrl_settings_conf,839	.pin_request = scmi_pinctrl_pin_request,840	.pin_free = scmi_pinctrl_pin_free,841};842 843static int scmi_pinctrl_protocol_init(const struct scmi_protocol_handle *ph)844{845	int ret;846	u32 version;847	struct scmi_pinctrl_info *pinfo;848 849	ret = ph->xops->version_get(ph, &version);850	if (ret)851		return ret;852 853	dev_dbg(ph->dev, "Pinctrl Version %d.%d\n",854		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));855 856	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);857	if (!pinfo)858		return -ENOMEM;859 860	ret = scmi_pinctrl_attributes_get(ph, pinfo);861	if (ret)862		return ret;863 864	pinfo->pins = devm_kcalloc(ph->dev, pinfo->nr_pins,865				   sizeof(*pinfo->pins), GFP_KERNEL);866	if (!pinfo->pins)867		return -ENOMEM;868 869	pinfo->groups = devm_kcalloc(ph->dev, pinfo->nr_groups,870				     sizeof(*pinfo->groups), GFP_KERNEL);871	if (!pinfo->groups)872		return -ENOMEM;873 874	pinfo->functions = devm_kcalloc(ph->dev, pinfo->nr_functions,875					sizeof(*pinfo->functions), GFP_KERNEL);876	if (!pinfo->functions)877		return -ENOMEM;878 879	pinfo->version = version;880 881	return ph->set_priv(ph, pinfo, version);882}883 884static int scmi_pinctrl_protocol_deinit(const struct scmi_protocol_handle *ph)885{886	int i;887	struct scmi_pinctrl_info *pi = ph->get_priv(ph);888 889	/* Free groups_pins allocated in scmi_pinctrl_get_group_info */890	for (i = 0; i < pi->nr_groups; i++) {891		if (pi->groups[i].present) {892			kfree(pi->groups[i].group_pins);893			pi->groups[i].present = false;894		}895	}896 897	/* Free groups allocated in scmi_pinctrl_get_function_info */898	for (i = 0; i < pi->nr_functions; i++) {899		if (pi->functions[i].present) {900			kfree(pi->functions[i].groups);901			pi->functions[i].present = false;902		}903	}904 905	return 0;906}907 908static const struct scmi_protocol scmi_pinctrl = {909	.id = SCMI_PROTOCOL_PINCTRL,910	.owner = THIS_MODULE,911	.instance_init = &scmi_pinctrl_protocol_init,912	.instance_deinit = &scmi_pinctrl_protocol_deinit,913	.ops = &pinctrl_proto_ops,914	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,915};916 917DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl)918