-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
clk: uniphier: add core support code for UniPhier clock driver
This includes UniPhier clock driver code, except SoC-specific data arrays. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
- Loading branch information
Masahiro Yamada
authored and
Stephen Boyd
committed
Sep 16, 2016
1 parent
bd8dd59
commit 734d82f
Showing
11 changed files
with
536 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
config CLK_UNIPHIER | ||
bool "Clock driver for UniPhier SoCs" | ||
depends on ARCH_UNIPHIER || COMPILE_TEST | ||
depends on OF && MFD_SYSCON | ||
default ARCH_UNIPHIER | ||
help | ||
Support for clock controllers on UniPhier SoCs. | ||
Say Y if you want to control clocks provided by System Control | ||
block, Media I/O block, Peripheral Block. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
obj-y += clk-uniphier-core.o | ||
obj-y += clk-uniphier-fixed-factor.o | ||
obj-y += clk-uniphier-fixed-rate.o | ||
obj-y += clk-uniphier-gate.o | ||
obj-y += clk-uniphier-mux.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* Copyright (C) 2016 Socionext Inc. | ||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/init.h> | ||
#include <linux/mfd/syscon.h> | ||
#include <linux/of.h> | ||
#include <linux/of_device.h> | ||
#include <linux/platform_device.h> | ||
|
||
#include "clk-uniphier.h" | ||
|
||
static struct clk_hw *uniphier_clk_register(struct device *dev, | ||
struct regmap *regmap, | ||
const struct uniphier_clk_data *data) | ||
{ | ||
switch (data->type) { | ||
case UNIPHIER_CLK_TYPE_FIXED_FACTOR: | ||
return uniphier_clk_register_fixed_factor(dev, data->name, | ||
&data->data.factor); | ||
case UNIPHIER_CLK_TYPE_FIXED_RATE: | ||
return uniphier_clk_register_fixed_rate(dev, data->name, | ||
&data->data.rate); | ||
case UNIPHIER_CLK_TYPE_GATE: | ||
return uniphier_clk_register_gate(dev, regmap, data->name, | ||
&data->data.gate); | ||
case UNIPHIER_CLK_TYPE_MUX: | ||
return uniphier_clk_register_mux(dev, regmap, data->name, | ||
&data->data.mux); | ||
default: | ||
dev_err(dev, "unsupported clock type\n"); | ||
return ERR_PTR(-EINVAL); | ||
} | ||
} | ||
|
||
static int uniphier_clk_probe(struct platform_device *pdev) | ||
{ | ||
struct device *dev = &pdev->dev; | ||
struct clk_hw_onecell_data *hw_data; | ||
const struct uniphier_clk_data *p, *data; | ||
struct regmap *regmap; | ||
struct device_node *parent; | ||
int clk_num = 0; | ||
|
||
data = of_device_get_match_data(dev); | ||
if (WARN_ON(!data)) | ||
return -EINVAL; | ||
|
||
parent = of_get_parent(dev->of_node); /* parent should be syscon node */ | ||
regmap = syscon_node_to_regmap(parent); | ||
of_node_put(parent); | ||
if (IS_ERR(regmap)) { | ||
dev_err(dev, "failed to get regmap (error %ld)\n", | ||
PTR_ERR(regmap)); | ||
return PTR_ERR(regmap); | ||
} | ||
|
||
for (p = data; p->name; p++) | ||
clk_num = max(clk_num, p->idx + 1); | ||
|
||
hw_data = devm_kzalloc(dev, | ||
sizeof(*hw_data) + clk_num * sizeof(struct clk_hw *), | ||
GFP_KERNEL); | ||
if (!hw_data) | ||
return -ENOMEM; | ||
|
||
hw_data->num = clk_num; | ||
|
||
/* avoid returning NULL for unused idx */ | ||
for (; clk_num >= 0; clk_num--) | ||
hw_data->hws[clk_num] = ERR_PTR(-EINVAL); | ||
|
||
for (p = data; p->name; p++) { | ||
struct clk_hw *hw; | ||
|
||
dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx); | ||
hw = uniphier_clk_register(dev, regmap, p); | ||
if (IS_ERR(hw)) { | ||
dev_err(dev, "failed to register %s (error %ld)\n", | ||
p->name, PTR_ERR(hw)); | ||
return PTR_ERR(hw); | ||
} | ||
|
||
if (p->idx >= 0) | ||
hw_data->hws[p->idx] = hw; | ||
} | ||
|
||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | ||
hw_data); | ||
} | ||
|
||
static int uniphier_clk_remove(struct platform_device *pdev) | ||
{ | ||
of_clk_del_provider(pdev->dev.of_node); | ||
|
||
return 0; | ||
} | ||
|
||
static const struct of_device_id uniphier_clk_match[] = { | ||
{ /* sentinel */ } | ||
}; | ||
|
||
static struct platform_driver uniphier_clk_driver = { | ||
.probe = uniphier_clk_probe, | ||
.remove = uniphier_clk_remove, | ||
.driver = { | ||
.name = "uniphier-clk", | ||
.of_match_table = uniphier_clk_match, | ||
}, | ||
}; | ||
builtin_platform_driver(uniphier_clk_driver); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright (C) 2016 Socionext Inc. | ||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/device.h> | ||
|
||
#include "clk-uniphier.h" | ||
|
||
struct clk_hw *uniphier_clk_register_fixed_factor(struct device *dev, | ||
const char *name, | ||
const struct uniphier_clk_fixed_factor_data *data) | ||
{ | ||
struct clk_fixed_factor *fix; | ||
struct clk_init_data init; | ||
int ret; | ||
|
||
fix = devm_kzalloc(dev, sizeof(*fix), GFP_KERNEL); | ||
if (!fix) | ||
return ERR_PTR(-ENOMEM); | ||
|
||
init.name = name; | ||
init.ops = &clk_fixed_factor_ops; | ||
init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; | ||
init.parent_names = data->parent_name ? &data->parent_name : NULL; | ||
init.num_parents = data->parent_name ? 1 : 0; | ||
|
||
fix->mult = data->mult; | ||
fix->div = data->div; | ||
fix->hw.init = &init; | ||
|
||
ret = devm_clk_hw_register(dev, &fix->hw); | ||
if (ret) | ||
return ERR_PTR(ret); | ||
|
||
return &fix->hw; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Copyright (C) 2016 Socionext Inc. | ||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/device.h> | ||
|
||
#include "clk-uniphier.h" | ||
|
||
struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, | ||
const char *name, | ||
const struct uniphier_clk_fixed_rate_data *data) | ||
{ | ||
struct clk_fixed_rate *fixed; | ||
struct clk_init_data init; | ||
int ret; | ||
|
||
/* allocate fixed-rate clock */ | ||
fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL); | ||
if (!fixed) | ||
return ERR_PTR(-ENOMEM); | ||
|
||
init.name = name; | ||
init.ops = &clk_fixed_rate_ops; | ||
init.parent_names = NULL; | ||
init.num_parents = 0; | ||
|
||
fixed->fixed_rate = data->fixed_rate; | ||
fixed->hw.init = &init; | ||
|
||
ret = devm_clk_hw_register(dev, &fixed->hw); | ||
if (ret) | ||
return ERR_PTR(ret); | ||
|
||
return &fixed->hw; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* Copyright (C) 2016 Socionext Inc. | ||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/device.h> | ||
#include <linux/regmap.h> | ||
|
||
#include "clk-uniphier.h" | ||
|
||
struct uniphier_clk_gate { | ||
struct clk_hw hw; | ||
struct regmap *regmap; | ||
unsigned int reg; | ||
unsigned int bit; | ||
}; | ||
|
||
#define to_uniphier_clk_gate(_hw) \ | ||
container_of(_hw, struct uniphier_clk_gate, hw) | ||
|
||
static int uniphier_clk_gate_endisable(struct clk_hw *hw, int enable) | ||
{ | ||
struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); | ||
|
||
return regmap_write_bits(gate->regmap, gate->reg, BIT(gate->bit), | ||
enable ? BIT(gate->bit) : 0); | ||
} | ||
|
||
static int uniphier_clk_gate_enable(struct clk_hw *hw) | ||
{ | ||
return uniphier_clk_gate_endisable(hw, 1); | ||
} | ||
|
||
static void uniphier_clk_gate_disable(struct clk_hw *hw) | ||
{ | ||
if (uniphier_clk_gate_endisable(hw, 0) < 0) | ||
pr_warn("failed to disable clk\n"); | ||
} | ||
|
||
static int uniphier_clk_gate_is_enabled(struct clk_hw *hw) | ||
{ | ||
struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); | ||
unsigned int val; | ||
|
||
if (regmap_read(gate->regmap, gate->reg, &val) < 0) | ||
pr_warn("is_enabled() may return wrong result\n"); | ||
|
||
return !!(val & BIT(gate->bit)); | ||
} | ||
|
||
static const struct clk_ops uniphier_clk_gate_ops = { | ||
.enable = uniphier_clk_gate_enable, | ||
.disable = uniphier_clk_gate_disable, | ||
.is_enabled = uniphier_clk_gate_is_enabled, | ||
}; | ||
|
||
struct clk_hw *uniphier_clk_register_gate(struct device *dev, | ||
struct regmap *regmap, | ||
const char *name, | ||
const struct uniphier_clk_gate_data *data) | ||
{ | ||
struct uniphier_clk_gate *gate; | ||
struct clk_init_data init; | ||
int ret; | ||
|
||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); | ||
if (!gate) | ||
return ERR_PTR(-ENOMEM); | ||
|
||
init.name = name; | ||
init.ops = &uniphier_clk_gate_ops; | ||
init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; | ||
init.parent_names = data->parent_name ? &data->parent_name : NULL; | ||
init.num_parents = data->parent_name ? 1 : 0; | ||
|
||
gate->regmap = regmap; | ||
gate->reg = data->reg; | ||
gate->bit = data->bit; | ||
gate->hw.init = &init; | ||
|
||
ret = devm_clk_hw_register(dev, &gate->hw); | ||
if (ret) | ||
return ERR_PTR(ret); | ||
|
||
return &gate->hw; | ||
} |
Oops, something went wrong.