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