Commit | Line | Data |
---|---|---|
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 <linux/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 | #include <linux/pm_qos_params.h> | |
36 | ||
37 | #define TVENC_C | |
38 | #include "tvenc.h" | |
39 | #include "msm_fb.h" | |
40 | ||
41 | static int tvenc_probe(struct platform_device *pdev); | |
42 | static int tvenc_remove(struct platform_device *pdev); | |
43 | ||
44 | static int tvenc_off(struct platform_device *pdev); | |
45 | static int tvenc_on(struct platform_device *pdev); | |
46 | ||
47 | static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; | |
48 | static int pdev_list_cnt; | |
49 | ||
50 | static struct clk *tvenc_clk; | |
51 | static struct clk *tvdac_clk; | |
52 | ||
53 | static struct platform_driver tvenc_driver = { | |
54 | .probe = tvenc_probe, | |
55 | .remove = tvenc_remove, | |
56 | .suspend = NULL, | |
57 | // .suspend_late = NULL, | |
58 | // .resume_early = NULL, | |
59 | .resume = NULL, | |
60 | .shutdown = NULL, | |
61 | .driver = { | |
62 | .name = "tvenc", | |
63 | }, | |
64 | }; | |
65 | ||
66 | static struct tvenc_platform_data *tvenc_pdata; | |
67 | ||
68 | static int tvenc_off(struct platform_device *pdev) | |
69 | { | |
70 | int ret = 0; | |
71 | ||
72 | ret = panel_next_off(pdev); | |
73 | ||
74 | clk_disable(tvenc_clk); | |
75 | clk_disable(tvdac_clk); | |
76 | ||
77 | if (tvenc_pdata && tvenc_pdata->pm_vid_en) | |
78 | ret = tvenc_pdata->pm_vid_en(0); | |
79 | ||
80 | //pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", | |
81 | // PM_QOS_DEFAULT_VALUE); | |
82 | ||
83 | if (ret) | |
84 | printk(KERN_ERR "%s: pm_vid_en(off) failed! %d\n", | |
85 | __func__, ret); | |
86 | ||
87 | return ret; | |
88 | } | |
89 | ||
90 | static int tvenc_on(struct platform_device *pdev) | |
91 | { | |
92 | int ret = 0; | |
93 | ||
94 | // pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", | |
95 | // 128000); | |
96 | if (tvenc_pdata && tvenc_pdata->pm_vid_en) | |
97 | ret = tvenc_pdata->pm_vid_en(1); | |
98 | ||
99 | if (ret) { | |
100 | printk(KERN_ERR "%s: pm_vid_en(on) failed! %d\n", | |
101 | __func__, ret); | |
102 | return ret; | |
103 | } | |
104 | ||
105 | clk_enable(tvenc_clk); | |
106 | clk_enable(tvdac_clk); | |
107 | ||
108 | ret = panel_next_on(pdev); | |
109 | ||
110 | return ret; | |
111 | } | |
112 | ||
113 | void tvenc_gen_test_pattern(struct msm_fb_data_type *mfd) | |
114 | { | |
115 | uint32 reg = 0, i; | |
116 | ||
117 | reg = readl(MSM_TV_ENC_CTL); | |
118 | reg |= TVENC_CTL_TEST_PATT_EN; | |
119 | ||
120 | for (i = 0; i < 3; i++) { | |
121 | TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ | |
122 | ||
123 | switch (i) { | |
124 | /* | |
125 | * TV Encoder - Color Bar Test Pattern | |
126 | */ | |
127 | case 0: | |
128 | reg |= TVENC_CTL_TPG_CLRBAR; | |
129 | break; | |
130 | /* | |
131 | * TV Encoder - Red Frame Test Pattern | |
132 | */ | |
133 | case 1: | |
134 | reg |= TVENC_CTL_TPG_REDCLR; | |
135 | break; | |
136 | /* | |
137 | * TV Encoder - Modulated Ramp Test Pattern | |
138 | */ | |
139 | default: | |
140 | reg |= TVENC_CTL_TPG_MODRAMP; | |
141 | break; | |
142 | } | |
143 | ||
144 | TV_OUT(TV_ENC_CTL, reg); | |
145 | mdelay(5000); | |
146 | ||
147 | switch (i) { | |
148 | /* | |
149 | * TV Encoder - Color Bar Test Pattern | |
150 | */ | |
151 | case 0: | |
152 | reg &= ~TVENC_CTL_TPG_CLRBAR; | |
153 | break; | |
154 | /* | |
155 | * TV Encoder - Red Frame Test Pattern | |
156 | */ | |
157 | case 1: | |
158 | reg &= ~TVENC_CTL_TPG_REDCLR; | |
159 | break; | |
160 | /* | |
161 | * TV Encoder - Modulated Ramp Test Pattern | |
162 | */ | |
163 | default: | |
164 | reg &= ~TVENC_CTL_TPG_MODRAMP; | |
165 | break; | |
166 | } | |
167 | } | |
168 | } | |
169 | ||
170 | static int tvenc_resource_initialized; | |
171 | ||
172 | static int tvenc_probe(struct platform_device *pdev) | |
173 | { | |
174 | struct msm_fb_data_type *mfd; | |
175 | struct platform_device *mdp_dev = NULL; | |
176 | struct msm_fb_panel_data *pdata = NULL; | |
177 | int rc; | |
178 | ||
179 | if (pdev->id == 0) { | |
180 | tvenc_base = ioremap(pdev->resource[0].start, | |
181 | pdev->resource[0].end - | |
182 | pdev->resource[0].start + 1); | |
183 | if (!tvenc_base) { | |
184 | printk(KERN_ERR | |
185 | "tvenc_base ioremap failed!\n"); | |
186 | return -ENOMEM; | |
187 | } | |
188 | tvenc_pdata = pdev->dev.platform_data; | |
189 | tvenc_resource_initialized = 1; | |
190 | return 0; | |
191 | } | |
192 | ||
193 | if (!tvenc_resource_initialized) | |
194 | return -EPERM; | |
195 | ||
196 | mfd = platform_get_drvdata(pdev); | |
197 | ||
198 | if (!mfd) | |
199 | return -ENODEV; | |
200 | ||
201 | if (mfd->key != MFD_KEY) | |
202 | return -EINVAL; | |
203 | ||
204 | if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) | |
205 | return -ENOMEM; | |
206 | ||
207 | if (tvenc_base == NULL) | |
208 | return -ENOMEM; | |
209 | ||
210 | mdp_dev = platform_device_alloc("mdp", pdev->id); | |
211 | if (!mdp_dev) | |
212 | return -ENOMEM; | |
213 | ||
214 | /* | |
215 | * link to the latest pdev | |
216 | */ | |
217 | mfd->pdev = mdp_dev; | |
218 | mfd->dest = DISPLAY_TV; | |
219 | ||
220 | /* | |
221 | * alloc panel device data | |
222 | */ | |
223 | if (platform_device_add_data | |
224 | (mdp_dev, pdev->dev.platform_data, | |
225 | sizeof(struct msm_fb_panel_data))) { | |
226 | printk(KERN_ERR "tvenc_probe: platform_device_add_data failed!\n"); | |
227 | platform_device_put(mdp_dev); | |
228 | return -ENOMEM; | |
229 | } | |
230 | /* | |
231 | * data chain | |
232 | */ | |
233 | pdata = mdp_dev->dev.platform_data; | |
234 | pdata->on = tvenc_on; | |
235 | pdata->off = tvenc_off; | |
236 | pdata->next = pdev; | |
237 | ||
238 | /* | |
239 | * get/set panel specific fb info | |
240 | */ | |
241 | mfd->panel_info = pdata->panel_info; | |
242 | mfd->fb_imgType = MDP_YCRYCB_H2V1; | |
243 | ||
244 | /* | |
245 | * set driver data | |
246 | */ | |
247 | platform_set_drvdata(mdp_dev, mfd); | |
248 | ||
249 | /* | |
250 | * register in mdp driver | |
251 | */ | |
252 | rc = platform_device_add(mdp_dev); | |
253 | if (rc) | |
254 | goto tvenc_probe_err; | |
255 | ||
256 | pdev_list[pdev_list_cnt++] = pdev; | |
257 | return 0; | |
258 | ||
259 | tvenc_probe_err: | |
260 | platform_device_put(mdp_dev); | |
261 | return rc; | |
262 | } | |
263 | ||
264 | static int tvenc_remove(struct platform_device *pdev) | |
265 | { | |
266 | // pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc"); | |
267 | return 0; | |
268 | } | |
269 | ||
270 | static int tvenc_register_driver(void) | |
271 | { | |
272 | return platform_driver_register(&tvenc_driver); | |
273 | } | |
274 | ||
275 | static int __init tvenc_driver_init(void) | |
276 | { | |
277 | tvenc_clk = clk_get(NULL, "tv_enc_clk"); | |
278 | tvdac_clk = clk_get(NULL, "tv_dac_clk"); | |
279 | ||
280 | if (IS_ERR(tvenc_clk)) { | |
281 | printk(KERN_ERR "error: can't get tvenc_clk!\n"); | |
282 | return IS_ERR(tvenc_clk); | |
283 | } | |
284 | ||
285 | if (IS_ERR(tvdac_clk)) { | |
286 | printk(KERN_ERR "error: can't get tvdac_clk!\n"); | |
287 | return IS_ERR(tvdac_clk); | |
288 | } | |
289 | ||
290 | // pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", | |
291 | // PM_QOS_DEFAULT_VALUE); | |
292 | return tvenc_register_driver(); | |
293 | } | |
294 | ||
295 | module_init(tvenc_driver_init); |