下面的两个宏是PM8058的MMP11(R15),MMP12(P15)管脚。
#define EXT_CHG_VALID_MPP 10
#define EXT_CHG_VALID_MPP_2 11

static struct pm8xxx_mpp_init_info isl_mpp[] = {
    PM8058_MPP_INIT(EXT_CHG_VALID_MPP, D_INPUT,
        PM8058_MPP_DIG_LEVEL_S3, DIN_TO_INT),
    PM8058_MPP_INIT(EXT_CHG_VALID_MPP_2, D_BI_DIR,
        PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_10KOHM),
};

//配置管脚功能函数
#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
static int smb137b_detection_setup(void)
{
    int ret = 0, i;

for (i = 0; i < ARRAY_SIZE(isl_mpp); i++) {
        ret = pm8xxx_mpp_config(isl_mpp[i].mpp,&isl_mpp[i].config);
    }

return ret;
}

static struct smb137b_platform_data smb137b_data __initdata = {
    .chg_detection_config = smb137b_detection_setup,
    .valid_n_gpio = PM8058_MPP_PM_TO_SYS(10),
    .batt_mah_rating = 950,
};

static struct i2c_board_info smb137b_charger_i2c_info[] __initdata = {
    {
        I2C_BOARD_INFO("smb137b", 0x08),
        .irq = PM8058_IRQ_BASE + PM8058_CBLPWR_IRQ,//计算后的irq值=464
        .platform_data = &smb137b_data,
    },
};
#endif

static int __devinit smb137b_probe(struct i2c_client *client,const struct i2c_device_id *id)

    /*配置usb检测管脚*/
    if (pdata->chg_detection_config)
        ret = pdata->chg_detection_config();

/*用该检测gpio引脚前,申请该GPIO*/
    ret = gpio_request(pdata->valid_n_gpio, "smb137b_charger_valid");

/*申请中断,该中断号码为464*/
    ret = request_threaded_irq(client->irq, NULL,smb137b_valid_handler,
                    IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                    "smb137b_charger_valid", client);

/*先读取一次检测管脚值*/
    ret = gpio_get_value_cansleep(smb137b_chg->valid_n_gpio);
    if (!ret) {

/*上报usb的插入状态*/
        msm_charger_notify_event(smb137b_chg->adapter_hw_chg[0],CHG_INSERTED_EVENT);
        smb137b_chg->usb_status = SMB137B_PRESENT;
    }

