Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1809)

Side by Side Diff: drivers/media/video/samsung/tv20/hpd.c

Issue 2036011: V4L/DVB : Add S5PV210 TV out driver support (Closed) Base URL: swsolcc@12.23.106.100:kernel-samsung.git
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « drivers/media/video/samsung/tv20/hpd.h ('k') | drivers/media/video/samsung/tv20/s5p_stda_grp.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* linux/drivers/media/video/samsung/tv20/hpd.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5PV210 - hpd interface ftn file for Samsung TVOut driver
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/interrupt.h>
16 #include <linux/fs.h>
17 #include <linux/miscdevice.h>
18 #include <linux/errno.h>
19 #include <linux/wait.h>
20 #include <linux/poll.h>
21 #include <linux/irq.h>
22 #include <linux/kobject.h>
23 #include <linux/workqueue.h>
24
25 #include <linux/io.h>
26
27 #include <mach/gpio.h>
28 #include <plat/gpio-cfg.h>
29
30 #include <mach/regs-hdmi.h>
31
32 #include "s5p_tv.h"
33 #include "hpd.h"
34
35 /* #define HPDDEBUG */
36
37 #define USEEXTINT
38
39 #ifdef HPDDEBUG
40 #define HPDIFPRINTK(fmt, args...) \
41 printk(KERN_INFO "[HPD_IF] %s: " fmt, __func__ , ## args)
42 #else
43 #define HPDIFPRINTK(fmt, args...)
44 #endif
45
46 static struct hpd_struct hpd_struct;
47
48 #ifndef USEEXTINT
49 static int last_hpd_state;
50 #endif
51
52 #ifdef CONFIG_PM
53 #ifndef USEEXTINT
54 static bool hdmi_on;
55 #endif
56 #endif
57
58 static DECLARE_WORK(hpd_work, s5p_tv_kobject_uevent);
59
60 int s5p_hpd_get_state(void)
61 {
62 return atomic_read(&hpd_struct.state);
63 }
64
65
66 int s5p_hpd_open(struct inode *inode, struct file *file)
67 {
68 #ifdef USEEXTINT
69 #else
70 /* adjust the duration of HPD detection */
71 s5p_tv_clk_gate(true);
72 hdmi_on = true;
73
74 s5p_hdmi_hpd_gen();
75
76 s3c_gpio_cfgpin(S5PV210_GPH1(5), S5P_GPH1_5_HDMI_HPD);
77 s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_UP);
78
79 s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG);
80 s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG);
81 #endif
82
83
84 return 0;
85 }
86
87 int s5p_hpd_release(struct inode *inode, struct file *file)
88 {
89 /* disable HPD interrupts */
90 #ifdef USEEXTINT
91 #else
92 s5p_tv_clk_gate(false);
93 hdmi_on = false;
94
95 s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG);
96 s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG);
97 #endif
98
99 return 0;
100 }
101
102 ssize_t s5p_hpd_read(struct file *file, char __user *buffer,
103 size_t count, loff_t *ppos)
104 {
105 ssize_t retval;
106
107 if (wait_event_interruptible(hpd_struct.waitq,
108 atomic_read(&hpd_struct.state) != -1))
109 return -ERESTARTSYS;
110
111 spin_lock_irq(&hpd_struct.lock);
112
113 retval = put_user(atomic_read(&hpd_struct.state),
114 (unsigned int __user *) buffer);
115
116 atomic_set(&hpd_struct.state, -1);
117
118 spin_unlock_irq(&hpd_struct.lock);
119
120 return retval;
121 }
122
123 unsigned int s5p_hpd_poll(struct file *file, poll_table *wait)
124 {
125 poll_wait(file, &hpd_struct.waitq, wait);
126
127 if (atomic_read(&hpd_struct.state) != -1)
128 return POLLIN | POLLRDNORM;
129
130 return 0;
131 }
132
133 static const struct file_operations hpd_fops = {
134 .owner = THIS_MODULE,
135 .open = s5p_hpd_open,
136 .release = s5p_hpd_release,
137 .read = s5p_hpd_read,
138 .poll = s5p_hpd_poll,
139 };
140
141 static struct miscdevice hpd_misc_device = {
142 HPD_MINOR,
143 "HPD",
144 &hpd_fops,
145 };
146
147 /*
148 * HPD interrupt handler
149 *
150 * Handles interrupt requests from HPD hardware.
151 * Handler changes value of internal variable and notifies waiting thread.
152 */
153 irqreturn_t s5p_hpd_irq_handler(int irq, void *dev_id)
154 {
155 #ifdef USEEXTINT
156 spin_lock_irq(&hpd_struct.lock);
157
158 if (gpio_get_value(S5PV210_GPH1(5))) {
159 if (atomic_read(&hpd_struct.state) == HPD_HI)
160 goto out;
161 atomic_set(&hpd_struct.state, HPD_HI);
162 } else {
163 if (atomic_read(&hpd_struct.state) == HPD_LO)
164 goto out;
165 atomic_set(&hpd_struct.state, HPD_LO);
166 }
167
168 if (atomic_read(&hpd_struct.state))
169 set_irq_type(IRQ_EINT13, IRQ_TYPE_LEVEL_LOW);
170 else
171 set_irq_type(IRQ_EINT13, IRQ_TYPE_LEVEL_HIGH);
172
173 /* Send UEvent for HPD - added by jyg1004 */
174 schedule_work(&hpd_work);
175
176 spin_unlock_irq(&hpd_struct.lock);
177
178 HPDIFPRINTK("hpd_status = %d\n", atomic_read(&hpd_struct.state));
179
180 return IRQ_HANDLED;
181 out:
182 spin_unlock_irq(&hpd_struct.lock);
183
184 return IRQ_HANDLED;
185 #else
186 u8 flag;
187 int ret = IRQ_HANDLED;
188
189 /* read flag register */
190 flag = s5p_hdmi_get_interrupts();
191
192 /* is this our interrupt? */
193
194 if (!(flag & (1 << HDMI_IRQ_HPD_PLUG | 1 << HDMI_IRQ_HPD_UNPLUG))) {
195 ret = IRQ_NONE;
196 goto out;
197 }
198
199 /* workaround: ignore HPD IRQ caused by reseting HDCP engine */
200 if (s5p_hdmi_get_swhpd_status()) {
201 s5p_hdmi_swhpd_disable();
202 /* clear pending bit */
203 s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG);
204 s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG);
205 ret = IRQ_HANDLED;
206 goto out;
207 }
208
209 if (flag == (1 << HDMI_IRQ_HPD_PLUG | 1 << HDMI_IRQ_HPD_UNPLUG)) {
210 HPDIFPRINTK("HPD_HI && HPD_LO\n");
211
212 if (last_hpd_state == HPD_HI && s5p_hdmi_get_hpd_status())
213 /*if ( last_hpd_state == HPD_HI ) */
214 flag = 1 << HDMI_IRQ_HPD_UNPLUG;
215 else
216 flag = 1 << HDMI_IRQ_HPD_PLUG;
217 }
218
219 if (flag & (1 << HDMI_IRQ_HPD_PLUG)) {
220 HPDIFPRINTK("HPD_HI\n");
221 /* clear pending bit */
222 s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG);
223 s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG);
224 atomic_set(&hpd_struct.state, HPD_HI);
225 /* workaround: enable HDMI_IRQ_HPD_UNPLUG interrupt */
226 s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG);
227 s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG);
228 last_hpd_state = HPD_HI;
229 wake_up_interruptible(&hpd_struct.waitq);
230 } else if (flag & (1 << HDMI_IRQ_HPD_UNPLUG)) {
231 HPDIFPRINTK("HPD_LO\n");
232 /* clear pending bit */
233 s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG);
234 s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG);
235 atomic_set(&hpd_struct.state, HPD_LO);
236 /* workaround: disable HDMI_IRQ_HPD_UNPLUG interrupt */
237 last_hpd_state = HPD_LO;
238 s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG);
239 s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG);
240 wake_up_interruptible(&hpd_struct.waitq);
241 }
242
243 out:
244 return IRQ_HANDLED;
245
246 #endif
247 }
248
249 static int __init s5p_hpd_probe(struct platform_device *pdev)
250 {
251 if (misc_register(&hpd_misc_device)) {
252 printk(KERN_WARNING
253 "Couldn't register device 10, %d.\n", HPD_MINOR);
254 return -EBUSY;
255 }
256
257 init_waitqueue_head(&hpd_struct.waitq);
258
259 spin_lock_init(&hpd_struct.lock);
260
261 atomic_set(&hpd_struct.state, -1);
262
263 #ifdef USEEXTINT
264 s3c_gpio_cfgpin(S5PV210_GPH1(5), S5P_GPH1_5_EXT_INT31_5);
265 s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_UP);
266
267 if (gpio_get_value(S5PV210_GPH1(5)))
268 atomic_set(&hpd_struct.state, HPD_HI);
269 else
270 atomic_set(&hpd_struct.state, HPD_LO);
271
272 set_irq_type(IRQ_EINT13, IRQ_TYPE_EDGE_BOTH);
273
274 if (request_irq(IRQ_EINT13, s5p_hpd_irq_handler, IRQF_DISABLED,
275 "hpd", s5p_hpd_irq_handler)) {
276 printk(KERN_ERR "failed to install %s irq\n", "hpd");
277 misc_deregister(&hpd_misc_device);
278 return -EIO;
279 }
280 #else
281 /* must be checked */
282 s5p_hdmi_register_isr(s5p_hpd_irq_handler, (u8)HDMI_IRQ_HPD_PLUG);
283 s5p_hdmi_register_isr(s5p_hpd_irq_handler, (u8)HDMI_IRQ_HPD_UNPLUG);
284 #endif
285
286 return 0;
287 }
288
289 static int s5p_hpd_remove(struct platform_device *pdev)
290 {
291 return 0;
292 }
293
294
295 #ifdef CONFIG_PM
296
297 int s5p_hpd_suspend(struct platform_device *dev, pm_message_t state)
298 {
299 #ifndef USEEXTINT
300 if (hdmi_on)
301 s5p_tv_clk_gate(false);
302 #endif
303 return 0;
304 }
305
306 int s5p_hpd_resume(struct platform_device *dev)
307 {
308 #ifndef USEEXTINT
309 if (hdmi_on)
310 s5p_tv_clk_gate(true);
311 #endif
312 return 0;
313 }
314 #else
315 #define s5p_hpd_suspend NULL
316 #define s5p_hpd_resume NULL
317 #endif
318
319 static struct platform_driver s5p_hpd_driver = {
320 .probe = s5p_hpd_probe,
321 .remove = s5p_hpd_remove,
322 .suspend = s5p_hpd_suspend,
323 .resume = s5p_hpd_resume,
324 .driver = {
325 .name = "s5p-hpd",
326 .owner = THIS_MODULE,
327 },
328 };
329
330 static char banner[] __initdata =
331 "S5PV210 HPD Driver, (c) 2010 Samsung Electronics\n";
332
333 int __init s5p_hpd_init(void)
334 {
335 int ret;
336
337 printk(banner);
338
339 ret = platform_driver_register(&s5p_hpd_driver);
340
341 if (ret) {
342 printk(KERN_ERR "Platform Device Register Failed %d\n", ret);
343 return -1;
344 }
345
346 return 0;
347 }
348
349 static void __exit s5p_hpd_exit(void)
350 {
351 misc_deregister(&hpd_misc_device);
352 }
353
354 module_init(s5p_hpd_init);
355 module_exit(s5p_hpd_exit);
356
357
OLDNEW
« no previous file with comments | « drivers/media/video/samsung/tv20/hpd.h ('k') | drivers/media/video/samsung/tv20/s5p_stda_grp.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698