mtk平台 mt_usb设备以及otg初始过程

注册mt_usb驱动

kernel-3.18/drivers/misc/mediatek/usb20/mt6735/usb20.c

static int __init usb20_init(void)
{

        ......

platform_driver_register(&mt_usb_driver);                        //注册mt_usb驱动
return platform_driver_register(&mt_usb_dts_driver);       //根据设备节点,注册mt_usb设备

}

mt_usb_driver定义如下

static struct platform_driver mt_usb_driver = {
.remove = mt_usb_remove,
.probe = mt_usb_probe,
.driver = {
  .name = "mt_usb",
  },

};

对应的platform_device如下

static struct platform_device mt_usb_device = {
.name = "mt_usb",
.id = -1,

};

mt_usb_probe负责初始化mt_usb设备,mt_usb_probe在mt_usb设备注册时会通过设备模型被调用


mt_usb设备在哪里注册

在usb20_init函数中mt_usb驱动注册之后,紧接着又注册了mt_usb_dts驱动

static struct platform_driver mt_usb_dts_driver = {
.remove = mt_usb_dts_remove,
.probe = mt_usb_dts_probe,
.driver = {
  .name = "mt_dts_usb",
#ifdef CONFIG_OF
  .of_match_table = apusb_of_ids,
#endif
  },

};

当系统启动之后,解析设备树,当满足apusb_of_ids时候就会调用mt_usb_dts_probe函数

static int mt_usb_dts_probe(struct platform_device *pdev)

{

        ......

mt_usb_device.dev.of_node = pdev->dev.of_node;

retval = platform_device_register(&mt_usb_device); 

        ......

}

mt_usb_dts_probe中注册了mt_usb设备

#ifdef CONFIG_OF
static const struct of_device_id apusb_of_ids[] = {
{.compatible = "mediatek,mt6735-usb20",},
{},
};


static struct platform_device mt_usb_device = {
.name = "mt_usb",
.id = -1,

};

#endif

触发mt_usb_dts_probe函数被调用的设备节点如下

                usb0:usb20@11200000 {
                        compatible = "mediatek,mt6735-usb20";
                        cell-index = <0>;
                        reg = <0x11200000 0x10000>,
                                <0x11210000 0x10000>;
                        interrupts = <0 72 0x8>;
                        mode = <2>;
                        multipoint = <1>;
                        dyn_fifo = <1>;
                        soft_con = <1>;
                        dma = <1>;
                        num_eps = <16>;
                        dma_channels = <8>;
                        clocks = <&perisys PERI_USB0>;
                        clock-names = "usb0";
                        VUSB33-supply = <&mt_pmic_vusb33_ldo_reg>;
                        iddig_gpio = <0 1>;
                        drvvbus_gpio = <83 2>;

                };

初始化mt_usb设备

mt_usb_dts_probe函数中调用platform_device_register(&mt_usb_device); 根据Linux设备模型,此处会match到mt_usb_driver,调用mt_usb_probe函数

static int mt_usb_probe(struct platform_device *pdev)

{

        musb_hdrc_platform_data有三种角色[MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG]

struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct mt_usb_glue *glue;
#ifdef CONFIG_OF
struct musb_hdrc_config *config;
struct device_node *np = pdev->dev.of_node;

#endif

        ......

musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;

}

        //初始化musb和pdata

        pdata->config = config;

musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &mt_usb_dmamask;

musb->dev.coherent_dma_mask = mt_usb_dmamask;

        ......

pdata->platform_ops = &mt_usb_ops;


platform_set_drvdata(pdev, glue);


ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err2;
}


ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
goto err2;
}


ret = platform_device_add(musb);

        //创建各种节点

}


static const struct musb_platform_ops mt_usb_ops = {
.init = mt_usb_init,
.exit = mt_usb_exit,
/*.set_mode     = mt_usb_set_mode, */
.try_idle = mt_usb_try_idle,
.enable = mt_usb_enable,
.disable = mt_usb_disable,
.set_vbus = mt_usb_set_vbus,
.vbus_status = mt_usb_get_vbus_status

};

mt_usb具体初始化过程

mt_usb设备被初始化成一个很大的数据机构struct musb,初始过程就是对该struct musb结构初始化

static int __init mt_usb_init(struct musb *musb)

