blob: 677b46c1a4ff7c4f94a91411239610f5e7b98548 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* 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 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/time.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/spinlock.h>
21#include <linux/delay.h>
22#include <mach/hardware.h>
23#include <asm/io.h>
24
25#include <asm/system.h>
26#include <asm/mach-types.h>
27#include <linux/semaphore.h>
28#include <linux/uaccess.h>
29#include <linux/clk.h>
30#include <mach/clk.h>
31#include <linux/platform_device.h>
32#include <linux/pm_runtime.h>
33
34#include "msm_fb.h"
35#include "mddihosti.h"
36
37static int mddi_ext_probe(struct platform_device *pdev);
38static int mddi_ext_remove(struct platform_device *pdev);
39
40static int mddi_ext_off(struct platform_device *pdev);
41static int mddi_ext_on(struct platform_device *pdev);
42
43static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
44static int pdev_list_cnt;
45
46static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state);
47static int mddi_ext_resume(struct platform_device *pdev);
48
49#ifdef CONFIG_HAS_EARLYSUSPEND
50static void mddi_ext_early_suspend(struct early_suspend *h);
51static void mddi_ext_early_resume(struct early_suspend *h);
52#endif
53
54static int mddi_ext_runtime_suspend(struct device *dev)
55{
56 dev_dbg(dev, "pm_runtime: suspending...\n");
57 return 0;
58}
59
60static int mddi_ext_runtime_resume(struct device *dev)
61{
62 dev_dbg(dev, "pm_runtime: resuming...\n");
63 return 0;
64}
65
66static int mddi_ext_runtime_idle(struct device *dev)
67{
68 dev_dbg(dev, "pm_runtime: idling...\n");
69 return 0;
70}
71static struct dev_pm_ops mddi_ext_dev_pm_ops = {
72 .runtime_suspend = mddi_ext_runtime_suspend,
73 .runtime_resume = mddi_ext_runtime_resume,
74 .runtime_idle = mddi_ext_runtime_idle,
75};
76
77static struct platform_driver mddi_ext_driver = {
78 .probe = mddi_ext_probe,
79 .remove = mddi_ext_remove,
80#ifndef CONFIG_HAS_EARLYSUSPEND
81#ifdef CONFIG_PM
82 .suspend = mddi_ext_suspend,
83 .resume = mddi_ext_resume,
84#endif
85#endif
86 .resume_early = NULL,
87 .resume = NULL,
88 .shutdown = NULL,
89 .driver = {
90 .name = "mddi_ext",
91 .pm = &mddi_ext_dev_pm_ops,
92 },
93};
94
95static struct clk *mddi_ext_clk;
96static struct clk *mddi_ext_pclk;
97static struct mddi_platform_data *mddi_ext_pdata;
98
99extern int int_mddi_ext_flag;
100
101static int mddi_ext_off(struct platform_device *pdev)
102{
103 int ret = 0;
104
105 ret = panel_next_off(pdev);
106 mddi_host_stop_ext_display();
107 pm_runtime_put(&pdev->dev);
108 return ret;
109}
110
111static int mddi_ext_on(struct platform_device *pdev)
112{
113 int ret = 0;
114 u32 clk_rate;
115 struct msm_fb_data_type *mfd;
116
117 mfd = platform_get_drvdata(pdev);
118 pm_runtime_get(&pdev->dev);
119 clk_rate = mfd->fbi->var.pixclock;
120 clk_rate = min(clk_rate, mfd->panel_info.clk_max);
121
122 if (mddi_ext_pdata &&
123 mddi_ext_pdata->mddi_sel_clk &&
124 mddi_ext_pdata->mddi_sel_clk(&clk_rate))
125 printk(KERN_ERR
126 "%s: can't select mddi io clk targate rate = %d\n",
127 __func__, clk_rate);
128
Matt Wagantalla12cc952011-11-08 18:14:50 -0800129 clk_rate = clk_round_rate(mddi_ext_clk, clk_rate);
130 if (clk_set_rate(mddi_ext_clk, clk_rate) < 0)
131 printk(KERN_ERR "%s: clk_set_rate failed\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 __func__);
133
134 mddi_host_start_ext_display();
135 ret = panel_next_on(pdev);
136
137 return ret;
138}
139
140static int mddi_ext_resource_initialized;
141
142static int mddi_ext_probe(struct platform_device *pdev)
143{
144 struct msm_fb_data_type *mfd;
145 struct platform_device *mdp_dev = NULL;
146 struct msm_fb_panel_data *pdata = NULL;
147 int rc;
148 resource_size_t size ;
149 u32 clk_rate;
150
151 if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
152 mddi_ext_pdata = pdev->dev.platform_data;
153
154 size = resource_size(&pdev->resource[0]);
155 msm_emdh_base = ioremap(pdev->resource[0].start, size);
156
157 MSM_FB_INFO("external mddi base address = 0x%x\n",
158 pdev->resource[0].start);
159
160 if (unlikely(!msm_emdh_base))
161 return -ENOMEM;
162
163 mddi_ext_resource_initialized = 1;
164 return 0;
165 }
166
167 if (!mddi_ext_resource_initialized)
168 return -EPERM;
169
170 mfd = platform_get_drvdata(pdev);
171
172 if (!mfd)
173 return -ENODEV;
174
175 if (mfd->key != MFD_KEY)
176 return -EINVAL;
177
178 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
179 return -ENOMEM;
180
181 mdp_dev = platform_device_alloc("mdp", pdev->id);
182 if (!mdp_dev)
183 return -ENOMEM;
184
185 /*
186 * link to the latest pdev
187 */
188 mfd->pdev = mdp_dev;
189 mfd->dest = DISPLAY_EXT_MDDI;
190
191 /*
192 * alloc panel device data
193 */
194 if (platform_device_add_data
195 (mdp_dev, pdev->dev.platform_data,
196 sizeof(struct msm_fb_panel_data))) {
197 printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n");
198 platform_device_put(mdp_dev);
199 return -ENOMEM;
200 }
201 /*
202 * data chain
203 */
204 pdata = mdp_dev->dev.platform_data;
205 pdata->on = mddi_ext_on;
206 pdata->off = mddi_ext_off;
207 pdata->next = pdev;
208
209 /*
210 * get/set panel specific fb info
211 */
212 mfd->panel_info = pdata->panel_info;
213 mfd->fb_imgType = MDP_RGB_565;
214
215 clk_rate = mfd->panel_info.clk_max;
216 if (mddi_ext_pdata &&
217 mddi_ext_pdata->mddi_sel_clk &&
218 mddi_ext_pdata->mddi_sel_clk(&clk_rate))
219 printk(KERN_ERR
220 "%s: can't select mddi io clk targate rate = %d\n",
221 __func__, clk_rate);
222
223 if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0)
224 printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
225 mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
226
227 /*
228 * set driver data
229 */
230 platform_set_drvdata(mdp_dev, mfd);
231 rc = pm_runtime_set_active(&pdev->dev);
232 if (rc < 0)
233 printk(KERN_ERR "pm_runtime: fail to set active\n");
234
235 rc = 0;
236 pm_runtime_enable(&pdev->dev);
237 /*
238 * register in mdp driver
239 */
240 rc = platform_device_add(mdp_dev);
241 if (rc)
242 goto mddi_ext_probe_err;
243
244 pdev_list[pdev_list_cnt++] = pdev;
245
246#ifdef CONFIG_HAS_EARLYSUSPEND
247 mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
248 mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend;
249 mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume;
250 register_early_suspend(&mfd->mddi_ext_early_suspend);
251#endif
252
253 return 0;
254
255mddi_ext_probe_err:
256 platform_device_put(mdp_dev);
257 return rc;
258}
259
260static int mddi_ext_is_in_suspend;
261
262static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state)
263{
264 if (mddi_ext_is_in_suspend)
265 return 0;
266
267 mddi_ext_is_in_suspend = 1;
268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 clk_disable(mddi_ext_clk);
270 if (mddi_ext_pclk)
271 clk_disable(mddi_ext_pclk);
272
273 disable_irq(INT_MDDI_EXT);
274
275 return 0;
276}
277
278static int mddi_ext_resume(struct platform_device *pdev)
279{
280 struct msm_fb_data_type *mfd;
281
282 mfd = platform_get_drvdata(pdev);
283
284 if (!mddi_ext_is_in_suspend)
285 return 0;
286
287 mddi_ext_is_in_suspend = 0;
288 enable_irq(INT_MDDI_EXT);
289
290 clk_enable(mddi_ext_clk);
291 if (mddi_ext_pclk)
292 clk_enable(mddi_ext_pclk);
293
294 return 0;
295}
296
297#ifdef CONFIG_HAS_EARLYSUSPEND
298static void mddi_ext_early_suspend(struct early_suspend *h)
299{
300 pm_message_t state;
301 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
302 mddi_ext_early_suspend);
303
304 state.event = PM_EVENT_SUSPEND;
305 mddi_ext_suspend(mfd->pdev, state);
306}
307
308static void mddi_ext_early_resume(struct early_suspend *h)
309{
310 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
311 mddi_ext_early_suspend);
312 mddi_ext_resume(mfd->pdev);
313}
314#endif
315
316static int mddi_ext_remove(struct platform_device *pdev)
317{
318 pm_runtim_disable(&pdev->dev);
319 iounmap(msm_emdh_base);
320 return 0;
321}
322
323static int mddi_ext_register_driver(void)
324{
325 return platform_driver_register(&mddi_ext_driver);
326}
327
328static int __init mddi_ext_driver_init(void)
329{
330 int ret;
331
332 mddi_ext_clk = clk_get(NULL, "emdh_clk");
333 if (IS_ERR(mddi_ext_clk)) {
334 printk(KERN_ERR "can't find emdh_clk\n");
335 return PTR_ERR(mddi_ext_clk);
336 }
337 clk_enable(mddi_ext_clk);
338
339 mddi_ext_pclk = clk_get(NULL, "emdh_pclk");
340 if (IS_ERR(mddi_ext_pclk))
341 mddi_ext_pclk = NULL;
342 else
343 clk_enable(mddi_ext_pclk);
344
345 ret = mddi_ext_register_driver();
346 if (ret) {
347 clk_disable(mddi_ext_clk);
348 clk_put(mddi_ext_clk);
349 if (mddi_ext_pclk) {
350 clk_disable(mddi_ext_pclk);
351 clk_put(mddi_ext_pclk);
352 }
353 printk(KERN_ERR "mddi_ext_register_driver() failed!\n");
354 return ret;
355 }
356 mddi_init();
357
358 return ret;
359}
360
361module_init(mddi_ext_driver_init);