zoukankan      html  css  js  c++  java
  • 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 ",
    +            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 ", 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


  • 相关阅读:
    制作一个html中闪动的title 来提示消息
    Unicode与 utf8的互相转换
    程序员找女友的类
    使用php将数组转为XML
    自己动手画一个HTML5的按钮
    浏览器推通知给桌面
    如何使用定时任务
    封装之property,多态,鸭子类型,classmethod与staticmethod
    面向对象
    继承与派生
  • 原文地址:https://www.cnblogs.com/hongjiujin/p/8176164.html
Copyright © 2011-2022 走看看