From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161161AbcFJNZL (ORCPT ); Fri, 10 Jun 2016 09:25:11 -0400 Received: from down.free-electrons.com ([37.187.137.238]:58583 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933291AbcFJNXx (ORCPT ); Fri, 10 Jun 2016 09:23:53 -0400 From: Gregory CLEMENT To: Mike Turquette , Stephen Boyd , linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Rob Herring , devicetree@vger.kernel.org, Thomas Petazzoni , linux-arm-kernel@lists.infradead.org, Jason Cooper , Andrew Lunn , Sebastian Hesselbarth , Gregory CLEMENT , Nadav Haklai , Victor Gu , Romain Perier , Omri Itach , Marcin Wojtas , Wilson Ding , Shadi Ammouri Subject: [PATCH 08/10] clk: mvebu Add the time base generator clocks for Armada 3700 Date: Fri, 10 Jun 2016 15:23:36 +0200 Message-Id: <1465565018-14172-9-git-send-email-gregory.clement@free-electrons.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1465565018-14172-1-git-send-email-gregory.clement@free-electrons.com> References: <1465565018-14172-1-git-send-email-gregory.clement@free-electrons.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org These clocks are children of the xtal clock and each one can be selected as a source for the peripheral clocks. According to the datasheet it should be possible to modify their rate, but currently it is not supported. Signed-off-by: Gregory CLEMENT --- drivers/clk/mvebu/Makefile | 1 + drivers/clk/mvebu/armada-37xx-tbg.c | 172 ++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 drivers/clk/mvebu/armada-37xx-tbg.c diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 4257a36d0219..72e3512a9d4a 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-tbg.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c new file mode 100644 index 000000000000..e9a331b85a78 --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-tbg.c @@ -0,0 +1,172 @@ +/* + * Marvell Armada 37xx SoC Time Base Generator clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NUM_TBG 4 + +#define TBG_CTRL0 0x4 +#define TBG_CTRL1 0x8 +#define TBG_CTRL7 0x20 +#define TBG_CTRL8 0x30 + +#define TBG_DIV_MASK 0x1FF + +#define TBG_A_REFDIV 0 +#define TBG_B_REFDIV 16 + +#define TBG_A_FBDIV 2 +#define TBG_B_FBDIV 18 + +#define TBG_A_VCODIV_SE 0 +#define TBG_B_VCODIV_SE 16 + +#define TBG_A_VCODIV_DIFF 1 +#define TBG_B_VCODIV_DIFF 17 + +struct tbg_def { + char *name; + u32 refdiv_offset; + u32 fbdiv_offset; + u32 vcodiv_reg; + u32 vcodiv_offset; +}; + +struct tbg_def tbg[NUM_TBG] = { + {"TBG-A-P", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL8, TBG_A_VCODIV_DIFF}, + {"TBG-B-P", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL8, TBG_B_VCODIV_DIFF}, + {"TBG-A-S", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL1, TBG_A_VCODIV_SE}, + {"TBG-B-S", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL1, TBG_B_VCODIV_SE}, +}; + +static struct clk_onecell_data clk_tbg_data; + +unsigned int tbg_get_mult(void __iomem *reg, struct tbg_def *ptbg) +{ + u32 val; + + val = readl(reg + TBG_CTRL0); + + return ((val >> ptbg->fbdiv_offset) & TBG_DIV_MASK) << 2; +} + +unsigned int tbg_get_div(void __iomem *reg, struct tbg_def *ptbg) +{ + u32 val; + unsigned int div; + + val = readl(reg + TBG_CTRL7); + + div = (val >> ptbg->refdiv_offset) & TBG_DIV_MASK; + if (div == 0) + div = 1; + val = readl(reg + ptbg->vcodiv_reg); + + div *= 1 << ((val >> ptbg->vcodiv_offset) & TBG_DIV_MASK); + + return div; +} + + +static int armada_3700_tbg_clock_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + const char *parent_name; + struct resource *res; + struct clk *parent; + void __iomem *reg; + int i, ret; + + parent = of_clk_get(np, 0); + if (IS_ERR(parent)) { + dev_err(dev, "Could get the clock parent\n"); + return -EINVAL; + } + parent_name = __clk_get_name(parent); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(dev, res); + if (IS_ERR(reg)) { + dev_err(dev, "Could not map the tbg clock registers\n"); + ret = PTR_ERR(reg); + goto put_clk; + } + + clk_tbg_data.clk_num = NUM_TBG; + clk_tbg_data.clks = devm_kcalloc(dev, clk_tbg_data.clk_num, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_tbg_data.clks) { + ret = -ENOMEM; + goto put_clk; + } + + for (i = 0; i < NUM_TBG; i++) { + const char *name; + unsigned int mult, div; + + name = tbg[i].name; + mult = tbg_get_mult(reg, &tbg[i]); + div = tbg_get_div(reg, &tbg[i]); + clk_tbg_data.clks[i] = clk_register_fixed_factor(NULL, name, + parent_name, 0, mult, div); + if (IS_ERR(clk_tbg_data.clks[i])) + dev_err(dev, "Can't register TBG clock %s\n", name); + } + + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_tbg_data); + + return 0; + +put_clk: + clk_put(parent); + return ret; +} + +static int armada_3700_tbg_clock_remove(struct platform_device *pdev) +{ + int i; + + of_clk_del_provider(pdev->dev.of_node); + for (i = 0; i < clk_tbg_data.clk_num; i++) + clk_unregister_fixed_factor(clk_tbg_data.clks[i]); + + return 0; +} + +static const struct of_device_id armada_3700_tbg_clock_of_match[] = { + { .compatible = "marvell,armada-3700-tbg-clock", }, + { } +}; + +MODULE_DEVICE_TABLE(of, armada_3700_tbg_clock_of_match); + +static struct platform_driver armada_3700_tbg_clock_driver = { + .probe = armada_3700_tbg_clock_probe, + .remove = armada_3700_tbg_clock_remove, + .driver = { + .name = "marvell-armada-3700-tbg-clock", + .of_match_table = armada_3700_tbg_clock_of_match, + }, +}; + +module_platform_driver(armada_3700_tbg_clock_driver); + +MODULE_AUTHOR("Gregory CLEMENT "); +MODULE_DESCRIPTION("Marvell Armada 37xx SoC Time Base Generator driver"); +MODULE_LICENSE("GPL v2"); -- 2.5.0