{

        ......

        //通用寄存器配置

usb_phy_generic_register();

musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);

        ......


        //fifo dma power is_host

musb->dma_irq = (int)SHARE_IRQ;
musb->fifo_cfg = fifo_cfg;
musb->fifo_cfg_size = ARRAY_SIZE(fifo_cfg);
musb->dyn_fifo = true;
musb->power = false;
musb->is_host = false;

musb->fifo_size = 8 * 1024;

        ......


        //regulator上电

reg = regulator_get(musb->controller, "vusb33");
if (!IS_ERR(reg)) {
#define VUSB33_VOL_MIN 3300000
#define VUSB33_VOL_MAX 3300000
ret = regulator_set_voltage(reg, VUSB33_VOL_MIN, VUSB33_VOL_MAX);
if (ret < 0)
DBG(0, "regulator set vol failed: %d\n", ret);
else
DBG(0, "regulator set vol ok, <%d,%d>\n", VUSB33_VOL_MIN, VUSB33_VOL_MAX);

ret = regulator_enable(reg);

if (ret < 0) {
DBG(0, "regulator_enable failed: %d\n", ret);
regulator_put(reg);
} else {
DBG(0, "enable USB regulator\n");
}
} else {
DBG(0, "regulator_get failed\n");

}

        ......


        //musb中断

musb->isr = mt_usb_interrupt;

        ......


        //初始化musb_idle定时器

        setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long)musb);

    

        //mtk otg初始化

#ifdef CONFIG_USB_MTK_OTG
mt_usb_otg_init(musb);
#endif


return 0;

}

  • regulator上电

Linux中可以通过regulator给设备上电,mtk平台的平台设备树中会描述给各个模块的上电情况

kernel-3.18/arch/arm64/boot/dts/mt6753.dts中有如下描述

ldo_regulators {

        compatible = " mediatek,mt_pmic_ldo_regulators";
......
        mt_pmic_vcn33_wifi_ldo_reg: ldo_vcn33_wifi {
                regulator-name = "vcn33_wifi";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3600000>;
                regulator-enable-ramp-delay = <264>;

        };

        mt_pmic_vusb33_ldo_reg: ldo_vusb33 {
                regulator-name = "vusb33";                //给mt_usb模块上电
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                regulator-enable-ramp-delay = <264>;
                regulator-boot-on;

        };

        mt_pmic_vefuse_ldo_reg: ldo_vefuse {
                regulator-name = "vefuse";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <2200000>;
                regulator-enable-ramp-delay = <264>;
        };
......

}

OTG设备初始化与OTG中断处理

  • otg初始化

kernel-3.18/drivers/misc/mediatek/usb20/mt6735/usb20_host.c

void mt_usb_otg_init(struct musb *musb)

{

        ......

        //读取设备树配置,获得所用pin

usb_node = of_find_compatible_node(NULL, NULL, "mediatek,mt6735-usb20");
if (usb_node == NULL) {
pr_err("USB OTG - get USB0 node failed\n");
} else {
if (of_property_read_u32_index(usb_node, "iddig_gpio", 0, &iddig_pin)) {
iddig_if_config = 0;
pr_err("get dtsi iddig_pin fail\n");

}

if (of_property_read_u32_index(usb_node, "iddig_gpio", 1, &iddig_pin_mode))
pr_err("get dtsi iddig_pin_mode fail\n");
if (of_property_read_u32_index(usb_node, "drvvbus_gpio", 0, &drvvbus_pin)) {
drvvbus_if_config = 0;
pr_err("get dtsi drvvbus_pin fail\n");

}

if (of_property_read_u32_index(usb_node, "drvvbus_gpio", 1, &drvvbus_pin_mode))

pr_err("get dtsi drvvbus_pin_mode fail\n");

                ......

}

        ......


        //初始化pin脚

mt_usb_init_drvvbus();

        ......


        //初始化otg中断

INIT_DELAYED_WORK(&musb->id_pin_work, musb_id_pin_work);

otg_int_init();

        ......

}


otg中断初始化

static void otg_int_init(void)