/*以后的处理都是在中断中进行处理*/
static irqreturn_t smb137b_valid_handler(int irq, void *dev_id)
{
    struct smb137b_data *smb137b_chg;

smb137b_chg = i2c_get_clientdata(client);
    smb137b_chg->current_hw_chg = smb137b_chg->adapter_hw_chg[0];
    
    /*读出检测管脚的电平值*/
    val = gpio_get_value_cansleep(smb137b_chg->valid_n_gpio);

if (val) {
        if (smb137b_chg->usb_status != SMB137B_ABSENT) {
            smb137b_chg->usb_status = SMB137B_ABSENT;
            /*如果为高电平,通知usb移出*/
            msm_charger_notify_event(smb137b_chg->current_hw_chg,CHG_REMOVED_EVENT);
        }
    } else if (smb137b_chg->usb_status == SMB137B_ABSENT) {
            smb137b_chg->usb_status = SMB137B_PRESENT;
            /*如果为高电平,通知usb插入*/
            msm_charger_notify_event(smb137b_chg->current_hw_chg,CHG_INSERTED_EVENT);
        }

下面进入发通知流程继续跟踪
int msm_charger_notify_event(struct msm_hardware_charger *hw_chg,
        enum msm_hardware_charger_event event)
{
    /*把该消息加入循环队列中*/
    msm_chg_enqueue_event(hw_chg, event);
    
    /*调度work*/
    queue_work(msm_chg.event_wq_thread, &msm_chg.queue_work);
    return 0;
}
下面的两行是在static int __init msm_charger_init(void)函数中进行初始化的:

INIT_WORK(&msm_chg.queue_work, process_events);
msm_chg.event_wq_thread = create_workqueue("msm_charger_eventd");   
该work的处理函数如下:
static void process_events(struct work_struct *work)
{
    struct msm_charger_event *event;
    int rc;
    /*循环处理等待队列中的消息*/
    do {
        rc = msm_chg_dequeue_event(&event);
        if (!rc)
            /*对单个的event进行处理*/
            handle_event(event->hw_chg, event->event);
    } while (!rc);
}
下面进入具体的handle_event函数分析:
static void handle_event(struct msm_hardware_charger *hw_chg, int event)
{
    struct msm_hardware_charger_priv *priv = NULL;

if (hw_chg)
        priv = hw_chg->charger_private;

switch (event) {
        case CHG_INSERTED_EVENT:
            if (hw_chg->type == CHG_TYPE_USB) {
                .................
                priv->hw_chg_state = CHG_PRESENT_STATE;

/*上报usb插入事件*/
                notify_usb_of_the_plugin_event(priv, 1);
                .........................
            break;
        case CHG_REMOVED_EVENT:
            if (hw_chg->type == CHG_TYPE_USB) {
                ...............
                usb_chg_current = 0;

/*上报usb移出事件*/
                notify_usb_of_the_plugin_event(priv, 0);
                ........................
            }
            break;
}

/*进入notify_usb_of_the_plugin_event函数继续跟踪*/
static void notify_usb_of_the_plugin_event(struct msm_hardware_charger_priv
        *hw_chg, int plugin)
{
    plugin = !!plugin;
    if (plugin == 1 && usb_notified_of_insertion == 0) {
        usb_notified_of_insertion = 1;
        if (notify_vbus_state_func_ptr) {
            /*调用回调函数*/
            (*notify_vbus_state_func_ptr) (plugin);
    }
    if (plugin == 0 && usb_notified_of_insertion == 1) {
        if (notify_vbus_state_func_ptr) {
            (*notify_vbus_state_func_ptr) (plugin);
        } 
        usb_notified_of_insertion = 0;
    }
}
/*下面进入回调函数的跟踪*/
/*在板级初始化时定义了一个全局函数指针*/
notify_vbus_state notify_vbus_state_func_ptr;

/*该函数指针在该回调函数中赋值*/
static int msm_hsusb_pmic_vbus_notif_init(void (*callback)(int online),
                                int init)
{
    int ret = -ENOTSUPP;
    if (machine_is_msm8x60_s9000() || pmic_id_notif_supported)) {
        if (init)
            ret = msm_charger_register_vbus_sn(callback);
        else {
            msm_charger_unregister_vbus_sn(callback);
            ret = 0;
        }
    } 
}
int msm_charger_register_vbus_sn(void (*callback)(int))
{
    notify_vbus_state_func_ptr = callback;
    return 0;
}

/*该回调函数注册的时机如下*/
#if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
static struct msm_otg_platform_data msm_otg_pdata = {
    ................
#ifdef CONFIG_BATTERY_MSM8X60
    .pmic_vbus_notif_init    = msm_hsusb_pmic_vbus_notif_init,
#endif
    .........................

};
#endif
/*把该平台数据赋值给平台设备*/
msm_device_otg.dev.platform_data = &msm_otg_pdata;

/*注册该平台设备*/
static struct platform_device *surf_devices[] __initdata = {
#if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
    &msm_device_otg,
#endif

static void __init msm8x60_init(struct msm_board_data *board_data)

    platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices));

static int __init msm_otg_probe(struct platform_device *pdev)
{
    ..............
    /*初始化work工作队列*/
    INIT_WORK(&dev->sm_work, msm_otg_sm_work);
    dev->wq = alloc_workqueue("k_otg", WQ_NON_REENTRANT, 0);
    ..................
    /*调用回调函数,为全局函数指针赋值*/
    if (dev->pdata->pmic_vbus_notif_init) {
        ret = dev->pdata->pmic_vbus_notif_init
            (&msm_otg_set_vbus_state, 1);
        if (!ret) {
            dev->pmic_vbus_notif_supp = 1;
        } 
    }
    ...............
    .......................
}
/*然后用该函数上报plug的值*/
void msm_otg_set_vbus_state(int online)
{
    struct msm_otg *dev = the_msm_otg;

/*如果上报插入事件,就设置B_SESS_VLD标志位*/
    if (online)
        set_bit(B_SESS_VLD, &dev->inputs);
    /*如果上报移除事件,就清除B_SESS_VLD标志位*/
    else
        clear_bit(B_SESS_VLD, &dev->inputs);
    
    /*获得wakelock锁*/
    wake_lock(&dev->wlock);
    
    /*调度工作队列中的work*/
    queue_work(dev->wq, &dev->sm_work);
}
/*下面进入work继续跟踪*/
static void msm_otg_sm_work(struct work_struct *w)

    enum usb_otg_state state;
    state = dev->otg.state;
    switch (state) {
        case OTG_STATE_UNDEFINED:
            if (!dev->otg.host || !is_host())
            {
                set_bit(ID, &dev->inputs);
            }

if (dev->otg.gadget && is_b_sess_vld())
            {
                set_bit(B_SESS_VLD, &dev->inputs);
            }

if ((test_bit(ID, &dev->inputs)) && !test_bit(ID_A, &dev->inputs)) {
                /*改变otg的状态机状态为OTG_STATE_B_IDLE*/
                dev->otg.state = OTG_STATE_B_IDLE;
            } 
            work = 1;
            break;
        case OTG_STATE_B_IDLE:
            if (test_bit(B_SESS_VLD, &dev->inputs) && !test_bit(ID_B, &dev->inputs)) {
            /*改变otg的状态机状态为OTG_STATE_B_PERIPHERAL*/
            dev->otg.state = OTG_STATE_B_PERIPHERAL;

msm_otg_set_power(&dev->otg, 0);
            
            /*启动外围设备*/
            msm_otg_start_peripheral(&dev->otg, 1);
        } 
        break;
    /*如果work为1,则继续调度work*/
    if (work)
        queue_work(dev->wq, &dev->sm_work);

/*上面的work牵涉到两个函数,通过寄存器的值判断,设置相应的位域*/
static int is_host(void)
{
    struct msm_otg *dev = the_msm_otg;

if (dev->pdata->otg_mode == OTG_ID)
    {
        /*读出该寄存器的第8位,如果读出的为1,则返回0,即该设备为B device*/
        return (OTGSC_ID & readl(USB_OTGSC)) ? 0 : 1;
    }
}

static int is_b_sess_vld(void)
{
    struct msm_otg *dev = the_msm_otg;

if (dev->pdata->otg_mode == OTG_ID)
    {
        /*读出该寄存器的第11位,如果为1,则返回1,该寄存器在spec中说明如下:Indicates that the Vbus is above the B session valid threshold.*/
        return (OTGSC_BSV & readl(USB_OTGSC)) ? 1 : 0;
    }
}
/*下面进入msm_otg_start_peripheral函数进行分析*/
static void msm_otg_start_peripheral(struct otg_transceiver *xceiv, int on)
{
    struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
    if (on) {
        usb_gadget_vbus_connect(xceiv->gadget);
    } 
}
/*设置gadget的vbus*/
static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
{
    if (!gadget->ops->vbus_session)
        return -EOPNOTSUPP;
    return gadget->ops->vbus_session(gadget, 1);
}
/*调用底层gadget的回调函数*/
gadget->ops->vbus_session(gadget, 1);

/*下面是该回调函数的结构体*/
static const struct usb_gadget_ops msm72k_ops = {
    .get_frame    = msm72k_get_frame,
    /*该回调函数*/
    .vbus_session    = msm72k_udc_vbus_session,
    .vbus_draw    = msm72k_udc_vbus_draw,
    .pullup        = msm72k_pullup,
    .wakeup        = msm72k_wakeup,
    .set_selfpowered = msm72k_set_selfpowered,
};
/*回调函数的注册过程如下*/
static int msm72k_probe(struct platform_device *pdev)
{
    ui = kzalloc(sizeof(struct usb_info), GFP_KERNEL);
    ui->gadget.ops = &msm72k_ops;
}
/*看下vbus的回调函数*/
static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
    /*设置vbus的状态*/
    msm_hsusb_set_vbus_state(is_active);
    return 0;
}
/*继续跟踪设置vbus的状态*/
void msm_hsusb_set_vbus_state(int online)
{
    struct usb_info *ui = the_usb_info;

/*根据传入的状态设置usb的状态位*/
    if (online) {
        ui->usb_state = USB_STATE_POWERED;
        ui->flags |= USB_FLAG_VBUS_ONLINE;
    } else {
        ui->gadget.speed = USB_SPEED_UNKNOWN;
        ui->usb_state = USB_STATE_NOTATTACHED;
        ui->flags |= USB_FLAG_VBUS_OFFLINE;
    }
    
    /*调度usb的工作队列*/
    if (in_interrupt()) {
        schedule_work(&ui->work);
    } else {
        usb_do_work(&ui->work);
        return;
    }
}
/*在usb_do_work中会进入一个大的状态机循环*/
static void usb_do_work(struct work_struct *w)
{
    struct usb_info *ui = container_of(w, struct usb_info, work);
    struct msm_otg *otg = to_msm_otg(ui->xceiv);
    unsigned long iflags;
    unsigned flags, _vbus;

for (;;) {
        spin_lock_irqsave(&ui->lock, iflags);
        flags = ui->flags;
        ui->flags = 0;
        _vbus = is_usb_online(ui);
        spin_unlock_irqrestore(&ui->lock, iflags);

/* give up if we have nothing to do */
        if (flags == 0)
            break;

switch (ui->state) {
        case USB_STATE_IDLE:
            if (flags & USB_FLAG_START) {
                int ret;
                /*重启设备控制器*/
                usb_reset(ui);
                
                /*申请中断处理函数*/
                ret = request_irq(otg->irq, usb_interrupt,IRQF_SHARED,ui->pdev->name, ui);
                ui->irq = otg->irq;
                
                /*改变设备状态*/
                ui->state = USB_STATE_ONLINE;
                usb_do_work_check_vbus(ui);
                
                /*使能D+数据线上的上拉电阻*/
                msm72k_pullup_internal(&ui->gadget, 1);
            break;
        case USB_STATE_ONLINE:
            if (flags & USB_FLAG_SUSPEND) {
                int maxpower = usb_get_max_power(ui);
                otg_set_power(ui->xceiv, 0);
                break;
            }
            if (flags & USB_FLAG_CONFIGURED) {
                int maxpower = usb_get_max_power(ui);
                switch_set_state(&ui->sdev,atomic_read(&ui->configured));
                ui->chg_current = maxpower;
                otg_set_power(ui->xceiv, maxpower);
                break;
            }
            if (flags & USB_FLAG_RESET) {
                msm72k_pullup_internal(&ui->gadget, 0);
                usb_reset(ui);
                msm72k_pullup_internal(&ui->gadget, 1);
                break;
            }
            break;
        case USB_STATE_OFFLINE:
            if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
                /*重启设备控制器*/
                usb_reset(ui);

/*改变设备状态*/
                ui->state = USB_STATE_ONLINE;
                usb_do_work_check_vbus(ui);

/*申请中断处理函数*/
                ret = request_irq(otg->irq, usb_interrupt,IRQF_SHARED,ui->pdev->name, ui);
                ui->irq = otg->irq;

/*使能D+数据线上的上拉电阻*/
                msm72k_pullup_internal(&ui->gadget, 1);
            }
            break;
        }
    }
}

/*中断函数的实时处理*/
static irqreturn_t usb_interrupt(int irq, void *data)
{
    struct usb_info *ui = data;
    unsigned n;
    unsigned long flags;

n = readl(USB_USBSTS);
    writel(n, USB_USBSTS);
    
    /*端口变化探测*/
    if (n & STS_PCI) {
        msm_hsusb_set_speed(ui);
        if (atomic_read(&ui->configured)) {
            ui->usb_state = USB_STATE_CONFIGURED;
            ui->flags = USB_FLAG_CONFIGURED;
            ui->driver->resume(&ui->gadget);
            schedule_work(&ui->work);
        } else {
            msm_hsusb_set_state(USB_STATE_DEFAULT);
        }
    }
    /*usb重启*/
    if (n & STS_URI) {
        dev_dbg(&ui->pdev->dev, "reset\n");
        ui->gadget.speed = USB_SPEED_UNKNOWN;
        msm_hsusb_set_state(USB_STATE_DEFAULT);
        ......................
    }
    /*usb挂起状态*/
    if (n & STS_SLI) {
        dev_dbg(&ui->pdev->dev, "suspend\n");
        ui->usb_state = USB_STATE_SUSPENDED;
        ui->flags = USB_FLAG_SUSPEND;
        ui->driver->suspend(&ui->gadget);
        schedule_work(&ui->work);
    }
    /*usb事务传输完成中断*/
    if (n & STS_UI) {
        n = readl(USB_ENDPTSETUPSTAT);
        if (n & EPT_RX(0))
            handle_setup(ui);

n = readl(USB_ENDPTCOMPLETE);
        writel(n, USB_ENDPTCOMPLETE);
        while (n) {
            unsigned bit = __ffs(n);
            handle_endpoint(ui, bit);
            n = n & (~(1 << bit));
        }
    }
    return IRQ_HANDLED;
}

Android4.0.3 USB OTG底层插入上报过程分析(1)相关推荐

  1. 通过OTG接口进入Android系统,Android4.0.3 USB OTG底层插入上报过程分析(1)

    下面的两个宏是PM8058的MMP11(R15),MMP12(P15)管脚. #define EXT_CHG_VALID_MPP 10 #define EXT_CHG_VALID_MPP_2 11 s ...

  2. iTop4412开发板Android4.0.3镜像OTG方式烧写

    iTop4412开发板Android4.0.3镜像OTG方式烧写 最近开始学习linux,入手一块讯为的iTop4412开发板,遵循讯为的框架学习法(毕竟科技更新速度如此之快,不可能什么都学,必须要懂 ...

  3. Android4.0平板通过OTG线连接Acr122U读取智慧校园卡

    Android4.0平板通过OTG线连接Acr122U读取智慧校园卡,使用读卡器官方提供的SDK,发送APDU的FF CA 00 00 00指令读取卡号UID,具体代码稍后上传.

  4. android 9.0上usb otg休眠问题

    问题:手机作为otg host时,怎样才能进入待机休眠? 参考高通文档:<80-NF283-1_C_Linux_USB_Implementation_Guide> section: 7.1 ...

  5. 全志android启动串口无打印,CSK.Blog-给MK802(USB大小的Android4.0小PC)引出串口信号,变成ARM开发版...

    最近忙各类事情,blog写的不系统,见谅. 这几天搞到了前不久被媒体宣传过的只有U盘大小的Android 4.0小PC.他的样子如下,使用HDMI接口连接显示器再外接一个usb键盘鼠标就能作为PC用了 ...

  6. [RK3288][Android6.0] USB OTG模式及切换

    Platform: RK3288 OS: Android 6.0 Kernel: 3.10.92 先提USB HOST/DEVICE/OTG概念: OTG控制器可以做host,也能做device,控制 ...

  7. android4.0.3源码之硬件gps简单移植

    [转]我和菜鸟一起学android4.0.3源码之硬件gps简单移植 2013-7-5阅读94 评论0 关于android定位方式 android 定位一般有四种方法,这四种方式分别是GPS定位.WI ...

  8. Android USB OTG U盘读写相关使用最全总结

    Android USB OTG U盘读写相关使用最全总结 https://blog.csdn.net/qq_29924041/article/details/80141514 androidOTG ( ...

  9. Android4.0与2.3的差异

    自从2011-10-19 google公司发布了android4.0版本,下载源码后,一直没有时间看下,正好需要看下JoyStick(游戏手柄)框架代码,所以两者代码进行对比浏览看看. Android ...

最新文章

  1. CentOS 漏洞修补
  2. hdu3400 两重三分
  3. 3.2.3节:特权级
  4. C#之windows桌面软件第五课:串口助手实现定时关闭设备、鼠标移动使按钮颜色变化功能
  5. CybersecurityVentures:中小企业将是SIEM市场增长的下一波热点
  6. Linux桌面环境介绍以及优缺点分析
  7. spring viewResolver 类别
  8. 作者:蓝梦微, 女, 中国人民大学信息学院博士生,CCF学生会员。
  9. Unity3D | 经典游戏Xiaoxiaole
  10. node状态管理cookie,session,token的各自特点和使用方法还有hash算法加密
  11. 打开应用商店显示服务器出错了,Win10应用商店提示“我们这边出错了”的三种解决方法...
  12. 基于免费的SDCC开发51单片机
  13. SpringMVC的基本使用+原理,一篇囊括
  14. ArcGIS打开影像图显示全黑色解决办法
  15. 广西艺术学院2012年本科招生专业考试通知
  16. 宠物保存服务市场现状及未来发展趋势分析
  17. 最新江苏安全员B考试单选练习题库
  18. 【论文笔记】Crop phenotyping in a context of Global Change: what to measure and how to do it
  19. 不到 20 人的 IT 公司该去吗?
  20. Option 82在校园网的应用与实现(转)

热门文章

  1. Java的四种引用,强弱软虚,用到的场景
  2. centos打显卡驱动命令_CentOS7显卡驱动问题
  3. Java中关于路径和使用exe4j打包成ext可执行程序的一些小总结
  4. oracle怎么解析sql,oracle SQL解析步骤小结
  5. 小强升职记梗概_《小强升职记》读后感
  6. m1mac安装linux,M1 Mac 能安装 Ubuntu 和 Linux 了 ??
  7. python归并排序 分词_python-归并排序
  8. win服务器系统程序原因
  9. SQL Server: Datetime,Datetime2
  10. springboot整合mybatis增删改查(三):mybatis逆向工程