From patchwork Tue Sep 18 18:35:34 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Murali Karicheri X-Patchwork-Id: 1474241 Return-Path: X-Original-To: patchwork-davinci@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from arroyo.ext.ti.com (arroyo.ext.ti.com [192.94.94.40]) by patchwork2.kernel.org (Postfix) with ESMTP id 1A97ADF24C for ; Tue, 18 Sep 2012 18:36:09 +0000 (UTC) Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id q8IIa7M0010993 for ; Tue, 18 Sep 2012 13:36:08 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8IIa7CP007164 for ; Tue, 18 Sep 2012 13:36:07 -0500 Received: from dlelxv23.itg.ti.com (172.17.1.198) by dfle72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.1.323.3; Tue, 18 Sep 2012 13:36:07 -0500 Received: from linux.omap.com (dlelxs01.itg.ti.com [157.170.227.31]) by dlelxv23.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8IIa7it004316 for ; Tue, 18 Sep 2012 13:36:07 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id E14B880655 for ; Tue, 18 Sep 2012 13:36:06 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dlelxv30.itg.ti.com (dlelxv30.itg.ti.com [172.17.2.17]) by linux.omap.com (Postfix) with ESMTP id 68EA580628 for ; Tue, 18 Sep 2012 13:35:46 -0500 (CDT) Received: from DFLE73.ent.ti.com (dfle73.ent.ti.com [128.247.5.110]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8IIZk5b006508; Tue, 18 Sep 2012 13:35:46 -0500 Received: from dlelxv22.itg.ti.com (172.17.1.197) by dfle73.ent.ti.com (128.247.5.110) with Microsoft SMTP Server id 14.1.323.3; Tue, 18 Sep 2012 13:35:46 -0500 Received: from ares-ubuntu.am.dhcp.ti.com (ares-ubuntu.am.dhcp.ti.com [158.218.103.17]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8IIZjl3007539; Tue, 18 Sep 2012 13:35:45 -0500 Received: from a0868495 by ares-ubuntu.am.dhcp.ti.com with local (Exim 4.76) (envelope-from ) id 1TE2e9-0001bM-Hh; Tue, 18 Sep 2012 14:35:45 -0400 From: Murali Karicheri To: , , , , , , , Subject: [RFC PATCH 01/10] clk:davinci - add Main PLL clock driver Date: Tue, 18 Sep 2012 14:35:34 -0400 Message-ID: <1347993342-6099-2-git-send-email-m-karicheri2@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1347993342-6099-1-git-send-email-m-karicheri2@ti.com> References: <1347993342-6099-1-git-send-email-m-karicheri2@ti.com> MIME-Version: 1.0 X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: Errors-To: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com This is the driver for the main PLL clock hardware found on DM SoCs. This driver borrowed code from arch/arm/mach-davinci/clock.c and implemented the driver as per common clock provider API. The main PLL hardware typically has a multiplier, a pre-divider and a post-divider. Some of the SoCs has the divider fixed meaning they can not be configured through a register. HAS_PREDIV and HAS_POSTDIV flags are used to tell the driver if a hardware has these dividers present or not. Driver is configured through the structure clk_davinci_pll_data that has the platform data for the driver. Signed-off-by: Murali Karicheri diff --git a/drivers/clk/davinci/clk-davinci-pll.c b/drivers/clk/davinci/clk-davinci-pll.c new file mode 100644 index 0000000..13e1690 --- /dev/null +++ b/drivers/clk/davinci/clk-davinci-pll.c @@ -0,0 +1,128 @@ +/* + * PLL clk driver DaVinci devices + * + * Copyright (C) 2006-2012 Texas Instruments. + * Copyright (C) 2008-2009 Deep Root Systems, LLC + * + * 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. + * TODO - Add set_parent_rate() + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PLLM 0x110 +#define PLLM_PLLM_MASK 0xff +#define PREDIV 0x114 +#define POSTDIV 0x128 +#define PLLDIV_EN BIT(15) + +/** + * struct clk_davinci_pll - DaVinci Main pll clock + * @hw: clk_hw for the pll + * @pll_data: PLL driver specific data + */ +struct clk_davinci_pll { + struct clk_hw hw; + struct clk_davinci_pll_data *pll_data; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct clk_davinci_pll, hw) + +static unsigned long clk_pllclk_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_davinci_pll *pll = to_clk_pll(hw); + struct clk_davinci_pll_data *pll_data = pll->pll_data; + u32 mult = 1, prediv = 1, postdiv = 1; + unsigned long rate = parent_rate; + + /* If there is a device specific recalc defined invoke it. Otherwise + * fallback to default one + */ + mult = __raw_readl(pll_data->pllm); + if (pll_data->pllm_multiplier) + mult = pll_data->pllm_multiplier * + (mult & pll_data->pllm_mask); + else + mult = (mult & pll_data->pllm_mask) + 1; + + if (pll_data->flags & CLK_DAVINCI_PLL_HAS_PREDIV) { + /* pre-divider is fixed, take prediv value from pll_data */ + if (pll_data->fixed_prediv) + prediv = pll_data->fixed_prediv; + else { + prediv = __raw_readl(pll_data->prediv); + if (prediv & PLLDIV_EN) + prediv = (prediv & pll_data->prediv_mask) + 1; + else + prediv = 1; + } + } + + if (pll_data->flags & CLK_DAVINCI_PLL_HAS_POSTDIV) { + postdiv = __raw_readl(pll_data->postdiv); + if (postdiv & PLLDIV_EN) + postdiv = (postdiv & pll_data->postdiv_mask) + 1; + else + postdiv = 1; + } + + rate /= prediv; + rate *= mult; + rate /= postdiv; + + pr_debug("PLL%d: input = %lu MHz [ ", + pll_data->num, parent_rate / 1000000); + if (prediv > 1) + pr_debug("/ %d ", prediv); + if (mult > 1) + pr_debug("* %d ", mult); + if (postdiv > 1) + pr_debug("/ %d ", postdiv); + pr_debug("] --> %lu MHz output.\n", rate / 1000000); + return rate; +} + +static const struct clk_ops clk_pll_ops = { + .recalc_rate = clk_pllclk_recalc, +}; + +struct clk *clk_register_davinci_pll(struct device *dev, const char *name, + const char *parent_name, + struct clk_davinci_pll_data *pll_data) +{ + struct clk_init_data init; + struct clk_davinci_pll *pll; + struct clk *clk; + + if (!pll_data) + return ERR_PTR(-ENODEV); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + init.name = name; + init.ops = &clk_pll_ops; + init.flags = pll_data->flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + pll->pll_data = pll_data; + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/include/linux/platform_data/clk-davinci-pll.h b/include/linux/platform_data/clk-davinci-pll.h new file mode 100644 index 0000000..69d44ab --- /dev/null +++ b/include/linux/platform_data/clk-davinci-pll.h @@ -0,0 +1,52 @@ +/* + * TI DaVinci clk-pll driver platform data definitions + * + * Copyright (C) 2006-2012 Texas Instruments. + * Copyright (C) 2008-2009 Deep Root Systems, LLC + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __CLK_DAVINCI_PLL_H +#define __CLK_DAVINCI_PLL_H + +/* PLL flags */ +#define CLK_DAVINCI_PLL_HAS_PREDIV BIT(0) +#define CLK_DAVINCI_PLL_HAS_POSTDIV BIT(1) + +struct clk_davinci_pll_data { + /* physical addresses set by platform code */ + u32 phy_pllm; + /* if PLL has a prediv register this should be non zero */ + u32 phy_prediv; + /* if PLL has a postdiv register this should be non zero */ + u32 phy_postdiv; + /* mapped addresses. should be initialized by */ + void __iomem *pllm; + void __iomem *prediv; + void __iomem *postdiv; + u32 pllm_mask; + u32 prediv_mask; + u32 postdiv_mask; + u32 num; + /* framework flags */ + u32 flags; + /* pll flags */ + u32 pll_flags; + u32 fixed_prediv; /* use this value for prediv */ + u32 pllm_multiplier; /* multiply PLLM by this factor. By default + * most SOC set this to zero that translates + * to a multiplier of 1 and incrementer of 1. + * To override default, set this factor */ +}; + +extern struct clk *clk_register_davinci_pll(struct device *dev, + const char *name, const char *parent_name, + struct clk_davinci_pll_data *pll_data); +#endif /* CLK_DAVINCI_PLL_H */