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

Side by Side Diff: drivers/media/video/samsung/tv20/cec.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/cec.h ('k') | drivers/media/video/samsung/tv20/cec_s5pv210.h » ('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/cec.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5PV210 - cec interface 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
22 #include <linux/io.h>
23 #include <asm/mach-types.h>
24 #include <linux/uaccess.h>
25
26 #include <mach/gpio.h>
27 #include <plat/gpio-cfg.h>
28
29 #include <mach/regs-hdmi.h>
30
31 #include "s5p_tv.h"
32 #include "cec.h"
33
34 #ifdef CECDEBUG
35 #define CECIFPRINTK(fmt, args...) \
36 printk(KERN_INFO "\t[CEC_IF] %s: " fmt, __func__ , ## args)
37 #else
38 #define CECIFPRINTK(fmt, args...)
39 #endif
40
41 static struct cec_rx_struct cec_rx_struct;
42 static struct cec_tx_struct cec_tx_struct;
43
44 static bool hdmi_on;
45
46 /**
47 * Change CEC Tx state to state
48 * @param state [in] new CEC Tx state.
49 */
50 void tv_cec_set_tx_state(enum cec_state state)
51 {
52 atomic_set(&cec_tx_struct.state, state);
53 }
54
55 /**
56 * Change CEC Rx state to @c state.
57 * @param state [in] new CEC Rx state.
58 */
59 void tv_cec_set_rx_state(enum cec_state state)
60 {
61 atomic_set(&cec_rx_struct.state, state);
62 }
63
64
65 int s5p_cec_open(struct inode *inode, struct file *file)
66 {
67 s5p_tv_clk_gate(true);
68
69 hdmi_on = true;
70
71 tv_cec_reset();
72
73 tv_cec_set_divider();
74
75 tv_cec_threshold();
76
77 tv_cec_unmask_tx_interrupts();
78
79 tv_cec_set_rx_state(STATE_RX);
80 tv_cec_unmask_rx_interrupts();
81 tv_cec_enable_rx();
82
83 return 0;
84 }
85
86 int s5p_cec_release(struct inode *inode, struct file *file)
87 {
88 s5p_tv_clk_gate(false);
89
90 hdmi_on = false;
91
92 tv_cec_mask_tx_interrupts();
93 tv_cec_mask_rx_interrupts();
94
95 return 0;
96 }
97
98 ssize_t s5p_cec_read(struct file *file, char __user *buffer,
99 size_t count, loff_t *ppos)
100 {
101 ssize_t retval;
102
103 if (wait_event_interruptible(cec_rx_struct.waitq,
104 atomic_read(&cec_rx_struct.state) == STATE_DONE)) {
105 return -ERESTARTSYS;
106 }
107
108 spin_lock_irq(&cec_rx_struct.lock);
109
110 if (cec_rx_struct.size > count) {
111 spin_unlock_irq(&cec_rx_struct.lock);
112 return -1;
113 }
114
115 if (copy_to_user(buffer, cec_rx_struct.buffer, cec_rx_struct.size)) {
116 spin_unlock_irq(&cec_rx_struct.lock);
117 printk(KERN_ERR " copy_to_user() failed!\n");
118 return -EFAULT;
119 }
120
121 retval = cec_rx_struct.size;
122
123 tv_cec_set_rx_state(STATE_RX);
124 spin_unlock_irq(&cec_rx_struct.lock);
125
126 return retval;
127 }
128
129 ssize_t s5p_cec_write(struct file *file, const char __user *buffer,
130 size_t count, loff_t *ppos)
131 {
132 char *data;
133
134 /* check data size */
135
136 if (count > CEC_TX_BUFF_SIZE || count == 0)
137 return -1;
138
139 data = kmalloc(count, GFP_KERNEL);
140
141 if (!data) {
142 printk(KERN_ERR " kmalloc() failed!\n");
143 return -1;
144 }
145
146 if (copy_from_user(data, buffer, count)) {
147 printk(KERN_ERR " copy_from_user() failed!\n");
148 kfree(data);
149 return -EFAULT;
150 }
151
152 tv_cec_copy_packet(data, count);
153
154 kfree(data);
155
156 /* wait for interrupt */
157 if (wait_event_interruptible(cec_tx_struct.waitq,
158 atomic_read(&cec_tx_struct.state) != STATE_TX)) {
159 return -ERESTARTSYS;
160 }
161
162 if (atomic_read(&cec_tx_struct.state) == STATE_ERROR)
163 return -1;
164
165
166 return count;
167 }
168
169 int s5p_cec_ioctl(struct inode *inode, struct file *file,
170 u32 cmd, unsigned long arg)
171 {
172 u32 laddr;
173
174 switch (cmd) {
175
176 case CEC_IOC_SETLADDR:
177 CECIFPRINTK("ioctl(CEC_IOC_SETLADDR)\n");
178
179 if (get_user(laddr, (u32 __user *) arg))
180 return -EFAULT;
181
182 CECIFPRINTK("logical address = 0x%02x\n", laddr);
183
184 tv_cec_set_addr(laddr);
185
186 break;
187
188 default:
189 return -EINVAL;
190 }
191
192 return 0;
193 }
194
195 u32 s5p_cec_poll(struct file *file, poll_table *wait)
196 {
197 poll_wait(file, &cec_rx_struct.waitq, wait);
198
199 if (atomic_read(&cec_rx_struct.state) == STATE_DONE)
200 return POLLIN | POLLRDNORM;
201
202 return 0;
203 }
204
205 static const struct file_operations cec_fops = {
206 .owner = THIS_MODULE,
207 .open = s5p_cec_open,
208 .release = s5p_cec_release,
209 .read = s5p_cec_read,
210 .write = s5p_cec_write,
211 .ioctl = s5p_cec_ioctl,
212 .poll = s5p_cec_poll,
213 };
214
215 static struct miscdevice cec_misc_device = {
216 .minor = CEC_MINOR,
217 .name = "CEC",
218 .fops = &cec_fops,
219 };
220
221
222 /**
223 * @brief CEC interrupt handler
224 *
225 * Handles interrupt requests from CEC hardware. \n
226 * Action depends on current state of CEC hardware.
227 */
228 irqreturn_t s5p_cec_irq_handler(int irq, void *dev_id)
229 {
230 /* u8 flag; */
231 u32 status = 0;
232
233 status = tv_cec_get_status();
234
235 if (status & CEC_STATUS_TX_DONE) {
236 if (status & CEC_STATUS_TX_ERROR) {
237 CECIFPRINTK(" CEC_STATUS_TX_ERROR!\n");
238 tv_cec_set_tx_state(STATE_ERROR);
239 } else {
240 CECIFPRINTK(" CEC_STATUS_TX_DONE!\n");
241 tv_cec_set_tx_state(STATE_DONE);
242 }
243
244 tv_clr_pending_tx();
245
246 wake_up_interruptible(&cec_tx_struct.waitq);
247 }
248
249 if (status & CEC_STATUS_RX_DONE) {
250 if (status & CEC_STATUS_RX_ERROR) {
251 CECIFPRINTK(" CEC_STATUS_RX_ERROR!\n");
252 tv_cec_rx_reset();
253
254 } else {
255 u32 size;
256
257 CECIFPRINTK(" CEC_STATUS_RX_DONE!\n");
258
259 /* copy data from internal buffer */
260 size = status >> 24;
261
262 spin_lock(&cec_rx_struct.lock);
263
264 tv_cec_get_rx_buf(size, cec_rx_struct.buffer);
265
266 cec_rx_struct.size = size;
267
268 tv_cec_set_rx_state(STATE_DONE);
269
270 spin_unlock(&cec_rx_struct.lock);
271
272 tv_cec_enable_rx();
273 }
274
275 /* clear interrupt pending bit */
276 tv_clr_pending_rx();
277
278 wake_up_interruptible(&cec_rx_struct.waitq);
279 }
280
281 return IRQ_HANDLED;
282 }
283
284 static int __init s5p_cec_probe(struct platform_device *pdev)
285 {
286 u8 *buffer;
287 int irq_num;
288 int ret;
289
290 s3c_gpio_cfgpin(S5PV210_GPH1(4), S5P_GPH1_4_HDMI_CEC);
291 s3c_gpio_setpull(S5PV210_GPH1(4), S3C_GPIO_PULL_NONE);
292
293 /* get ioremap addr */
294 tv_cec_probe(pdev);
295
296 if (misc_register(&cec_misc_device)) {
297 printk(KERN_WARNING
298 "Couldn't register device 10, %d.\n", CEC_MINOR);
299 return -EBUSY;
300 }
301
302 irq_num = platform_get_irq(pdev, 0);
303 if (irq_num < 0) {
304 printk(KERN_ERR "failed to get %s irq resource\n", "cec");
305 ret = -ENOENT;
306 return ret;
307 }
308
309 ret = request_irq(irq_num, s5p_cec_irq_handler, IRQF_DISABLED,
310 pdev->name, &pdev->id);
311 if (ret != 0) {
312 printk(KERN_ERR "failed to install %s irq (%d)\n", "cec", ret);
313 return ret;
314 }
315
316 init_waitqueue_head(&cec_rx_struct.waitq);
317 spin_lock_init(&cec_rx_struct.lock);
318 init_waitqueue_head(&cec_tx_struct.waitq);
319
320 buffer = kmalloc(CEC_TX_BUFF_SIZE, GFP_KERNEL);
321
322 if (!buffer) {
323 printk(KERN_ERR " kmalloc() failed!\n");
324 misc_deregister(&cec_misc_device);
325 return -EIO;
326 }
327
328 cec_rx_struct.buffer = buffer;
329
330 cec_rx_struct.size = 0;
331
332 return 0;
333 }
334
335 static int s5p_cec_remove(struct platform_device *pdev)
336 {
337 return 0;
338 }
339
340 #ifdef CONFIG_PM
341
342 int s5p_cec_suspend(struct platform_device *dev, pm_message_t state)
343 {
344 if (hdmi_on)
345 s5p_tv_clk_gate(false);
346
347 return 0;
348 }
349
350 int s5p_cec_resume(struct platform_device *dev)
351 {
352 if (hdmi_on)
353 s5p_tv_clk_gate(true);
354
355 return 0;
356 }
357 #else
358 #define s5p_cec_suspend NULL
359 #define s5p_cec_resume NULL
360 #endif
361
362 static struct platform_driver s5p_cec_driver = {
363 .probe = s5p_cec_probe,
364 .remove = s5p_cec_remove,
365 .suspend = s5p_cec_suspend,
366 .resume = s5p_cec_resume,
367 .driver = {
368 .name = "s5p-cec",
369 .owner = THIS_MODULE,
370 },
371 };
372
373 static char banner[] __initdata =
374 "S5PV210 CEC Driver, (c) 2010 Samsung Electronics\n";
375
376 int __init s5p_cec_init(void)
377 {
378 int ret;
379
380 printk(banner);
381
382 ret = platform_driver_register(&s5p_cec_driver);
383
384 if (ret) {
385 printk(KERN_ERR "Platform Device Register Failed %d\n", ret);
386 return -1;
387 }
388
389 return 0;
390 }
391
392 static void __exit s5p_cec_exit(void)
393 {
394 kfree(cec_rx_struct.buffer);
395
396 platform_driver_unregister(&s5p_cec_driver);
397
398 }
399
400 module_init(s5p_cec_init);
401 module_exit(s5p_cec_exit);
402
403 MODULE_AUTHOR("SangPil Moon");
404 MODULE_DESCRIPTION("S5PV210 CEC driver");
405 MODULE_LICENSE("GPL");
OLDNEW
« no previous file with comments | « drivers/media/video/samsung/tv20/cec.h ('k') | drivers/media/video/samsung/tv20/cec_s5pv210.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698