cregit-Linux how code gets into the kernel

Release 4.14 drivers/clk/clk-divider.c

Directory: drivers/clk
/*
 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Adjustable divider clock implementation
 */

#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/log2.h>

/*
 * DOC: basic adjustable divider clock that cannot gate
 *
 * Traits of this clock:
 * prepare - clk_prepare only ensures that parents are prepared
 * enable - clk_enable only ensures that parents are enabled
 * rate - rate is adjustable.  clk->rate = ceiling(parent->rate / divisor)
 * parent - fixed parent.  No clk_set_parent support
 */


#define div_mask(width)	((1 << (width)) - 1)


static unsigned int _get_table_maxdiv(const struct clk_div_table *table, u8 width) { unsigned int maxdiv = 0, mask = div_mask(width); const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) if (clkt->div > maxdiv && clkt->val <= mask) maxdiv = clkt->div; return maxdiv; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak5577.46%150.00%
Stephen Boyd1622.54%150.00%
Total71100.00%2100.00%


static unsigned int _get_table_mindiv(const struct clk_div_table *table) { unsigned int mindiv = UINT_MAX; const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) if (clkt->div < mindiv) mindiv = clkt->div; return mindiv; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin55100.00%1100.00%
Total55100.00%1100.00%


static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, unsigned long flags) { if (flags & CLK_DIVIDER_ONE_BASED) return div_mask(width); if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << div_mask(width); if (table) return _get_table_maxdiv(table, width); return div_mask(width) + 1; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak5177.27%250.00%
Stephen Boyd1522.73%250.00%
Total66100.00%4100.00%


static unsigned int _get_table_div(const struct clk_div_table *table, unsigned int val) { const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) if (clkt->val == val) return clkt->div; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak52100.00%1100.00%
Total52100.00%1100.00%


static unsigned int _get_div(const struct clk_div_table *table, unsigned int val, unsigned long flags, u8 width) { if (flags & CLK_DIVIDER_ONE_BASED) return val; if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << val; if (flags & CLK_DIVIDER_MAX_AT_ZERO) return val ? val : div_mask(width) + 1; if (table) return _get_table_div(table, val); return val + 1; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak5164.56%250.00%
Jim Quinlan2126.58%125.00%
Stephen Boyd78.86%125.00%
Total79100.00%4100.00%


static unsigned int _get_table_val(const struct clk_div_table *table, unsigned int div) { const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) if (clkt->div == div) return clkt->val; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak52100.00%1100.00%
Total52100.00%1100.00%


static unsigned int _get_val(const struct clk_div_table *table, unsigned int div, unsigned long flags, u8 width) { if (flags & CLK_DIVIDER_ONE_BASED) return div; if (flags & CLK_DIVIDER_POWER_OF_TWO) return __ffs(div); if (flags & CLK_DIVIDER_MAX_AT_ZERO) return (div == div_mask(width) + 1) ? 0 : div; if (table) return _get_table_val(table, div); return div - 1; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak5059.52%240.00%
Jim Quinlan2529.76%120.00%
Stephen Boyd78.33%120.00%
James Hogan22.38%120.00%
Total84100.00%5100.00%


unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned int val, const struct clk_div_table *table, unsigned long flags) { struct clk_divider *divider = to_clk_divider(hw); unsigned int div; div = _get_div(table, val, flags, divider->width); if (!div) { WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", clk_hw_get_name(hw)); return parent_rate; } return DIV_ROUND_UP_ULL((u64)parent_rate, div); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Turquette2728.12%112.50%
Rajendra Nayak2222.92%112.50%
Stephen Boyd1919.79%225.00%
Jim Quinlan1414.58%112.50%
Sören Brinkmann77.29%112.50%
Brian Norris44.17%112.50%
Tomi Valkeinen33.12%112.50%
Total96100.00%8100.00%

EXPORT_SYMBOL_GPL(divider_recalc_rate);
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_divider *divider = to_clk_divider(hw); unsigned int val; val = clk_readl(divider->reg) >> divider->shift; val &= div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, divider->flags); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd70100.00%1100.00%
Total70100.00%1100.00%


static bool _is_valid_table_div(const struct clk_div_table *table, unsigned int div) { const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) if (clkt->div == div) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak49100.00%1100.00%
Total49100.00%1100.00%


static bool _is_valid_div(const struct clk_div_table *table, unsigned int div, unsigned long flags) { if (flags & CLK_DIVIDER_POWER_OF_TWO) return is_power_of_2(div); if (table) return _is_valid_table_div(table, div); return true; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak3982.98%133.33%
Stephen Boyd714.89%133.33%
James Hogan12.13%133.33%
Total47100.00%3100.00%


static int _round_up_table(const struct clk_div_table *table, int div) { const struct clk_div_table *clkt; int up = INT_MAX; for (clkt = table; clkt->div; clkt++) { if (clkt->div == div) return clkt->div; else if (clkt->div < div) continue; if ((clkt->div - div) < (up - div)) up = clkt->div; } return up; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin89100.00%2100.00%
Total89100.00%2100.00%


static int _round_down_table(const struct clk_div_table *table, int div) { const struct clk_div_table *clkt; int down = _get_table_mindiv(table); for (clkt = table; clkt->div; clkt++) { if (clkt->div == div) return clkt->div; else if (clkt->div > div) continue; if ((div - clkt->div) < (div - down)) down = clkt->div; } return down; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin92100.00%1100.00%
Total92100.00%1100.00%


static int _div_round_up(const struct clk_div_table *table, unsigned long parent_rate, unsigned long rate, unsigned long flags) { int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); if (flags & CLK_DIVIDER_POWER_OF_TWO) div = __roundup_pow_of_two(div); if (table) div = _round_up_table(table, div); return div; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin5583.33%133.33%
Stephen Boyd710.61%133.33%
Brian Norris46.06%133.33%
Total66100.00%3100.00%


static int _div_round_closest(const struct clk_div_table *table, unsigned long parent_rate, unsigned long rate, unsigned long flags) { int up, down; unsigned long up_rate, down_rate; up = DIV_ROUND_UP_ULL((u64)parent_rate, rate); down = parent_rate / rate; if (flags & CLK_DIVIDER_POWER_OF_TWO) { up = __roundup_pow_of_two(up); down = __rounddown_pow_of_two(down); } else if (table) { up = _round_up_table(table, up); down = _round_down_table(table, down); } up_rate = DIV_ROUND_UP_ULL((u64)parent_rate, up); down_rate = DIV_ROUND_UP_ULL((u64)parent_rate, down); return (rate - up_rate) <= (down_rate - rate) ? up : down; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin8660.99%120.00%
Uwe Kleine-König3625.53%240.00%
Brian Norris128.51%120.00%
Stephen Boyd74.96%120.00%
Total141100.00%5100.00%


static int _div_round(const struct clk_div_table *table, unsigned long parent_rate, unsigned long rate, unsigned long flags) { if (flags & CLK_DIVIDER_ROUND_CLOSEST) return _div_round_closest(table, parent_rate, rate, flags); return _div_round_up(table, parent_rate, rate, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin4175.93%150.00%
Stephen Boyd1324.07%150.00%
Total54100.00%2100.00%


static bool _is_best_div(unsigned long rate, unsigned long now, unsigned long best, unsigned long flags) { if (flags & CLK_DIVIDER_ROUND_CLOSEST) return abs(rate - now) < abs(rate - best); return now <= rate && now > best; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin4280.77%133.33%
Tomasz Figa611.54%133.33%
Stephen Boyd47.69%133.33%
Total52100.00%3100.00%


static int _next_div(const struct clk_div_table *table, int div, unsigned long flags) { div++; if (flags & CLK_DIVIDER_POWER_OF_TWO) return __roundup_pow_of_two(div); if (table) return _round_up_table(table, div); return div; }

Contributors

PersonTokensPropCommitsCommitProp
Maxime Coquelin4285.71%150.00%
Stephen Boyd714.29%150.00%
Total49100.00%2100.00%


static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *best_parent_rate, const struct clk_div_table *table, u8 width, unsigned long flags) { int i, bestdiv = 0; unsigned long parent_rate, best = 0, now, maxdiv; unsigned long parent_rate_saved = *best_parent_rate; if (!rate) rate = 1; maxdiv = _get_maxdiv(table, width, flags); if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { parent_rate = *best_parent_rate; bestdiv = _div_round(table, parent_rate, rate, flags); bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; return bestdiv; } /* * The maximum divider we can use without overflowing * unsigned long in rate * i below */ maxdiv = min(ULONG_MAX / rate, maxdiv); for (i = _next_div(table, 0, flags); i <= maxdiv; i = _next_div(table, i, flags)) { if (rate * i == parent_rate_saved) { /* * It's the most ideal case if the requested rate can be * divided from parent clock without needing to change * parent rate, so return the divider immediately. */ *best_parent_rate = parent_rate_saved; return i; } parent_rate = clk_hw_round_rate(parent, rate * i); now = DIV_ROUND_UP_ULL((u64)parent_rate, i); if (_is_best_div(rate, now, best, flags)) { bestdiv = i; best = now; *best_parent_rate = parent_rate; } } if (!bestdiv) { bestdiv = _get_maxdiv(table, width, flags); *best_parent_rate = clk_hw_round_rate(parent, 1); } return bestdiv; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Turquette17060.28%16.67%
Stephen Boyd3412.06%320.00%
Shawn Guo3412.06%213.33%
Maxime Coquelin134.61%320.00%
Masahiro Yamada82.84%16.67%
Rajendra Nayak82.84%16.67%
Maxime Ripard72.48%16.67%
Brian Norris41.42%16.67%
Tomi Valkeinen31.06%16.67%
Uwe Kleine-König10.35%16.67%
Total282100.00%15100.00%


long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *prate, const struct clk_div_table *table, u8 width, unsigned long flags) { int div; div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags); return DIV_ROUND_UP_ULL((u64)*prate, div); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Turquette3752.11%120.00%
Stephen Boyd1926.76%120.00%
Maxime Ripard811.27%120.00%
Brian Norris45.63%120.00%
Tomi Valkeinen34.23%120.00%
Total71100.00%5100.00%

EXPORT_SYMBOL_GPL(divider_round_rate_parent);
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_divider *divider = to_clk_divider(hw); int bestdiv; /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { bestdiv = clk_readl(divider->reg) >> divider->shift; bestdiv &= div_mask(divider->width); bestdiv = _get_div(divider->table, bestdiv, divider->flags, divider->width); return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); } return divider_round_rate(hw, rate, prate, divider->table, divider->width, divider->flags); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd7865.55%114.29%
Michael Turquette2420.17%114.29%
Heiko Stübner54.20%114.29%
Brian Norris43.36%114.29%
Jim Quinlan43.36%114.29%
Shawn Guo32.52%114.29%
Geert Uytterhoeven10.84%114.29%
Total119100.00%7100.00%


int divider_get_val(unsigned long rate, unsigned long parent_rate, const struct clk_div_table *table, u8 width, unsigned long flags) { unsigned int div, value; div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); if (!_is_valid_div(table, div, flags)) return -EINVAL; value = _get_val(table, div, flags, width); return min_t(unsigned int, value, div_mask(width)); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd4453.01%112.50%
Maxime Coquelin1315.66%112.50%
Michael Turquette1012.05%112.50%
Rajendra Nayak67.23%112.50%
Brian Norris44.82%112.50%
Tomi Valkeinen33.61%112.50%
Jim Quinlan22.41%112.50%
Shawn Guo11.20%112.50%
Total83100.00%8100.00%

EXPORT_SYMBOL_GPL(divider_get_val);
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_divider *divider = to_clk_divider(hw); int value; unsigned long flags = 0; u32 val; value = divider_get_val(rate, parent_rate, divider->table, divider->width, divider->flags); if (value < 0) return value; if (divider->lock) spin_lock_irqsave(divider->lock, flags); else __acquire(divider->lock); if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { val = div_mask(divider->width) << (divider->shift + 16); } else { val = clk_readl(divider->reg); val &= ~(div_mask(divider->width) << divider->shift); } val |= (u32)value << divider->shift; clk_writel(val, divider->reg); if (divider->lock) spin_unlock_irqrestore(divider->lock, flags); else __release(divider->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Turquette7840.00%114.29%
Stephen Boyd7337.44%228.57%
Haojian Zhuang2814.36%114.29%
Alex Frid126.15%114.29%
Rajendra Nayak21.03%114.29%
Gerhard Sittig21.03%114.29%
Total195100.00%7100.00%

const struct clk_ops clk_divider_ops = { .recalc_rate = clk_divider_recalc_rate, .round_rate = clk_divider_round_rate, .set_rate = clk_divider_set_rate, }; EXPORT_SYMBOL_GPL(clk_divider_ops); const struct clk_ops clk_divider_ro_ops = { .recalc_rate = clk_divider_recalc_rate, .round_rate = clk_divider_round_rate, }; EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
static struct clk_hw *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_divider *div; struct clk_hw *hw; struct clk_init_data init; int ret; if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { if (width + shift > 16) { pr_warn("divider value exceeds LOWORD field\n"); return ERR_PTR(-EINVAL); } } /* allocate the divider */ div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) return ERR_PTR(-ENOMEM); init.name = name; if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) init.ops = &clk_divider_ro_ops; else init.ops = &clk_divider_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); /* struct clk_divider assignments */ div->reg = reg; div->shift = shift; div->width = width; div->flags = clk_divider_flags; div->lock = lock; div->hw.init = &init; div->table = table; /* register the clock */ hw = &div->hw; ret = clk_hw_register(dev, hw); if (ret) { kfree(div); hw = ERR_PTR(ret); } return hw; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Turquette12345.90%222.22%
Saravana Kannan5721.27%111.11%
Haojian Zhuang3011.19%111.11%
Stephen Boyd2810.45%222.22%
Rajendra Nayak165.97%222.22%
Heiko Stübner145.22%111.11%
Total268100.00%9100.00%

/** * clk_register_divider - register a divider clock with the clock framework * @dev: device registering this clock * @name: name of this clock * @parent_name: name of clock's parent * @flags: framework-specific flags * @reg: register address to adjust divider * @shift: number of bits to shift the bitfield * @width: width of the bitfield * @clk_divider_flags: divider-specific flags for this clock * @lock: shared register lock for this clock */
struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, spinlock_t *lock) { struct clk_hw *hw; hw = _register_divider(dev, name, parent_name, flags, reg, shift, width, clk_divider_flags, NULL, lock); if (IS_ERR(hw)) return ERR_CAST(hw); return hw->clk; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak6772.83%150.00%
Stephen Boyd2527.17%150.00%
Total92100.00%2100.00%

EXPORT_SYMBOL_GPL(clk_register_divider); /** * clk_hw_register_divider - register a divider clock with the clock framework * @dev: device registering this clock * @name: name of this clock * @parent_name: name of clock's parent * @flags: framework-specific flags * @reg: register address to adjust divider * @shift: number of bits to shift the bitfield * @width: width of the bitfield * @clk_divider_flags: divider-specific flags for this clock * @lock: shared register lock for this clock */
struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, spinlock_t *lock) { return _register_divider(dev, name, parent_name, flags, reg, shift, width, clk_divider_flags, NULL, lock); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd68100.00%1100.00%
Total68100.00%1100.00%

EXPORT_SYMBOL_GPL(clk_hw_register_divider); /** * clk_register_divider_table - register a table based divider clock with * the clock framework * @dev: device registering this clock * @name: name of this clock * @parent_name: name of clock's parent * @flags: framework-specific flags * @reg: register address to adjust divider * @shift: number of bits to shift the bitfield * @width: width of the bitfield * @clk_divider_flags: divider-specific flags for this clock * @table: array of divider/value pairs ending with a div set to 0 * @lock: shared register lock for this clock */
struct clk *clk_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_hw *hw; hw = _register_divider(dev, name, parent_name, flags, reg, shift, width, clk_divider_flags, table, lock); if (IS_ERR(hw)) return ERR_CAST(hw); return hw->clk; }

Contributors

PersonTokensPropCommitsCommitProp
Rajendra Nayak7374.49%150.00%
Stephen Boyd2525.51%150.00%
Total98100.00%2100.00%

EXPORT_SYMBOL_GPL(clk_register_divider_table); /** * clk_hw_register_divider_table - register a table based divider clock with * the clock framework * @dev: device registering this clock * @name: name of this clock * @parent_name: name of clock's parent * @flags: framework-specific flags * @reg: register address to adjust divider * @shift: number of bits to shift the bitfield * @width: width of the bitfield * @clk_divider_flags: divider-specific flags for this clock * @table: array of divider/value pairs ending with a div set to 0 * @lock: shared register lock for this clock */
struct clk_hw *clk_hw_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { return _register_divider(dev, name, parent_name, flags, reg, shift, width, clk_divider_flags, table, lock); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd74100.00%1100.00%
Total74100.00%1100.00%

EXPORT_SYMBOL_GPL(clk_hw_register_divider_table);
void clk_unregister_divider(struct clk *clk) { struct clk_divider *div; struct clk_hw *hw; hw = __clk_get_hw(clk); if (!hw) return; div = to_clk_divider(hw); clk_unregister(clk); kfree(div); }

Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski50100.00%1100.00%
Total50100.00%1100.00%

EXPORT_SYMBOL_GPL(clk_unregister_divider); /** * clk_hw_unregister_divider - unregister a clk divider * @hw: hardware-specific clock data to unregister */
void clk_hw_unregister_divider(struct clk_hw *hw) { struct clk_divider *div; div = to_clk_divider(hw); clk_hw_unregister(hw); kfree(div); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd32100.00%1100.00%
Total32100.00%1100.00%

EXPORT_SYMBOL_GPL(clk_hw_unregister_divider);

Overall Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd71225.20%717.07%
Rajendra Nayak59521.06%37.32%
Maxime Coquelin52818.69%49.76%
Michael Turquette52018.41%24.88%
Jim Quinlan662.34%12.44%
Haojian Zhuang582.05%12.44%
Saravana Kannan572.02%12.44%
Krzysztof Kozlowski551.95%12.44%
Heiko Stübner411.45%24.88%
Shawn Guo391.38%49.76%
Brian Norris371.31%12.44%
Uwe Kleine-König371.31%37.32%
Maxime Ripard160.57%12.44%
Tomi Valkeinen120.42%12.44%
Alex Frid120.42%12.44%
Fabio Estevam100.35%12.44%
Masahiro Yamada80.28%12.44%
Sören Brinkmann70.25%12.44%
James Hogan60.21%24.88%
Tomasz Figa60.21%12.44%
Gerhard Sittig20.07%12.44%
Geert Uytterhoeven10.04%12.44%
Total2825100.00%41100.00%
Directory: drivers/clk
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.