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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: drivers/media/video/samsung/tv20/hpd.c
diff --git a/drivers/media/video/samsung/tv20/hpd.c b/drivers/media/video/samsung/tv20/hpd.c
new file mode 100644
index 0000000000000000000000000000000000000000..11c8bf50c080bff58f8031905a674dd7508c14b5
--- /dev/null
+++ b/drivers/media/video/samsung/tv20/hpd.c
@@ -0,0 +1,357 @@
+/* linux/drivers/media/video/samsung/tv20/hpd.c
+*
+* Copyright (c) 2010 Samsung Electronics Co., Ltd.
+* http://www.samsung.com/
+*
+* S5PV210 - hpd interface ftn file for Samsung TVOut driver
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/irq.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+
+#include <linux/io.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+#include <mach/regs-hdmi.h>
+
+#include "s5p_tv.h"
+#include "hpd.h"
+
+/* #define HPDDEBUG */
+
+#define USEEXTINT
+
+#ifdef HPDDEBUG
+#define HPDIFPRINTK(fmt, args...) \
+ printk(KERN_INFO "[HPD_IF] %s: " fmt, __func__ , ## args)
+#else
+#define HPDIFPRINTK(fmt, args...)
+#endif
+
+static struct hpd_struct hpd_struct;
+
+#ifndef USEEXTINT
+static int last_hpd_state;
+#endif
+
+#ifdef CONFIG_PM
+ #ifndef USEEXTINT
+ static bool hdmi_on;
+ #endif
+#endif
+
+static DECLARE_WORK(hpd_work, s5p_tv_kobject_uevent);
+
+int s5p_hpd_get_state(void)
+{
+ return atomic_read(&hpd_struct.state);
+}
+
+
+int s5p_hpd_open(struct inode *inode, struct file *file)
+{
+#ifdef USEEXTINT
+#else
+ /* adjust the duration of HPD detection */
+ s5p_tv_clk_gate(true);
+ hdmi_on = true;
+
+ s5p_hdmi_hpd_gen();
+
+ s3c_gpio_cfgpin(S5PV210_GPH1(5), S5P_GPH1_5_HDMI_HPD);
+ s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_UP);
+
+ s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG);
+ s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG);
+#endif
+
+
+ return 0;
+}
+
+int s5p_hpd_release(struct inode *inode, struct file *file)
+{
+ /* disable HPD interrupts */
+#ifdef USEEXTINT
+#else
+ s5p_tv_clk_gate(false);
+ hdmi_on = false;
+
+ s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG);
+ s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG);
+#endif
+
+ return 0;
+}
+
+ssize_t s5p_hpd_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+
+ if (wait_event_interruptible(hpd_struct.waitq,
+ atomic_read(&hpd_struct.state) != -1))
+ return -ERESTARTSYS;
+
+ spin_lock_irq(&hpd_struct.lock);
+
+ retval = put_user(atomic_read(&hpd_struct.state),
+ (unsigned int __user *) buffer);
+
+ atomic_set(&hpd_struct.state, -1);
+
+ spin_unlock_irq(&hpd_struct.lock);
+
+ return retval;
+}
+
+unsigned int s5p_hpd_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &hpd_struct.waitq, wait);
+
+ if (atomic_read(&hpd_struct.state) != -1)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static const struct file_operations hpd_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_hpd_open,
+ .release = s5p_hpd_release,
+ .read = s5p_hpd_read,
+ .poll = s5p_hpd_poll,
+};
+
+static struct miscdevice hpd_misc_device = {
+ HPD_MINOR,
+ "HPD",
+ &hpd_fops,
+};
+
+/*
+ * HPD interrupt handler
+ *
+ * Handles interrupt requests from HPD hardware.
+ * Handler changes value of internal variable and notifies waiting thread.
+ */
+irqreturn_t s5p_hpd_irq_handler(int irq, void *dev_id)
+{
+#ifdef USEEXTINT
+ spin_lock_irq(&hpd_struct.lock);
+
+ if (gpio_get_value(S5PV210_GPH1(5))) {
+ if (atomic_read(&hpd_struct.state) == HPD_HI)
+ goto out;
+ atomic_set(&hpd_struct.state, HPD_HI);
+ } else {
+ if (atomic_read(&hpd_struct.state) == HPD_LO)
+ goto out;
+ atomic_set(&hpd_struct.state, HPD_LO);
+ }
+
+ if (atomic_read(&hpd_struct.state))
+ set_irq_type(IRQ_EINT13, IRQ_TYPE_LEVEL_LOW);
+ else
+ set_irq_type(IRQ_EINT13, IRQ_TYPE_LEVEL_HIGH);
+
+ /* Send UEvent for HPD - added by jyg1004 */
+ schedule_work(&hpd_work);
+
+ spin_unlock_irq(&hpd_struct.lock);
+
+ HPDIFPRINTK("hpd_status = %d\n", atomic_read(&hpd_struct.state));
+
+ return IRQ_HANDLED;
+out:
+ spin_unlock_irq(&hpd_struct.lock);
+
+ return IRQ_HANDLED;
+#else
+ u8 flag;
+ int ret = IRQ_HANDLED;
+
+ /* read flag register */
+ flag = s5p_hdmi_get_interrupts();
+
+ /* is this our interrupt? */
+
+ if (!(flag & (1 << HDMI_IRQ_HPD_PLUG | 1 << HDMI_IRQ_HPD_UNPLUG))) {
+ ret = IRQ_NONE;
+ goto out;
+ }
+
+ /* workaround: ignore HPD IRQ caused by reseting HDCP engine */
+ if (s5p_hdmi_get_swhpd_status()) {
+ s5p_hdmi_swhpd_disable();
+ /* clear pending bit */
+ s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG);
+ s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG);
+ ret = IRQ_HANDLED;
+ goto out;
+ }
+
+ if (flag == (1 << HDMI_IRQ_HPD_PLUG | 1 << HDMI_IRQ_HPD_UNPLUG)) {
+ HPDIFPRINTK("HPD_HI && HPD_LO\n");
+
+ if (last_hpd_state == HPD_HI && s5p_hdmi_get_hpd_status())
+ /*if ( last_hpd_state == HPD_HI ) */
+ flag = 1 << HDMI_IRQ_HPD_UNPLUG;
+ else
+ flag = 1 << HDMI_IRQ_HPD_PLUG;
+ }
+
+ if (flag & (1 << HDMI_IRQ_HPD_PLUG)) {
+ HPDIFPRINTK("HPD_HI\n");
+ /* clear pending bit */
+ s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG);
+ s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG);
+ atomic_set(&hpd_struct.state, HPD_HI);
+ /* workaround: enable HDMI_IRQ_HPD_UNPLUG interrupt */
+ s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG);
+ s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG);
+ last_hpd_state = HPD_HI;
+ wake_up_interruptible(&hpd_struct.waitq);
+ } else if (flag & (1 << HDMI_IRQ_HPD_UNPLUG)) {
+ HPDIFPRINTK("HPD_LO\n");
+ /* clear pending bit */
+ s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG);
+ s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG);
+ atomic_set(&hpd_struct.state, HPD_LO);
+ /* workaround: disable HDMI_IRQ_HPD_UNPLUG interrupt */
+ last_hpd_state = HPD_LO;
+ s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG);
+ s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG);
+ wake_up_interruptible(&hpd_struct.waitq);
+ }
+
+out:
+ return IRQ_HANDLED;
+
+#endif
+}
+
+static int __init s5p_hpd_probe(struct platform_device *pdev)
+{
+ if (misc_register(&hpd_misc_device)) {
+ printk(KERN_WARNING
+ "Couldn't register device 10, %d.\n", HPD_MINOR);
+ return -EBUSY;
+ }
+
+ init_waitqueue_head(&hpd_struct.waitq);
+
+ spin_lock_init(&hpd_struct.lock);
+
+ atomic_set(&hpd_struct.state, -1);
+
+#ifdef USEEXTINT
+ s3c_gpio_cfgpin(S5PV210_GPH1(5), S5P_GPH1_5_EXT_INT31_5);
+ s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_UP);
+
+ if (gpio_get_value(S5PV210_GPH1(5)))
+ atomic_set(&hpd_struct.state, HPD_HI);
+ else
+ atomic_set(&hpd_struct.state, HPD_LO);
+
+ set_irq_type(IRQ_EINT13, IRQ_TYPE_EDGE_BOTH);
+
+ if (request_irq(IRQ_EINT13, s5p_hpd_irq_handler, IRQF_DISABLED,
+ "hpd", s5p_hpd_irq_handler)) {
+ printk(KERN_ERR "failed to install %s irq\n", "hpd");
+ misc_deregister(&hpd_misc_device);
+ return -EIO;
+ }
+#else
+ /* must be checked */
+ s5p_hdmi_register_isr(s5p_hpd_irq_handler, (u8)HDMI_IRQ_HPD_PLUG);
+ s5p_hdmi_register_isr(s5p_hpd_irq_handler, (u8)HDMI_IRQ_HPD_UNPLUG);
+#endif
+
+ return 0;
+}
+
+static int s5p_hpd_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+int s5p_hpd_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifndef USEEXTINT
+ if (hdmi_on)
+ s5p_tv_clk_gate(false);
+#endif
+ return 0;
+}
+
+int s5p_hpd_resume(struct platform_device *dev)
+{
+#ifndef USEEXTINT
+ if (hdmi_on)
+ s5p_tv_clk_gate(true);
+#endif
+ return 0;
+}
+#else
+#define s5p_hpd_suspend NULL
+#define s5p_hpd_resume NULL
+#endif
+
+static struct platform_driver s5p_hpd_driver = {
+ .probe = s5p_hpd_probe,
+ .remove = s5p_hpd_remove,
+ .suspend = s5p_hpd_suspend,
+ .resume = s5p_hpd_resume,
+ .driver = {
+ .name = "s5p-hpd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static char banner[] __initdata =
+ "S5PV210 HPD Driver, (c) 2010 Samsung Electronics\n";
+
+int __init s5p_hpd_init(void)
+{
+ int ret;
+
+ printk(banner);
+
+ ret = platform_driver_register(&s5p_hpd_driver);
+
+ if (ret) {
+ printk(KERN_ERR "Platform Device Register Failed %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit s5p_hpd_exit(void)
+{
+ misc_deregister(&hpd_misc_device);
+}
+
+module_init(s5p_hpd_init);
+module_exit(s5p_hpd_exit);
+
+
« 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