imx6Q USB OTG Host/Device纯软件切换

From 87f295ccaf081b4ef06218fc8028d3c3d075ede7 Mon Sep 17 00:00:00 2001
From: hongjiujin <hongjiujin@xxx.com>
Date: Tue, 2 Jan 2018 10:39:04 +0800
Subject: [PATCH] imx6: chipidea

The hardware didn't use OTG_ID pin in design and use USB A for OTG.
Chipidea will initialize otg to HOST once boot completed, which read OTGSC_IDIE.
So we implement otg role switch in SW only(/sys/kernel/debug/ci_hdrc.0/otgswitch).
---
 debug.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/debug.c b/debug.c
index a4f7db2..b215674 100644
--- a/debug.c
+++ b/debug.c
@@ -16,6 +16,7 @@
 #include "udc.h"
 #include "bits.h"
 #include "otg.h"
+#include "host.h"
 
 /**
  * ci_device_show: prints information about device capabilities and status
@@ -343,6 +344,110 @@ static const struct file_operations ci_role_fops = {
     .release    = single_release,
 };
 
+#define CI_VBUS_STABLE_TIMEOUT_MS 100
+
+void handle_otg_switch(struct ci_hdrc *ci, enum ci_role role)
+{
+    int ret = 0;
+
+    if (role != ci->role) {
+        dev_dbg(ci->dev, "switching from %s to %s\n",
+            ci_role(ci)->name, ci->roles[role]->name);
+
+        while (ci_hdrc_host_has_device(ci)) {
+            enable_irq(ci->irq);
+            usleep_range(10000, 15000);
+            disable_irq_nosync(ci->irq);
+        }
+
+        ci_role_stop(ci);
+
+        if (role == CI_ROLE_GADGET) {
+            /* wait vbus lower than OTGSC_BSV */
+            ret = hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+                    CI_VBUS_STABLE_TIMEOUT_MS);
+        }
+        else if (ci->vbus_active)
+            /*
+             * If the role switch happens(e.g. during
+             * system sleep), and we lose vbus drop
+             * event, disconnect gadget for it before
+             * start host.
+             */
+               usb_gadget_vbus_disconnect(&ci->gadget);
+
+        ci_role_start(ci, role);
+        /*
+         * If the role switch happens(e.g. during system
+         * sleep) and vbus keeps on afterwards, we connect
+         * gadget as vbus connect event lost.
+         */
+        if (ret == -ETIMEDOUT)
+            usb_gadget_vbus_connect(&ci->gadget);
+    }
+}
+
+static int ci_otgswitch_show(struct seq_file *s, void *data)
+{
+    struct ci_hdrc *ci = s->private;
+
+    seq_printf(s, "%s\n", ci_role(ci)->name);
+
+    return 0;
+}
+
+static ssize_t ci_otgswitch_write(struct file *file, const char __user *ubuf,
+                 size_t count, loff_t *ppos)
+{
+    struct seq_file *s = file->private_data;
+    struct ci_hdrc *ci = s->private;
+    enum ci_role role;
+    char buf[8];
+    int ret;
+
+    if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+    return -EFAULT;
+
+    for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+     if (ci->roles[role] &&
+        !strncmp(buf, ci->roles[role]->name,
+        strlen(ci->roles[role]->name)))
+        break;
+
+     if (role == CI_ROLE_END || role == ci->role)
+        return -EINVAL;
+
+    pm_runtime_get_sync(ci->dev);
+    disable_irq(ci->irq);
+
+    if (role == CI_ROLE_HOST) {
+        ci->fsm.id = 0;
+
+    } else if (role == CI_ROLE_GADGET) {
+        ci->fsm.id = 1;
+    }
+
+    handle_otg_switch(ci, role);
+    enable_irq(ci->irq);
+    pm_runtime_put_sync(ci->dev);
+
+    return ret ? ret : count;
+}
+
+
+static int ci_otgswitch_open(struct inode *inode, struct file *file)
+{
+    return single_open(file, ci_otgswitch_show, inode->i_private);
+}
+
+static const struct file_operations ci_otgswitch_fops = {
+    .open        = ci_otgswitch_open,
+    .write        = ci_otgswitch_write,
+    .read        = seq_read,
+    .llseek        = seq_lseek,
+    .release    = single_release,
+};
+
 static int ci_registers_show(struct seq_file *s, void *unused)
 {
     struct ci_hdrc *ci = s->private;
@@ -433,6 +538,11 @@ int dbg_create_files(struct ci_hdrc *ci)
     if (!dent)
         goto err;
 
+    dent = debugfs_create_file("otgswitch", S_IRUGO | S_IWUSR, ci->debugfs, ci,
+                   &ci_otgswitch_fops);
+    if (!dent)
+        goto err;
+
     dent = debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci,
                 &ci_registers_fops);
 
--
2.7.4


转载于:https://www.cnblogs.com/hongjiujin/p/8176164.html

imx6q是一款处理器,它没有/dev/dsp设备节点。在Linux系统中,/dev/dsp通常用于访问音频设备的数字信号处理器(DSP)。然而,imx6q处理器使用的音频设备驱动程序不会创建/dev/dsp设备节点。 相反,imx6q处理器使用ALSA(Advanced Linux Sound Architecture)作为音频子系统。ALSA提供了一组用户空间工具和库,用于管理音频设备和音频数据的输入和输出。在imx6q上,您可以使用ALSA工具和库来访问和控制音频设备。 要在imx6q上使用音频设备,您需要编译和加载适当的内核模块。根据您提供的引用\[1\],\[2\]和\[3\],看起来您正在编译和配置与imx6q处理器上的MIC1388音频编解码器相关的内核模块。 一旦您成功编译和加载了适当的内核模块,您可以使用ALSA工具(如aplay和arecord)来播放和录制音频数据。您可以使用命令行界面或编写自己的应用程序来与ALSA进行交互。 请注意,具体的配置和使用方法可能因您的系统和环境而有所不同。建议您参考相关的文档和资源,以获取更详细的指导和说明。 #### 引用[.reference_title] - *1* *2* *3* [imx6q添加虚拟声卡](https://blog.csdn.net/weixin_41176628/article/details/115360591)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值