Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756505Ab3JHQW1 (ORCPT ); Tue, 8 Oct 2013 12:22:27 -0400 Received: from eusmtp01.atmel.com ([212.144.249.242]:63108 "EHLO eusmtp01.atmel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756112Ab3JHQWZ (ORCPT ); Tue, 8 Oct 2013 12:22:25 -0400 Message-ID: <5254313E.90007@atmel.com> Date: Tue, 8 Oct 2013 18:22:22 +0200 From: Nicolas Ferre Organization: atmel User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.0 MIME-Version: 1.0 To: Boris BREZILLON , Grant Likely , Rob Herring , Rob Landley , Andrew Victor , "Jean-Christophe Plagniol-Villard" , Russell King , Mike Turquette , "Felipe Balbi" , Greg Kroah-Hartman , Ludovic Desroches , Josh Wu , Richard Genoud CC: , , Subject: Re: [PATCH v3 16/19] clk: at91: add PMC smd clock References: <1375937608-3773-1-git-send-email-b.brezillon@overkiz.com> <1375946243-9736-1-git-send-email-b.brezillon@overkiz.com> In-Reply-To: <1375946243-9736-1-git-send-email-b.brezillon@overkiz.com> Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit X-Originating-IP: [10.161.30.18] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8017 Lines: 285 On 08/08/2013 09:17, Boris BREZILLON : > This patch adds at91 smd (Soft Modem) clock implementation using common clk > framework. > > Not used by any driver right now. > > Signed-off-by: Boris BREZILLON > --- > arch/arm/mach-at91/Kconfig | 5 ++ > drivers/clk/at91/Makefile | 1 + > drivers/clk/at91/clk-smd.c | 171 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/clk/at91/pmc.c | 7 ++ > drivers/clk/at91/pmc.h | 5 ++ > 5 files changed, 189 insertions(+) > create mode 100644 drivers/clk/at91/clk-smd.c > > diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig > index b76dc4c..97033f7 100644 > --- a/arch/arm/mach-at91/Kconfig > +++ b/arch/arm/mach-at91/Kconfig > @@ -39,6 +39,9 @@ config AT91_SAM9G45_RESET > config AT91_SAM9_TIME > bool > > +config HAVE_AT91_SMD > + bool > + > config SOC_AT91SAM9 > bool > select AT91_SAM9_TIME > @@ -85,6 +88,7 @@ config SOC_SAMA5D3 > select HAVE_AT91_DBGU1 > select AT91_USE_OLD_CLK > select HAVE_AT91_UTMI > + select HAVE_AT91_SMD > select HAVE_AT91_USB_CLK > help > Select this if you are using one of Atmel's SAMA5D3 family SoC. > @@ -157,6 +161,7 @@ config SOC_AT91SAM9X5 > select SOC_AT91SAM9 > select AT91_USE_OLD_CLK > select HAVE_AT91_UTMI > + select HAVE_AT91_SMD > select HAVE_AT91_USB_CLK > help > Select this if you are using one of Atmel's AT91SAM9x5 family SoC. > diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile > index 61db058..0e92b71 100644 > --- a/drivers/clk/at91/Makefile > +++ b/drivers/clk/at91/Makefile > @@ -9,3 +9,4 @@ obj-y += clk-system.o clk-peripheral.o > obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS) += clk-programmable.o > obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o > obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o > +obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o > diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c > new file mode 100644 > index 0000000..a7cf14a > --- /dev/null > +++ b/drivers/clk/at91/clk-smd.c > @@ -0,0 +1,171 @@ > +/* > + * drivers/clk/at91/clk-smd.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 "pmc.h" > + > +#define SMD_SOURCE_MAX 2 > + > +#define to_at91sam9x5_clk_smd(hw) \ > + container_of(hw, struct at91sam9x5_clk_smd, hw) > +struct at91sam9x5_clk_smd { > + struct clk_hw hw; > + struct at91_pmc *pmc; > +}; > + > +static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + u32 tmp; > + u8 smddiv; > + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); > + struct at91_pmc *pmc = smd->pmc; > + > + tmp = pmc_read(pmc, AT91_PMC_SMD); > + smddiv = (tmp & AT91_PMC_SMD_DIV) >> 8; > + return parent_rate / (smddiv + 1); > +} > + > +static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ > + unsigned long div; > + unsigned long bestrate; > + unsigned long tmp; > + > + if (rate >= *parent_rate) > + return *parent_rate; > + > + div = *parent_rate / rate; > + if (div > 15) > + return *parent_rate / 16; > + > + bestrate = *parent_rate / div; > + tmp = *parent_rate / (div + 1); > + if (bestrate - rate > rate - tmp) > + bestrate = tmp; > + > + return bestrate; > +} > + > +static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index) > +{ > + u32 tmp; > + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); > + struct at91_pmc *pmc = smd->pmc; > + > + if (index > 1) > + return -EINVAL; > + tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS; > + if (index) > + tmp |= AT91_PMC_SMDS; > + pmc_write(pmc, AT91_PMC_SMD, tmp); > + return 0; > +} > + > +static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw) > +{ > + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); > + struct at91_pmc *pmc = smd->pmc; > + > + return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS; > +} > + > +static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + u32 tmp; > + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); > + struct at91_pmc *pmc = smd->pmc; > + unsigned long div = parent_rate / rate; > + > + if (parent_rate % rate || div < 1 || div > 16) > + return -EINVAL; > + tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV; > + tmp |= (div - 1) << 8; > + pmc_write(pmc, AT91_PMC_SMD, tmp); > + > + return 0; > +} > + > +static const struct clk_ops at91sam9x5_smd_ops = { > + .recalc_rate = at91sam9x5_clk_smd_recalc_rate, > + .round_rate = at91sam9x5_clk_smd_round_rate, > + .get_parent = at91sam9x5_clk_smd_get_parent, > + .set_parent = at91sam9x5_clk_smd_set_parent, > + .set_rate = at91sam9x5_clk_smd_set_rate, > +}; > + > +static struct clk * __init > +at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name, > + const char **parent_names, u8 num_parents) > +{ > + struct at91sam9x5_clk_smd *smd; > + struct clk *clk = NULL; > + struct clk_init_data init; > + > + smd = kzalloc(sizeof(*smd), GFP_KERNEL); > + if (!smd) > + return ERR_PTR(-ENOMEM); > + > + init.name = name; > + init.ops = &at91sam9x5_smd_ops; > + init.parent_names = parent_names; > + init.num_parents = num_parents; > + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; > + > + smd->hw.init = &init; > + smd->pmc = pmc; > + > + clk = clk_register(NULL, &smd->hw); > + > + if (IS_ERR(clk)) > + kfree(smd); > + > + return clk; > +} > + > +void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, > + struct at91_pmc *pmc) > +{ > + struct clk *clk; > + int i; > + int num_parents; > + const char *parent_names[SMD_SOURCE_MAX]; > + const char *name = np->name; > + > + num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); > + if (num_parents <= 0 || num_parents >= SMD_SOURCE_MAX) > + return; > + > + for (i = 0; i < num_parents; i++) { > + parent_names[i] = of_clk_get_parent_name(np, i); > + if (!parent_names[i]) > + return; > + } > + > + of_property_read_string(np, "clock-output-names", &name); > + > + clk = at91sam9x5_clk_register_smd(pmc, name, parent_names, > + num_parents); > + > + if (IS_ERR(clk)) > + return; > + > + of_clk_add_provider(np, of_clk_src_simple_get, clk); > +} > diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c > index e46de3d..0a731c8 100644 > --- a/drivers/clk/at91/pmc.c > +++ b/drivers/clk/at91/pmc.c > @@ -298,6 +298,13 @@ static const struct of_device_id pmc_clk_ids[] __initdata = { > .data = of_at91sam9x5_clk_usb_setup, > }, > #endif > + /* SMD clock */ > +#if defined(CONFIG_HAVE_AT91_SMD) > + { > + .compatible = "atmel,at91sam9x5-clk-smd", > + .data = of_at91sam9x5_clk_smd_setup, > + }, > +#endif > { /*sentinel*/ } > }; > > diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h > index b2efff5..43f2516 100644 > --- a/drivers/clk/at91/pmc.h > +++ b/drivers/clk/at91/pmc.h > @@ -103,4 +103,9 @@ extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, > struct at91_pmc *pmc); > #endif > > +#if defined(CONFIG_HAVE_AT91_SMD) > +extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, > + struct at91_pmc *pmc); > +#endif > + > #endif /* __PMC_H_ */ > -- Nicolas Ferre -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/