2 * vlv2_plat_clock.c - VLV2 platform clock driver
3 * Copyright (C) 2013 Intel Corporation
5 * Author: Asutosh Pathak <asutosh.pathak@intel.com>
6 * Author: Chandra Sekhar Anagani <chandra.sekhar.anagani@intel.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 #include <linux/err.h>
24 #include <linux/init.h>
25 #include <linux/platform_device.h>
26 #include "../../include/linux/vlv2_plat_clock.h"
28 /* NOTE: Most of below constants could come from platform data.
29 * To be fixed when appropriate ACPI support comes.
31 #define VLV2_PMC_CLK_BASE_ADDRESS 0xfed03060
32 #define PLT_CLK_CTL_OFFSET(x) (0x04 * (x))
34 #define CLK_CONFG_BIT_POS 0
35 #define CLK_CONFG_BIT_LEN 2
36 #define CLK_CONFG_D3_GATED 0
37 #define CLK_CONFG_FORCE_ON 1
38 #define CLK_CONFG_FORCE_OFF 2
40 #define CLK_FREQ_TYPE_BIT_POS 2
41 #define CLK_FREQ_TYPE_BIT_LEN 1
42 #define CLK_FREQ_TYPE_XTAL 0 /* 25 MHz */
43 #define CLK_FREQ_TYPE_PLL 1 /* 19.2 MHz */
45 #define MAX_CLK_COUNT 5
47 /* Helper macros to manipulate bitfields */
48 #define REG_MASK(n) (((1 << (n##_BIT_LEN)) - 1) << (n##_BIT_POS))
49 #define REG_SET_FIELD(r, n, v) (((r) & ~REG_MASK(n)) | \
50 (((v) << (n##_BIT_POS)) & REG_MASK(n)))
51 #define REG_GET_FIELD(r, n) (((r) & REG_MASK(n)) >> n##_BIT_POS)
53 * vlv2 platform has 6 platform clocks, controlled by 4 byte registers
54 * Total size required for mapping is 6*4 = 24 bytes
56 #define PMC_MAP_SIZE 24
58 static DEFINE_MUTEX(clk_mutex);
59 static void __iomem *pmc_base;
62 * vlv2_plat_set_clock_freq - Set clock frequency to a specified platform clock
63 * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
64 * @freq_type: Clock frequency (0-25 MHz(XTAL), 1-19.2 MHz(PLL) )
66 int vlv2_plat_set_clock_freq(int clk_num, int freq_type)
70 if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
71 pr_err("Clock number out of range (%d)\n", clk_num);
75 if (freq_type != CLK_FREQ_TYPE_XTAL &&
76 freq_type != CLK_FREQ_TYPE_PLL) {
77 pr_err("wrong clock type\n");
82 pr_err("memio map is not set\n");
86 addr = pmc_base + PLT_CLK_CTL_OFFSET(clk_num);
88 mutex_lock(&clk_mutex);
89 writel(REG_SET_FIELD(readl(addr), CLK_FREQ_TYPE, freq_type), addr);
90 mutex_unlock(&clk_mutex);
94 EXPORT_SYMBOL_GPL(vlv2_plat_set_clock_freq);
97 * vlv2_plat_get_clock_freq - Get the status of specified platform clock
98 * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
100 * Returns 0 for 25 MHz(XTAL) and 1 for 19.2 MHz(PLL)
102 int vlv2_plat_get_clock_freq(int clk_num)
106 if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
107 pr_err("Clock number out of range (%d)\n", clk_num);
112 pr_err("memio map is not set\n");
116 mutex_lock(&clk_mutex);
117 ret = REG_GET_FIELD(readl(pmc_base + PLT_CLK_CTL_OFFSET(clk_num)),
119 mutex_unlock(&clk_mutex);
122 EXPORT_SYMBOL_GPL(vlv2_plat_get_clock_freq);
125 * vlv2_plat_configure_clock - Configure the specified platform clock
126 * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
127 * @conf: Clock gating:
128 * 0 - Clock gated on D3 state
132 int vlv2_plat_configure_clock(int clk_num, u32 conf)
136 if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
137 pr_err("Clock number out of range (%d)\n", clk_num);
141 if (conf != CLK_CONFG_D3_GATED &&
142 conf != CLK_CONFG_FORCE_ON &&
143 conf != CLK_CONFG_FORCE_OFF) {
144 pr_err("Invalid clock configuration requested\n");
149 pr_err("memio map is not set\n");
153 addr = pmc_base + PLT_CLK_CTL_OFFSET(clk_num);
155 mutex_lock(&clk_mutex);
156 writel(REG_SET_FIELD(readl(addr), CLK_CONFG, conf), addr);
157 mutex_unlock(&clk_mutex);
160 EXPORT_SYMBOL_GPL(vlv2_plat_configure_clock);
163 * vlv2_plat_get_clock_status - Get the status of specified platform clock
164 * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
166 * Returns 1 - On, 0 - Off
168 int vlv2_plat_get_clock_status(int clk_num)
172 if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
173 pr_err("Clock number out of range (%d)\n", clk_num);
178 pr_err("memio map is not set\n");
182 mutex_lock(&clk_mutex);
183 ret = (int)REG_GET_FIELD(readl(pmc_base + PLT_CLK_CTL_OFFSET(clk_num)),
185 mutex_unlock(&clk_mutex);
188 EXPORT_SYMBOL_GPL(vlv2_plat_get_clock_status);
190 static int vlv2_plat_clk_probe(struct platform_device *pdev)
194 pmc_base = ioremap_nocache(VLV2_PMC_CLK_BASE_ADDRESS, PMC_MAP_SIZE);
196 dev_err(&pdev->dev, "I/O memory remapping failed\n");
200 /* Initialize all clocks as disabled */
201 for (i = 0; i < MAX_CLK_COUNT; i++)
202 vlv2_plat_configure_clock(i, CLK_CONFG_FORCE_OFF);
204 dev_info(&pdev->dev, "vlv2_plat_clk initialized\n");
208 static const struct platform_device_id vlv2_plat_clk_id[] = {
209 {"vlv2_plat_clk", 0},
213 static int vlv2_resume(struct device *device)
217 /* Initialize all clocks as disabled */
218 for (i = 0; i < MAX_CLK_COUNT; i++)
219 vlv2_plat_configure_clock(i, CLK_CONFG_FORCE_OFF);
224 static int vlv2_suspend(struct device *device)
229 static const struct dev_pm_ops vlv2_pm_ops = {
230 .suspend = vlv2_suspend,
231 .resume = vlv2_resume,
234 static struct platform_driver vlv2_plat_clk_driver = {
235 .probe = vlv2_plat_clk_probe,
236 .id_table = vlv2_plat_clk_id,
238 .name = "vlv2_plat_clk",
243 static int __init vlv2_plat_clk_init(void)
245 return platform_driver_register(&vlv2_plat_clk_driver);
247 arch_initcall(vlv2_plat_clk_init);