Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
[sfrench/cifs-2.6.git] / drivers / staging / msm / mddi.c
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
42 static int mddi_probe(struct platform_device *pdev);
43 static int mddi_remove(struct platform_device *pdev);
44
45 static int mddi_off(struct platform_device *pdev);
46 static int mddi_on(struct platform_device *pdev);
47
48 static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
49 static int mddi_resume(struct platform_device *pdev);
50
51 #ifdef CONFIG_HAS_EARLYSUSPEND
52 static void mddi_early_suspend(struct early_suspend *h);
53 static void mddi_early_resume(struct early_suspend *h);
54 #endif
55
56 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
57 static int pdev_list_cnt;
58 static struct clk *mddi_clk;
59 static struct clk *mddi_pclk;
60 static struct mddi_platform_data *mddi_pdata;
61
62 static 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
79 extern int int_mddi_pri_flag;
80
81 static 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
93 static 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
123 static int mddi_resource_initialized;
124
125 static 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
236 mddi_probe_err:
237         platform_device_put(mdp_dev);
238         return rc;
239 }
240
241 static int mddi_pad_ctrl;
242 static int mddi_power_locked;
243 static int mddi_is_in_suspend;
244
245 void 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
273 static 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
283 static 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
308 static 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
318 static 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
326 static 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
336 static int mddi_register_driver(void)
337 {
338         return platform_driver_register(&mddi_driver);
339 }
340
341 static 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
375 module_init(mddi_driver_init);