1// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Pinctrl Protocol
4 *
5 * Copyright (C) 2024 EPAM
6 * Copyright 2024 NXP
7 */
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		0x10000
24
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 int
273iter_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 void
331iter_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 int
352iter_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 int
370iter_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 int
394scmi_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 int
463scmi_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 int
740scmi_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};
916DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl)
917