Merge branch 'setlocalversion-speedup' into kbuild/rc-fixes
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / msm / mddi.c
CommitLineData
9d200153
SM
1/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/sched.h>
21#include <linux/time.h>
22#include <linux/init.h>
23#include <linux/interrupt.h>
24#include <linux/spinlock.h>
25#include <linux/delay.h>
26#include <mach/hardware.h>
27#include <asm/io.h>
28
29#include <asm/system.h>
30#include <asm/mach-types.h>
31#include <linux/semaphore.h>
32#include <linux/uaccess.h>
33#include <linux/clk.h>
34#include <linux/platform_device.h>
35
36#include "msm_fb.h"
37#include "mddihosti.h"
38#include "mddihost.h"
39#include <mach/gpio.h>
40#include <mach/clk.h>
41
42static int mddi_probe(struct platform_device *pdev);
43static int mddi_remove(struct platform_device *pdev);
44
45static int mddi_off(struct platform_device *pdev);
46static int mddi_on(struct platform_device *pdev);
47
48static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
49static int mddi_resume(struct platform_device *pdev);
50
51#ifdef CONFIG_HAS_EARLYSUSPEND
52static void mddi_early_suspend(struct early_suspend *h);
53static void mddi_early_resume(struct early_suspend *h);
54#endif
55
56static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
57static int pdev_list_cnt;
58static struct clk *mddi_clk;
59static struct clk *mddi_pclk;
60static struct mddi_platform_data *mddi_pdata;
61
62static struct platform_driver mddi_driver = {
63 .probe = mddi_probe,
64 .remove = mddi_remove,
65#ifndef CONFIG_HAS_EARLYSUSPEND
66#ifdef CONFIG_PM
67 .suspend = mddi_suspend,
68 .resume = mddi_resume,
69#endif
70#endif
71 .suspend_late = NULL,
72 .resume_early = NULL,
73 .shutdown = NULL,
74 .driver = {
75 .name = "mddi",
76 },
77};
78
79extern int int_mddi_pri_flag;
80
81static int mddi_off(struct platform_device *pdev)
82{
83 int ret = 0;
84
85 ret = panel_next_off(pdev);
86
87 if (mddi_pdata && mddi_pdata->mddi_power_save)
88 mddi_pdata->mddi_power_save(0);
89
90 return ret;
91}
92
93static int mddi_on(struct platform_device *pdev)
94{
95 int ret = 0;
96 u32 clk_rate;
97 struct msm_fb_data_type *mfd;
98
99 mfd = platform_get_drvdata(pdev);
100
101 if (mddi_pdata && mddi_pdata->mddi_power_save)
102 mddi_pdata->mddi_power_save(1);
103
104 clk_rate = mfd->fbi->var.pixclock;
105 clk_rate = min(clk_rate, mfd->panel_info.clk_max);
106
107 if (mddi_pdata &&
108 mddi_pdata->mddi_sel_clk &&
109 mddi_pdata->mddi_sel_clk(&clk_rate))
110 printk(KERN_ERR
111 "%s: can't select mddi io clk targate rate = %d\n",
112 __func__, clk_rate);
113
114 if (clk_set_min_rate(mddi_clk, clk_rate) < 0)
115 printk(KERN_ERR "%s: clk_set_min_rate failed\n",
116 __func__);
117
118 ret = panel_next_on(pdev);
119
120 return ret;
121}
122
123static int mddi_resource_initialized;
124
125static int mddi_probe(struct platform_device *pdev)
126{
127 struct msm_fb_data_type *mfd;
128 struct platform_device *mdp_dev = NULL;
129 struct msm_fb_panel_data *pdata = NULL;
130 int rc;
131 resource_size_t size ;
132 u32 clk_rate;
133
134 if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
135 mddi_pdata = pdev->dev.platform_data;
136
137 size = resource_size(&pdev->resource[0]);
138 msm_pmdh_base = ioremap(pdev->resource[0].start, size);
139
140 MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n",
141 pdev->resource[0].start, (int) msm_pmdh_base);
142
143 if (unlikely(!msm_pmdh_base))
144 return -ENOMEM;
145
146 if (mddi_pdata && mddi_pdata->mddi_power_save)
147 mddi_pdata->mddi_power_save(1);
148
149 mddi_resource_initialized = 1;
150 return 0;
151 }
152
153 if (!mddi_resource_initialized)
154 return -EPERM;
155
156 mfd = platform_get_drvdata(pdev);
157
158 if (!mfd)
159 return -ENODEV;
160
161 if (mfd->key != MFD_KEY)
162 return -EINVAL;
163
164 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
165 return -ENOMEM;
166
167 mdp_dev = platform_device_alloc("mdp", pdev->id);
168 if (!mdp_dev)
169 return -ENOMEM;
170
171 /*
172 * link to the latest pdev
173 */
174 mfd->pdev = mdp_dev;
175 mfd->dest = DISPLAY_LCD;
176
177 /*
178 * alloc panel device data
179 */
180 if (platform_device_add_data
181 (mdp_dev, pdev->dev.platform_data,
182 sizeof(struct msm_fb_panel_data))) {
183 printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n");
184 platform_device_put(mdp_dev);
185 return -ENOMEM;
186 }
187 /*
188 * data chain
189 */
190 pdata = mdp_dev->dev.platform_data;
191 pdata->on = mddi_on;
192 pdata->off = mddi_off;
193 pdata->next = pdev;
194
195 /*
196 * get/set panel specific fb info
197 */
198 mfd->panel_info = pdata->panel_info;
199 mfd->fb_imgType = MDP_RGB_565;
200
201 clk_rate = mfd->panel_info.clk_max;
202 if (mddi_pdata &&
203 mddi_pdata->mddi_sel_clk &&
204 mddi_pdata->mddi_sel_clk(&clk_rate))
205 printk(KERN_ERR
206 "%s: can't select mddi io clk targate rate = %d\n",
207 __func__, clk_rate);
208
209 if (clk_set_max_rate(mddi_clk, clk_rate) < 0)
210 printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
211 mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
212
213 /*
214 * set driver data
215 */
216 platform_set_drvdata(mdp_dev, mfd);
217
218 /*
219 * register in mdp driver
220 */
221 rc = platform_device_add(mdp_dev);
222 if (rc)
223 goto mddi_probe_err;
224
225 pdev_list[pdev_list_cnt++] = pdev;
226
227#ifdef CONFIG_HAS_EARLYSUSPEND
228 mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
229 mfd->mddi_early_suspend.suspend = mddi_early_suspend;
230 mfd->mddi_early_suspend.resume = mddi_early_resume;
231 register_early_suspend(&mfd->mddi_early_suspend);
232#endif
233
234 return 0;
235
236mddi_probe_err:
237 platform_device_put(mdp_dev);
238 return rc;
239}
240
241static int mddi_pad_ctrl;
242static int mddi_power_locked;
243static int mddi_is_in_suspend;
244
245void mddi_disable(int lock)
246{
247 mddi_host_type host_idx = MDDI_HOST_PRIM;
248
249 if (mddi_power_locked)
250 return;
251
252 if (lock)
253 mddi_power_locked = 1;
254
255 if (mddi_host_timer.function)
256 del_timer_sync(&mddi_host_timer);
257
258 mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
259 mddi_host_reg_out(PAD_CTL, 0x0);
260
261 if (clk_set_min_rate(mddi_clk, 0) < 0)
262 printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
263
264 clk_disable(mddi_clk);
265 if (mddi_pclk)
266 clk_disable(mddi_pclk);
267 disable_irq(INT_MDDI_PRI);
268
269 if (mddi_pdata && mddi_pdata->mddi_power_save)
270 mddi_pdata->mddi_power_save(0);
271}
272
273static int mddi_suspend(struct platform_device *pdev, pm_message_t state)
274{
275 if (mddi_is_in_suspend)
276 return 0;
277
278 mddi_is_in_suspend = 1;
279 mddi_disable(0);
280 return 0;
281}
282
283static int mddi_resume(struct platform_device *pdev)
284{
285 mddi_host_type host_idx = MDDI_HOST_PRIM;
286
287 if (!mddi_is_in_suspend)
288 return 0;
289
290 mddi_is_in_suspend = 0;
291
292 if (mddi_power_locked)
293 return 0;
294
295 enable_irq(INT_MDDI_PRI);
296 clk_enable(mddi_clk);
297 if (mddi_pclk)
298 clk_enable(mddi_pclk);
299 mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl);
300
301 if (mddi_host_timer.function)
302 mddi_host_timer_service(0);
303
304 return 0;
305}
306
307#ifdef CONFIG_HAS_EARLYSUSPEND
308static void mddi_early_suspend(struct early_suspend *h)
309{
310 pm_message_t state;
311 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
312 mddi_early_suspend);
313
314 state.event = PM_EVENT_SUSPEND;
315 mddi_suspend(mfd->pdev, state);
316}
317
318static void mddi_early_resume(struct early_suspend *h)
319{
320 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
321 mddi_early_suspend);
322 mddi_resume(mfd->pdev);
323}
324#endif
325
326static int mddi_remove(struct platform_device *pdev)
327{
328 if (mddi_host_timer.function)
329 del_timer_sync(&mddi_host_timer);
330
331 iounmap(msm_pmdh_base);
332
333 return 0;
334}
335
336static int mddi_register_driver(void)
337{
338 return platform_driver_register(&mddi_driver);
339}
340
341static int __init mddi_driver_init(void)
342{
343 int ret;
344
345 mddi_clk = clk_get(NULL, "mddi_clk");
346 if (IS_ERR(mddi_clk)) {
347 printk(KERN_ERR "can't find mddi_clk \n");
348 return PTR_ERR(mddi_clk);
349 }
350 clk_enable(mddi_clk);
351
352 mddi_pclk = clk_get(NULL, "mddi_pclk");
353 if (IS_ERR(mddi_pclk))
354 mddi_pclk = NULL;
355 else
356 clk_enable(mddi_pclk);
357
358 ret = mddi_register_driver();
359 if (ret) {
360 clk_disable(mddi_clk);
361 clk_put(mddi_clk);
362 if (mddi_pclk) {
363 clk_disable(mddi_pclk);
364 clk_put(mddi_pclk);
365 }
366 printk(KERN_ERR "mddi_register_driver() failed!\n");
367 return ret;
368 }
369
370 mddi_init();
371
372 return ret;
373}
374
375module_init(mddi_driver_init);