注册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
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
};