linux/drivers/clk/clkdev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * drivers/clk/clkdev.c
   4 *
   5 *  Copyright (C) 2008 Russell King.
   6 *
   7 * Helper for the clk API to assist looking up a struct clk.
   8 */
   9#include <linux/module.h>
  10#include <linux/kernel.h>
  11#include <linux/device.h>
  12#include <linux/list.h>
  13#include <linux/errno.h>
  14#include <linux/err.h>
  15#include <linux/string.h>
  16#include <linux/mutex.h>
  17#include <linux/clk.h>
  18#include <linux/clkdev.h>
  19#include <linux/clk-provider.h>
  20#include <linux/of.h>
  21
  22#include "clk.h"
  23
  24static LIST_HEAD(clocks);
  25static DEFINE_MUTEX(clocks_mutex);
  26
  27/*
  28 * Find the correct struct clk for the device and connection ID.
  29 * We do slightly fuzzy matching here:
  30 *  An entry with a NULL ID is assumed to be a wildcard.
  31 *  If an entry has a device ID, it must match
  32 *  If an entry has a connection ID, it must match
  33 * Then we take the most specific entry - with the following
  34 * order of precedence: dev+con > dev only > con only.
  35 */
  36static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
  37{
  38        struct clk_lookup *p, *cl = NULL;
  39        int match, best_found = 0, best_possible = 0;
  40
  41        if (dev_id)
  42                best_possible += 2;
  43        if (con_id)
  44                best_possible += 1;
  45
  46        lockdep_assert_held(&clocks_mutex);
  47
  48        list_for_each_entry(p, &clocks, node) {
  49                match = 0;
  50                if (p->dev_id) {
  51                        if (!dev_id || strcmp(p->dev_id, dev_id))
  52                                continue;
  53                        match += 2;
  54                }
  55                if (p->con_id) {
  56                        if (!con_id || strcmp(p->con_id, con_id))
  57                                continue;
  58                        match += 1;
  59                }
  60
  61                if (match > best_found) {
  62                        cl = p;
  63                        if (match != best_possible)
  64                                best_found = match;
  65                        else
  66                                break;
  67                }
  68        }
  69        return cl;
  70}
  71
  72struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id)
  73{
  74        struct clk_lookup *cl;
  75        struct clk_hw *hw = ERR_PTR(-ENOENT);
  76
  77        mutex_lock(&clocks_mutex);
  78        cl = clk_find(dev_id, con_id);
  79        if (cl)
  80                hw = cl->clk_hw;
  81        mutex_unlock(&clocks_mutex);
  82
  83        return hw;
  84}
  85
  86static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
  87                                 const char *con_id)
  88{
  89        struct clk_hw *hw = clk_find_hw(dev_id, con_id);
  90
  91        return clk_hw_create_clk(dev, hw, dev_id, con_id);
  92}
  93
  94struct clk *clk_get_sys(const char *dev_id, const char *con_id)
  95{
  96        return __clk_get_sys(NULL, dev_id, con_id);
  97}
  98EXPORT_SYMBOL(clk_get_sys);
  99
 100struct clk *clk_get(struct device *dev, const char *con_id)
 101{
 102        const char *dev_id = dev ? dev_name(dev) : NULL;
 103        struct clk_hw *hw;
 104
 105        if (dev && dev->of_node) {
 106                hw = of_clk_get_hw(dev->of_node, 0, con_id);
 107                if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER)
 108                        return clk_hw_create_clk(dev, hw, dev_id, con_id);
 109        }
 110
 111        return __clk_get_sys(dev, dev_id, con_id);
 112}
 113EXPORT_SYMBOL(clk_get);
 114
 115void clk_put(struct clk *clk)
 116{
 117        __clk_put(clk);
 118}
 119EXPORT_SYMBOL(clk_put);
 120
 121static void __clkdev_add(struct clk_lookup *cl)
 122{
 123        mutex_lock(&clocks_mutex);
 124        list_add_tail(&cl->node, &clocks);
 125        mutex_unlock(&clocks_mutex);
 126}
 127
 128void clkdev_add(struct clk_lookup *cl)
 129{
 130        if (!cl->clk_hw)
 131                cl->clk_hw = __clk_get_hw(cl->clk);
 132        __clkdev_add(cl);
 133}
 134EXPORT_SYMBOL(clkdev_add);
 135
 136void clkdev_add_table(struct clk_lookup *cl, size_t num)
 137{
 138        mutex_lock(&clocks_mutex);
 139        while (num--) {
 140                cl->clk_hw = __clk_get_hw(cl->clk);
 141                list_add_tail(&cl->node, &clocks);
 142                cl++;
 143        }
 144        mutex_unlock(&clocks_mutex);
 145}
 146
 147#define MAX_DEV_ID      20
 148#define MAX_CON_ID      16
 149
 150struct clk_lookup_alloc {
 151        struct clk_lookup cl;
 152        char    dev_id[MAX_DEV_ID];
 153        char    con_id[MAX_CON_ID];
 154};
 155
 156static struct clk_lookup * __ref
 157vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
 158        va_list ap)
 159{
 160        struct clk_lookup_alloc *cla;
 161
 162        cla = kzalloc(sizeof(*cla), GFP_KERNEL);
 163        if (!cla)
 164                return NULL;
 165
 166        cla->cl.clk_hw = hw;
 167        if (con_id) {
 168                strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
 169                cla->cl.con_id = cla->con_id;
 170        }
 171
 172        if (dev_fmt) {
 173                vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
 174                cla->cl.dev_id = cla->dev_id;
 175        }
 176
 177        return &cla->cl;
 178}
 179
 180static struct clk_lookup *
 181vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
 182        va_list ap)
 183{
 184        struct clk_lookup *cl;
 185
 186        cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
 187        if (cl)
 188                __clkdev_add(cl);
 189
 190        return cl;
 191}
 192
 193/**
 194 * clkdev_create - allocate and add a clkdev lookup structure
 195 * @clk: struct clk to associate with all clk_lookups
 196 * @con_id: connection ID string on device
 197 * @dev_fmt: format string describing device name
 198 *
 199 * Returns a clk_lookup structure, which can be later unregistered and
 200 * freed.
 201 */
 202struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
 203        const char *dev_fmt, ...)
 204{
 205        struct clk_lookup *cl;
 206        va_list ap;
 207
 208        va_start(ap, dev_fmt);
 209        cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap);
 210        va_end(ap);
 211
 212        return cl;
 213}
 214EXPORT_SYMBOL_GPL(clkdev_create);
 215
 216/**
 217 * clkdev_hw_create - allocate and add a clkdev lookup structure
 218 * @hw: struct clk_hw to associate with all clk_lookups
 219 * @con_id: connection ID string on device
 220 * @dev_fmt: format string describing device name
 221 *
 222 * Returns a clk_lookup structure, which can be later unregistered and
 223 * freed.
 224 */
 225struct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id,
 226        const char *dev_fmt, ...)
 227{
 228        struct clk_lookup *cl;
 229        va_list ap;
 230
 231        va_start(ap, dev_fmt);
 232        cl = vclkdev_create(hw, con_id, dev_fmt, ap);
 233        va_end(ap);
 234
 235        return cl;
 236}
 237EXPORT_SYMBOL_GPL(clkdev_hw_create);
 238
 239int clk_add_alias(const char *alias, const char *alias_dev_name,
 240        const char *con_id, struct device *dev)
 241{
 242        struct clk *r = clk_get(dev, con_id);
 243        struct clk_lookup *l;
 244
 245        if (IS_ERR(r))
 246                return PTR_ERR(r);
 247
 248        l = clkdev_create(r, alias, alias_dev_name ? "%s" : NULL,
 249                          alias_dev_name);
 250        clk_put(r);
 251
 252        return l ? 0 : -ENODEV;
 253}
 254EXPORT_SYMBOL(clk_add_alias);
 255
 256/*
 257 * clkdev_drop - remove a clock dynamically allocated
 258 */
 259void clkdev_drop(struct clk_lookup *cl)
 260{
 261        mutex_lock(&clocks_mutex);
 262        list_del(&cl->node);
 263        mutex_unlock(&clocks_mutex);
 264        kfree(cl);
 265}
 266EXPORT_SYMBOL(clkdev_drop);
 267
 268static struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw,
 269                                                const char *con_id,
 270                                                const char *dev_id, ...)
 271{
 272        struct clk_lookup *cl;
 273        va_list ap;
 274
 275        va_start(ap, dev_id);
 276        cl = vclkdev_create(hw, con_id, dev_id, ap);
 277        va_end(ap);
 278
 279        return cl;
 280}
 281
 282static int do_clk_register_clkdev(struct clk_hw *hw,
 283        struct clk_lookup **cl, const char *con_id, const char *dev_id)
 284{
 285        if (IS_ERR(hw))
 286                return PTR_ERR(hw);
 287        /*
 288         * Since dev_id can be NULL, and NULL is handled specially, we must
 289         * pass it as either a NULL format string, or with "%s".
 290         */
 291        if (dev_id)
 292                *cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
 293        else
 294                *cl = __clk_register_clkdev(hw, con_id, NULL);
 295
 296        return *cl ? 0 : -ENOMEM;
 297}
 298
 299/**
 300 * clk_register_clkdev - register one clock lookup for a struct clk
 301 * @clk: struct clk to associate with all clk_lookups
 302 * @con_id: connection ID string on device
 303 * @dev_id: string describing device name
 304 *
 305 * con_id or dev_id may be NULL as a wildcard, just as in the rest of
 306 * clkdev.
 307 *
 308 * To make things easier for mass registration, we detect error clks
 309 * from a previous clk_register() call, and return the error code for
 310 * those.  This is to permit this function to be called immediately
 311 * after clk_register().
 312 */
 313int clk_register_clkdev(struct clk *clk, const char *con_id,
 314        const char *dev_id)
 315{
 316        struct clk_lookup *cl;
 317
 318        if (IS_ERR(clk))
 319                return PTR_ERR(clk);
 320
 321        return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id,
 322                                              dev_id);
 323}
 324EXPORT_SYMBOL(clk_register_clkdev);
 325
 326/**
 327 * clk_hw_register_clkdev - register one clock lookup for a struct clk_hw
 328 * @hw: struct clk_hw to associate with all clk_lookups
 329 * @con_id: connection ID string on device
 330 * @dev_id: format string describing device name
 331 *
 332 * con_id or dev_id may be NULL as a wildcard, just as in the rest of
 333 * clkdev.
 334 *
 335 * To make things easier for mass registration, we detect error clk_hws
 336 * from a previous clk_hw_register_*() call, and return the error code for
 337 * those.  This is to permit this function to be called immediately
 338 * after clk_hw_register_*().
 339 */
 340int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
 341        const char *dev_id)
 342{
 343        struct clk_lookup *cl;
 344
 345        return do_clk_register_clkdev(hw, &cl, con_id, dev_id);
 346}
 347EXPORT_SYMBOL(clk_hw_register_clkdev);
 348
 349static void devm_clkdev_release(struct device *dev, void *res)
 350{
 351        clkdev_drop(*(struct clk_lookup **)res);
 352}
 353
 354static int devm_clk_match_clkdev(struct device *dev, void *res, void *data)
 355{
 356        struct clk_lookup **l = res;
 357
 358        return *l == data;
 359}
 360
 361/**
 362 * devm_clk_release_clkdev - Resource managed clkdev lookup release
 363 * @dev: device this lookup is bound
 364 * @con_id: connection ID string on device
 365 * @dev_id: format string describing device name
 366 *
 367 * Drop the clkdev lookup created with devm_clk_hw_register_clkdev.
 368 * Normally this function will not need to be called and the resource
 369 * management code will ensure that the resource is freed.
 370 */
 371void devm_clk_release_clkdev(struct device *dev, const char *con_id,
 372                             const char *dev_id)
 373{
 374        struct clk_lookup *cl;
 375        int rval;
 376
 377        mutex_lock(&clocks_mutex);
 378        cl = clk_find(dev_id, con_id);
 379        mutex_unlock(&clocks_mutex);
 380
 381        WARN_ON(!cl);
 382        rval = devres_release(dev, devm_clkdev_release,
 383                              devm_clk_match_clkdev, cl);
 384        WARN_ON(rval);
 385}
 386EXPORT_SYMBOL(devm_clk_release_clkdev);
 387
 388/**
 389 * devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw
 390 * @dev: device this lookup is bound
 391 * @hw: struct clk_hw to associate with all clk_lookups
 392 * @con_id: connection ID string on device
 393 * @dev_id: format string describing device name
 394 *
 395 * con_id or dev_id may be NULL as a wildcard, just as in the rest of
 396 * clkdev.
 397 *
 398 * To make things easier for mass registration, we detect error clk_hws
 399 * from a previous clk_hw_register_*() call, and return the error code for
 400 * those.  This is to permit this function to be called immediately
 401 * after clk_hw_register_*().
 402 */
 403int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
 404                                const char *con_id, const char *dev_id)
 405{
 406        int rval = -ENOMEM;
 407        struct clk_lookup **cl;
 408
 409        cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL);
 410        if (cl) {
 411                rval = do_clk_register_clkdev(hw, cl, con_id, dev_id);
 412                if (!rval)
 413                        devres_add(dev, cl);
 414                else
 415                        devres_free(cl);
 416        }
 417        return rval;
 418}
 419EXPORT_SYMBOL(devm_clk_hw_register_clkdev);
 420