linux/drivers/clk/keystone/sci-clk.c
<<
>>
Prefs
   1/*
   2 * SCI Clock driver for keystone based devices
   3 *
   4 * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
   5 *      Tero Kristo <t-kristo@ti.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  12 * kind, whether express or implied; without even the implied warranty
  13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16#include <linux/clk-provider.h>
  17#include <linux/err.h>
  18#include <linux/io.h>
  19#include <linux/module.h>
  20#include <linux/of_address.h>
  21#include <linux/of_device.h>
  22#include <linux/platform_device.h>
  23#include <linux/slab.h>
  24#include <linux/soc/ti/ti_sci_protocol.h>
  25#include <linux/bsearch.h>
  26#include <linux/list_sort.h>
  27
  28#define SCI_CLK_SSC_ENABLE              BIT(0)
  29#define SCI_CLK_ALLOW_FREQ_CHANGE       BIT(1)
  30#define SCI_CLK_INPUT_TERMINATION       BIT(2)
  31
  32/**
  33 * struct sci_clk_provider - TI SCI clock provider representation
  34 * @sci: Handle to the System Control Interface protocol handler
  35 * @ops: Pointer to the SCI ops to be used by the clocks
  36 * @dev: Device pointer for the clock provider
  37 * @clocks: Clocks array for this device
  38 * @num_clocks: Total number of clocks for this provider
  39 */
  40struct sci_clk_provider {
  41        const struct ti_sci_handle *sci;
  42        const struct ti_sci_clk_ops *ops;
  43        struct device *dev;
  44        struct sci_clk **clocks;
  45        int num_clocks;
  46};
  47
  48/**
  49 * struct sci_clk - TI SCI clock representation
  50 * @hw:          Hardware clock cookie for common clock framework
  51 * @dev_id:      Device index
  52 * @clk_id:      Clock index
  53 * @num_parents: Number of parents for this clock
  54 * @provider:    Master clock provider
  55 * @flags:       Flags for the clock
  56 * @node:        Link for handling clocks probed via DT
  57 */
  58struct sci_clk {
  59        struct clk_hw hw;
  60        u16 dev_id;
  61        u32 clk_id;
  62        u32 num_parents;
  63        struct sci_clk_provider *provider;
  64        u8 flags;
  65        struct list_head node;
  66};
  67
  68#define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
  69
  70/**
  71 * sci_clk_prepare - Prepare (enable) a TI SCI clock
  72 * @hw: clock to prepare
  73 *
  74 * Prepares a clock to be actively used. Returns the SCI protocol status.
  75 */
  76static int sci_clk_prepare(struct clk_hw *hw)
  77{
  78        struct sci_clk *clk = to_sci_clk(hw);
  79        bool enable_ssc = clk->flags & SCI_CLK_SSC_ENABLE;
  80        bool allow_freq_change = clk->flags & SCI_CLK_ALLOW_FREQ_CHANGE;
  81        bool input_termination = clk->flags & SCI_CLK_INPUT_TERMINATION;
  82
  83        return clk->provider->ops->get_clock(clk->provider->sci, clk->dev_id,
  84                                             clk->clk_id, enable_ssc,
  85                                             allow_freq_change,
  86                                             input_termination);
  87}
  88
  89/**
  90 * sci_clk_unprepare - Un-prepares (disables) a TI SCI clock
  91 * @hw: clock to unprepare
  92 *
  93 * Un-prepares a clock from active state.
  94 */
  95static void sci_clk_unprepare(struct clk_hw *hw)
  96{
  97        struct sci_clk *clk = to_sci_clk(hw);
  98        int ret;
  99
 100        ret = clk->provider->ops->put_clock(clk->provider->sci, clk->dev_id,
 101                                            clk->clk_id);
 102        if (ret)
 103                dev_err(clk->provider->dev,
 104                        "unprepare failed for dev=%d, clk=%d, ret=%d\n",
 105                        clk->dev_id, clk->clk_id, ret);
 106}
 107
 108/**
 109 * sci_clk_is_prepared - Check if a TI SCI clock is prepared or not
 110 * @hw: clock to check status for
 111 *
 112 * Checks if a clock is prepared (enabled) in hardware. Returns non-zero
 113 * value if clock is enabled, zero otherwise.
 114 */
 115static int sci_clk_is_prepared(struct clk_hw *hw)
 116{
 117        struct sci_clk *clk = to_sci_clk(hw);
 118        bool req_state, current_state;
 119        int ret;
 120
 121        ret = clk->provider->ops->is_on(clk->provider->sci, clk->dev_id,
 122                                        clk->clk_id, &req_state,
 123                                        &current_state);
 124        if (ret) {
 125                dev_err(clk->provider->dev,
 126                        "is_prepared failed for dev=%d, clk=%d, ret=%d\n",
 127                        clk->dev_id, clk->clk_id, ret);
 128                return 0;
 129        }
 130
 131        return req_state;
 132}
 133
 134/**
 135 * sci_clk_recalc_rate - Get clock rate for a TI SCI clock
 136 * @hw: clock to get rate for
 137 * @parent_rate: parent rate provided by common clock framework, not used
 138 *
 139 * Gets the current clock rate of a TI SCI clock. Returns the current
 140 * clock rate, or zero in failure.
 141 */
 142static unsigned long sci_clk_recalc_rate(struct clk_hw *hw,
 143                                         unsigned long parent_rate)
 144{
 145        struct sci_clk *clk = to_sci_clk(hw);
 146        u64 freq;
 147        int ret;
 148
 149        ret = clk->provider->ops->get_freq(clk->provider->sci, clk->dev_id,
 150                                           clk->clk_id, &freq);
 151        if (ret) {
 152                dev_err(clk->provider->dev,
 153                        "recalc-rate failed for dev=%d, clk=%d, ret=%d\n",
 154                        clk->dev_id, clk->clk_id, ret);
 155                return 0;
 156        }
 157
 158        return freq;
 159}
 160
 161/**
 162 * sci_clk_determine_rate - Determines a clock rate a clock can be set to
 163 * @hw: clock to change rate for
 164 * @req: requested rate configuration for the clock
 165 *
 166 * Determines a suitable clock rate and parent for a TI SCI clock.
 167 * The parent handling is un-used, as generally the parent clock rates
 168 * are not known by the kernel; instead these are internally handled
 169 * by the firmware. Returns 0 on success, negative error value on failure.
 170 */
 171static int sci_clk_determine_rate(struct clk_hw *hw,
 172                                  struct clk_rate_request *req)
 173{
 174        struct sci_clk *clk = to_sci_clk(hw);
 175        int ret;
 176        u64 new_rate;
 177
 178        ret = clk->provider->ops->get_best_match_freq(clk->provider->sci,
 179                                                      clk->dev_id,
 180                                                      clk->clk_id,
 181                                                      req->min_rate,
 182                                                      req->rate,
 183                                                      req->max_rate,
 184                                                      &new_rate);
 185        if (ret) {
 186                dev_err(clk->provider->dev,
 187                        "determine-rate failed for dev=%d, clk=%d, ret=%d\n",
 188                        clk->dev_id, clk->clk_id, ret);
 189                return ret;
 190        }
 191
 192        req->rate = new_rate;
 193
 194        return 0;
 195}
 196
 197/**
 198 * sci_clk_set_rate - Set rate for a TI SCI clock
 199 * @hw: clock to change rate for
 200 * @rate: target rate for the clock
 201 * @parent_rate: rate of the clock parent, not used for TI SCI clocks
 202 *
 203 * Sets a clock frequency for a TI SCI clock. Returns the TI SCI
 204 * protocol status.
 205 */
 206static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 207                            unsigned long parent_rate)
 208{
 209        struct sci_clk *clk = to_sci_clk(hw);
 210
 211        return clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
 212                                            clk->clk_id, rate, rate, rate);
 213}
 214
 215/**
 216 * sci_clk_get_parent - Get the current parent of a TI SCI clock
 217 * @hw: clock to get parent for
 218 *
 219 * Returns the index of the currently selected parent for a TI SCI clock.
 220 */
 221static u8 sci_clk_get_parent(struct clk_hw *hw)
 222{
 223        struct sci_clk *clk = to_sci_clk(hw);
 224        u32 parent_id = 0;
 225        int ret;
 226
 227        ret = clk->provider->ops->get_parent(clk->provider->sci, clk->dev_id,
 228                                             clk->clk_id, (void *)&parent_id);
 229        if (ret) {
 230                dev_err(clk->provider->dev,
 231                        "get-parent failed for dev=%d, clk=%d, ret=%d\n",
 232                        clk->dev_id, clk->clk_id, ret);
 233                return 0;
 234        }
 235
 236        parent_id = parent_id - clk->clk_id - 1;
 237
 238        return (u8)parent_id;
 239}
 240
 241/**
 242 * sci_clk_set_parent - Set the parent of a TI SCI clock
 243 * @hw: clock to set parent for
 244 * @index: new parent index for the clock
 245 *
 246 * Sets the parent of a TI SCI clock. Return TI SCI protocol status.
 247 */
 248static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
 249{
 250        struct sci_clk *clk = to_sci_clk(hw);
 251
 252        return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
 253                                              clk->clk_id,
 254                                              index + 1 + clk->clk_id);
 255}
 256
 257static const struct clk_ops sci_clk_ops = {
 258        .prepare = sci_clk_prepare,
 259        .unprepare = sci_clk_unprepare,
 260        .is_prepared = sci_clk_is_prepared,
 261        .recalc_rate = sci_clk_recalc_rate,
 262        .determine_rate = sci_clk_determine_rate,
 263        .set_rate = sci_clk_set_rate,
 264        .get_parent = sci_clk_get_parent,
 265        .set_parent = sci_clk_set_parent,
 266};
 267
 268/**
 269 * _sci_clk_get - Gets a handle for an SCI clock
 270 * @provider: Handle to SCI clock provider
 271 * @sci_clk: Handle to the SCI clock to populate
 272 *
 273 * Gets a handle to an existing TI SCI hw clock, or builds a new clock
 274 * entry and registers it with the common clock framework. Called from
 275 * the common clock framework, when a corresponding of_clk_get call is
 276 * executed, or recursively from itself when parsing parent clocks.
 277 * Returns 0 on success, negative error code on failure.
 278 */
 279static int _sci_clk_build(struct sci_clk_provider *provider,
 280                          struct sci_clk *sci_clk)
 281{
 282        struct clk_init_data init = { NULL };
 283        char *name = NULL;
 284        char **parent_names = NULL;
 285        int i;
 286        int ret = 0;
 287
 288        name = kasprintf(GFP_KERNEL, "clk:%d:%d", sci_clk->dev_id,
 289                         sci_clk->clk_id);
 290
 291        init.name = name;
 292
 293        /*
 294         * From kernel point of view, we only care about a clocks parents,
 295         * if it has more than 1 possible parent. In this case, it is going
 296         * to have mux functionality. Otherwise it is going to act as a root
 297         * clock.
 298         */
 299        if (sci_clk->num_parents < 2)
 300                sci_clk->num_parents = 0;
 301
 302        if (sci_clk->num_parents) {
 303                parent_names = kcalloc(sci_clk->num_parents, sizeof(char *),
 304                                       GFP_KERNEL);
 305
 306                if (!parent_names) {
 307                        ret = -ENOMEM;
 308                        goto err;
 309                }
 310
 311                for (i = 0; i < sci_clk->num_parents; i++) {
 312                        char *parent_name;
 313
 314                        parent_name = kasprintf(GFP_KERNEL, "clk:%d:%d",
 315                                                sci_clk->dev_id,
 316                                                sci_clk->clk_id + 1 + i);
 317                        if (!parent_name) {
 318                                ret = -ENOMEM;
 319                                goto err;
 320                        }
 321                        parent_names[i] = parent_name;
 322                }
 323                init.parent_names = (void *)parent_names;
 324        }
 325
 326        init.ops = &sci_clk_ops;
 327        init.num_parents = sci_clk->num_parents;
 328        sci_clk->hw.init = &init;
 329
 330        ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
 331        if (ret)
 332                dev_err(provider->dev, "failed clk register with %d\n", ret);
 333
 334err:
 335        if (parent_names) {
 336                for (i = 0; i < sci_clk->num_parents; i++)
 337                        kfree(parent_names[i]);
 338
 339                kfree(parent_names);
 340        }
 341
 342        kfree(name);
 343
 344        return ret;
 345}
 346
 347static int _cmp_sci_clk(const void *a, const void *b)
 348{
 349        const struct sci_clk *ca = a;
 350        const struct sci_clk *cb = *(struct sci_clk **)b;
 351
 352        if (ca->dev_id == cb->dev_id && ca->clk_id == cb->clk_id)
 353                return 0;
 354        if (ca->dev_id > cb->dev_id ||
 355            (ca->dev_id == cb->dev_id && ca->clk_id > cb->clk_id))
 356                return 1;
 357        return -1;
 358}
 359
 360/**
 361 * sci_clk_get - Xlate function for getting clock handles
 362 * @clkspec: device tree clock specifier
 363 * @data: pointer to the clock provider
 364 *
 365 * Xlate function for retrieving clock TI SCI hw clock handles based on
 366 * device tree clock specifier. Called from the common clock framework,
 367 * when a corresponding of_clk_get call is executed. Returns a pointer
 368 * to the TI SCI hw clock struct, or ERR_PTR value in failure.
 369 */
 370static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data)
 371{
 372        struct sci_clk_provider *provider = data;
 373        struct sci_clk **clk;
 374        struct sci_clk key;
 375
 376        if (clkspec->args_count != 2)
 377                return ERR_PTR(-EINVAL);
 378
 379        key.dev_id = clkspec->args[0];
 380        key.clk_id = clkspec->args[1];
 381
 382        clk = bsearch(&key, provider->clocks, provider->num_clocks,
 383                      sizeof(clk), _cmp_sci_clk);
 384
 385        if (!clk)
 386                return ERR_PTR(-ENODEV);
 387
 388        return &(*clk)->hw;
 389}
 390
 391static int ti_sci_init_clocks(struct sci_clk_provider *p)
 392{
 393        int i;
 394        int ret;
 395
 396        for (i = 0; i < p->num_clocks; i++) {
 397                ret = _sci_clk_build(p, p->clocks[i]);
 398                if (ret)
 399                        return ret;
 400        }
 401
 402        return 0;
 403}
 404
 405static const struct of_device_id ti_sci_clk_of_match[] = {
 406        { .compatible = "ti,k2g-sci-clk" },
 407        { /* Sentinel */ },
 408};
 409MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match);
 410
 411#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
 412static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
 413{
 414        int ret;
 415        int num_clks = 0;
 416        struct sci_clk **clks = NULL;
 417        struct sci_clk **tmp_clks;
 418        struct sci_clk *sci_clk;
 419        int max_clks = 0;
 420        int clk_id = 0;
 421        int dev_id = 0;
 422        u32 num_parents = 0;
 423        int gap_size = 0;
 424        struct device *dev = provider->dev;
 425
 426        while (1) {
 427                ret = provider->ops->get_num_parents(provider->sci, dev_id,
 428                                                     clk_id,
 429                                                     (void *)&num_parents);
 430                if (ret) {
 431                        gap_size++;
 432                        if (!clk_id) {
 433                                if (gap_size >= 5)
 434                                        break;
 435                                dev_id++;
 436                        } else {
 437                                if (gap_size >= 2) {
 438                                        dev_id++;
 439                                        clk_id = 0;
 440                                        gap_size = 0;
 441                                } else {
 442                                        clk_id++;
 443                                }
 444                        }
 445                        continue;
 446                }
 447
 448                gap_size = 0;
 449
 450                if (num_clks == max_clks) {
 451                        tmp_clks = devm_kmalloc_array(dev, max_clks + 64,
 452                                                      sizeof(sci_clk),
 453                                                      GFP_KERNEL);
 454                        memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk));
 455                        if (max_clks)
 456                                devm_kfree(dev, clks);
 457                        max_clks += 64;
 458                        clks = tmp_clks;
 459                }
 460
 461                sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL);
 462                if (!sci_clk)
 463                        return -ENOMEM;
 464                sci_clk->dev_id = dev_id;
 465                sci_clk->clk_id = clk_id;
 466                sci_clk->provider = provider;
 467                sci_clk->num_parents = num_parents;
 468
 469                clks[num_clks] = sci_clk;
 470
 471                clk_id++;
 472                num_clks++;
 473        }
 474
 475        provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
 476                                              GFP_KERNEL);
 477        if (!provider->clocks)
 478                return -ENOMEM;
 479
 480        memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk));
 481
 482        provider->num_clocks = num_clks;
 483
 484        devm_kfree(dev, clks);
 485
 486        return 0;
 487}
 488
 489#else
 490
 491static int _cmp_sci_clk_list(void *priv, struct list_head *a,
 492                             struct list_head *b)
 493{
 494        struct sci_clk *ca = container_of(a, struct sci_clk, node);
 495        struct sci_clk *cb = container_of(b, struct sci_clk, node);
 496
 497        return _cmp_sci_clk(ca, &cb);
 498}
 499
 500static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider)
 501{
 502        struct device *dev = provider->dev;
 503        struct device_node *np = NULL;
 504        int ret;
 505        int index;
 506        struct of_phandle_args args;
 507        struct list_head clks;
 508        struct sci_clk *sci_clk, *prev;
 509        int num_clks = 0;
 510        int num_parents;
 511        int clk_id;
 512        const char * const clk_names[] = {
 513                "clocks", "assigned-clocks", "assigned-clock-parents", NULL
 514        };
 515        const char * const *clk_name;
 516
 517        INIT_LIST_HEAD(&clks);
 518
 519        clk_name = clk_names;
 520
 521        while (*clk_name) {
 522                np = of_find_node_with_property(np, *clk_name);
 523                if (!np) {
 524                        clk_name++;
 525                        break;
 526                }
 527
 528                if (!of_device_is_available(np))
 529                        continue;
 530
 531                index = 0;
 532
 533                do {
 534                        ret = of_parse_phandle_with_args(np, *clk_name,
 535                                                         "#clock-cells", index,
 536                                                         &args);
 537                        if (ret)
 538                                break;
 539
 540                        if (args.args_count == 2 && args.np == dev->of_node) {
 541                                sci_clk = devm_kzalloc(dev, sizeof(*sci_clk),
 542                                                       GFP_KERNEL);
 543                                if (!sci_clk)
 544                                        return -ENOMEM;
 545
 546                                sci_clk->dev_id = args.args[0];
 547                                sci_clk->clk_id = args.args[1];
 548                                sci_clk->provider = provider;
 549                                provider->ops->get_num_parents(provider->sci,
 550                                                               sci_clk->dev_id,
 551                                                               sci_clk->clk_id,
 552                                                               (void *)&sci_clk->num_parents);
 553                                list_add_tail(&sci_clk->node, &clks);
 554
 555                                num_clks++;
 556
 557                                num_parents = sci_clk->num_parents;
 558                                if (num_parents == 1)
 559                                        num_parents = 0;
 560
 561                                /*
 562                                 * Linux kernel has inherent limitation
 563                                 * of 255 clock parents at the moment.
 564                                 * Right now, it is not expected that
 565                                 * any mux clock from sci-clk driver
 566                                 * would exceed that limit either, but
 567                                 * the ABI basically provides that
 568                                 * possibility. Print out a warning if
 569                                 * this happens for any clock.
 570                                 */
 571                                if (num_parents >= 255) {
 572                                        dev_warn(dev, "too many parents for dev=%d, clk=%d (%d), cropping to 255.\n",
 573                                                 sci_clk->dev_id,
 574                                                 sci_clk->clk_id, num_parents);
 575                                        num_parents = 255;
 576                                }
 577
 578                                clk_id = args.args[1] + 1;
 579
 580                                while (num_parents--) {
 581                                        sci_clk = devm_kzalloc(dev,
 582                                                               sizeof(*sci_clk),
 583                                                               GFP_KERNEL);
 584                                        if (!sci_clk)
 585                                                return -ENOMEM;
 586                                        sci_clk->dev_id = args.args[0];
 587                                        sci_clk->clk_id = clk_id++;
 588                                        sci_clk->provider = provider;
 589                                        list_add_tail(&sci_clk->node, &clks);
 590
 591                                        num_clks++;
 592                                }
 593                        }
 594
 595                        index++;
 596                } while (args.np);
 597        }
 598
 599        list_sort(NULL, &clks, _cmp_sci_clk_list);
 600
 601        provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
 602                                              GFP_KERNEL);
 603        if (!provider->clocks)
 604                return -ENOMEM;
 605
 606        num_clks = 0;
 607        prev = NULL;
 608
 609        list_for_each_entry(sci_clk, &clks, node) {
 610                if (prev && prev->dev_id == sci_clk->dev_id &&
 611                    prev->clk_id == sci_clk->clk_id)
 612                        continue;
 613
 614                provider->clocks[num_clks++] = sci_clk;
 615                prev = sci_clk;
 616        }
 617
 618        provider->num_clocks = num_clks;
 619
 620        return 0;
 621}
 622#endif
 623
 624/**
 625 * ti_sci_clk_probe - Probe function for the TI SCI clock driver
 626 * @pdev: platform device pointer to be probed
 627 *
 628 * Probes the TI SCI clock device. Allocates a new clock provider
 629 * and registers this to the common clock framework. Also applies
 630 * any required flags to the identified clocks via clock lists
 631 * supplied from DT. Returns 0 for success, negative error value
 632 * for failure.
 633 */
 634static int ti_sci_clk_probe(struct platform_device *pdev)
 635{
 636        struct device *dev = &pdev->dev;
 637        struct device_node *np = dev->of_node;
 638        struct sci_clk_provider *provider;
 639        const struct ti_sci_handle *handle;
 640        int ret;
 641
 642        handle = devm_ti_sci_get_handle(dev);
 643        if (IS_ERR(handle))
 644                return PTR_ERR(handle);
 645
 646        provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
 647        if (!provider)
 648                return -ENOMEM;
 649
 650        provider->sci = handle;
 651        provider->ops = &handle->ops.clk_ops;
 652        provider->dev = dev;
 653
 654#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
 655        ret = ti_sci_scan_clocks_from_fw(provider);
 656        if (ret) {
 657                dev_err(dev, "scan clocks from FW failed: %d\n", ret);
 658                return ret;
 659        }
 660#else
 661        ret = ti_sci_scan_clocks_from_dt(provider);
 662        if (ret) {
 663                dev_err(dev, "scan clocks from DT failed: %d\n", ret);
 664                return ret;
 665        }
 666#endif
 667
 668        ret = ti_sci_init_clocks(provider);
 669        if (ret) {
 670                pr_err("ti-sci-init-clocks failed.\n");
 671                return ret;
 672        }
 673
 674        return of_clk_add_hw_provider(np, sci_clk_get, provider);
 675}
 676
 677/**
 678 * ti_sci_clk_remove - Remove TI SCI clock device
 679 * @pdev: platform device pointer for the device to be removed
 680 *
 681 * Removes the TI SCI device. Unregisters the clock provider registered
 682 * via common clock framework. Any memory allocated for the device will
 683 * be free'd silently via the devm framework. Returns 0 always.
 684 */
 685static int ti_sci_clk_remove(struct platform_device *pdev)
 686{
 687        of_clk_del_provider(pdev->dev.of_node);
 688
 689        return 0;
 690}
 691
 692static struct platform_driver ti_sci_clk_driver = {
 693        .probe = ti_sci_clk_probe,
 694        .remove = ti_sci_clk_remove,
 695        .driver = {
 696                .name = "ti-sci-clk",
 697                .of_match_table = of_match_ptr(ti_sci_clk_of_match),
 698        },
 699};
 700module_platform_driver(ti_sci_clk_driver);
 701
 702MODULE_LICENSE("GPL v2");
 703MODULE_DESCRIPTION("TI System Control Interface(SCI) Clock driver");
 704MODULE_AUTHOR("Tero Kristo");
 705MODULE_ALIAS("platform:ti-sci-clk");
 706