summaryrefslogtreecommitdiffstats
path: root/drivers/clk/qcom/gcc-msm8974.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-07 20:27:30 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-07 20:27:30 -0700
commit1a5700bc2d10cd379a795fd2bb377a190af5acd4 (patch)
treee9f754cbc34020dd23c1d2e3e45fb6890ba7593c /drivers/clk/qcom/gcc-msm8974.c
parenta68a7509d3af8ee458d32b2416b0c2aaf2a4a7e3 (diff)
parent3cbcb16095f916f50a5a55066fcc4be06946ce1e (diff)
downloadlinux-next.tar.bz2
Merge tag 'clk-for-linus-3.16' of git://git.linaro.org/people/mike.turquette/linux into nextnext
Pull clock framework updates from Mike Turquette: "The clock framework changes for 3.16 are pretty typical: mostly clock driver additions and fixes. There are additions to the clock core code for some of the basic types (e.g. the common divider type has some fixes and featured added to it). One minor annoyance is a last-minute dependency that wasn't handled quite right. Commit ba0fae3b06a6 ("clk: berlin: add core clock driver for BG2/BG2CD") in this pull request depends on include/dt-bindings/clock/berlin2.h, which is already in your tree via the arm-soc pull request. Building for the berlin platform will break when the clk tree is built on it's own, but merged into your master branch everything should be fine" * tag 'clk-for-linus-3.16' of git://git.linaro.org/people/mike.turquette/linux: (75 commits) mmc: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs clk: export __clk_round_rate for providers clk: versatile: free icst on error return clk: qcom: Return error pointers for unimplemented clocks clk: qcom: Support msm8974pro global clock control hardware clk: qcom: Properly support display clocks on msm8974 clk: qcom: Support display RCG clocks clk: qcom: Return highest rate when round_rate() exceeds plan clk: qcom: Fix mmcc-8974's PLL configurations clk: qcom: Fix clk_rcg2_is_enabled() check clk: berlin: add core clock driver for BG2Q clk: berlin: add core clock driver for BG2/BG2CD clk: berlin: add driver for BG2x complex divider cells clk: berlin: add driver for BG2x simple PLLs clk: berlin: add driver for BG2x audio/video PLL clk: st: Terminate of match table clk/exynos4: Fix compilation warning ARM: shmobile: r8a7779: Add clock index macros for DT sources clk: divider: Fix overflow in clk_divider_bestdiv clk: u300: Terminate of match table ...
Diffstat (limited to 'drivers/clk/qcom/gcc-msm8974.c')
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c207
1 files changed, 136 insertions, 71 deletions
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 51d457e2b959..7af7c18d2144 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8974.h>
#include <dt-bindings/reset/qcom,gcc-msm8974.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -34,6 +35,7 @@
#define P_XO 0
#define P_GPLL0 1
#define P_GPLL1 1
+#define P_GPLL4 2
static const u8 gcc_xo_gpll0_map[] = {
[P_XO] = 0,
@@ -45,6 +47,18 @@ static const char *gcc_xo_gpll0[] = {
"gpll0_vote",
};
+static const u8 gcc_xo_gpll0_gpll4_map[] = {
+ [P_XO] = 0,
+ [P_GPLL0] = 1,
+ [P_GPLL4] = 5,
+};
+
+static const char *gcc_xo_gpll0_gpll4[] = {
+ "xo",
+ "gpll0_vote",
+ "gpll4_vote",
+};
+
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll gpll0 = {
@@ -137,6 +151,33 @@ static struct clk_regmap gpll1_vote = {
},
};
+static struct clk_pll gpll4 = {
+ .l_reg = 0x1dc4,
+ .m_reg = 0x1dc8,
+ .n_reg = 0x1dcc,
+ .config_reg = 0x1dd4,
+ .mode_reg = 0x1dc0,
+ .status_reg = 0x1ddc,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll4",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap gpll4_vote = {
+ .enable_reg = 0x1480,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4_vote",
+ .parent_names = (const char *[]){ "gpll4" },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
static const struct freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, P_GPLL0, 1, 5, 24),
{ }
@@ -811,18 +852,33 @@ static const struct freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = {
{ }
};
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_pro[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0, 15, 1, 2),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(192000000, P_GPLL4, 4, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(384000000, P_GPLL4, 2, 0, 0),
+ { }
+};
+
+static struct clk_init_data sdcc1_apps_clk_src_init = {
+ .name = "sdcc1_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+};
+
static struct clk_rcg2 sdcc1_apps_clk_src = {
.cmd_rcgr = 0x04d0,
.mnd_width = 8,
.hid_width = 5,
.parent_map = gcc_xo_gpll0_map,
.freq_tbl = ftbl_gcc_sdcc1_4_apps_clk,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "sdcc1_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
- .ops = &clk_rcg2_ops,
- },
+ .clkr.hw.init = &sdcc1_apps_clk_src_init,
};
static struct clk_rcg2 sdcc2_apps_clk_src = {
@@ -1340,7 +1396,7 @@ static struct clk_branch gcc_blsp1_uart6_apps_clk = {
};
static struct clk_branch gcc_blsp2_ahb_clk = {
- .halt_reg = 0x05c4,
+ .halt_reg = 0x0944,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x1484,
@@ -1994,6 +2050,38 @@ static struct clk_branch gcc_sdcc1_apps_clk = {
},
};
+static struct clk_branch gcc_sdcc1_cdccal_ff_clk = {
+ .halt_reg = 0x04e8,
+ .clkr = {
+ .enable_reg = 0x04e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_cdccal_ff_clk",
+ .parent_names = (const char *[]){
+ "xo"
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_cdccal_sleep_clk = {
+ .halt_reg = 0x04e4,
+ .clkr = {
+ .enable_reg = 0x04e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_cdccal_sleep_clk",
+ .parent_names = (const char *[]){
+ "sleep_clk_src"
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_sdcc2_ahb_clk = {
.halt_reg = 0x0508,
.clkr = {
@@ -2483,6 +2571,10 @@ static struct clk_regmap *gcc_msm8974_clocks[] = {
[GCC_USB_HSIC_IO_CAL_SLEEP_CLK] = &gcc_usb_hsic_io_cal_sleep_clk.clkr,
[GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr,
[GCC_MMSS_GPLL0_CLK_SRC] = &gcc_mmss_gpll0_clk_src,
+ [GPLL4] = NULL,
+ [GPLL4_VOTE] = NULL,
+ [GCC_SDCC1_CDCCAL_SLEEP_CLK] = NULL,
+ [GCC_SDCC1_CDCCAL_FF_CLK] = NULL,
};
static const struct qcom_reset_map gcc_msm8974_resets[] = {
@@ -2574,51 +2666,51 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8974_desc = {
+ .config = &gcc_msm8974_regmap_config,
+ .clks = gcc_msm8974_clocks,
+ .num_clks = ARRAY_SIZE(gcc_msm8974_clocks),
+ .resets = gcc_msm8974_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8974_resets),
+};
+
static const struct of_device_id gcc_msm8974_match_table[] = {
{ .compatible = "qcom,gcc-msm8974" },
+ { .compatible = "qcom,gcc-msm8974pro" , .data = (void *)1UL },
+ { .compatible = "qcom,gcc-msm8974pro-ac", .data = (void *)1UL },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
+static void msm8974_pro_clock_override(void)
+{
+ sdcc1_apps_clk_src_init.parent_names = gcc_xo_gpll0_gpll4;
+ sdcc1_apps_clk_src_init.num_parents = 3;
+ sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_pro;
+ sdcc1_apps_clk_src.parent_map = gcc_xo_gpll0_gpll4_map;
+
+ gcc_msm8974_clocks[GPLL4] = &gpll4.clkr;
+ gcc_msm8974_clocks[GPLL4_VOTE] = &gpll4_vote;
+ gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_SLEEP_CLK] =
+ &gcc_sdcc1_cdccal_sleep_clk.clkr;
+ gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_FF_CLK] =
+ &gcc_sdcc1_cdccal_ff_clk.clkr;
+}
static int gcc_msm8974_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8974_clocks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
+ struct device *dev = &pdev->dev;
+ bool pro;
+ const struct of_device_id *id;
+
+ id = of_match_device(gcc_msm8974_match_table, dev);
+ if (!id)
+ return -ENODEV;
+ pro = !!(id->data);
+
+ if (pro)
+ msm8974_pro_clock_override();
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
@@ -2631,39 +2723,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8974_clocks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8974_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &gcc_msm8974_desc);
}
static int gcc_msm8974_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}