upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / dev-pd.c
1 /* linux/arch/arm/mach-s5pv310/dev-pd.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * S5PV310 - Power Domain support
7  *
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.
11 */
12
13 #include <linux/io.h>
14 #include <linux/kernel.h>
15 #include <linux/platform_device.h>
16 #include <linux/delay.h>
17
18 #include <plat/pd.h>
19
20 #include <mach/regs-pmu.h>
21 #include <mach/regs-clock.h>
22
23 static int s5pv310_pd_init(struct device *dev)
24 {
25         struct samsung_pd_info *pdata =  dev->platform_data;
26         struct s5pv310_pd_data *data = (struct s5pv310_pd_data *) pdata->data;
27
28         if (data->read_phy_addr) {
29                 data->read_base = ioremap(data->read_phy_addr, SZ_4K);
30                 if (!data->read_base)
31                         return -ENOMEM;
32         }
33
34         return 0;
35 }
36
37 int s5pv310_pd_enable(struct device *dev)
38 {
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;
42         u32 timeout;
43         u32 gate_block_reg, tmp = 0;
44
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)))
51                 return 0;
52
53         if (data->read_base)
54                 /*  save IP clock gating register */
55                 tmp = __raw_readl(data->clk_base);
56
57         /*  enable all the clocks of IPs in the power domain */
58         __raw_writel(0xffffffff, data->clk_base);
59
60         __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base);
61
62         /* Wait max 5ms warn at 1ms */
63         timeout = 50;
64         while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN)
65                 != S5P_INT_LOCAL_PWR_EN) {
66                 if (timeout == 40)
67                         pr_warn("Power domain %s enable taking too much time.\n",
68                                         dev_name(dev));
69                 if (timeout == 0) {
70                         pr_err("Power domain %s enable failed.\n",
71                                 dev_name(dev));
72                         return -ETIMEDOUT;
73                 }
74                 timeout--;
75                 udelay(100);
76         }
77
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);
82
83         if (data->read_base) {
84                 /* dummy read to check the completion of power-on sequence */
85                 __raw_readl(data->read_base);
86
87                 /* restore IP clock gating register */
88                 __raw_writel(tmp, data->clk_base);
89         }
90
91         return 0;
92 }
93
94 static int s5pv310_pd_disable(struct device *dev)
95 {
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;
100
101         __raw_writel(0, pdata->base);
102
103         /* Wait max 1ms */
104         timeout = 10;
105         while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) {
106                 if (timeout == 0) {
107                         printk(KERN_ERR "Power domain %s disable failed.\n",
108                                 dev_name(dev));
109                         return -ETIMEDOUT;
110                 }
111                 timeout--;
112                 udelay(100);
113         }
114
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);
119
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);
123
124         return 0;
125 }
126
127 struct platform_device s5pv310_device_pd[] = {
128         [PD_CAM] = {
129                 .name           = "samsung-pd",
130                 .id             = PD_CAM,
131                 .dev = {
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,
140                                 },
141                         },
142                 },
143         },
144         [PD_TV] = {
145                 .name           = "samsung-pd",
146                 .id             = PD_TV,
147                 .dev = {
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,
156                                 },
157                         },
158                 },
159         },
160         [PD_MFC] = {
161                 .name           = "samsung-pd",
162                 .id             = PD_MFC,
163                 .dev = {
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,
172                                 },
173                         },
174                 },
175         },
176         [PD_G3D] = {
177                 .name           = "samsung-pd",
178                 .id             = PD_G3D,
179                 .dev = {
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,
188                                 },
189                         },
190                 },
191         },
192         [PD_LCD0] = {
193                 .name           = "samsung-pd",
194                 .id             = PD_LCD0,
195                 .dev = {
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,
204                                 },
205                         },
206                 },
207         },
208         [PD_LCD1] = {
209                 .name           = "samsung-pd",
210                 .id             = PD_LCD1,
211                 .dev = {
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,
220                                 },
221                         },
222                 },
223         },
224         [PD_GPS] = {
225                 .name           = "samsung-pd",
226                 .id             = PD_GPS,
227                 .dev = {
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,
236                                 },
237                         },
238                 },
239         },
240 };
241 EXPORT_SYMBOL(s5pv310_device_pd);