RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / msm / mddi_ext.c
blobc0c168c7199d9dde4840997db03c6eca372e4df6
1 /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
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.
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.
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.
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>
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 <mach/clk.h>
35 #include <linux/platform_device.h>
37 #include "msm_fb.h"
38 #include "mddihosti.h"
40 static int mddi_ext_probe(struct platform_device *pdev);
41 static int mddi_ext_remove(struct platform_device *pdev);
43 static int mddi_ext_off(struct platform_device *pdev);
44 static int mddi_ext_on(struct platform_device *pdev);
46 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
47 static int pdev_list_cnt;
49 static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state);
50 static int mddi_ext_resume(struct platform_device *pdev);
52 #ifdef CONFIG_HAS_EARLYSUSPEND
53 static void mddi_ext_early_suspend(struct early_suspend *h);
54 static void mddi_ext_early_resume(struct early_suspend *h);
55 #endif
57 static struct platform_driver mddi_ext_driver = {
58 .probe = mddi_ext_probe,
59 .remove = mddi_ext_remove,
60 #ifndef CONFIG_HAS_EARLYSUSPEND
61 #ifdef CONFIG_PM
62 .suspend = mddi_ext_suspend,
63 .resume = mddi_ext_resume,
64 #endif
65 #endif
66 .resume_early = NULL,
67 .resume = NULL,
68 .shutdown = NULL,
69 .driver = {
70 .name = "mddi_ext",
74 static struct clk *mddi_ext_clk;
75 static struct mddi_platform_data *mddi_ext_pdata;
77 extern int int_mddi_ext_flag;
79 static int mddi_ext_off(struct platform_device *pdev)
81 int ret = 0;
83 ret = panel_next_off(pdev);
84 mddi_host_stop_ext_display();
86 return ret;
89 static int mddi_ext_on(struct platform_device *pdev)
91 int ret = 0;
92 u32 clk_rate;
93 struct msm_fb_data_type *mfd;
95 mfd = platform_get_drvdata(pdev);
97 clk_rate = mfd->fbi->var.pixclock;
98 clk_rate = min(clk_rate, mfd->panel_info.clk_max);
100 if (mddi_ext_pdata &&
101 mddi_ext_pdata->mddi_sel_clk &&
102 mddi_ext_pdata->mddi_sel_clk(&clk_rate))
103 printk(KERN_ERR
104 "%s: can't select mddi io clk targate rate = %d\n",
105 __func__, clk_rate);
107 if (clk_set_min_rate(mddi_ext_clk, clk_rate) < 0)
108 printk(KERN_ERR "%s: clk_set_min_rate failed\n",
109 __func__);
111 mddi_host_start_ext_display();
112 ret = panel_next_on(pdev);
114 return ret;
117 static int mddi_ext_resource_initialized;
119 static int mddi_ext_probe(struct platform_device *pdev)
121 struct msm_fb_data_type *mfd;
122 struct platform_device *mdp_dev = NULL;
123 struct msm_fb_panel_data *pdata = NULL;
124 int rc;
125 resource_size_t size ;
126 u32 clk_rate;
128 if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
129 mddi_ext_pdata = pdev->dev.platform_data;
131 size = resource_size(&pdev->resource[0]);
132 msm_emdh_base = ioremap(pdev->resource[0].start, size);
134 MSM_FB_INFO("external mddi base address = 0x%x\n",
135 pdev->resource[0].start);
137 if (unlikely(!msm_emdh_base))
138 return -ENOMEM;
140 mddi_ext_resource_initialized = 1;
141 return 0;
144 if (!mddi_ext_resource_initialized)
145 return -EPERM;
147 mfd = platform_get_drvdata(pdev);
149 if (!mfd)
150 return -ENODEV;
152 if (mfd->key != MFD_KEY)
153 return -EINVAL;
155 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
156 return -ENOMEM;
158 mdp_dev = platform_device_alloc("mdp", pdev->id);
159 if (!mdp_dev)
160 return -ENOMEM;
163 * link to the latest pdev
165 mfd->pdev = mdp_dev;
166 mfd->dest = DISPLAY_EXT_MDDI;
169 * alloc panel device data
171 if (platform_device_add_data
172 (mdp_dev, pdev->dev.platform_data,
173 sizeof(struct msm_fb_panel_data))) {
174 printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n");
175 platform_device_put(mdp_dev);
176 return -ENOMEM;
179 * data chain
181 pdata = mdp_dev->dev.platform_data;
182 pdata->on = mddi_ext_on;
183 pdata->off = mddi_ext_off;
184 pdata->next = pdev;
187 * get/set panel specific fb info
189 mfd->panel_info = pdata->panel_info;
190 mfd->fb_imgType = MDP_RGB_565;
192 clk_rate = mfd->panel_info.clk_max;
193 if (mddi_ext_pdata &&
194 mddi_ext_pdata->mddi_sel_clk &&
195 mddi_ext_pdata->mddi_sel_clk(&clk_rate))
196 printk(KERN_ERR
197 "%s: can't select mddi io clk targate rate = %d\n",
198 __func__, clk_rate);
200 if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0)
201 printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
202 mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
205 * set driver data
207 platform_set_drvdata(mdp_dev, mfd);
210 * register in mdp driver
212 rc = platform_device_add(mdp_dev);
213 if (rc)
214 goto mddi_ext_probe_err;
216 pdev_list[pdev_list_cnt++] = pdev;
218 #ifdef CONFIG_HAS_EARLYSUSPEND
219 mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
220 mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend;
221 mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume;
222 register_early_suspend(&mfd->mddi_ext_early_suspend);
223 #endif
225 return 0;
227 mddi_ext_probe_err:
228 platform_device_put(mdp_dev);
229 return rc;
232 static int mddi_ext_is_in_suspend;
234 static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state)
236 if (mddi_ext_is_in_suspend)
237 return 0;
239 mddi_ext_is_in_suspend = 1;
241 if (clk_set_min_rate(mddi_ext_clk, 0) < 0)
242 printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
244 clk_disable(mddi_ext_clk);
245 disable_irq(INT_MDDI_EXT);
247 return 0;
250 static int mddi_ext_resume(struct platform_device *pdev)
252 struct msm_fb_data_type *mfd;
254 mfd = platform_get_drvdata(pdev);
256 if (!mddi_ext_is_in_suspend)
257 return 0;
259 mddi_ext_is_in_suspend = 0;
260 enable_irq(INT_MDDI_EXT);
262 clk_enable(mddi_ext_clk);
264 return 0;
267 #ifdef CONFIG_HAS_EARLYSUSPEND
268 static void mddi_ext_early_suspend(struct early_suspend *h)
270 pm_message_t state;
271 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
272 mddi_ext_early_suspend);
274 state.event = PM_EVENT_SUSPEND;
275 mddi_ext_suspend(mfd->pdev, state);
278 static void mddi_ext_early_resume(struct early_suspend *h)
280 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
281 mddi_ext_early_suspend);
282 mddi_ext_resume(mfd->pdev);
284 #endif
286 static int mddi_ext_remove(struct platform_device *pdev)
288 iounmap(msm_emdh_base);
289 return 0;
292 static int mddi_ext_register_driver(void)
294 return platform_driver_register(&mddi_ext_driver);
297 static int __init mddi_ext_driver_init(void)
299 int ret;
301 mddi_ext_clk = clk_get(NULL, "emdh_clk");
302 if (IS_ERR(mddi_ext_clk)) {
303 printk(KERN_ERR "can't find emdh_clk\n");
304 return PTR_ERR(mddi_ext_clk);
306 clk_enable(mddi_ext_clk);
308 ret = mddi_ext_register_driver();
309 if (ret) {
310 clk_disable(mddi_ext_clk);
311 clk_put(mddi_ext_clk);
312 printk(KERN_ERR "mddi_ext_register_driver() failed!\n");
313 return ret;
315 mddi_init();
317 return ret;
320 module_init(mddi_ext_driver_init);