mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 23:51:33 +00:00
Merge tag 'u-boot-clk-23Oct2019' of https://gitlab.denx.de/u-boot/custodians/u-boot-clk
- Add I2C clocks for i.MX6Q CCF driver - Fix check in clk_set_default_parents() - Managed API to get clock from device tree - Fixes for core clock code (including sandbox regression tests)
This commit is contained in:
commit
412326d1bc
12 changed files with 406 additions and 63 deletions
|
@ -226,14 +226,18 @@
|
|||
clk_sandbox: clk-sbox {
|
||||
compatible = "sandbox,clk";
|
||||
#clock-cells = <1>;
|
||||
assigned-clocks = <&clk_sandbox 3>;
|
||||
assigned-clock-rates = <321>;
|
||||
};
|
||||
|
||||
clk-test {
|
||||
compatible = "sandbox,clk-test";
|
||||
clocks = <&clk_fixed>,
|
||||
<&clk_sandbox 1>,
|
||||
<&clk_sandbox 0>;
|
||||
clock-names = "fixed", "i2c", "spi";
|
||||
<&clk_sandbox 0>,
|
||||
<&clk_sandbox 3>,
|
||||
<&clk_sandbox 2>;
|
||||
clock-names = "fixed", "i2c", "spi", "uart2", "uart1";
|
||||
};
|
||||
|
||||
ccf: clk-ccf {
|
||||
|
|
|
@ -19,6 +19,8 @@ struct udevice;
|
|||
enum sandbox_clk_id {
|
||||
SANDBOX_CLK_ID_SPI,
|
||||
SANDBOX_CLK_ID_I2C,
|
||||
SANDBOX_CLK_ID_UART1,
|
||||
SANDBOX_CLK_ID_UART2,
|
||||
|
||||
SANDBOX_CLK_ID_COUNT,
|
||||
};
|
||||
|
@ -33,10 +35,15 @@ enum sandbox_clk_test_id {
|
|||
SANDBOX_CLK_TEST_ID_FIXED,
|
||||
SANDBOX_CLK_TEST_ID_SPI,
|
||||
SANDBOX_CLK_TEST_ID_I2C,
|
||||
SANDBOX_CLK_TEST_ID_DEVM1,
|
||||
SANDBOX_CLK_TEST_ID_DEVM2,
|
||||
SANDBOX_CLK_TEST_ID_DEVM_NULL,
|
||||
|
||||
SANDBOX_CLK_TEST_ID_COUNT,
|
||||
};
|
||||
|
||||
#define SANDBOX_CLK_TEST_NON_DEVM_COUNT SANDBOX_CLK_TEST_ID_DEVM1
|
||||
|
||||
/**
|
||||
* sandbox_clk_query_rate - Query the current rate of a sandbox clock.
|
||||
*
|
||||
|
@ -53,6 +60,14 @@ ulong sandbox_clk_query_rate(struct udevice *dev, int id);
|
|||
* @return: The rate of the clock.
|
||||
*/
|
||||
int sandbox_clk_query_enable(struct udevice *dev, int id);
|
||||
/**
|
||||
* sandbox_clk_query_requested - Query the requested state of a sandbox clock.
|
||||
*
|
||||
* @dev: The sandbox clock provider device.
|
||||
* @id: The clock to query.
|
||||
* @return: The rate of the clock.
|
||||
*/
|
||||
int sandbox_clk_query_requested(struct udevice *dev, int id);
|
||||
|
||||
/**
|
||||
* sandbox_clk_test_get - Ask the sandbox clock test device to request its
|
||||
|
@ -62,6 +77,16 @@ int sandbox_clk_query_enable(struct udevice *dev, int id);
|
|||
* @return: 0 if OK, or a negative error code.
|
||||
*/
|
||||
int sandbox_clk_test_get(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sandbox_clk_test_devm_get - Ask the sandbox clock test device to request its
|
||||
* clocks using the managed API.
|
||||
*
|
||||
* @dev: The sandbox clock test (client) devivce.
|
||||
* @return: 0 if OK, or a negative error code.
|
||||
*/
|
||||
int sandbox_clk_test_devm_get(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sandbox_clk_test_get_bulk - Ask the sandbox clock test device to request its
|
||||
* clocks with the bulk clk API.
|
||||
|
@ -146,5 +171,13 @@ int sandbox_clk_test_release_bulk(struct udevice *dev);
|
|||
* @return: 0 if OK, or a negative error code.
|
||||
*/
|
||||
int sandbox_clk_test_valid(struct udevice *dev);
|
||||
/**
|
||||
* sandbox_clk_test_valid - Ask the sandbox clock test device to check its
|
||||
* clocks are valid.
|
||||
*
|
||||
* @dev: The sandbox clock test (client) devivce.
|
||||
* @return: 0 if OK, or a negative error code.
|
||||
*/
|
||||
struct clk *sandbox_clk_test_get_devm_clk(struct udevice *dev, int id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -178,7 +178,7 @@ bulk_get_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int clk_set_default_parents(struct udevice *dev)
|
||||
static int clk_set_default_parents(struct udevice *dev, int stage)
|
||||
{
|
||||
struct clk clk, parent_clk;
|
||||
int index;
|
||||
|
@ -214,8 +214,18 @@ static int clk_set_default_parents(struct udevice *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(&clk, &parent_clk);
|
||||
/* This is clk provider device trying to reparent itself
|
||||
* It cannot be done right now but need to wait after the
|
||||
* device is probed
|
||||
*/
|
||||
if (stage == 0 && clk.dev == dev)
|
||||
continue;
|
||||
|
||||
if (stage > 0 && clk.dev != dev)
|
||||
/* do not setup twice the parent clocks */
|
||||
continue;
|
||||
|
||||
ret = clk_set_parent(&clk, &parent_clk);
|
||||
/*
|
||||
* Not all drivers may support clock-reparenting (as of now).
|
||||
* Ignore errors due to this.
|
||||
|
@ -223,7 +233,7 @@ static int clk_set_default_parents(struct udevice *dev)
|
|||
if (ret == -ENOSYS)
|
||||
continue;
|
||||
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
debug("%s: failed to reparent clock %d for %s\n",
|
||||
__func__, index, dev_read_name(dev));
|
||||
return ret;
|
||||
|
@ -233,7 +243,7 @@ static int clk_set_default_parents(struct udevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int clk_set_default_rates(struct udevice *dev)
|
||||
static int clk_set_default_rates(struct udevice *dev, int stage)
|
||||
{
|
||||
struct clk clk;
|
||||
int index;
|
||||
|
@ -268,7 +278,19 @@ static int clk_set_default_rates(struct udevice *dev)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* This is clk provider device trying to program itself
|
||||
* It cannot be done right now but need to wait after the
|
||||
* device is probed
|
||||
*/
|
||||
if (stage == 0 && clk.dev == dev)
|
||||
continue;
|
||||
|
||||
if (stage > 0 && clk.dev != dev)
|
||||
/* do not setup twice the parent clocks */
|
||||
continue;
|
||||
|
||||
ret = clk_set_rate(&clk, rates[index]);
|
||||
|
||||
if (ret < 0) {
|
||||
debug("%s: failed to set rate on clock index %d (%ld) for %s\n",
|
||||
__func__, index, clk.id, dev_read_name(dev));
|
||||
|
@ -281,7 +303,7 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int clk_set_defaults(struct udevice *dev)
|
||||
int clk_set_defaults(struct udevice *dev, int stage)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -294,11 +316,11 @@ int clk_set_defaults(struct udevice *dev)
|
|||
|
||||
debug("%s(%s)\n", __func__, dev_read_name(dev));
|
||||
|
||||
ret = clk_set_default_parents(dev);
|
||||
ret = clk_set_default_parents(dev, stage);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_set_default_rates(dev);
|
||||
ret = clk_set_default_rates(dev, stage);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -349,9 +371,12 @@ int clk_release_all(struct clk *clk, int count)
|
|||
|
||||
int clk_request(struct udevice *dev, struct clk *clk)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(dev);
|
||||
const struct clk_ops *ops;
|
||||
|
||||
debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(dev);
|
||||
|
||||
clk->dev = dev;
|
||||
|
||||
|
@ -363,9 +388,12 @@ int clk_request(struct udevice *dev, struct clk *clk)
|
|||
|
||||
int clk_free(struct clk *clk)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(clk->dev);
|
||||
const struct clk_ops *ops;
|
||||
|
||||
debug("%s(clk=%p)\n", __func__, clk);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(clk->dev);
|
||||
|
||||
if (!ops->free)
|
||||
return 0;
|
||||
|
@ -375,9 +403,12 @@ int clk_free(struct clk *clk)
|
|||
|
||||
ulong clk_get_rate(struct clk *clk)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(clk->dev);
|
||||
const struct clk_ops *ops;
|
||||
|
||||
debug("%s(clk=%p)\n", __func__, clk);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(clk->dev);
|
||||
|
||||
if (!ops->get_rate)
|
||||
return -ENOSYS;
|
||||
|
@ -391,6 +422,8 @@ struct clk *clk_get_parent(struct clk *clk)
|
|||
struct clk *pclk;
|
||||
|
||||
debug("%s(clk=%p)\n", __func__, clk);
|
||||
if (!clk)
|
||||
return NULL;
|
||||
|
||||
pdev = dev_get_parent(clk->dev);
|
||||
pclk = dev_get_clk_ptr(pdev);
|
||||
|
@ -406,6 +439,8 @@ long long clk_get_parent_rate(struct clk *clk)
|
|||
struct clk *pclk;
|
||||
|
||||
debug("%s(clk=%p)\n", __func__, clk);
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
pclk = clk_get_parent(clk);
|
||||
if (IS_ERR(pclk))
|
||||
|
@ -424,9 +459,12 @@ long long clk_get_parent_rate(struct clk *clk)
|
|||
|
||||
ulong clk_set_rate(struct clk *clk, ulong rate)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(clk->dev);
|
||||
const struct clk_ops *ops;
|
||||
|
||||
debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(clk->dev);
|
||||
|
||||
if (!ops->set_rate)
|
||||
return -ENOSYS;
|
||||
|
@ -436,9 +474,12 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
|
|||
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(clk->dev);
|
||||
const struct clk_ops *ops;
|
||||
|
||||
debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(clk->dev);
|
||||
|
||||
if (!ops->set_parent)
|
||||
return -ENOSYS;
|
||||
|
@ -448,11 +489,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
|
|||
|
||||
int clk_enable(struct clk *clk)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(clk->dev);
|
||||
const struct clk_ops *ops;
|
||||
struct clk *clkp = NULL;
|
||||
int ret;
|
||||
|
||||
debug("%s(clk=%p)\n", __func__, clk);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(clk->dev);
|
||||
|
||||
if (CONFIG_IS_ENABLED(CLK_CCF)) {
|
||||
/* Take id 0 as a non-valid clk, such as dummy */
|
||||
|
@ -505,11 +549,14 @@ int clk_enable_bulk(struct clk_bulk *bulk)
|
|||
|
||||
int clk_disable(struct clk *clk)
|
||||
{
|
||||
const struct clk_ops *ops = clk_dev_ops(clk->dev);
|
||||
const struct clk_ops *ops;
|
||||
struct clk *clkp = NULL;
|
||||
int ret;
|
||||
|
||||
debug("%s(clk=%p)\n", __func__, clk);
|
||||
if (!clk)
|
||||
return 0;
|
||||
ops = clk_dev_ops(clk->dev);
|
||||
|
||||
if (CONFIG_IS_ENABLED(CLK_CCF)) {
|
||||
if (clk->id && !clk_get_by_id(clk->id, &clkp)) {
|
||||
|
@ -589,6 +636,10 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
|
|||
if (p == q)
|
||||
return true;
|
||||
|
||||
/* trivial case #2: on the clk pointer is NULL */
|
||||
if (!p || !q)
|
||||
return false;
|
||||
|
||||
/* same device, id and data */
|
||||
if (p->dev == q->dev && p->id == q->id && p->data == q->data)
|
||||
return true;
|
||||
|
@ -596,7 +647,69 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void devm_clk_release(struct udevice *dev, void *res)
|
||||
{
|
||||
clk_free(res);
|
||||
}
|
||||
|
||||
static int devm_clk_match(struct udevice *dev, void *res, void *data)
|
||||
{
|
||||
return res == data;
|
||||
}
|
||||
|
||||
struct clk *devm_clk_get(struct udevice *dev, const char *id)
|
||||
{
|
||||
int rc;
|
||||
struct clk *clk;
|
||||
|
||||
clk = devres_alloc(devm_clk_release, sizeof(struct clk), __GFP_ZERO);
|
||||
if (unlikely(!clk))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rc = clk_get_by_name(dev, id, clk);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
|
||||
devres_add(dev, clk);
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *devm_clk_get_optional(struct udevice *dev, const char *id)
|
||||
{
|
||||
struct clk *clk = devm_clk_get(dev, id);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
return NULL;
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void devm_clk_put(struct udevice *dev, struct clk *clk)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!clk)
|
||||
return;
|
||||
|
||||
rc = devres_release(dev, devm_clk_release, devm_clk_match, clk);
|
||||
WARN_ON(rc);
|
||||
}
|
||||
|
||||
int clk_uclass_post_probe(struct udevice *dev)
|
||||
{
|
||||
/*
|
||||
* when a clock provider is probed. Call clk_set_defaults()
|
||||
* also after the device is probed. This takes care of cases
|
||||
* where the DT is used to setup default parents and rates
|
||||
* using assigned-clocks
|
||||
*/
|
||||
clk_set_defaults(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(clk) = {
|
||||
.id = UCLASS_CLK,
|
||||
.name = "clk",
|
||||
.post_probe = clk_uclass_post_probe,
|
||||
};
|
||||
|
|
|
@ -10,14 +10,19 @@
|
|||
#include <asm/clk.h>
|
||||
|
||||
struct sandbox_clk_priv {
|
||||
bool probed;
|
||||
ulong rate[SANDBOX_CLK_ID_COUNT];
|
||||
bool enabled[SANDBOX_CLK_ID_COUNT];
|
||||
bool requested[SANDBOX_CLK_ID_COUNT];
|
||||
};
|
||||
|
||||
static ulong sandbox_clk_get_rate(struct clk *clk)
|
||||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (!priv->probed)
|
||||
return -ENODEV;
|
||||
|
||||
if (clk->id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -29,6 +34,9 @@ static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate)
|
|||
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
ulong old_rate;
|
||||
|
||||
if (!priv->probed)
|
||||
return -ENODEV;
|
||||
|
||||
if (clk->id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -45,6 +53,9 @@ static int sandbox_clk_enable(struct clk *clk)
|
|||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (!priv->probed)
|
||||
return -ENODEV;
|
||||
|
||||
if (clk->id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -57,6 +68,9 @@ static int sandbox_clk_disable(struct clk *clk)
|
|||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (!priv->probed)
|
||||
return -ENODEV;
|
||||
|
||||
if (clk->id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -65,13 +79,45 @@ static int sandbox_clk_disable(struct clk *clk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_clk_request(struct clk *clk)
|
||||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (clk->id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
priv->requested[clk->id] = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_clk_free(struct clk *clk)
|
||||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (clk->id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
priv->requested[clk->id] = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops sandbox_clk_ops = {
|
||||
.get_rate = sandbox_clk_get_rate,
|
||||
.set_rate = sandbox_clk_set_rate,
|
||||
.enable = sandbox_clk_enable,
|
||||
.disable = sandbox_clk_disable,
|
||||
.request = sandbox_clk_request,
|
||||
.free = sandbox_clk_free,
|
||||
};
|
||||
|
||||
static int sandbox_clk_probe(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->probed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sandbox_clk_ids[] = {
|
||||
{ .compatible = "sandbox,clk" },
|
||||
{ }
|
||||
|
@ -82,6 +128,7 @@ U_BOOT_DRIVER(clk_sandbox) = {
|
|||
.id = UCLASS_CLK,
|
||||
.of_match = sandbox_clk_ids,
|
||||
.ops = &sandbox_clk_ops,
|
||||
.probe = sandbox_clk_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_clk_priv),
|
||||
};
|
||||
|
||||
|
@ -104,3 +151,12 @@ int sandbox_clk_query_enable(struct udevice *dev, int id)
|
|||
|
||||
return priv->enabled[id];
|
||||
}
|
||||
|
||||
int sandbox_clk_query_requested(struct udevice *dev, int id)
|
||||
{
|
||||
struct sandbox_clk_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
|
||||
return -EINVAL;
|
||||
return priv->requested[id];
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include <asm/clk.h>
|
||||
|
||||
struct sandbox_clk_test {
|
||||
struct clk clks[SANDBOX_CLK_TEST_ID_COUNT];
|
||||
struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
|
||||
struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
|
||||
struct clk_bulk bulk;
|
||||
};
|
||||
|
||||
|
@ -24,7 +25,7 @@ int sandbox_clk_test_get(struct udevice *dev)
|
|||
struct sandbox_clk_test *sbct = dev_get_priv(dev);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
|
||||
for (i = 0; i < SANDBOX_CLK_TEST_NON_DEVM_COUNT; i++) {
|
||||
ret = clk_get_by_name(dev, sandbox_clk_test_names[i],
|
||||
&sbct->clks[i]);
|
||||
if (ret)
|
||||
|
@ -34,6 +35,37 @@ int sandbox_clk_test_get(struct udevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sandbox_clk_test_devm_get(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_clk_test *sbct = dev_get_priv(dev);
|
||||
struct clk *clk;
|
||||
|
||||
clk = devm_clk_get(dev, "no-an-existing-clock");
|
||||
if (!IS_ERR(clk)) {
|
||||
dev_err(dev, "devm_clk_get() should have failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(dev, "uart2");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM1] = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "uart1");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM2] = clk;
|
||||
|
||||
sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM_NULL] = NULL;
|
||||
clk = devm_clk_get_optional(dev, "not_an_existing_clock");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
if (clk)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sandbox_clk_test_get_bulk(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_clk_test *sbct = dev_get_priv(dev);
|
||||
|
@ -48,7 +80,7 @@ ulong sandbox_clk_test_get_rate(struct udevice *dev, int id)
|
|||
if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
return clk_get_rate(&sbct->clks[id]);
|
||||
return clk_get_rate(sbct->clkps[id]);
|
||||
}
|
||||
|
||||
ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate)
|
||||
|
@ -58,7 +90,7 @@ ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate)
|
|||
if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
return clk_set_rate(&sbct->clks[id], rate);
|
||||
return clk_set_rate(sbct->clkps[id], rate);
|
||||
}
|
||||
|
||||
int sandbox_clk_test_enable(struct udevice *dev, int id)
|
||||
|
@ -68,7 +100,7 @@ int sandbox_clk_test_enable(struct udevice *dev, int id)
|
|||
if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
return clk_enable(&sbct->clks[id]);
|
||||
return clk_enable(sbct->clkps[id]);
|
||||
}
|
||||
|
||||
int sandbox_clk_test_enable_bulk(struct udevice *dev)
|
||||
|
@ -85,7 +117,7 @@ int sandbox_clk_test_disable(struct udevice *dev, int id)
|
|||
if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
return clk_disable(&sbct->clks[id]);
|
||||
return clk_disable(sbct->clkps[id]);
|
||||
}
|
||||
|
||||
int sandbox_clk_test_disable_bulk(struct udevice *dev)
|
||||
|
@ -100,7 +132,8 @@ int sandbox_clk_test_free(struct udevice *dev)
|
|||
struct sandbox_clk_test *sbct = dev_get_priv(dev);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
|
||||
devm_clk_put(dev, sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM1]);
|
||||
for (i = 0; i < SANDBOX_CLK_TEST_NON_DEVM_COUNT; i++) {
|
||||
ret = clk_free(&sbct->clks[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -122,13 +155,27 @@ int sandbox_clk_test_valid(struct udevice *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
|
||||
if (!clk_valid(&sbct->clks[i]))
|
||||
return -EINVAL;
|
||||
if (!clk_valid(sbct->clkps[i]))
|
||||
if (i != SANDBOX_CLK_TEST_ID_DEVM_NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_clk_test_probe(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_clk_test *sbct = dev_get_priv(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SANDBOX_CLK_TEST_ID_DEVM1; i++)
|
||||
sbct->clkps[i] = &sbct->clks[i];
|
||||
for (i = SANDBOX_CLK_TEST_ID_DEVM1; i < SANDBOX_CLK_TEST_ID_COUNT; i++)
|
||||
sbct->clkps[i] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sandbox_clk_test_ids[] = {
|
||||
{ .compatible = "sandbox,clk-test" },
|
||||
{ }
|
||||
|
@ -138,5 +185,6 @@ U_BOOT_DRIVER(sandbox_clk_test) = {
|
|||
.name = "sandbox_clk_test",
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = sandbox_clk_test_ids,
|
||||
.probe = sandbox_clk_test_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_clk_test),
|
||||
};
|
||||
|
|
|
@ -89,6 +89,9 @@ static struct clk_ops imx6q_clk_ops = {
|
|||
};
|
||||
|
||||
static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *const periph_sels[] = { "periph_pre", "periph_clk2", };
|
||||
static const char *const periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m",
|
||||
"pll2_pfd0_352m", "pll2_198m", };
|
||||
|
||||
static int imx6q_clk_probe(struct udevice *dev)
|
||||
{
|
||||
|
@ -161,6 +164,24 @@ static int imx6q_clk_probe(struct udevice *dev)
|
|||
clk_dm(IMX6QDL_CLK_USDHC4,
|
||||
imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8));
|
||||
|
||||
clk_dm(IMX6QDL_CLK_PERIPH_PRE,
|
||||
imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels,
|
||||
ARRAY_SIZE(periph_pre_sels)));
|
||||
clk_dm(IMX6QDL_CLK_PERIPH,
|
||||
imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48,
|
||||
5, periph_sels, ARRAY_SIZE(periph_sels)));
|
||||
clk_dm(IMX6QDL_CLK_AHB,
|
||||
imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3,
|
||||
base + 0x48, 1));
|
||||
clk_dm(IMX6QDL_CLK_IPG,
|
||||
imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2));
|
||||
clk_dm(IMX6QDL_CLK_IPG_PER,
|
||||
imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6));
|
||||
clk_dm(IMX6QDL_CLK_I2C1,
|
||||
imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6));
|
||||
clk_dm(IMX6QDL_CLK_I2C2,
|
||||
imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,14 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent,
|
|||
reg, shift, width, 0);
|
||||
}
|
||||
|
||||
static inline struct clk *
|
||||
imx_clk_busy_divider(const char *name, const char *parent, void __iomem *reg,
|
||||
u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift)
|
||||
{
|
||||
return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
|
||||
reg, shift, width, 0);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u8 width)
|
||||
{
|
||||
|
@ -126,6 +134,16 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
|
|||
width, 0);
|
||||
}
|
||||
|
||||
static inline struct clk *
|
||||
imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width,
|
||||
void __iomem *busy_reg, u8 busy_shift,
|
||||
const char * const *parents, int num_parents)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
CLK_SET_RATE_NO_REPARENT, reg, shift,
|
||||
width, 0);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char * const *parents,
|
||||
int num_parents)
|
||||
|
|
|
@ -423,7 +423,7 @@ int device_probe(struct udevice *dev)
|
|||
* Process 'assigned-{clocks/clock-parents/clock-rates}'
|
||||
* properties
|
||||
*/
|
||||
ret = clk_set_defaults(dev);
|
||||
ret = clk_set_defaults(dev, 0);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -3,36 +3,6 @@
|
|||
#include <common.h>
|
||||
#include "brcmnand_compat.h"
|
||||
|
||||
struct clk *devm_clk_get(struct udevice *dev, const char *id)
|
||||
{
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
|
||||
if (!clk) {
|
||||
debug("%s: can't allocate clock\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ret = clk_get_by_name(dev, id, clk);
|
||||
if (ret < 0) {
|
||||
debug("%s: can't get clock (ret = %d)!\n", __func__, ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
int clk_prepare_enable(struct clk *clk)
|
||||
{
|
||||
return clk_enable(clk);
|
||||
}
|
||||
|
||||
void clk_disable_unprepare(struct clk *clk)
|
||||
{
|
||||
clk_disable(clk);
|
||||
}
|
||||
|
||||
static char *devm_kvasprintf(struct udevice *dev, gfp_t gfp, const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
|
||||
struct clk *devm_clk_get(struct udevice *dev, const char *id);
|
||||
int clk_prepare_enable(struct clk *clk);
|
||||
void clk_disable_unprepare(struct clk *clk);
|
||||
|
||||
char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...);
|
||||
|
||||
#endif /* __BRCMNAND_COMPAT_H */
|
||||
|
|
|
@ -154,6 +154,37 @@ int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk);
|
|||
*/
|
||||
int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
|
||||
|
||||
/**
|
||||
* devm_clk_get - lookup and obtain a managed reference to a clock producer.
|
||||
* @dev: device for clock "consumer"
|
||||
* @id: clock consumer ID
|
||||
*
|
||||
* Returns a struct clk corresponding to the clock producer, or
|
||||
* valid IS_ERR() condition containing errno. The implementation
|
||||
* uses @dev and @id to determine the clock consumer, and thereby
|
||||
* the clock producer. (IOW, @id may be identical strings, but
|
||||
* clk_get may return different clock producers depending on @dev.)
|
||||
*
|
||||
* Drivers must assume that the clock source is not enabled.
|
||||
*
|
||||
* devm_clk_get should not be called from within interrupt context.
|
||||
*
|
||||
* The clock will automatically be freed when the device is unbound
|
||||
* from the bus.
|
||||
*/
|
||||
struct clk *devm_clk_get(struct udevice *dev, const char *id);
|
||||
|
||||
/**
|
||||
* devm_clk_get_optional - lookup and obtain a managed reference to an optional
|
||||
* clock producer.
|
||||
* @dev: device for clock "consumer"
|
||||
* @id: clock consumer ID
|
||||
*
|
||||
* Behaves the same as devm_clk_get() except where there is no clock producer.
|
||||
* In this case, instead of returning -ENOENT, the function returns NULL.
|
||||
*/
|
||||
struct clk *devm_clk_get_optional(struct udevice *dev, const char *id);
|
||||
|
||||
/**
|
||||
* clk_release_all() - Disable (turn off)/Free an array of previously
|
||||
* requested clocks.
|
||||
|
@ -168,6 +199,19 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
|
|||
*/
|
||||
int clk_release_all(struct clk *clk, int count);
|
||||
|
||||
/**
|
||||
* devm_clk_put - "free" a managed clock source
|
||||
* @dev: device used to acquire the clock
|
||||
* @clk: clock source acquired with devm_clk_get()
|
||||
*
|
||||
* Note: drivers must ensure that all clk_enable calls made on this
|
||||
* clock source are balanced by clk_disable calls prior to calling
|
||||
* this function.
|
||||
*
|
||||
* clk_put should not be called from within interrupt context.
|
||||
*/
|
||||
void devm_clk_put(struct udevice *dev, struct clk *clk);
|
||||
|
||||
#else
|
||||
static inline int clk_get_by_index(struct udevice *dev, int index,
|
||||
struct clk *clk)
|
||||
|
@ -200,10 +244,13 @@ static inline int clk_release_all(struct clk *clk, int count)
|
|||
*
|
||||
* @dev: A device to process (the ofnode associated with this device
|
||||
* will be processed).
|
||||
* @stage: A integer. 0 indicates that this is called before the device
|
||||
* is probed. 1 indicates that this is called just after the
|
||||
* device has been probed
|
||||
*/
|
||||
int clk_set_defaults(struct udevice *dev);
|
||||
int clk_set_defaults(struct udevice *dev, int stage);
|
||||
#else
|
||||
static inline int clk_set_defaults(struct udevice *dev)
|
||||
static inline int clk_set_defaults(struct udevice *dev, int stage)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -356,7 +403,7 @@ int soc_clk_dump(void);
|
|||
*/
|
||||
static inline bool clk_valid(struct clk *clk)
|
||||
{
|
||||
return !!clk->dev;
|
||||
return clk && !!clk->dev;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,3 +426,6 @@ int clk_get_by_id(ulong id, struct clk **clkp);
|
|||
*/
|
||||
bool clk_dev_binded(struct clk *clk);
|
||||
#endif
|
||||
|
||||
#define clk_prepare_enable(clk) clk_enable(clk)
|
||||
#define clk_disable_unprepare(clk) clk_disable(clk)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <dm.h>
|
||||
#include <asm/clk.h>
|
||||
#include <dm/test.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <linux/err.h>
|
||||
#include <test/ut.h>
|
||||
|
||||
|
@ -53,8 +54,19 @@ static int dm_test_clk(struct unit_test_state *uts)
|
|||
ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test",
|
||||
&dev_test));
|
||||
ut_assertok(sandbox_clk_test_get(dev_test));
|
||||
ut_assertok(sandbox_clk_test_devm_get(dev_test));
|
||||
ut_assertok(sandbox_clk_test_valid(dev_test));
|
||||
|
||||
ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_DEVM_NULL));
|
||||
ut_asserteq(0, sandbox_clk_test_set_rate(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_DEVM_NULL,
|
||||
0));
|
||||
ut_asserteq(0, sandbox_clk_test_enable(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_DEVM_NULL));
|
||||
ut_asserteq(0, sandbox_clk_test_disable(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_DEVM_NULL));
|
||||
|
||||
ut_asserteq(1234,
|
||||
sandbox_clk_test_get_rate(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_FIXED));
|
||||
|
@ -62,6 +74,10 @@ static int dm_test_clk(struct unit_test_state *uts)
|
|||
SANDBOX_CLK_TEST_ID_SPI));
|
||||
ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_I2C));
|
||||
ut_asserteq(321, sandbox_clk_test_get_rate(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_DEVM1));
|
||||
ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
|
||||
SANDBOX_CLK_TEST_ID_DEVM2));
|
||||
|
||||
rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_FIXED,
|
||||
12345);
|
||||
|
@ -121,8 +137,25 @@ static int dm_test_clk(struct unit_test_state *uts)
|
|||
ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
|
||||
ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
|
||||
|
||||
ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_SPI));
|
||||
ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_I2C));
|
||||
ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_UART2));
|
||||
ut_assertok(sandbox_clk_test_free(dev_test));
|
||||
ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_SPI));
|
||||
ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_I2C));
|
||||
ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_UART2));
|
||||
|
||||
ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_UART1));
|
||||
ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL));
|
||||
ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
|
||||
SANDBOX_CLK_ID_UART1));
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_clk, DM_TESTF_SCAN_FDT);
|
||||
|
@ -159,6 +192,7 @@ static int dm_test_clk_bulk(struct unit_test_state *uts)
|
|||
ut_assertok(sandbox_clk_test_release_bulk(dev_test));
|
||||
ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
|
||||
ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
|
||||
ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue