1 /* linux/arch/arm/mach-s5pv310/dev-pd.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * S5PV310 - Power Domain support
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
14 #include <linux/kernel.h>
15 #include <linux/platform_device.h>
16 #include <linux/delay.h>
20 #include <mach/regs-pmu.h>
21 #include <mach/regs-clock.h>
23 static int s5pv310_pd_init(struct device *dev)
25 struct samsung_pd_info *pdata = dev->platform_data;
26 struct s5pv310_pd_data *data = (struct s5pv310_pd_data *) pdata->data;
28 if (data->read_phy_addr) {
29 data->read_base = ioremap(data->read_phy_addr, SZ_4K);
37 int s5pv310_pd_enable(struct device *dev)
39 struct platform_device *pdev = to_platform_device(dev);
40 struct samsung_pd_info *pdata = dev->platform_data;
41 struct s5pv310_pd_data *data = (struct s5pv310_pd_data *) pdata->data;
43 u32 gate_block_reg, tmp = 0;
45 /* Skip if it's already enabled */
46 if (((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN)
47 == S5P_INT_LOCAL_PWR_EN) &&
48 ((__raw_readl(pdata->base) & S5P_INT_LOCAL_PWR_EN)
49 == S5P_INT_LOCAL_PWR_EN) &&
50 (__raw_readl(S5P_CLKGATE_BLOCK) & (1 << pdev->id)))
54 /* save IP clock gating register */
55 tmp = __raw_readl(data->clk_base);
57 /* enable all the clocks of IPs in the power domain */
58 __raw_writel(0xffffffff, data->clk_base);
60 __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base);
62 /* Wait max 5ms warn at 1ms */
64 while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN)
65 != S5P_INT_LOCAL_PWR_EN) {
67 pr_warn("Power domain %s enable taking too much time.\n",
70 pr_err("Power domain %s enable failed.\n",
78 /* enable gate block. */
79 gate_block_reg = __raw_readl(S5P_CLKGATE_BLOCK);
80 gate_block_reg |= (1 << pdev->id);
81 __raw_writel(gate_block_reg, S5P_CLKGATE_BLOCK);
83 if (data->read_base) {
84 /* dummy read to check the completion of power-on sequence */
85 __raw_readl(data->read_base);
87 /* restore IP clock gating register */
88 __raw_writel(tmp, data->clk_base);
94 static int s5pv310_pd_disable(struct device *dev)
96 struct platform_device *pdev = to_platform_device(dev);
97 struct samsung_pd_info *pdata = dev->platform_data;
98 struct s5pv310_pd_data *data = (struct s5pv310_pd_data *) pdata->data;
99 u32 gate_block_reg, timeout;
101 __raw_writel(0, pdata->base);
105 while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) {
107 printk(KERN_ERR "Power domain %s disable failed.\n",
115 /* disable gate block. */
116 gate_block_reg = __raw_readl(S5P_CLKGATE_BLOCK);
117 gate_block_reg &= ~(1 << pdev->id);
118 __raw_writel(gate_block_reg, S5P_CLKGATE_BLOCK);
120 /* disable all the clocks of IPs in the power domain */
121 if (data->clk_disable_value && !data->read_base)
122 __raw_writel(data->clk_disable_value, data->clk_base);
127 struct platform_device s5pv310_device_pd[] = {
129 .name = "samsung-pd",
132 .platform_data = &(struct samsung_pd_info) {
133 .init = s5pv310_pd_init,
134 .enable = s5pv310_pd_enable,
135 .disable = s5pv310_pd_disable,
136 .base = S5P_PMU_CAM_CONF,
137 .data = &(struct s5pv310_pd_data) {
138 .clk_base = S5P_CLKGATE_IP_CAM,
139 .read_phy_addr = S5PV310_PA_FIMC0,
145 .name = "samsung-pd",
148 .platform_data = &(struct samsung_pd_info) {
149 .init = s5pv310_pd_init,
150 .enable = s5pv310_pd_enable,
151 .disable = s5pv310_pd_disable,
152 .base = S5P_PMU_TV_CONF,
153 .data = &(struct s5pv310_pd_data) {
154 .clk_base = S5P_CLKGATE_IP_TV,
155 .read_phy_addr = S5PV310_PA_VP,
161 .name = "samsung-pd",
164 .platform_data = &(struct samsung_pd_info) {
165 .init = s5pv310_pd_init,
166 .enable = s5pv310_pd_enable,
167 .disable = s5pv310_pd_disable,
168 .base = S5P_PMU_MFC_CONF,
169 .data = &(struct s5pv310_pd_data) {
170 .clk_base = S5P_CLKGATE_IP_MFC,
171 .clk_disable_value = 0xffffffe0,
177 .name = "samsung-pd",
180 .platform_data = &(struct samsung_pd_info) {
181 .init = s5pv310_pd_init,
182 .enable = s5pv310_pd_enable,
183 .disable = s5pv310_pd_disable,
184 .base = S5P_PMU_G3D_CONF,
185 .data = &(struct s5pv310_pd_data) {
186 .clk_base = S5P_CLKGATE_IP_G3D,
187 .clk_disable_value = 0xfffffff8,
193 .name = "samsung-pd",
196 .platform_data = &(struct samsung_pd_info) {
197 .init = s5pv310_pd_init,
198 .enable = s5pv310_pd_enable,
199 .disable = s5pv310_pd_disable,
200 .base = S5P_PMU_LCD0_CONF,
201 .data = &(struct s5pv310_pd_data) {
202 .clk_base = S5P_CLKGATE_IP_LCD0,
203 .read_phy_addr = S5PV310_PA_LCD0,
209 .name = "samsung-pd",
212 .platform_data = &(struct samsung_pd_info) {
213 .init = s5pv310_pd_init,
214 .enable = s5pv310_pd_enable,
215 .disable = s5pv310_pd_disable,
216 .base = S5P_PMU_LCD1_CONF,
217 .data = &(struct s5pv310_pd_data) {
218 .clk_base = S5P_CLKGATE_IP_LCD1,
219 .read_phy_addr = S5PV310_PA_LCD1,
225 .name = "samsung-pd",
228 .platform_data = &(struct samsung_pd_info) {
229 .init = s5pv310_pd_init,
230 .enable = s5pv310_pd_enable,
231 .disable = s5pv310_pd_disable,
232 .base = S5P_PMU_GPS_CONF,
233 .data = &(struct s5pv310_pd_data) {
234 .clk_base = S5P_CLKGATE_IP_GPS,
235 .clk_disable_value = 0xfffffffc,
241 EXPORT_SYMBOL(s5pv310_device_pd);