From patchwork Thu Aug 8 07:14:17 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris BREZILLON X-Patchwork-Id: 2840791 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id EFEA29F479 for ; Thu, 8 Aug 2013 07:16:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C225F20164 for ; Thu, 8 Aug 2013 07:16:17 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8734220319 for ; Thu, 8 Aug 2013 07:16:16 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V7KSB-0004jH-BW; Thu, 08 Aug 2013 07:16:11 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V7KS9-0000Ea-13; Thu, 08 Aug 2013 07:16:09 +0000 Received: from 9.mo4.mail-out.ovh.net ([46.105.40.176] helo=mo4.mail-out.ovh.net) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V7KS4-0000By-HL for linux-arm-kernel@lists.infradead.org; Thu, 08 Aug 2013 07:16:05 +0000 Received: from mail438.ha.ovh.net (b6.ovh.net [213.186.33.56]) by mo4.mail-out.ovh.net (Postfix) with SMTP id 1F655104E187 for ; Thu, 8 Aug 2013 09:15:41 +0200 (CEST) Received: from b0.ovh.net (HELO queueout) (213.186.33.50) by b0.ovh.net with SMTP; 8 Aug 2013 09:19:14 +0200 Received: from cha74-5-78-236-240-82.fbx.proxad.net (HELO localhost.localdomain) (b.brezillon@overkiz.com@78.236.240.82) by ns0.ovh.net with SMTP; 8 Aug 2013 09:19:14 +0200 From: Boris BREZILLON To: Grant Likely , Rob Herring , Rob Landley , Andrew Victor , Nicolas Ferre , Jean-Christophe Plagniol-Villard , Russell King , Mike Turquette , Felipe Balbi , Greg Kroah-Hartman , Ludovic Desroches , Josh Wu , Richard Genoud X-Ovh-Mailout: 178.32.228.4 (mo4.mail-out.ovh.net) Subject: [PATCH v3 14/19] clk: at91: add PMC utmi clock Date: Thu, 8 Aug 2013 09:14:17 +0200 Message-Id: <1375946057-9651-1-git-send-email-b.brezillon@overkiz.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1375937608-3773-1-git-send-email-b.brezillon@overkiz.com> References: <1375937608-3773-1-git-send-email-b.brezillon@overkiz.com> X-Ovh-Tracer-Id: 5053320257286666288 X-Ovh-Remote: 78.236.240.82 (cha74-5-78-236-240-82.fbx.proxad.net) X-Ovh-Local: 213.186.33.20 (ns0.ovh.net) X-OVH-SPAMSTATE: OK X-OVH-SPAMSCORE: -100 X-OVH-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrfeeikedrtdehucetufdoteggodetrfcurfhrohhfihhlvgemucfqggfjnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd X-Spam-Check: DONE|U 0.5/N X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrfeeikedrtdehucetufdoteggodetrfcurfhrohhfihhlvgemucfqggfjnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130808_031604_764851_6BF5D924 X-CRM114-Status: GOOD ( 24.28 ) X-Spam-Score: -0.2 (/) Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Boris BREZILLON X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.4 required=5.0 tests=BAYES_00,KHOP_BIG_TO_CC, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds new at91 utmi clock implementation using common clk framework. This clock is a pll with a fixed factor (x40). It is used as a source for usb clock. Signed-off-by: Boris BREZILLON --- arch/arm/mach-at91/Kconfig | 7 ++ drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-utmi.c | 161 +++++++++++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.c | 7 ++ drivers/clk/at91/pmc.h | 5 ++ 5 files changed, 181 insertions(+) create mode 100644 drivers/clk/at91/clk-utmi.c diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 85b53a4..6ad37da 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -1,5 +1,8 @@ if ARCH_AT91 +config HAVE_AT91_UTMI + bool + config HAVE_AT91_DBGU0 bool @@ -78,6 +81,7 @@ config SOC_SAMA5D3 select HAVE_FB_ATMEL select HAVE_AT91_DBGU1 select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI help Select this if you are using one of Atmel's SAMA5D3 family SoC. This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35. @@ -124,6 +128,7 @@ config SOC_AT91SAM9RL select HAVE_FB_ATMEL select SOC_AT91SAM9 select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI config SOC_AT91SAM9G45 bool "AT91SAM9G45 or AT91SAM9M10 families" @@ -131,6 +136,7 @@ config SOC_AT91SAM9G45 select HAVE_FB_ATMEL select SOC_AT91SAM9 select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI help Select this if you are using one of Atmel's AT91SAM9G45 family SoC. This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. @@ -141,6 +147,7 @@ config SOC_AT91SAM9X5 select HAVE_FB_ATMEL select SOC_AT91SAM9 select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI help Select this if you are using one of Atmel's AT91SAM9x5 family SoC. This means that your SAM9 name finishes with a '5' (except if it is diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 3873b62..a824883 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -7,3 +7,4 @@ obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o obj-y += clk-system.o clk-peripheral.o obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS) += clk-programmable.o +obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c new file mode 100644 index 0000000..244ff9e --- /dev/null +++ b/drivers/clk/at91/clk-utmi.c @@ -0,0 +1,161 @@ +/* + * drivers/clk/at91/clk-utmi.c + * + * Copyright (C) 2013 Boris BREZILLON + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) + +struct clk_utmi { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned int irq; + wait_queue_head_t wait; +}; + +static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id) +{ + struct clk_utmi *utmi = (struct clk_utmi *)dev_id; + + wake_up(&utmi->wait); + disable_irq_nosync(utmi->irq); + + return IRQ_HANDLED; +} + +static int clk_utmi_prepare(struct clk_hw *hw) +{ + struct clk_utmi *utmi = to_clk_utmi(hw); + struct at91_pmc *pmc = utmi->pmc; + u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN | + AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN; + + pmc_write(pmc, AT91_CKGR_UCKR, tmp); + + while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) { + enable_irq(utmi->irq); + wait_event(utmi->wait, + pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); + } + + return 0; +} + +static int clk_utmi_is_ready(struct clk_hw *hw) +{ + struct clk_utmi *utmi = to_clk_utmi(hw); + struct at91_pmc *pmc = utmi->pmc; + + return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); +} + +static void clk_utmi_disable(struct clk_hw *hw) +{ + struct clk_utmi *utmi = to_clk_utmi(hw); + struct at91_pmc *pmc = utmi->pmc; + u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN; + + pmc_write(pmc, AT91_CKGR_UCKR, tmp); +} + +static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate * 40; +} + +static const struct clk_ops utmi_ops = { + .prepare = clk_utmi_prepare, + .is_prepared = clk_utmi_is_ready, + .disable = clk_utmi_disable, + .is_enabled = clk_utmi_is_ready, + .recalc_rate = clk_utmi_recalc_rate, +}; + +static struct clk * __init +at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, + const char *name, const char *parent_name) +{ + int ret; + struct clk_utmi *utmi; + struct clk *clk = NULL; + struct clk_init_data init; + + utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &utmi_ops; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.flags = CLK_SET_RATE_GATE; + + utmi->hw.init = &init; + utmi->pmc = pmc; + utmi->irq = irq; + init_waitqueue_head(&utmi->wait); + irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); + ret = request_irq(utmi->irq, clk_utmi_irq_handler, + IRQF_TRIGGER_HIGH, "clk-utmi", utmi); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &utmi->hw); + + if (IS_ERR(clk)) + kfree(utmi); + + return clk; +} + +static void __init +of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc) +{ + unsigned int irq; + struct clk *clk; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + + clk = at91_clk_register_utmi(pmc, irq, name, parent_name); + + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +} + +void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_utmi_setup(np, pmc); +} diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 66a627d..238f0d2 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -280,6 +280,13 @@ static const struct of_device_id pmc_clk_ids[] __initdata = { .data = of_at91sam9x5_clk_prog_setup, }, #endif + /* UTMI clock */ +#if defined(CONFIG_HAVE_AT91_UTMI) + { + .compatible = "atmel,at91sam9x5-clk-utmi", + .data = of_at91sam9x5_clk_utmi_setup, + }, +#endif { /*sentinel*/ } }; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 5f20dc1..3ba9503 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -91,4 +91,9 @@ extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc); #endif +#if defined(CONFIG_HAVE_AT91_UTMI) +extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, + struct at91_pmc *pmc); +#endif + #endif /* __PMC_H_ */