805 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Zynq UltraScale+ MPSoC clock controller4 *5 * Copyright (C) 2016-2019 Xilinx6 *7 * Based on drivers/clk/zynq/clkc.c8 */9 10#include <linux/bitfield.h>11#include <linux/clk.h>12#include <linux/clk-provider.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/slab.h>17#include <linux/string.h>18 19#include "clk-zynqmp.h"20 21#define MAX_PARENT 10022#define MAX_NODES 623#define MAX_NAME_LEN 5024 25/* Flags for parents */26#define PARENT_CLK_SELF 027#define PARENT_CLK_NODE1 128#define PARENT_CLK_NODE2 229#define PARENT_CLK_NODE3 330#define PARENT_CLK_NODE4 431#define PARENT_CLK_EXTERNAL 532 33#define END_OF_CLK_NAME "END_OF_CLK"34#define END_OF_TOPOLOGY_NODE 135#define END_OF_PARENTS 136#define RESERVED_CLK_NAME ""37 38#define CLK_GET_NAME_RESP_LEN 1639#define CLK_GET_TOPOLOGY_RESP_WORDS 340#define CLK_GET_PARENTS_RESP_WORDS 341#define CLK_GET_ATTR_RESP_WORDS 142 43enum clk_type {44 CLK_TYPE_OUTPUT,45 CLK_TYPE_EXTERNAL,46};47 48/**49 * struct clock_parent - Clock parent50 * @name: Parent name51 * @id: Parent clock ID52 * @flag: Parent flags53 */54struct clock_parent {55 char name[MAX_NAME_LEN];56 int id;57 u32 flag;58};59 60/**61 * struct zynqmp_clock - Clock62 * @clk_name: Clock name63 * @valid: Validity flag of clock64 * @type: Clock type (Output/External)65 * @node: Clock topology nodes66 * @num_nodes: Number of nodes present in topology67 * @parent: Parent of clock68 * @num_parents: Number of parents of clock69 * @clk_id: Clock id70 */71struct zynqmp_clock {72 char clk_name[MAX_NAME_LEN];73 u32 valid;74 enum clk_type type;75 struct clock_topology node[MAX_NODES];76 u32 num_nodes;77 struct clock_parent parent[MAX_PARENT];78 u32 num_parents;79 u32 clk_id;80};81 82struct name_resp {83 char name[CLK_GET_NAME_RESP_LEN];84};85 86struct topology_resp {87#define CLK_TOPOLOGY_TYPE GENMASK(3, 0)88#define CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS GENMASK(7, 4)89#define CLK_TOPOLOGY_FLAGS GENMASK(23, 8)90#define CLK_TOPOLOGY_TYPE_FLAGS GENMASK(31, 24)91 u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS];92};93 94struct parents_resp {95#define NA_PARENT 0xFFFFFFFF96#define DUMMY_PARENT 0xFFFFFFFE97#define CLK_PARENTS_ID GENMASK(15, 0)98#define CLK_PARENTS_FLAGS GENMASK(31, 16)99 u32 parents[CLK_GET_PARENTS_RESP_WORDS];100};101 102struct attr_resp {103#define CLK_ATTR_VALID BIT(0)104#define CLK_ATTR_TYPE BIT(2)105#define CLK_ATTR_NODE_INDEX GENMASK(13, 0)106#define CLK_ATTR_NODE_TYPE GENMASK(19, 14)107#define CLK_ATTR_NODE_SUBCLASS GENMASK(25, 20)108#define CLK_ATTR_NODE_CLASS GENMASK(31, 26)109 u32 attr[CLK_GET_ATTR_RESP_WORDS];110};111 112static const char clk_type_postfix[][10] = {113 [TYPE_INVALID] = "",114 [TYPE_MUX] = "_mux",115 [TYPE_GATE] = "",116 [TYPE_DIV1] = "_div1",117 [TYPE_DIV2] = "_div2",118 [TYPE_FIXEDFACTOR] = "_ff",119 [TYPE_PLL] = ""120};121 122static struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id,123 const char * const *parents,124 u8 num_parents,125 const struct clock_topology *nodes)126 = {127 [TYPE_INVALID] = NULL,128 [TYPE_MUX] = zynqmp_clk_register_mux,129 [TYPE_PLL] = zynqmp_clk_register_pll,130 [TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor,131 [TYPE_DIV1] = zynqmp_clk_register_divider,132 [TYPE_DIV2] = zynqmp_clk_register_divider,133 [TYPE_GATE] = zynqmp_clk_register_gate134};135 136static struct zynqmp_clock *clock;137static struct clk_hw_onecell_data *zynqmp_data;138static unsigned int clock_max_idx;139 140/**141 * zynqmp_is_valid_clock() - Check whether clock is valid or not142 * @clk_id: Clock index143 *144 * Return: 1 if clock is valid, 0 if clock is invalid else error code145 */146static inline int zynqmp_is_valid_clock(u32 clk_id)147{148 if (clk_id >= clock_max_idx)149 return -ENODEV;150 151 return clock[clk_id].valid;152}153 154/**155 * zynqmp_get_clock_name() - Get name of clock from Clock index156 * @clk_id: Clock index157 * @clk_name: Name of clock158 *159 * Return: 0 on success else error code160 */161static int zynqmp_get_clock_name(u32 clk_id, char *clk_name)162{163 int ret;164 165 ret = zynqmp_is_valid_clock(clk_id);166 if (ret == 1) {167 strscpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN);168 return 0;169 }170 171 return ret == 0 ? -EINVAL : ret;172}173 174/**175 * zynqmp_get_clock_type() - Get type of clock176 * @clk_id: Clock index177 * @type: Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL178 *179 * Return: 0 on success else error code180 */181static int zynqmp_get_clock_type(u32 clk_id, u32 *type)182{183 int ret;184 185 ret = zynqmp_is_valid_clock(clk_id);186 if (ret == 1) {187 *type = clock[clk_id].type;188 return 0;189 }190 191 return ret == 0 ? -EINVAL : ret;192}193 194/**195 * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system196 * @nclocks: Number of clocks in system/board.197 *198 * Call firmware API to get number of clocks.199 *200 * Return: 0 on success else error code.201 */202static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks)203{204 struct zynqmp_pm_query_data qdata = {0};205 u32 ret_payload[PAYLOAD_ARG_CNT];206 int ret;207 208 qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS;209 210 ret = zynqmp_pm_query_data(qdata, ret_payload);211 *nclocks = ret_payload[1];212 213 return ret;214}215 216/**217 * zynqmp_pm_clock_get_name() - Get the name of clock for given id218 * @clock_id: ID of the clock to be queried219 * @response: Name of the clock with the given id220 *221 * This function is used to get name of clock specified by given222 * clock ID.223 *224 * Return: 0 on success else error+reason225 */226static int zynqmp_pm_clock_get_name(u32 clock_id,227 struct name_resp *response)228{229 struct zynqmp_pm_query_data qdata = {0};230 u32 ret_payload[PAYLOAD_ARG_CNT];231 int ret;232 233 qdata.qid = PM_QID_CLOCK_GET_NAME;234 qdata.arg1 = clock_id;235 236 ret = zynqmp_pm_query_data(qdata, ret_payload);237 if (ret)238 return ret;239 240 memcpy(response, ret_payload, sizeof(*response));241 242 return 0;243}244 245/**246 * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id247 * @clock_id: ID of the clock to be queried248 * @index: Node index of clock topology249 * @response: Buffer used for the topology response250 *251 * This function is used to get topology information for the clock252 * specified by given clock ID.253 *254 * This API will return 3 node of topology with a single response. To get255 * other nodes, master should call same API in loop with new256 * index till error is returned. E.g First call should have257 * index 0 which will return nodes 0,1 and 2. Next call, index258 * should be 3 which will return nodes 3,4 and 5 and so on.259 *260 * Return: 0 on success else error+reason261 */262static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index,263 struct topology_resp *response)264{265 struct zynqmp_pm_query_data qdata = {0};266 u32 ret_payload[PAYLOAD_ARG_CNT];267 int ret;268 269 qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY;270 qdata.arg1 = clock_id;271 qdata.arg2 = index;272 273 ret = zynqmp_pm_query_data(qdata, ret_payload);274 memcpy(response, &ret_payload[1], sizeof(*response));275 276 return ret;277}278 279unsigned long zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag)280{281 unsigned long ccf_flag = 0;282 283 if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_GATE)284 ccf_flag |= CLK_SET_RATE_GATE;285 if (zynqmp_flag & ZYNQMP_CLK_SET_PARENT_GATE)286 ccf_flag |= CLK_SET_PARENT_GATE;287 if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_PARENT)288 ccf_flag |= CLK_SET_RATE_PARENT;289 if (zynqmp_flag & ZYNQMP_CLK_IGNORE_UNUSED)290 ccf_flag |= CLK_IGNORE_UNUSED;291 if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_NO_REPARENT)292 ccf_flag |= CLK_SET_RATE_NO_REPARENT;293 if (zynqmp_flag & ZYNQMP_CLK_IS_CRITICAL)294 ccf_flag |= CLK_IS_CRITICAL;295 296 return ccf_flag;297}298 299/**300 * zynqmp_clk_register_fixed_factor() - Register fixed factor with the301 * clock framework302 * @name: Name of this clock303 * @clk_id: Clock ID304 * @parents: Name of this clock's parents305 * @num_parents: Number of parents306 * @nodes: Clock topology node307 *308 * Return: clock hardware to the registered clock309 */310struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,311 const char * const *parents,312 u8 num_parents,313 const struct clock_topology *nodes)314{315 u32 mult, div;316 struct clk_hw *hw;317 struct zynqmp_pm_query_data qdata = {0};318 u32 ret_payload[PAYLOAD_ARG_CNT];319 int ret;320 unsigned long flag;321 322 qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;323 qdata.arg1 = clk_id;324 325 ret = zynqmp_pm_query_data(qdata, ret_payload);326 if (ret)327 return ERR_PTR(ret);328 329 mult = ret_payload[1];330 div = ret_payload[2];331 332 flag = zynqmp_clk_map_common_ccf_flags(nodes->flag);333 334 hw = clk_hw_register_fixed_factor(NULL, name,335 parents[0],336 flag, mult,337 div);338 339 return hw;340}341 342/**343 * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id344 * @clock_id: Clock ID345 * @index: Parent index346 * @response: Parents of the given clock347 *348 * This function is used to get 3 parents for the clock specified by349 * given clock ID.350 *351 * This API will return 3 parents with a single response. To get352 * other parents, master should call same API in loop with new353 * parent index till error is returned. E.g First call should have354 * index 0 which will return parents 0,1 and 2. Next call, index355 * should be 3 which will return parent 3,4 and 5 and so on.356 *357 * Return: 0 on success else error+reason358 */359static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index,360 struct parents_resp *response)361{362 struct zynqmp_pm_query_data qdata = {0};363 u32 ret_payload[PAYLOAD_ARG_CNT];364 int ret;365 366 qdata.qid = PM_QID_CLOCK_GET_PARENTS;367 qdata.arg1 = clock_id;368 qdata.arg2 = index;369 370 ret = zynqmp_pm_query_data(qdata, ret_payload);371 memcpy(response, &ret_payload[1], sizeof(*response));372 373 return ret;374}375 376/**377 * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id378 * @clock_id: Clock ID379 * @response: Clock attributes response380 *381 * This function is used to get clock's attributes(e.g. valid, clock type, etc).382 *383 * Return: 0 on success else error+reason384 */385static int zynqmp_pm_clock_get_attributes(u32 clock_id,386 struct attr_resp *response)387{388 struct zynqmp_pm_query_data qdata = {0};389 u32 ret_payload[PAYLOAD_ARG_CNT];390 int ret;391 392 qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES;393 qdata.arg1 = clock_id;394 395 ret = zynqmp_pm_query_data(qdata, ret_payload);396 memcpy(response, &ret_payload[1], sizeof(*response));397 398 return ret;399}400 401/**402 * __zynqmp_clock_get_topology() - Get topology data of clock from firmware403 * response data404 * @topology: Clock topology405 * @response: Clock topology data received from firmware406 * @nnodes: Number of nodes407 *408 * Return: 0 on success else error+reason409 */410static int __zynqmp_clock_get_topology(struct clock_topology *topology,411 struct topology_resp *response,412 u32 *nnodes)413{414 int i;415 u32 type;416 417 for (i = 0; i < ARRAY_SIZE(response->topology); i++) {418 type = FIELD_GET(CLK_TOPOLOGY_TYPE, response->topology[i]);419 if (type == TYPE_INVALID)420 return END_OF_TOPOLOGY_NODE;421 topology[*nnodes].type = type;422 topology[*nnodes].flag = FIELD_GET(CLK_TOPOLOGY_FLAGS,423 response->topology[i]);424 topology[*nnodes].type_flag =425 FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS,426 response->topology[i]);427 topology[*nnodes].custom_type_flag =428 FIELD_GET(CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS,429 response->topology[i]);430 (*nnodes)++;431 }432 433 return 0;434}435 436/**437 * zynqmp_clock_get_topology() - Get topology of clock from firmware using438 * PM_API439 * @clk_id: Clock index440 * @topology: Clock topology441 * @num_nodes: Number of nodes442 *443 * Return: 0 on success else error+reason444 */445static int zynqmp_clock_get_topology(u32 clk_id,446 struct clock_topology *topology,447 u32 *num_nodes)448{449 int j, ret;450 struct topology_resp response = { };451 452 *num_nodes = 0;453 for (j = 0; j <= MAX_NODES; j += ARRAY_SIZE(response.topology)) {454 ret = zynqmp_pm_clock_get_topology(clock[clk_id].clk_id, j,455 &response);456 if (ret)457 return ret;458 ret = __zynqmp_clock_get_topology(topology, &response,459 num_nodes);460 if (ret == END_OF_TOPOLOGY_NODE)461 return 0;462 }463 464 return 0;465}466 467/**468 * __zynqmp_clock_get_parents() - Get parents info of clock from firmware469 * response data470 * @parents: Clock parents471 * @response: Clock parents data received from firmware472 * @nparent: Number of parent473 *474 * Return: 0 on success else error+reason475 */476static int __zynqmp_clock_get_parents(struct clock_parent *parents,477 struct parents_resp *response,478 u32 *nparent)479{480 int i;481 struct clock_parent *parent;482 483 for (i = 0; i < ARRAY_SIZE(response->parents); i++) {484 if (response->parents[i] == NA_PARENT)485 return END_OF_PARENTS;486 487 parent = &parents[i];488 parent->id = FIELD_GET(CLK_PARENTS_ID, response->parents[i]);489 if (response->parents[i] == DUMMY_PARENT) {490 strcpy(parent->name, "dummy_name");491 parent->flag = 0;492 } else {493 parent->flag = FIELD_GET(CLK_PARENTS_FLAGS,494 response->parents[i]);495 if (zynqmp_get_clock_name(parent->id, parent->name))496 continue;497 }498 *nparent += 1;499 }500 501 return 0;502}503 504/**505 * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API506 * @clk_id: Clock index507 * @parents: Clock parents508 * @num_parents: Total number of parents509 *510 * Return: 0 on success else error+reason511 */512static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents,513 u32 *num_parents)514{515 int j = 0, ret;516 struct parents_resp response = { };517 518 *num_parents = 0;519 do {520 /* Get parents from firmware */521 ret = zynqmp_pm_clock_get_parents(clock[clk_id].clk_id, j,522 &response);523 if (ret)524 return ret;525 526 ret = __zynqmp_clock_get_parents(&parents[j], &response,527 num_parents);528 if (ret == END_OF_PARENTS)529 return 0;530 j += ARRAY_SIZE(response.parents);531 } while (*num_parents <= MAX_PARENT);532 533 return 0;534}535 536/**537 * zynqmp_get_parent_list() - Create list of parents name538 * @np: Device node539 * @clk_id: Clock index540 * @parent_list: List of parent's name541 * @num_parents: Total number of parents542 *543 * Return: 0 on success else error+reason544 */545static int zynqmp_get_parent_list(struct device_node *np, u32 clk_id,546 const char **parent_list, u32 *num_parents)547{548 int i = 0, ret;549 u32 total_parents = clock[clk_id].num_parents;550 struct clock_topology *clk_nodes;551 struct clock_parent *parents;552 553 clk_nodes = clock[clk_id].node;554 parents = clock[clk_id].parent;555 556 for (i = 0; i < total_parents; i++) {557 if (!parents[i].flag) {558 parent_list[i] = parents[i].name;559 } else if (parents[i].flag == PARENT_CLK_EXTERNAL) {560 ret = of_property_match_string(np, "clock-names",561 parents[i].name);562 if (ret < 0)563 strcpy(parents[i].name, "dummy_name");564 parent_list[i] = parents[i].name;565 } else {566 strcat(parents[i].name,567 clk_type_postfix[clk_nodes[parents[i].flag - 1].568 type]);569 parent_list[i] = parents[i].name;570 }571 }572 573 *num_parents = total_parents;574 return 0;575}576 577/**578 * zynqmp_register_clk_topology() - Register clock topology579 * @clk_id: Clock index580 * @clk_name: Clock Name581 * @num_parents: Total number of parents582 * @parent_names: List of parents name583 *584 * Return: Returns either clock hardware or error+reason585 */586static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,587 int num_parents,588 const char **parent_names)589{590 int j;591 u32 num_nodes, clk_dev_id;592 char *clk_out[MAX_NODES];593 struct clock_topology *nodes;594 struct clk_hw *hw = NULL;595 596 nodes = clock[clk_id].node;597 num_nodes = clock[clk_id].num_nodes;598 clk_dev_id = clock[clk_id].clk_id;599 600 for (j = 0; j < num_nodes; j++) {601 /*602 * Clock name received from firmware is output clock name.603 * Intermediate clock names are postfixed with type of clock.604 */605 if (j != (num_nodes - 1)) {606 clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name,607 clk_type_postfix[nodes[j].type]);608 } else {609 clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name);610 }611 612 if (!clk_topology[nodes[j].type])613 continue;614 615 hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id,616 parent_names,617 num_parents,618 &nodes[j]);619 if (IS_ERR(hw))620 pr_warn_once("%s() 0x%x: %s register fail with %ld\n",621 __func__, clk_dev_id, clk_name,622 PTR_ERR(hw));623 624 parent_names[0] = clk_out[j];625 }626 627 for (j = 0; j < num_nodes; j++)628 kfree(clk_out[j]);629 630 return hw;631}632 633/**634 * zynqmp_register_clocks() - Register clocks635 * @np: Device node636 *637 * Return: 0 on success else error code638 */639static int zynqmp_register_clocks(struct device_node *np)640{641 int ret;642 u32 i, total_parents = 0, type = 0;643 const char *parent_names[MAX_PARENT];644 645 for (i = 0; i < clock_max_idx; i++) {646 char clk_name[MAX_NAME_LEN];647 648 /* get clock name, continue to next clock if name not found */649 if (zynqmp_get_clock_name(i, clk_name))650 continue;651 652 /* Check if clock is valid and output clock.653 * Do not register invalid or external clock.654 */655 ret = zynqmp_get_clock_type(i, &type);656 if (ret || type != CLK_TYPE_OUTPUT)657 continue;658 659 /* Get parents of clock*/660 if (zynqmp_get_parent_list(np, i, parent_names,661 &total_parents)) {662 WARN_ONCE(1, "No parents found for %s\n",663 clock[i].clk_name);664 continue;665 }666 667 zynqmp_data->hws[i] =668 zynqmp_register_clk_topology(i, clk_name,669 total_parents,670 parent_names);671 }672 673 for (i = 0; i < clock_max_idx; i++) {674 if (IS_ERR(zynqmp_data->hws[i])) {675 pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n",676 clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i]));677 WARN_ON(1);678 }679 }680 return 0;681}682 683/**684 * zynqmp_get_clock_info() - Get clock information from firmware using PM_API685 */686static void zynqmp_get_clock_info(void)687{688 int i, ret;689 u32 type = 0;690 u32 nodetype, subclass, class;691 struct attr_resp attr;692 struct name_resp name;693 694 for (i = 0; i < clock_max_idx; i++) {695 ret = zynqmp_pm_clock_get_attributes(i, &attr);696 if (ret)697 continue;698 699 clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]);700 /* skip query for Invalid clock */701 ret = zynqmp_is_valid_clock(i);702 if (ret != CLK_ATTR_VALID)703 continue;704 705 clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ?706 CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT;707 708 nodetype = FIELD_GET(CLK_ATTR_NODE_TYPE, attr.attr[0]);709 subclass = FIELD_GET(CLK_ATTR_NODE_SUBCLASS, attr.attr[0]);710 class = FIELD_GET(CLK_ATTR_NODE_CLASS, attr.attr[0]);711 712 clock[i].clk_id = FIELD_PREP(CLK_ATTR_NODE_CLASS, class) |713 FIELD_PREP(CLK_ATTR_NODE_SUBCLASS, subclass) |714 FIELD_PREP(CLK_ATTR_NODE_TYPE, nodetype) |715 FIELD_PREP(CLK_ATTR_NODE_INDEX, i);716 717 zynqmp_pm_clock_get_name(clock[i].clk_id, &name);718 719 /*720 * Terminate with NULL character in case name provided by firmware721 * is longer and truncated due to size limit.722 */723 name.name[sizeof(name.name) - 1] = '\0';724 725 if (!strcmp(name.name, RESERVED_CLK_NAME))726 continue;727 strscpy(clock[i].clk_name, name.name, MAX_NAME_LEN);728 }729 730 /* Get topology of all clock */731 for (i = 0; i < clock_max_idx; i++) {732 ret = zynqmp_get_clock_type(i, &type);733 if (ret || type != CLK_TYPE_OUTPUT)734 continue;735 736 ret = zynqmp_clock_get_topology(i, clock[i].node,737 &clock[i].num_nodes);738 if (ret)739 continue;740 741 ret = zynqmp_clock_get_parents(i, clock[i].parent,742 &clock[i].num_parents);743 if (ret)744 continue;745 }746}747 748/**749 * zynqmp_clk_setup() - Setup the clock framework and register clocks750 * @np: Device node751 *752 * Return: 0 on success else error code753 */754static int zynqmp_clk_setup(struct device_node *np)755{756 int ret;757 758 ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx);759 if (ret)760 return ret;761 762 zynqmp_data = kzalloc(struct_size(zynqmp_data, hws, clock_max_idx),763 GFP_KERNEL);764 if (!zynqmp_data)765 return -ENOMEM;766 767 clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL);768 if (!clock) {769 kfree(zynqmp_data);770 return -ENOMEM;771 }772 773 zynqmp_get_clock_info();774 zynqmp_register_clocks(np);775 776 zynqmp_data->num = clock_max_idx;777 return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data);778}779 780static int zynqmp_clock_probe(struct platform_device *pdev)781{782 int ret;783 struct device *dev = &pdev->dev;784 785 ret = zynqmp_clk_setup(dev->of_node);786 787 return ret;788}789 790static const struct of_device_id zynqmp_clock_of_match[] = {791 {.compatible = "xlnx,zynqmp-clk"},792 {.compatible = "xlnx,versal-clk"},793 {},794};795MODULE_DEVICE_TABLE(of, zynqmp_clock_of_match);796 797static struct platform_driver zynqmp_clock_driver = {798 .driver = {799 .name = "zynqmp_clock",800 .of_match_table = zynqmp_clock_of_match,801 },802 .probe = zynqmp_clock_probe,803};804module_platform_driver(zynqmp_clock_driver);805