xref: /linux/drivers/firmware/arm_scmi/pinctrl.c (revision b8979c6b4d0d1b36e94f5bc483fd86e38107e554)
12145af01SPeng Fan // SPDX-License-Identifier: GPL-2.0
22145af01SPeng Fan /*
32145af01SPeng Fan  * System Control and Management Interface (SCMI) Pinctrl Protocol
42145af01SPeng Fan  *
52145af01SPeng Fan  * Copyright (C) 2024 EPAM
62145af01SPeng Fan  * Copyright 2024 NXP
72145af01SPeng Fan  */
82145af01SPeng Fan 
92145af01SPeng Fan #include <asm/byteorder.h>
102145af01SPeng Fan #include <linux/bits.h>
112145af01SPeng Fan #include <linux/bitfield.h>
122145af01SPeng Fan #include <linux/device.h>
132145af01SPeng Fan #include <linux/module.h>
142145af01SPeng Fan #include <linux/scmi_protocol.h>
152145af01SPeng Fan #include <linux/slab.h>
162145af01SPeng Fan #include <linux/string.h>
172145af01SPeng Fan #include <linux/types.h>
182145af01SPeng Fan 
192145af01SPeng Fan #include "common.h"
202145af01SPeng Fan #include "protocols.h"
212145af01SPeng Fan 
222145af01SPeng Fan /* Updated only after ALL the mandatory features for that version are merged */
232145af01SPeng Fan #define SCMI_PROTOCOL_SUPPORTED_VERSION		0x10000
242145af01SPeng Fan 
252145af01SPeng Fan #define GET_GROUPS_NR(x)	le32_get_bits((x), GENMASK(31, 16))
262145af01SPeng Fan #define GET_PINS_NR(x)		le32_get_bits((x), GENMASK(15, 0))
272145af01SPeng Fan #define GET_FUNCTIONS_NR(x)	le32_get_bits((x), GENMASK(15, 0))
282145af01SPeng Fan 
292145af01SPeng Fan #define EXT_NAME_FLAG(x)	le32_get_bits((x), BIT(31))
302145af01SPeng Fan #define NUM_ELEMS(x)		le32_get_bits((x), GENMASK(15, 0))
312145af01SPeng Fan 
322145af01SPeng Fan #define REMAINING(x)		le32_get_bits((x), GENMASK(31, 16))
332145af01SPeng Fan #define RETURNED(x)		le32_get_bits((x), GENMASK(11, 0))
342145af01SPeng Fan 
352145af01SPeng Fan #define CONFIG_FLAG_MASK	GENMASK(19, 18)
362145af01SPeng Fan #define SELECTOR_MASK		GENMASK(17, 16)
372145af01SPeng Fan #define SKIP_CONFIGS_MASK	GENMASK(15, 8)
382145af01SPeng Fan #define CONFIG_TYPE_MASK	GENMASK(7, 0)
392145af01SPeng Fan 
402145af01SPeng Fan enum scmi_pinctrl_protocol_cmd {
412145af01SPeng Fan 	PINCTRL_ATTRIBUTES = 0x3,
422145af01SPeng Fan 	PINCTRL_LIST_ASSOCIATIONS = 0x4,
432145af01SPeng Fan 	PINCTRL_SETTINGS_GET = 0x5,
442145af01SPeng Fan 	PINCTRL_SETTINGS_CONFIGURE = 0x6,
452145af01SPeng Fan 	PINCTRL_REQUEST = 0x7,
462145af01SPeng Fan 	PINCTRL_RELEASE = 0x8,
472145af01SPeng Fan 	PINCTRL_NAME_GET = 0x9,
482145af01SPeng Fan 	PINCTRL_SET_PERMISSIONS = 0xa,
492145af01SPeng Fan };
502145af01SPeng Fan 
512145af01SPeng Fan struct scmi_msg_settings_conf {
522145af01SPeng Fan 	__le32 identifier;
532145af01SPeng Fan 	__le32 function_id;
542145af01SPeng Fan 	__le32 attributes;
552145af01SPeng Fan 	__le32 configs[];
562145af01SPeng Fan };
572145af01SPeng Fan 
582145af01SPeng Fan struct scmi_msg_settings_get {
592145af01SPeng Fan 	__le32 identifier;
602145af01SPeng Fan 	__le32 attributes;
612145af01SPeng Fan };
622145af01SPeng Fan 
632145af01SPeng Fan struct scmi_resp_settings_get {
642145af01SPeng Fan 	__le32 function_selected;
652145af01SPeng Fan 	__le32 num_configs;
662145af01SPeng Fan 	__le32 configs[];
672145af01SPeng Fan };
682145af01SPeng Fan 
692145af01SPeng Fan struct scmi_msg_pinctrl_protocol_attributes {
702145af01SPeng Fan 	__le32 attributes_low;
712145af01SPeng Fan 	__le32 attributes_high;
722145af01SPeng Fan };
732145af01SPeng Fan 
742145af01SPeng Fan struct scmi_msg_pinctrl_attributes {
752145af01SPeng Fan 	__le32 identifier;
762145af01SPeng Fan 	__le32 flags;
772145af01SPeng Fan };
782145af01SPeng Fan 
792145af01SPeng Fan struct scmi_resp_pinctrl_attributes {
802145af01SPeng Fan 	__le32 attributes;
812145af01SPeng Fan 	u8 name[SCMI_SHORT_NAME_MAX_SIZE];
822145af01SPeng Fan };
832145af01SPeng Fan 
842145af01SPeng Fan struct scmi_msg_pinctrl_list_assoc {
852145af01SPeng Fan 	__le32 identifier;
862145af01SPeng Fan 	__le32 flags;
872145af01SPeng Fan 	__le32 index;
882145af01SPeng Fan };
892145af01SPeng Fan 
902145af01SPeng Fan struct scmi_resp_pinctrl_list_assoc {
912145af01SPeng Fan 	__le32 flags;
922145af01SPeng Fan 	__le16 array[];
932145af01SPeng Fan };
942145af01SPeng Fan 
952145af01SPeng Fan struct scmi_msg_request {
962145af01SPeng Fan 	__le32 identifier;
972145af01SPeng Fan 	__le32 flags;
982145af01SPeng Fan };
992145af01SPeng Fan 
1002145af01SPeng Fan struct scmi_group_info {
1012145af01SPeng Fan 	char name[SCMI_MAX_STR_SIZE];
1022145af01SPeng Fan 	bool present;
1032145af01SPeng Fan 	u32 *group_pins;
1042145af01SPeng Fan 	u32 nr_pins;
1052145af01SPeng Fan };
1062145af01SPeng Fan 
1072145af01SPeng Fan struct scmi_function_info {
1082145af01SPeng Fan 	char name[SCMI_MAX_STR_SIZE];
1092145af01SPeng Fan 	bool present;
1102145af01SPeng Fan 	u32 *groups;
1112145af01SPeng Fan 	u32 nr_groups;
1122145af01SPeng Fan };
1132145af01SPeng Fan 
1142145af01SPeng Fan struct scmi_pin_info {
1152145af01SPeng Fan 	char name[SCMI_MAX_STR_SIZE];
1162145af01SPeng Fan 	bool present;
1172145af01SPeng Fan };
1182145af01SPeng Fan 
1192145af01SPeng Fan struct scmi_pinctrl_info {
1202145af01SPeng Fan 	u32 version;
1212145af01SPeng Fan 	int nr_groups;
1222145af01SPeng Fan 	int nr_functions;
1232145af01SPeng Fan 	int nr_pins;
1242145af01SPeng Fan 	struct scmi_group_info *groups;
1252145af01SPeng Fan 	struct scmi_function_info *functions;
1262145af01SPeng Fan 	struct scmi_pin_info *pins;
1272145af01SPeng Fan };
1282145af01SPeng Fan 
1292145af01SPeng Fan static int scmi_pinctrl_attributes_get(const struct scmi_protocol_handle *ph,
1302145af01SPeng Fan 				       struct scmi_pinctrl_info *pi)
1312145af01SPeng Fan {
1322145af01SPeng Fan 	int ret;
1332145af01SPeng Fan 	struct scmi_xfer *t;
1342145af01SPeng Fan 	struct scmi_msg_pinctrl_protocol_attributes *attr;
1352145af01SPeng Fan 
1362145af01SPeng Fan 	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);
1372145af01SPeng Fan 	if (ret)
1382145af01SPeng Fan 		return ret;
1392145af01SPeng Fan 
1402145af01SPeng Fan 	attr = t->rx.buf;
1412145af01SPeng Fan 
1422145af01SPeng Fan 	ret = ph->xops->do_xfer(ph, t);
1432145af01SPeng Fan 	if (!ret) {
1442145af01SPeng Fan 		pi->nr_functions = GET_FUNCTIONS_NR(attr->attributes_high);
1452145af01SPeng Fan 		pi->nr_groups = GET_GROUPS_NR(attr->attributes_low);
1462145af01SPeng Fan 		pi->nr_pins = GET_PINS_NR(attr->attributes_low);
1472145af01SPeng Fan 		if (pi->nr_pins == 0) {
1482145af01SPeng Fan 			dev_warn(ph->dev, "returned zero pins\n");
1492145af01SPeng Fan 			ret = -EINVAL;
1502145af01SPeng Fan 		}
1512145af01SPeng Fan 	}
1522145af01SPeng Fan 
1532145af01SPeng Fan 	ph->xops->xfer_put(ph, t);
1542145af01SPeng Fan 	return ret;
1552145af01SPeng Fan }
1562145af01SPeng Fan 
1572145af01SPeng Fan static int scmi_pinctrl_count_get(const struct scmi_protocol_handle *ph,
1582145af01SPeng Fan 				  enum scmi_pinctrl_selector_type type)
1592145af01SPeng Fan {
1602145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
1612145af01SPeng Fan 
1622145af01SPeng Fan 	switch (type) {
1632145af01SPeng Fan 	case PIN_TYPE:
1642145af01SPeng Fan 		return pi->nr_pins;
1652145af01SPeng Fan 	case GROUP_TYPE:
1662145af01SPeng Fan 		return pi->nr_groups;
1672145af01SPeng Fan 	case FUNCTION_TYPE:
1682145af01SPeng Fan 		return pi->nr_functions;
1692145af01SPeng Fan 	default:
1702145af01SPeng Fan 		return -EINVAL;
1712145af01SPeng Fan 	}
1722145af01SPeng Fan }
1732145af01SPeng Fan 
1742145af01SPeng Fan static int scmi_pinctrl_validate_id(const struct scmi_protocol_handle *ph,
1752145af01SPeng Fan 				    u32 selector,
1762145af01SPeng Fan 				    enum scmi_pinctrl_selector_type type)
1772145af01SPeng Fan {
1782145af01SPeng Fan 	int value;
1792145af01SPeng Fan 
1802145af01SPeng Fan 	value = scmi_pinctrl_count_get(ph, type);
1812145af01SPeng Fan 	if (value < 0)
1822145af01SPeng Fan 		return value;
1832145af01SPeng Fan 
1842145af01SPeng Fan 	if (selector >= value || value == 0)
1852145af01SPeng Fan 		return -EINVAL;
1862145af01SPeng Fan 
1872145af01SPeng Fan 	return 0;
1882145af01SPeng Fan }
1892145af01SPeng Fan 
1902145af01SPeng Fan static int scmi_pinctrl_attributes(const struct scmi_protocol_handle *ph,
1912145af01SPeng Fan 				   enum scmi_pinctrl_selector_type type,
1922145af01SPeng Fan 				   u32 selector, char *name,
1932145af01SPeng Fan 				   u32 *n_elems)
1942145af01SPeng Fan {
1952145af01SPeng Fan 	int ret;
1962145af01SPeng Fan 	struct scmi_xfer *t;
1972145af01SPeng Fan 	struct scmi_msg_pinctrl_attributes *tx;
1982145af01SPeng Fan 	struct scmi_resp_pinctrl_attributes *rx;
1992145af01SPeng Fan 	bool ext_name_flag;
2002145af01SPeng Fan 
2012145af01SPeng Fan 	if (!name)
2022145af01SPeng Fan 		return -EINVAL;
2032145af01SPeng Fan 
2042145af01SPeng Fan 	ret = scmi_pinctrl_validate_id(ph, selector, type);
2052145af01SPeng Fan 	if (ret)
2062145af01SPeng Fan 		return ret;
2072145af01SPeng Fan 
2082145af01SPeng Fan 	ret = ph->xops->xfer_get_init(ph, PINCTRL_ATTRIBUTES, sizeof(*tx),
2092145af01SPeng Fan 				      sizeof(*rx), &t);
2102145af01SPeng Fan 	if (ret)
2112145af01SPeng Fan 		return ret;
2122145af01SPeng Fan 
2132145af01SPeng Fan 	tx = t->tx.buf;
2142145af01SPeng Fan 	rx = t->rx.buf;
2152145af01SPeng Fan 	tx->identifier = cpu_to_le32(selector);
2162145af01SPeng Fan 	tx->flags = cpu_to_le32(type);
2172145af01SPeng Fan 
2182145af01SPeng Fan 	ret = ph->xops->do_xfer(ph, t);
2192145af01SPeng Fan 	if (!ret) {
2202145af01SPeng Fan 		if (n_elems)
2212145af01SPeng Fan 			*n_elems = NUM_ELEMS(rx->attributes);
2222145af01SPeng Fan 
2232145af01SPeng Fan 		strscpy(name, rx->name, SCMI_SHORT_NAME_MAX_SIZE);
2242145af01SPeng Fan 
2252145af01SPeng Fan 		ext_name_flag = !!EXT_NAME_FLAG(rx->attributes);
2262145af01SPeng Fan 	}
2272145af01SPeng Fan 
2282145af01SPeng Fan 	ph->xops->xfer_put(ph, t);
2292145af01SPeng Fan 
2302145af01SPeng Fan 	if (ret)
2312145af01SPeng Fan 		return ret;
2322145af01SPeng Fan 	/*
2332145af01SPeng Fan 	 * If supported overwrite short name with the extended one;
2342145af01SPeng Fan 	 * on error just carry on and use already provided short name.
2352145af01SPeng Fan 	 */
2362145af01SPeng Fan 	if (ext_name_flag)
2372145af01SPeng Fan 		ret = ph->hops->extended_name_get(ph, PINCTRL_NAME_GET,
2382145af01SPeng Fan 						  selector, (u32 *)&type, name,
2392145af01SPeng Fan 						  SCMI_MAX_STR_SIZE);
2402145af01SPeng Fan 	return ret;
2412145af01SPeng Fan }
2422145af01SPeng Fan 
2432145af01SPeng Fan struct scmi_pinctrl_ipriv {
2442145af01SPeng Fan 	u32 selector;
2452145af01SPeng Fan 	enum scmi_pinctrl_selector_type type;
2462145af01SPeng Fan 	u32 *array;
2472145af01SPeng Fan };
2482145af01SPeng Fan 
2492145af01SPeng Fan static void iter_pinctrl_assoc_prepare_message(void *message,
2502145af01SPeng Fan 					       u32 desc_index,
2512145af01SPeng Fan 					       const void *priv)
2522145af01SPeng Fan {
2532145af01SPeng Fan 	struct scmi_msg_pinctrl_list_assoc *msg = message;
2542145af01SPeng Fan 	const struct scmi_pinctrl_ipriv *p = priv;
2552145af01SPeng Fan 
2562145af01SPeng Fan 	msg->identifier = cpu_to_le32(p->selector);
2572145af01SPeng Fan 	msg->flags = cpu_to_le32(p->type);
2582145af01SPeng Fan 	msg->index = cpu_to_le32(desc_index);
2592145af01SPeng Fan }
2602145af01SPeng Fan 
2612145af01SPeng Fan static int iter_pinctrl_assoc_update_state(struct scmi_iterator_state *st,
2622145af01SPeng Fan 					   const void *response, void *priv)
2632145af01SPeng Fan {
2642145af01SPeng Fan 	const struct scmi_resp_pinctrl_list_assoc *r = response;
2652145af01SPeng Fan 
2662145af01SPeng Fan 	st->num_returned = RETURNED(r->flags);
2672145af01SPeng Fan 	st->num_remaining = REMAINING(r->flags);
2682145af01SPeng Fan 
2692145af01SPeng Fan 	return 0;
2702145af01SPeng Fan }
2712145af01SPeng Fan 
2722145af01SPeng Fan static int
2732145af01SPeng Fan iter_pinctrl_assoc_process_response(const struct scmi_protocol_handle *ph,
2742145af01SPeng Fan 				    const void *response,
2752145af01SPeng Fan 				    struct scmi_iterator_state *st, void *priv)
2762145af01SPeng Fan {
2772145af01SPeng Fan 	const struct scmi_resp_pinctrl_list_assoc *r = response;
2782145af01SPeng Fan 	struct scmi_pinctrl_ipriv *p = priv;
2792145af01SPeng Fan 
2802145af01SPeng Fan 	p->array[st->desc_index + st->loop_idx] =
2812145af01SPeng Fan 		le16_to_cpu(r->array[st->loop_idx]);
2822145af01SPeng Fan 
2832145af01SPeng Fan 	return 0;
2842145af01SPeng Fan }
2852145af01SPeng Fan 
2862145af01SPeng Fan static int scmi_pinctrl_list_associations(const struct scmi_protocol_handle *ph,
2872145af01SPeng Fan 					  u32 selector,
2882145af01SPeng Fan 					  enum scmi_pinctrl_selector_type type,
2892145af01SPeng Fan 					  u16 size, u32 *array)
2902145af01SPeng Fan {
2912145af01SPeng Fan 	int ret;
2922145af01SPeng Fan 	void *iter;
2932145af01SPeng Fan 	struct scmi_iterator_ops ops = {
2942145af01SPeng Fan 		.prepare_message = iter_pinctrl_assoc_prepare_message,
2952145af01SPeng Fan 		.update_state = iter_pinctrl_assoc_update_state,
2962145af01SPeng Fan 		.process_response = iter_pinctrl_assoc_process_response,
2972145af01SPeng Fan 	};
2982145af01SPeng Fan 	struct scmi_pinctrl_ipriv ipriv = {
2992145af01SPeng Fan 		.selector = selector,
3002145af01SPeng Fan 		.type = type,
3012145af01SPeng Fan 		.array = array,
3022145af01SPeng Fan 	};
3032145af01SPeng Fan 
3042145af01SPeng Fan 	if (!array || !size || type == PIN_TYPE)
3052145af01SPeng Fan 		return -EINVAL;
3062145af01SPeng Fan 
3072145af01SPeng Fan 	ret = scmi_pinctrl_validate_id(ph, selector, type);
3082145af01SPeng Fan 	if (ret)
3092145af01SPeng Fan 		return ret;
3102145af01SPeng Fan 
3112145af01SPeng Fan 	iter = ph->hops->iter_response_init(ph, &ops, size,
3122145af01SPeng Fan 					    PINCTRL_LIST_ASSOCIATIONS,
3132145af01SPeng Fan 					    sizeof(struct scmi_msg_pinctrl_list_assoc),
3142145af01SPeng Fan 					    &ipriv);
3152145af01SPeng Fan 	if (IS_ERR(iter))
3162145af01SPeng Fan 		return PTR_ERR(iter);
3172145af01SPeng Fan 
3182145af01SPeng Fan 	return ph->hops->iter_response_run(iter);
3192145af01SPeng Fan }
3202145af01SPeng Fan 
3212145af01SPeng Fan struct scmi_settings_get_ipriv {
3222145af01SPeng Fan 	u32 selector;
3232145af01SPeng Fan 	enum scmi_pinctrl_selector_type type;
3242145af01SPeng Fan 	bool get_all;
3252145af01SPeng Fan 	unsigned int *nr_configs;
3262145af01SPeng Fan 	enum scmi_pinctrl_conf_type *config_types;
3272145af01SPeng Fan 	u32 *config_values;
3282145af01SPeng Fan };
3292145af01SPeng Fan 
3302145af01SPeng Fan static void
3312145af01SPeng Fan iter_pinctrl_settings_get_prepare_message(void *message, u32 desc_index,
3322145af01SPeng Fan 					  const void *priv)
3332145af01SPeng Fan {
3342145af01SPeng Fan 	struct scmi_msg_settings_get *msg = message;
3352145af01SPeng Fan 	const struct scmi_settings_get_ipriv *p = priv;
3362145af01SPeng Fan 	u32 attributes;
3372145af01SPeng Fan 
3382145af01SPeng Fan 	attributes = FIELD_PREP(SELECTOR_MASK, p->type);
3392145af01SPeng Fan 
3402145af01SPeng Fan 	if (p->get_all) {
3412145af01SPeng Fan 		attributes |= FIELD_PREP(CONFIG_FLAG_MASK, 1) |
3422145af01SPeng Fan 			FIELD_PREP(SKIP_CONFIGS_MASK, desc_index);
3432145af01SPeng Fan 	} else {
3442145af01SPeng Fan 		attributes |= FIELD_PREP(CONFIG_TYPE_MASK, p->config_types[0]);
3452145af01SPeng Fan 	}
3462145af01SPeng Fan 
3472145af01SPeng Fan 	msg->attributes = cpu_to_le32(attributes);
3482145af01SPeng Fan 	msg->identifier = cpu_to_le32(p->selector);
3492145af01SPeng Fan }
3502145af01SPeng Fan 
3512145af01SPeng Fan static int
3522145af01SPeng Fan iter_pinctrl_settings_get_update_state(struct scmi_iterator_state *st,
3532145af01SPeng Fan 				       const void *response, void *priv)
3542145af01SPeng Fan {
3552145af01SPeng Fan 	const struct scmi_resp_settings_get *r = response;
3562145af01SPeng Fan 	struct scmi_settings_get_ipriv *p = priv;
3572145af01SPeng Fan 
3582145af01SPeng Fan 	if (p->get_all) {
3592145af01SPeng Fan 		st->num_returned = le32_get_bits(r->num_configs, GENMASK(7, 0));
3602145af01SPeng Fan 		st->num_remaining = le32_get_bits(r->num_configs, GENMASK(31, 24));
3612145af01SPeng Fan 	} else {
3622145af01SPeng Fan 		st->num_returned = 1;
3632145af01SPeng Fan 		st->num_remaining = 0;
3642145af01SPeng Fan 	}
3652145af01SPeng Fan 
3662145af01SPeng Fan 	return 0;
3672145af01SPeng Fan }
3682145af01SPeng Fan 
3692145af01SPeng Fan static int
3702145af01SPeng Fan iter_pinctrl_settings_get_process_response(const struct scmi_protocol_handle *ph,
3712145af01SPeng Fan 					   const void *response,
3722145af01SPeng Fan 					   struct scmi_iterator_state *st,
3732145af01SPeng Fan 					   void *priv)
3742145af01SPeng Fan {
3752145af01SPeng Fan 	const struct scmi_resp_settings_get *r = response;
3762145af01SPeng Fan 	struct scmi_settings_get_ipriv *p = priv;
3772145af01SPeng Fan 	u32 type = le32_get_bits(r->configs[st->loop_idx * 2], GENMASK(7, 0));
3782145af01SPeng Fan 	u32 val = le32_to_cpu(r->configs[st->loop_idx * 2 + 1]);
3792145af01SPeng Fan 
3802145af01SPeng Fan 	if (p->get_all) {
3812145af01SPeng Fan 		p->config_types[st->desc_index + st->loop_idx] = type;
3822145af01SPeng Fan 	} else {
3832145af01SPeng Fan 		if (p->config_types[0] != type)
3842145af01SPeng Fan 			return -EINVAL;
3852145af01SPeng Fan 	}
3862145af01SPeng Fan 
3872145af01SPeng Fan 	p->config_values[st->desc_index + st->loop_idx] = val;
3882145af01SPeng Fan 	++*p->nr_configs;
3892145af01SPeng Fan 
3902145af01SPeng Fan 	return 0;
3912145af01SPeng Fan }
3922145af01SPeng Fan 
3932145af01SPeng Fan static int
3942145af01SPeng Fan scmi_pinctrl_settings_get(const struct scmi_protocol_handle *ph, u32 selector,
3952145af01SPeng Fan 			  enum scmi_pinctrl_selector_type type,
3962145af01SPeng Fan 			  unsigned int *nr_configs,
3972145af01SPeng Fan 			  enum scmi_pinctrl_conf_type *config_types,
3982145af01SPeng Fan 			  u32 *config_values)
3992145af01SPeng Fan {
4002145af01SPeng Fan 	int ret;
4012145af01SPeng Fan 	void *iter;
4022145af01SPeng Fan 	unsigned int max_configs = *nr_configs;
4032145af01SPeng Fan 	struct scmi_iterator_ops ops = {
4042145af01SPeng Fan 		.prepare_message = iter_pinctrl_settings_get_prepare_message,
4052145af01SPeng Fan 		.update_state = iter_pinctrl_settings_get_update_state,
4062145af01SPeng Fan 		.process_response = iter_pinctrl_settings_get_process_response,
4072145af01SPeng Fan 	};
4082145af01SPeng Fan 	struct scmi_settings_get_ipriv ipriv = {
4092145af01SPeng Fan 		.selector = selector,
4102145af01SPeng Fan 		.type = type,
4112145af01SPeng Fan 		.get_all = (max_configs > 1),
4122145af01SPeng Fan 		.nr_configs = nr_configs,
4132145af01SPeng Fan 		.config_types = config_types,
4142145af01SPeng Fan 		.config_values = config_values,
4152145af01SPeng Fan 	};
4162145af01SPeng Fan 
4172145af01SPeng Fan 	if (!config_types || !config_values || type == FUNCTION_TYPE)
4182145af01SPeng Fan 		return -EINVAL;
4192145af01SPeng Fan 
4202145af01SPeng Fan 	ret = scmi_pinctrl_validate_id(ph, selector, type);
4212145af01SPeng Fan 	if (ret)
4222145af01SPeng Fan 		return ret;
4232145af01SPeng Fan 
4242145af01SPeng Fan 	/* Prepare to count returned configs */
4252145af01SPeng Fan 	*nr_configs = 0;
4262145af01SPeng Fan 	iter = ph->hops->iter_response_init(ph, &ops, max_configs,
4272145af01SPeng Fan 					    PINCTRL_SETTINGS_GET,
4282145af01SPeng Fan 					    sizeof(struct scmi_msg_settings_get),
4292145af01SPeng Fan 					    &ipriv);
4302145af01SPeng Fan 	if (IS_ERR(iter))
4312145af01SPeng Fan 		return PTR_ERR(iter);
4322145af01SPeng Fan 
4332145af01SPeng Fan 	return ph->hops->iter_response_run(iter);
4342145af01SPeng Fan }
4352145af01SPeng Fan 
4362145af01SPeng Fan static int scmi_pinctrl_settings_get_one(const struct scmi_protocol_handle *ph,
4372145af01SPeng Fan 					 u32 selector,
4382145af01SPeng Fan 					 enum scmi_pinctrl_selector_type type,
4392145af01SPeng Fan 					 enum scmi_pinctrl_conf_type config_type,
4402145af01SPeng Fan 					 u32 *config_value)
4412145af01SPeng Fan {
4422145af01SPeng Fan 	unsigned int nr_configs = 1;
4432145af01SPeng Fan 
4442145af01SPeng Fan 	return scmi_pinctrl_settings_get(ph, selector, type, &nr_configs,
4452145af01SPeng Fan 					 &config_type, config_value);
4462145af01SPeng Fan }
4472145af01SPeng Fan 
4482145af01SPeng Fan static int scmi_pinctrl_settings_get_all(const struct scmi_protocol_handle *ph,
4492145af01SPeng Fan 					 u32 selector,
4502145af01SPeng Fan 					 enum scmi_pinctrl_selector_type type,
4512145af01SPeng Fan 					 unsigned int *nr_configs,
4522145af01SPeng Fan 					 enum scmi_pinctrl_conf_type *config_types,
4532145af01SPeng Fan 					 u32 *config_values)
4542145af01SPeng Fan {
4552145af01SPeng Fan 	if (!nr_configs || *nr_configs == 0)
4562145af01SPeng Fan 		return -EINVAL;
4572145af01SPeng Fan 
4582145af01SPeng Fan 	return scmi_pinctrl_settings_get(ph, selector, type, nr_configs,
4592145af01SPeng Fan 					 config_types, config_values);
4602145af01SPeng Fan }
4612145af01SPeng Fan 
4622145af01SPeng Fan static int
4632145af01SPeng Fan scmi_pinctrl_settings_conf(const struct scmi_protocol_handle *ph,
4642145af01SPeng Fan 			   u32 selector,
4652145af01SPeng Fan 			   enum scmi_pinctrl_selector_type type,
4662145af01SPeng Fan 			   u32 nr_configs,
4672145af01SPeng Fan 			   enum scmi_pinctrl_conf_type *config_type,
4682145af01SPeng Fan 			   u32 *config_value)
4692145af01SPeng Fan {
4702145af01SPeng Fan 	struct scmi_xfer *t;
4712145af01SPeng Fan 	struct scmi_msg_settings_conf *tx;
4722145af01SPeng Fan 	u32 attributes;
4732145af01SPeng Fan 	int ret, i;
4742145af01SPeng Fan 	u32 configs_in_chunk, conf_num = 0;
4752145af01SPeng Fan 	u32 chunk;
4762145af01SPeng Fan 	int max_msg_size = ph->hops->get_max_msg_size(ph);
4772145af01SPeng Fan 
4782145af01SPeng Fan 	if (!config_type || !config_value || type == FUNCTION_TYPE)
4792145af01SPeng Fan 		return -EINVAL;
4802145af01SPeng Fan 
4812145af01SPeng Fan 	ret = scmi_pinctrl_validate_id(ph, selector, type);
4822145af01SPeng Fan 	if (ret)
4832145af01SPeng Fan 		return ret;
4842145af01SPeng Fan 
4852145af01SPeng Fan 	configs_in_chunk = (max_msg_size - sizeof(*tx)) / (sizeof(__le32) * 2);
4862145af01SPeng Fan 	while (conf_num < nr_configs) {
4872145af01SPeng Fan 		chunk = (nr_configs - conf_num > configs_in_chunk) ?
4882145af01SPeng Fan 			configs_in_chunk : nr_configs - conf_num;
4892145af01SPeng Fan 
4902145af01SPeng Fan 		ret = ph->xops->xfer_get_init(ph, PINCTRL_SETTINGS_CONFIGURE,
4912145af01SPeng Fan 					      sizeof(*tx) +
4922145af01SPeng Fan 					      chunk * 2 * sizeof(__le32), 0, &t);
4932145af01SPeng Fan 		if (ret)
4942145af01SPeng Fan 			break;
4952145af01SPeng Fan 
4962145af01SPeng Fan 		tx = t->tx.buf;
4972145af01SPeng Fan 		tx->identifier = cpu_to_le32(selector);
4982145af01SPeng Fan 		tx->function_id = cpu_to_le32(0xFFFFFFFF);
4992145af01SPeng Fan 		attributes = FIELD_PREP(GENMASK(1, 0), type) |
5002145af01SPeng Fan 			FIELD_PREP(GENMASK(9, 2), chunk);
5012145af01SPeng Fan 		tx->attributes = cpu_to_le32(attributes);
5022145af01SPeng Fan 
5032145af01SPeng Fan 		for (i = 0; i < chunk; i++) {
5042145af01SPeng Fan 			tx->configs[i * 2] =
5052145af01SPeng Fan 				cpu_to_le32(config_type[conf_num + i]);
5062145af01SPeng Fan 			tx->configs[i * 2 + 1] =
5072145af01SPeng Fan 				cpu_to_le32(config_value[conf_num + i]);
5082145af01SPeng Fan 		}
5092145af01SPeng Fan 
5102145af01SPeng Fan 		ret = ph->xops->do_xfer(ph, t);
5112145af01SPeng Fan 
5122145af01SPeng Fan 		ph->xops->xfer_put(ph, t);
5132145af01SPeng Fan 
5142145af01SPeng Fan 		if (ret)
5152145af01SPeng Fan 			break;
5162145af01SPeng Fan 
5172145af01SPeng Fan 		conf_num += chunk;
5182145af01SPeng Fan 	}
5192145af01SPeng Fan 
5202145af01SPeng Fan 	return ret;
5212145af01SPeng Fan }
5222145af01SPeng Fan 
5232145af01SPeng Fan static int scmi_pinctrl_function_select(const struct scmi_protocol_handle *ph,
5242145af01SPeng Fan 					u32 group,
5252145af01SPeng Fan 					enum scmi_pinctrl_selector_type type,
5262145af01SPeng Fan 					u32 function_id)
5272145af01SPeng Fan {
5282145af01SPeng Fan 	int ret;
5292145af01SPeng Fan 	struct scmi_xfer *t;
5302145af01SPeng Fan 	struct scmi_msg_settings_conf *tx;
5312145af01SPeng Fan 	u32 attributes;
5322145af01SPeng Fan 
5332145af01SPeng Fan 	ret = scmi_pinctrl_validate_id(ph, group, type);
5342145af01SPeng Fan 	if (ret)
5352145af01SPeng Fan 		return ret;
5362145af01SPeng Fan 
5372145af01SPeng Fan 	ret = ph->xops->xfer_get_init(ph, PINCTRL_SETTINGS_CONFIGURE,
5382145af01SPeng Fan 				      sizeof(*tx), 0, &t);
5392145af01SPeng Fan 	if (ret)
5402145af01SPeng Fan 		return ret;
5412145af01SPeng Fan 
5422145af01SPeng Fan 	tx = t->tx.buf;
5432145af01SPeng Fan 	tx->identifier = cpu_to_le32(group);
5442145af01SPeng Fan 	tx->function_id = cpu_to_le32(function_id);
5452145af01SPeng Fan 	attributes = FIELD_PREP(GENMASK(1, 0), type) | BIT(10);
5462145af01SPeng Fan 	tx->attributes = cpu_to_le32(attributes);
5472145af01SPeng Fan 
5482145af01SPeng Fan 	ret = ph->xops->do_xfer(ph, t);
5492145af01SPeng Fan 	ph->xops->xfer_put(ph, t);
5502145af01SPeng Fan 
5512145af01SPeng Fan 	return ret;
5522145af01SPeng Fan }
5532145af01SPeng Fan 
5542145af01SPeng Fan static int scmi_pinctrl_request_free(const struct scmi_protocol_handle *ph,
5552145af01SPeng Fan 				     u32 identifier,
5562145af01SPeng Fan 				     enum scmi_pinctrl_selector_type type,
5572145af01SPeng Fan 				     enum scmi_pinctrl_protocol_cmd cmd)
5582145af01SPeng Fan {
5592145af01SPeng Fan 	int ret;
5602145af01SPeng Fan 	struct scmi_xfer *t;
5612145af01SPeng Fan 	struct scmi_msg_request *tx;
5622145af01SPeng Fan 
5632145af01SPeng Fan 	if (type == FUNCTION_TYPE)
5642145af01SPeng Fan 		return -EINVAL;
5652145af01SPeng Fan 
5662145af01SPeng Fan 	if (cmd != PINCTRL_REQUEST && cmd != PINCTRL_RELEASE)
5672145af01SPeng Fan 		return -EINVAL;
5682145af01SPeng Fan 
5692145af01SPeng Fan 	ret = scmi_pinctrl_validate_id(ph, identifier, type);
5702145af01SPeng Fan 	if (ret)
5712145af01SPeng Fan 		return ret;
5722145af01SPeng Fan 
5732145af01SPeng Fan 	ret = ph->xops->xfer_get_init(ph, cmd, sizeof(*tx), 0, &t);
5742145af01SPeng Fan 	if (ret)
5752145af01SPeng Fan 		return ret;
5762145af01SPeng Fan 
5772145af01SPeng Fan 	tx = t->tx.buf;
5782145af01SPeng Fan 	tx->identifier = cpu_to_le32(identifier);
5792145af01SPeng Fan 	tx->flags = cpu_to_le32(type);
5802145af01SPeng Fan 
5812145af01SPeng Fan 	ret = ph->xops->do_xfer(ph, t);
5822145af01SPeng Fan 	ph->xops->xfer_put(ph, t);
5832145af01SPeng Fan 
5842145af01SPeng Fan 	return ret;
5852145af01SPeng Fan }
5862145af01SPeng Fan 
5872145af01SPeng Fan static int scmi_pinctrl_pin_request(const struct scmi_protocol_handle *ph,
5882145af01SPeng Fan 				    u32 pin)
5892145af01SPeng Fan {
5902145af01SPeng Fan 	return scmi_pinctrl_request_free(ph, pin, PIN_TYPE, PINCTRL_REQUEST);
5912145af01SPeng Fan }
5922145af01SPeng Fan 
5932145af01SPeng Fan static int scmi_pinctrl_pin_free(const struct scmi_protocol_handle *ph, u32 pin)
5942145af01SPeng Fan {
5952145af01SPeng Fan 	return scmi_pinctrl_request_free(ph, pin, PIN_TYPE, PINCTRL_RELEASE);
5962145af01SPeng Fan }
5972145af01SPeng Fan 
5982145af01SPeng Fan static int scmi_pinctrl_get_group_info(const struct scmi_protocol_handle *ph,
5992145af01SPeng Fan 				       u32 selector,
6002145af01SPeng Fan 				       struct scmi_group_info *group)
6012145af01SPeng Fan {
6022145af01SPeng Fan 	int ret;
6032145af01SPeng Fan 
6042145af01SPeng Fan 	ret = scmi_pinctrl_attributes(ph, GROUP_TYPE, selector, group->name,
6052145af01SPeng Fan 				      &group->nr_pins);
6062145af01SPeng Fan 	if (ret)
6072145af01SPeng Fan 		return ret;
6082145af01SPeng Fan 
6092145af01SPeng Fan 	if (!group->nr_pins) {
6102145af01SPeng Fan 		dev_err(ph->dev, "Group %d has 0 elements", selector);
6112145af01SPeng Fan 		return -ENODATA;
6122145af01SPeng Fan 	}
6132145af01SPeng Fan 
6142145af01SPeng Fan 	group->group_pins = kmalloc_array(group->nr_pins,
6152145af01SPeng Fan 					  sizeof(*group->group_pins),
6162145af01SPeng Fan 					  GFP_KERNEL);
6172145af01SPeng Fan 	if (!group->group_pins)
6182145af01SPeng Fan 		return -ENOMEM;
6192145af01SPeng Fan 
6202145af01SPeng Fan 	ret = scmi_pinctrl_list_associations(ph, selector, GROUP_TYPE,
6212145af01SPeng Fan 					     group->nr_pins, group->group_pins);
6222145af01SPeng Fan 	if (ret) {
6232145af01SPeng Fan 		kfree(group->group_pins);
6242145af01SPeng Fan 		return ret;
6252145af01SPeng Fan 	}
6262145af01SPeng Fan 
6272145af01SPeng Fan 	group->present = true;
6282145af01SPeng Fan 	return 0;
6292145af01SPeng Fan }
6302145af01SPeng Fan 
6312145af01SPeng Fan static int scmi_pinctrl_get_group_name(const struct scmi_protocol_handle *ph,
6322145af01SPeng Fan 				       u32 selector, const char **name)
6332145af01SPeng Fan {
6342145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
6352145af01SPeng Fan 
6362145af01SPeng Fan 	if (!name)
6372145af01SPeng Fan 		return -EINVAL;
6382145af01SPeng Fan 
6392145af01SPeng Fan 	if (selector >= pi->nr_groups || pi->nr_groups == 0)
6402145af01SPeng Fan 		return -EINVAL;
6412145af01SPeng Fan 
6422145af01SPeng Fan 	if (!pi->groups[selector].present) {
6432145af01SPeng Fan 		int ret;
6442145af01SPeng Fan 
6452145af01SPeng Fan 		ret = scmi_pinctrl_get_group_info(ph, selector,
6462145af01SPeng Fan 						  &pi->groups[selector]);
6472145af01SPeng Fan 		if (ret)
6482145af01SPeng Fan 			return ret;
6492145af01SPeng Fan 	}
6502145af01SPeng Fan 
6512145af01SPeng Fan 	*name = pi->groups[selector].name;
6522145af01SPeng Fan 
6532145af01SPeng Fan 	return 0;
6542145af01SPeng Fan }
6552145af01SPeng Fan 
6562145af01SPeng Fan static int scmi_pinctrl_group_pins_get(const struct scmi_protocol_handle *ph,
6572145af01SPeng Fan 				       u32 selector, const u32 **pins,
6582145af01SPeng Fan 				       u32 *nr_pins)
6592145af01SPeng Fan {
6602145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
6612145af01SPeng Fan 
6622145af01SPeng Fan 	if (!pins || !nr_pins)
6632145af01SPeng Fan 		return -EINVAL;
6642145af01SPeng Fan 
6652145af01SPeng Fan 	if (selector >= pi->nr_groups || pi->nr_groups == 0)
6662145af01SPeng Fan 		return -EINVAL;
6672145af01SPeng Fan 
6682145af01SPeng Fan 	if (!pi->groups[selector].present) {
6692145af01SPeng Fan 		int ret;
6702145af01SPeng Fan 
6712145af01SPeng Fan 		ret = scmi_pinctrl_get_group_info(ph, selector,
6722145af01SPeng Fan 						  &pi->groups[selector]);
6732145af01SPeng Fan 		if (ret)
6742145af01SPeng Fan 			return ret;
6752145af01SPeng Fan 	}
6762145af01SPeng Fan 
6772145af01SPeng Fan 	*pins = pi->groups[selector].group_pins;
6782145af01SPeng Fan 	*nr_pins = pi->groups[selector].nr_pins;
6792145af01SPeng Fan 
6802145af01SPeng Fan 	return 0;
6812145af01SPeng Fan }
6822145af01SPeng Fan 
6832145af01SPeng Fan static int scmi_pinctrl_get_function_info(const struct scmi_protocol_handle *ph,
6842145af01SPeng Fan 					  u32 selector,
6852145af01SPeng Fan 					  struct scmi_function_info *func)
6862145af01SPeng Fan {
6872145af01SPeng Fan 	int ret;
6882145af01SPeng Fan 
6892145af01SPeng Fan 	ret = scmi_pinctrl_attributes(ph, FUNCTION_TYPE, selector, func->name,
6902145af01SPeng Fan 				      &func->nr_groups);
6912145af01SPeng Fan 	if (ret)
6922145af01SPeng Fan 		return ret;
6932145af01SPeng Fan 
6942145af01SPeng Fan 	if (!func->nr_groups) {
6952145af01SPeng Fan 		dev_err(ph->dev, "Function %d has 0 elements", selector);
6962145af01SPeng Fan 		return -ENODATA;
6972145af01SPeng Fan 	}
6982145af01SPeng Fan 
6992145af01SPeng Fan 	func->groups = kmalloc_array(func->nr_groups, sizeof(*func->groups),
7002145af01SPeng Fan 				     GFP_KERNEL);
7012145af01SPeng Fan 	if (!func->groups)
7022145af01SPeng Fan 		return -ENOMEM;
7032145af01SPeng Fan 
7042145af01SPeng Fan 	ret = scmi_pinctrl_list_associations(ph, selector, FUNCTION_TYPE,
7052145af01SPeng Fan 					     func->nr_groups, func->groups);
7062145af01SPeng Fan 	if (ret) {
7072145af01SPeng Fan 		kfree(func->groups);
7082145af01SPeng Fan 		return ret;
7092145af01SPeng Fan 	}
7102145af01SPeng Fan 
7112145af01SPeng Fan 	func->present = true;
7122145af01SPeng Fan 	return 0;
7132145af01SPeng Fan }
7142145af01SPeng Fan 
7152145af01SPeng Fan static int scmi_pinctrl_get_function_name(const struct scmi_protocol_handle *ph,
7162145af01SPeng Fan 					  u32 selector, const char **name)
7172145af01SPeng Fan {
7182145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
7192145af01SPeng Fan 
7202145af01SPeng Fan 	if (!name)
7212145af01SPeng Fan 		return -EINVAL;
7222145af01SPeng Fan 
7232145af01SPeng Fan 	if (selector >= pi->nr_functions || pi->nr_functions == 0)
7242145af01SPeng Fan 		return -EINVAL;
7252145af01SPeng Fan 
7262145af01SPeng Fan 	if (!pi->functions[selector].present) {
7272145af01SPeng Fan 		int ret;
7282145af01SPeng Fan 
7292145af01SPeng Fan 		ret = scmi_pinctrl_get_function_info(ph, selector,
7302145af01SPeng Fan 						     &pi->functions[selector]);
7312145af01SPeng Fan 		if (ret)
7322145af01SPeng Fan 			return ret;
7332145af01SPeng Fan 	}
7342145af01SPeng Fan 
7352145af01SPeng Fan 	*name = pi->functions[selector].name;
7362145af01SPeng Fan 	return 0;
7372145af01SPeng Fan }
7382145af01SPeng Fan 
7392145af01SPeng Fan static int
7402145af01SPeng Fan scmi_pinctrl_function_groups_get(const struct scmi_protocol_handle *ph,
7412145af01SPeng Fan 				 u32 selector, u32 *nr_groups,
7422145af01SPeng Fan 				 const u32 **groups)
7432145af01SPeng Fan {
7442145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
7452145af01SPeng Fan 
7462145af01SPeng Fan 	if (!groups || !nr_groups)
7472145af01SPeng Fan 		return -EINVAL;
7482145af01SPeng Fan 
7492145af01SPeng Fan 	if (selector >= pi->nr_functions || pi->nr_functions == 0)
7502145af01SPeng Fan 		return -EINVAL;
7512145af01SPeng Fan 
7522145af01SPeng Fan 	if (!pi->functions[selector].present) {
7532145af01SPeng Fan 		int ret;
7542145af01SPeng Fan 
7552145af01SPeng Fan 		ret = scmi_pinctrl_get_function_info(ph, selector,
7562145af01SPeng Fan 						     &pi->functions[selector]);
7572145af01SPeng Fan 		if (ret)
7582145af01SPeng Fan 			return ret;
7592145af01SPeng Fan 	}
7602145af01SPeng Fan 
7612145af01SPeng Fan 	*groups = pi->functions[selector].groups;
7622145af01SPeng Fan 	*nr_groups = pi->functions[selector].nr_groups;
7632145af01SPeng Fan 
7642145af01SPeng Fan 	return 0;
7652145af01SPeng Fan }
7662145af01SPeng Fan 
7672145af01SPeng Fan static int scmi_pinctrl_mux_set(const struct scmi_protocol_handle *ph,
7682145af01SPeng Fan 				u32 selector, u32 group)
7692145af01SPeng Fan {
7702145af01SPeng Fan 	return scmi_pinctrl_function_select(ph, group, GROUP_TYPE, selector);
7712145af01SPeng Fan }
7722145af01SPeng Fan 
7732145af01SPeng Fan static int scmi_pinctrl_get_pin_info(const struct scmi_protocol_handle *ph,
7742145af01SPeng Fan 				     u32 selector, struct scmi_pin_info *pin)
7752145af01SPeng Fan {
7762145af01SPeng Fan 	int ret;
7772145af01SPeng Fan 
7782145af01SPeng Fan 	if (!pin)
7792145af01SPeng Fan 		return -EINVAL;
7802145af01SPeng Fan 
7812145af01SPeng Fan 	ret = scmi_pinctrl_attributes(ph, PIN_TYPE, selector, pin->name, NULL);
7822145af01SPeng Fan 	if (ret)
7832145af01SPeng Fan 		return ret;
7842145af01SPeng Fan 
7852145af01SPeng Fan 	pin->present = true;
7862145af01SPeng Fan 	return 0;
7872145af01SPeng Fan }
7882145af01SPeng Fan 
7892145af01SPeng Fan static int scmi_pinctrl_get_pin_name(const struct scmi_protocol_handle *ph,
7902145af01SPeng Fan 				     u32 selector, const char **name)
7912145af01SPeng Fan {
7922145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
7932145af01SPeng Fan 
7942145af01SPeng Fan 	if (!name)
7952145af01SPeng Fan 		return -EINVAL;
7962145af01SPeng Fan 
7972145af01SPeng Fan 	if (selector >= pi->nr_pins)
7982145af01SPeng Fan 		return -EINVAL;
7992145af01SPeng Fan 
8002145af01SPeng Fan 	if (!pi->pins[selector].present) {
8012145af01SPeng Fan 		int ret;
8022145af01SPeng Fan 
8032145af01SPeng Fan 		ret = scmi_pinctrl_get_pin_info(ph, selector, &pi->pins[selector]);
8042145af01SPeng Fan 		if (ret)
8052145af01SPeng Fan 			return ret;
8062145af01SPeng Fan 	}
8072145af01SPeng Fan 
8082145af01SPeng Fan 	*name = pi->pins[selector].name;
8092145af01SPeng Fan 
8102145af01SPeng Fan 	return 0;
8112145af01SPeng Fan }
8122145af01SPeng Fan 
8132145af01SPeng Fan static int scmi_pinctrl_name_get(const struct scmi_protocol_handle *ph,
8142145af01SPeng Fan 				 u32 selector,
8152145af01SPeng Fan 				 enum scmi_pinctrl_selector_type type,
8162145af01SPeng Fan 				 const char **name)
8172145af01SPeng Fan {
8182145af01SPeng Fan 	switch (type) {
8192145af01SPeng Fan 	case PIN_TYPE:
8202145af01SPeng Fan 		return scmi_pinctrl_get_pin_name(ph, selector, name);
8212145af01SPeng Fan 	case GROUP_TYPE:
8222145af01SPeng Fan 		return scmi_pinctrl_get_group_name(ph, selector, name);
8232145af01SPeng Fan 	case FUNCTION_TYPE:
8242145af01SPeng Fan 		return scmi_pinctrl_get_function_name(ph, selector, name);
8252145af01SPeng Fan 	default:
8262145af01SPeng Fan 		return -EINVAL;
8272145af01SPeng Fan 	}
8282145af01SPeng Fan }
8292145af01SPeng Fan 
8302145af01SPeng Fan static const struct scmi_pinctrl_proto_ops pinctrl_proto_ops = {
8312145af01SPeng Fan 	.count_get = scmi_pinctrl_count_get,
8322145af01SPeng Fan 	.name_get = scmi_pinctrl_name_get,
8332145af01SPeng Fan 	.group_pins_get = scmi_pinctrl_group_pins_get,
8342145af01SPeng Fan 	.function_groups_get = scmi_pinctrl_function_groups_get,
8352145af01SPeng Fan 	.mux_set = scmi_pinctrl_mux_set,
8362145af01SPeng Fan 	.settings_get_one = scmi_pinctrl_settings_get_one,
8372145af01SPeng Fan 	.settings_get_all = scmi_pinctrl_settings_get_all,
8382145af01SPeng Fan 	.settings_conf = scmi_pinctrl_settings_conf,
8392145af01SPeng Fan 	.pin_request = scmi_pinctrl_pin_request,
8402145af01SPeng Fan 	.pin_free = scmi_pinctrl_pin_free,
8412145af01SPeng Fan };
8422145af01SPeng Fan 
8432145af01SPeng Fan static int scmi_pinctrl_protocol_init(const struct scmi_protocol_handle *ph)
8442145af01SPeng Fan {
8452145af01SPeng Fan 	int ret;
8462145af01SPeng Fan 	u32 version;
8472145af01SPeng Fan 	struct scmi_pinctrl_info *pinfo;
8482145af01SPeng Fan 
8492145af01SPeng Fan 	ret = ph->xops->version_get(ph, &version);
8502145af01SPeng Fan 	if (ret)
8512145af01SPeng Fan 		return ret;
8522145af01SPeng Fan 
8532145af01SPeng Fan 	dev_dbg(ph->dev, "Pinctrl Version %d.%d\n",
8542145af01SPeng Fan 		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
8552145af01SPeng Fan 
8562145af01SPeng Fan 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
8572145af01SPeng Fan 	if (!pinfo)
8582145af01SPeng Fan 		return -ENOMEM;
8592145af01SPeng Fan 
8602145af01SPeng Fan 	ret = scmi_pinctrl_attributes_get(ph, pinfo);
8612145af01SPeng Fan 	if (ret)
8622145af01SPeng Fan 		return ret;
8632145af01SPeng Fan 
8642145af01SPeng Fan 	pinfo->pins = devm_kcalloc(ph->dev, pinfo->nr_pins,
8652145af01SPeng Fan 				   sizeof(*pinfo->pins), GFP_KERNEL);
8662145af01SPeng Fan 	if (!pinfo->pins)
8672145af01SPeng Fan 		return -ENOMEM;
8682145af01SPeng Fan 
8692145af01SPeng Fan 	pinfo->groups = devm_kcalloc(ph->dev, pinfo->nr_groups,
8702145af01SPeng Fan 				     sizeof(*pinfo->groups), GFP_KERNEL);
8712145af01SPeng Fan 	if (!pinfo->groups)
8722145af01SPeng Fan 		return -ENOMEM;
8732145af01SPeng Fan 
8742145af01SPeng Fan 	pinfo->functions = devm_kcalloc(ph->dev, pinfo->nr_functions,
8752145af01SPeng Fan 					sizeof(*pinfo->functions), GFP_KERNEL);
8762145af01SPeng Fan 	if (!pinfo->functions)
8772145af01SPeng Fan 		return -ENOMEM;
8782145af01SPeng Fan 
8792145af01SPeng Fan 	pinfo->version = version;
8802145af01SPeng Fan 
8812145af01SPeng Fan 	return ph->set_priv(ph, pinfo, version);
8822145af01SPeng Fan }
8832145af01SPeng Fan 
8842145af01SPeng Fan static int scmi_pinctrl_protocol_deinit(const struct scmi_protocol_handle *ph)
8852145af01SPeng Fan {
8862145af01SPeng Fan 	int i;
8872145af01SPeng Fan 	struct scmi_pinctrl_info *pi = ph->get_priv(ph);
8882145af01SPeng Fan 
8892145af01SPeng Fan 	/* Free groups_pins allocated in scmi_pinctrl_get_group_info */
8902145af01SPeng Fan 	for (i = 0; i < pi->nr_groups; i++) {
8912145af01SPeng Fan 		if (pi->groups[i].present) {
8922145af01SPeng Fan 			kfree(pi->groups[i].group_pins);
8932145af01SPeng Fan 			pi->groups[i].present = false;
8942145af01SPeng Fan 		}
8952145af01SPeng Fan 	}
8962145af01SPeng Fan 
8972145af01SPeng Fan 	/* Free groups allocated in scmi_pinctrl_get_function_info */
8982145af01SPeng Fan 	for (i = 0; i < pi->nr_functions; i++) {
8992145af01SPeng Fan 		if (pi->functions[i].present) {
9002145af01SPeng Fan 			kfree(pi->functions[i].groups);
9012145af01SPeng Fan 			pi->functions[i].present = false;
9022145af01SPeng Fan 		}
9032145af01SPeng Fan 	}
9042145af01SPeng Fan 
9052145af01SPeng Fan 	return 0;
9062145af01SPeng Fan }
9072145af01SPeng Fan 
9082145af01SPeng Fan static const struct scmi_protocol scmi_pinctrl = {
9092145af01SPeng Fan 	.id = SCMI_PROTOCOL_PINCTRL,
9102145af01SPeng Fan 	.owner = THIS_MODULE,
9112145af01SPeng Fan 	.instance_init = &scmi_pinctrl_protocol_init,
9122145af01SPeng Fan 	.instance_deinit = &scmi_pinctrl_protocol_deinit,
9132145af01SPeng Fan 	.ops = &pinctrl_proto_ops,
9142145af01SPeng Fan 	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
9152145af01SPeng Fan };
916*50db2ef5SSudeep Holla 
9172145af01SPeng Fan DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl)
918