From patchwork Wed Apr 3 09:46:52 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 15848 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 5904223E06 for ; Wed, 3 Apr 2013 09:47:57 +0000 (UTC) Received: from mail-ye0-f198.google.com (mail-ye0-f198.google.com [209.85.213.198]) by fiordland.canonical.com (Postfix) with ESMTP id D205DA1850B for ; Wed, 3 Apr 2013 09:47:56 +0000 (UTC) Received: by mail-ye0-f198.google.com with SMTP id m12sf1812082yen.1 for ; Wed, 03 Apr 2013 02:47:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-beenthere:x-received:received-spf:x-received :x-forwarded-to:x-forwarded-for:delivered-to:x-received:received-spf :from:to:cc:subject:date:message-id:x-mailer:mime-version :x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe :content-type; bh=mjfSMuKxrpbwoDmZnWgguAQVJxbGpNwHn2Z9v7bLeNg=; b=HEppIGVPhhDp3Mfp1jd6MHWvbDzYN410FGLZZewmNY0gcPxMkIm1AN5PDZOHoWocBx 2gVKridLJ1VWonHJL94SPbaPwIAIJo84vN8NtsFspxU5p4d079zfHxXI0ZIHJv7rEDqN Bm/1yoZmjbFfut5pVW2zilt6HzTeBDkc3QrKhQpc9UH3/sJ60Qi9kth+XzUd0K0UpMTr LztIzctDWR8JoPD3YwPUjWtkVsdrI3IftOENMZQyGFoWvkp5GQiSR+1ORgRuq51jxp0b 0Jv+hDuRQYvdjLzwQCNeor4bd7O/pGwSUyPt0iO86R6wYPWSeaFPXpg7r5kFK9dgnVCf 8yMQ== X-Received: by 10.224.172.200 with SMTP id m8mr779912qaz.0.1364982476404; Wed, 03 Apr 2013 02:47:56 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.130.134 with SMTP id oe6ls816314qeb.46.gmail; Wed, 03 Apr 2013 02:47:56 -0700 (PDT) X-Received: by 10.52.20.104 with SMTP id m8mr518185vde.77.1364982475594; Wed, 03 Apr 2013 02:47:55 -0700 (PDT) Received: from mail-vb0-x22d.google.com (mail-vb0-x22d.google.com [2607:f8b0:400c:c02::22d]) by mx.google.com with ESMTPS id d10si4367633vdv.80.2013.04.03.02.47.54 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 03 Apr 2013 02:47:54 -0700 (PDT) Received-SPF: neutral (google.com: 2607:f8b0:400c:c02::22d is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=2607:f8b0:400c:c02::22d; Received: by mail-vb0-f45.google.com with SMTP id w15so298252vbf.32 for ; Wed, 03 Apr 2013 02:47:54 -0700 (PDT) X-Received: by 10.52.76.103 with SMTP id j7mr518488vdw.90.1364982474588; Wed, 03 Apr 2013 02:47:54 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.59.4.204 with SMTP id cg12csp162559ved; Wed, 3 Apr 2013 02:47:53 -0700 (PDT) X-Received: by 10.14.202.71 with SMTP id c47mr2098462eeo.39.1364982473166; Wed, 03 Apr 2013 02:47:53 -0700 (PDT) Received: from eu1sys200aog110.obsmtp.com (eu1sys200aog110.obsmtp.com [207.126.144.129]) by mx.google.com with SMTP id t43si7778623eeg.64.2013.04.03.02.47.46 (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 03 Apr 2013 02:47:53 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.129 is neither permitted nor denied by best guess record for domain of ulf.hansson@stericsson.com) client-ip=207.126.144.129; Received: from beta.dmz-ap.st.com ([138.198.100.35]) (using TLSv1) by eu1sys200aob110.postini.com ([207.126.147.11]) with SMTP ID DSNKUVv6wYajN5dcLi4095SyXRED3Gi3qdBc@postini.com; Wed, 03 Apr 2013 09:47:51 UTC Received: from zeta.dmz-ap.st.com (ns6.st.com [138.198.234.13]) by beta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 80204E9; Wed, 3 Apr 2013 09:39:34 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 59FC351F; Wed, 3 Apr 2013 09:47:41 +0000 (GMT) Received: from exdcvycastm003.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm003", Issuer "exdcvycastm003" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 37F82A8083; Wed, 3 Apr 2013 11:47:36 +0200 (CEST) Received: from steludxu1397.lud.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.1) with Microsoft SMTP Server (TLS) id 8.3.279.5; Wed, 3 Apr 2013 11:47:39 +0200 From: Ulf Hansson To: , Mike Turquette Cc: Linus Walleij , Par-Olof Hakansson , Ulf Hansson Subject: [PATCH V2 1/3] clk: ux500: Add support for sysctrl clocks Date: Wed, 3 Apr 2013 11:46:52 +0200 Message-ID: <1364982412-9853-1-git-send-email-ulf.hansson@stericsson.com> X-Mailer: git-send-email 1.7.10 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQnUSieK12A5CnvVSO90yrycsBdue1vrj6YOFHc8d5TXQfPMt4hv9qTA3JNbe+OnOdUaWCFZ X-Original-Sender: patch@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 2607:f8b0:400c:c02::22d is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Ulf Hansson The abx500 sysctrl clocks are using the ab8500 sysctrl driver to modify the clock hardware. Sysctrl clocks are represented by a ab8500 sysctrl register and with a corresponding bitmask. The sysctrl clocks are slow path clocks, which means clk_prepare and clk_unprepare will be used to gate|ungate these clocks. Signed-off-by: Ulf Hansson --- Changes in v2: - Removed wrong header file. --- drivers/clk/ux500/Makefile | 1 + drivers/clk/ux500/clk-sysctrl.c | 223 +++++++++++++++++++++++++++++++++++++++ drivers/clk/ux500/clk.h | 29 +++++ 3 files changed, 253 insertions(+) create mode 100644 drivers/clk/ux500/clk-sysctrl.c diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile index bcc0c11..c6a806e 100644 --- a/drivers/clk/ux500/Makefile +++ b/drivers/clk/ux500/Makefile @@ -5,6 +5,7 @@ # Clock types obj-y += clk-prcc.o obj-y += clk-prcmu.o +obj-y += clk-sysctrl.o # Clock definitions obj-y += u8500_clk.o diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c new file mode 100644 index 0000000..162a02b --- /dev/null +++ b/drivers/clk/ux500/clk-sysctrl.c @@ -0,0 +1,223 @@ +/* + * Sysctrl clock implementation for ux500 platform. + * + * Copyright (C) 2013 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "clk.h" + +#define SYSCTRL_MAX_NUM_PARENTS 4 + +#define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw) + +struct clk_sysctrl { + struct clk_hw hw; + struct device *dev; + u8 parent_index; + u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS]; + u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS]; + u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS]; + unsigned long rate; + unsigned long enable_delay_us; +}; + +/* Sysctrl clock operations. */ + +static int clk_sysctrl_prepare(struct clk_hw *hw) +{ + int ret; + struct clk_sysctrl *clk = to_clk_sysctrl(hw); + + ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0], + clk->reg_bits[0]); + + if (!ret && clk->enable_delay_us) + usleep_range(clk->enable_delay_us, clk->enable_delay_us); + + return ret; +} + +static void clk_sysctrl_unprepare(struct clk_hw *hw) +{ + struct clk_sysctrl *clk = to_clk_sysctrl(hw); + if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0])) + dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n", + __func__, __clk_get_name(hw->clk)); +} + +static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_sysctrl *clk = to_clk_sysctrl(hw); + return clk->rate; +} + +static int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_sysctrl *clk = to_clk_sysctrl(hw); + u8 old_index = clk->parent_index; + int ret = 0; + + if (clk->reg_sel[old_index]) { + ret = ab8500_sysctrl_clear(clk->reg_sel[old_index], + clk->reg_mask[old_index]); + if (ret) + return ret; + } + + if (clk->reg_sel[index]) { + ret = ab8500_sysctrl_write(clk->reg_sel[index], + clk->reg_mask[index], + clk->reg_bits[index]); + if (ret) { + if (clk->reg_sel[old_index]) + ab8500_sysctrl_write(clk->reg_sel[old_index], + clk->reg_mask[old_index], + clk->reg_bits[old_index]); + return ret; + } + } + clk->parent_index = index; + + return ret; +} + +static u8 clk_sysctrl_get_parent(struct clk_hw *hw) +{ + struct clk_sysctrl *clk = to_clk_sysctrl(hw); + return clk->parent_index; +} + +static struct clk_ops clk_sysctrl_gate_ops = { + .prepare = clk_sysctrl_prepare, + .unprepare = clk_sysctrl_unprepare, +}; + +static struct clk_ops clk_sysctrl_gate_fixed_rate_ops = { + .prepare = clk_sysctrl_prepare, + .unprepare = clk_sysctrl_unprepare, + .recalc_rate = clk_sysctrl_recalc_rate, +}; + +static struct clk_ops clk_sysctrl_set_parent_ops = { + .set_parent = clk_sysctrl_set_parent, + .get_parent = clk_sysctrl_get_parent, +}; + +static struct clk *clk_reg_sysctrl(struct device *dev, + const char *name, + const char **parent_names, + u8 num_parents, + u16 *reg_sel, + u8 *reg_mask, + u8 *reg_bits, + unsigned long rate, + unsigned long enable_delay_us, + unsigned long flags, + struct clk_ops *clk_sysctrl_ops) +{ + struct clk_sysctrl *clk; + struct clk_init_data clk_sysctrl_init; + struct clk *clk_reg; + int i; + + if (!dev) + return ERR_PTR(-EINVAL); + + if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) { + dev_err(dev, "clk_sysctrl: invalid arguments passed\n"); + return ERR_PTR(-EINVAL); + } + + clk = devm_kzalloc(dev, sizeof(struct clk_sysctrl), GFP_KERNEL); + if (!clk) { + dev_err(dev, "clk_sysctrl: could not allocate clk\n"); + return ERR_PTR(-ENOMEM); + } + + for (i = 0; i < num_parents; i++) { + clk->reg_sel[i] = reg_sel[i]; + clk->reg_bits[i] = reg_bits[i]; + clk->reg_mask[i] = reg_mask[i]; + } + + clk->parent_index = 0; + clk->rate = rate; + clk->enable_delay_us = enable_delay_us; + clk->dev = dev; + + clk_sysctrl_init.name = name; + clk_sysctrl_init.ops = clk_sysctrl_ops; + clk_sysctrl_init.flags = flags; + clk_sysctrl_init.parent_names = parent_names; + clk_sysctrl_init.num_parents = num_parents; + clk->hw.init = &clk_sysctrl_init; + + clk_reg = devm_clk_register(clk->dev, &clk->hw); + if (IS_ERR_OR_NULL(clk_reg)) { + dev_err(dev, "clk_sysctrl: clk_register failed\n"); + return ERR_PTR(-ENOMEM); + } + + return clk_reg; +} + +struct clk *clk_reg_sysctrl_gate(struct device *dev, + const char *name, + const char *parent_name, + u16 reg_sel, + u8 reg_mask, + u8 reg_bits, + unsigned long enable_delay_us, + unsigned long flags) +{ + const char **parent_names = (parent_name ? &parent_name : NULL); + u8 num_parents = (parent_name ? 1 : 0); + + return clk_reg_sysctrl(dev, name, parent_names, num_parents, + ®_sel, ®_mask, ®_bits, 0, enable_delay_us, + flags, &clk_sysctrl_gate_ops); +} + +struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev, + const char *name, + const char *parent_name, + u16 reg_sel, + u8 reg_mask, + u8 reg_bits, + unsigned long rate, + unsigned long enable_delay_us, + unsigned long flags) +{ + const char **parent_names = (parent_name ? &parent_name : NULL); + u8 num_parents = (parent_name ? 1 : 0); + + return clk_reg_sysctrl(dev, name, parent_names, num_parents, + ®_sel, ®_mask, ®_bits, + rate, enable_delay_us, flags, + &clk_sysctrl_gate_fixed_rate_ops); +} + +struct clk *clk_reg_sysctrl_set_parent(struct device *dev, + const char *name, + const char **parent_names, + u8 num_parents, + u16 *reg_sel, + u8 *reg_mask, + u8 *reg_bits, + unsigned long flags) +{ + return clk_reg_sysctrl(dev, name, parent_names, num_parents, + reg_sel, reg_mask, reg_bits, 0, 0, flags, + &clk_sysctrl_set_parent_ops); +} diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h index c3e4491..3d2dfdc 100644 --- a/drivers/clk/ux500/clk.h +++ b/drivers/clk/ux500/clk.h @@ -11,6 +11,7 @@ #define __UX500_CLK_H #include +#include struct clk *clk_reg_prcc_pclk(const char *name, const char *parent_name, @@ -57,4 +58,32 @@ struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name, unsigned long rate, unsigned long flags); +struct clk *clk_reg_sysctrl_gate(struct device *dev, + const char *name, + const char *parent_name, + u16 reg_sel, + u8 reg_mask, + u8 reg_bits, + unsigned long enable_delay_us, + unsigned long flags); + +struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev, + const char *name, + const char *parent_name, + u16 reg_sel, + u8 reg_mask, + u8 reg_bits, + unsigned long rate, + unsigned long enable_delay_us, + unsigned long flags); + +struct clk *clk_reg_sysctrl_set_parent(struct device *dev, + const char *name, + const char **parent_names, + u8 num_parents, + u16 *reg_sel, + u8 *reg_mask, + u8 *reg_bits, + unsigned long flags); + #endif /* __UX500_CLK_H */