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