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