• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/staging/msm/
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);
376