{

        ......

        使用pinctl配置otg中断pin输入输出,上下拉特性

pinctrl_iddig_init = pinctrl_lookup_state(pinctrl, "iddig_init");
if (IS_ERR(pinctrl_iddig_init))
pr_err("Cannot find usb pinctrl iddig_init\n");
else
pinctrl_select_state(pinctrl, pinctrl_iddig_init);


pinctrl_iddig_enable = pinctrl_lookup_state(pinctrl, "iddig_enable");

pinctrl_iddig_disable = pinctrl_lookup_state(pinctrl, "iddig_disable");

if (IS_ERR(pinctrl_iddig_enable))
pr_err("Cannot find usb pinctrl iddig_enable\n");


if (IS_ERR(pinctrl_iddig_disable))
pr_err("Cannot find usb pinctrl iddig_disable\n");
else

pinctrl_select_state(pinctrl, pinctrl_iddig_disable);

        ......


        //根据pin脚拿到中断号,设置debounce,注册中断处理otg中断

        gpio_set_debounce(iddig_pin, 64000);
usb_iddig_number = mt_gpio_to_irq(iddig_pin);

ret = request_irq(usb_iddig_number, mt_usb_ext_iddig_int, IRQF_TRIGGER_LOW, "USB_IDDIG", NULL);

        ......

}


otg中断处理

当otg插入或拔出,产生中断时,会调用otg_int_init函数中注册的mt_usb_ext_iddig_int函数

static irqreturn_t mt_usb_ext_iddig_int(int irq, void *dev_id)
{
iddig_cnt++;


queue_delayed_work(mtk_musb->st_wq, &
mtk_musb->id_pin_work, msecs_to_jiffies(sw_deboun_time));
DBG(0, "id pin interrupt assert\n");
disable_irq_nosync(usb_iddig_number);
return IRQ_HANDLED;

}

中断处理函数唤醒之前注册的id_pin_work


mtk_musb->id_pin_work在mt_usb_otg_init函数中注册

INIT_DELAYED_WORK(&musb->id_pin_work, musb_id_pin_work);

static void musb_id_pin_work(struct work_struct *data)

{

        ......

        //判断musb的角色[host device]

if (host_plug_test_triggered)
mtk_musb->is_host = !mtk_musb->is_host;
else
mtk_musb->is_host =
musb_is_host();


        //这里调用内核中的switch_dev模块将状态变化以event的形式发送给上层【kobject_event】

switch_set_state((struct switch_dev *)&otg_state, mtk_musb->is_host);

        ......


        //host device处理

if (mtk_musb->is_host) {                //host

ep_config_from_table_for_host(mtk_musb);

mt_usb_set_vbus(mtk_musb, 1);

                

                //底层操作,设置一些寄存器

                ......

                

                //使能 速度设置 is_active

musb_start(mtk_musb);
MUSB_HST_MODE(mtk_musb);
switch_int_to_device(mtk_musb);

        }else{                                            //device

                ......

                //vbus下电

mt_usb_set_vbus(mtk_musb, 0);

                //底层操作,寄存器设置

                ......


                //musb idle

musb_stop(mtk_musb);
mtk_musb->xceiv->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(mtk_musb);
switch_int_to_host(mtk_musb);

        }

}

musb_is_host()函数根据id_pin的高低状态判断musb处于host还是device状态


思考:前面流程中mt_usb_init函数是在哪里被调用的呢

还记得在mt_usb_probe函数中有下面这么一段话吗,mt_usb_ops里面的方法怎么被调用

static int mt_usb_probe(struct platform_device *pdev)

{

        struct platform_device *musb;

        ......

pdata->platform_ops = &mt_usb_ops;


platform_set_drvdata(pdev, glue);


ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err2;
}


        //下面语句相当于musb->device.platform_data = pdata

ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
goto err2;
}


ret = platform_device_add(musb);         ......

}

上面platform_ops会在另外一个driver中被使用到,platform_device_add(musb)会触发调用该驱动的probe函数那就是musb-hdrc,代码位于如下路径

kernel-3.18/drivers/misc/mediatek/usb20/musb_core.c

musb-hdrc的初始化过程

static int __init musb_init(void)

{
if (usb_disabled())
return 0;


pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", musb_driver_name);
return platform_driver_register(
&musb_driver );
}

static struct platform_driver musb_driver = {
.driver = {
  .name = (char *)musb_driver_name,
  .bus = &platform_bus_type,
#if (!defined(CONFIG_MACH_MT2701)) && (!defined(CONFIG_ARCH_MT7623))
  .of_match_table = apusb_of_ids,
#endif
  .owner = THIS_MODULE,
  .pm = MUSB_DEV_PM_OPS,
  },
.probe =
musb_probe,
.remove = musb_remove,
.shutdown = musb_shutdown,

};


static int musb_probe(struct platform_device *pdev)

{

struct device *dev = &pdev->dev;

int irq = 0;
int status;
void __iomem *base;
#ifdef CONFIG_OF
void __iomem *pbase;
unsigned long usb_mac_base;
unsigned long usb_phy_base;

pr_info("musb probe\n");
DBG(0, "musb_removed to 0\n");
musb_removed = 0;
if (
dts_np) {
DBG(0, "dts node from dts_np\n");
pdev->dev.of_node = dts_np;

} else {

DBG(0, "dts node from of_find_compatible_node\n");
pdev->dev.of_node = of_find_compatible_node(NULL, NULL, "mediatek,USB0");
}
if (pdev->dev.of_node == NULL)
pr_info("USB get node failed\n");
base = of_iomap(pdev->dev.of_node, 0);
usb_irq_number = irq_of_parse_and_map(pdev->dev.of_node, 0);

pbase = of_iomap(pdev->dev.of_node, 1);


usb_mac_base = (unsigned long)base;
usb_phy_base = (unsigned long)pbase;
irq = usb_irq_number;
pr_info("musb probe reg: 0x%lx ,0x%lx , irq: 0x%d\n", usb_mac_base, usb_phy_base,
usb_irq_number);
#endif
#ifdef CONFIG_OF
status = musb_init_controller(dev, irq, base, pbase);
#else
base = (void *)USB_BASE;
status = musb_init_controller(dev, irq, base);

#endif


#if 0
if (status < 0)
iounmap(base);
#endif

#ifdef CONFIG_OF
usb_mac_base = (unsigned long)mtk_musb->xceiv->io_priv;
pr_info("musb core probe done base 0x%lx\n", usb_mac_base);
#endif

return status;

}


static int musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl, void __iomem *ctrlp)

{

int status;
struct musb *musb;
struct musb_hdrc_platform_data *plat = dev->platform_data;

struct usb_hcd *hcd;            //host controler driver

        ......


/* allocate */
musb = allocate_instance(dev, plat->config, ctrl);
if (!musb) {
status = -ENOMEM;
goto fail0;
}

mtk_musb = musb;

        ......


        //使用参数初始化struct musb结构,从此struct musb就可以使用

        musb->ops = plat->platform_ops;

        ......


status = musb_platform_init(musb);

        ......

        musb_platform_enable(musb);

        ......


/* setup musb parts of the core (especially endpoints) */
status = musb_core_init(plat->config->multipoint

? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC, musb);

        ......


        //host side setup

/* host side needs more setup */
hcd = musb_to_hcd(musb);
otg_set_host(musb->xceiv->otg, &hcd->self);
hcd->self.otg_port = 1;
musb->xceiv->otg->host = &hcd->self;

hcd->power_budget = 2 * (plat->power ? : 250);

        ......

}

musb_init_controller函数会完成以下部分逻辑

host controler driver

特殊端点如端点0

中断,otg

usb_gadget

mt_usb初始化

其中musb_platform_init,musb_platform_enable等函数都会调用mt_usb驱动中注册方法集实现,如

static inline int musb_platform_init(struct musb *musb)
{
if (!musb->ops->init)
return -EINVAL;


return musb->ops->init(musb);

}

static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
{
if (musb->ops->set_vbus)
musb->ops->set_vbus(musb, is_on);
}


static inline void musb_platform_enable(struct musb *musb)
{
if (musb->ops->enable)
musb->ops->enable(musb);

}

实际上使用的是mt_usb_init、mt_usb_set_vbus、mt_usb_enable等函数实现

static const struct musb_platform_ops mt_usb_ops = {
.init =
mt_usb_init,
.exit = mt_usb_exit,
/*.set_mode     = mt_usb_set_mode, */
.try_idle = mt_usb_try_idle,
.enable =
mt_usb_enable,
.disable = mt_usb_disable,
//delete XWQEOKF-99 by kaili.lu 20171218 start
//.set_vbus =
mt_usb_set_vbus,
//delete XWQEOKF-99 by kaili.lu 20171218 end
.vbus_status = mt_usb_get_vbus_status
};











猜你喜欢

转载自blog.csdn.net/zhanghao864442969/article/details/79420824