小白自制Linux开发板 七. USB驱动配置
本文章基于
https://whycan.com/t_3087.html
https://whycan.com/t_6021.html
整理
F1c100s芯片支持USB的OTG模式,也就是可以通过更改UsbId拉低或拉高方式定义当前的开发板可以作为host还是device。
- usbid 拉高时,开发板作为外设方式。
- usbid 拉低时,开发板作为主机方式。
当然除了使用硬件方式,还可以通过Linux系统直接更改当前USB的模式。
1. 原理图
在F1c100s中PE2引脚是作为usbid功能来使用,因为为了使用Sunxi-tool 所以我在画原理图的时候默认将PE2做了上拉处理。
这个芯片只有一个usb引脚

为了可以引出更多的usb外设,所以这里使用了FE8.1这个USB Hub芯片,这个芯片最多可以引出4个Usb接口。具体原理图如下:

2. 设备树与驱动代码配置
硬件处理完成,接下来就是软件部分修改了,打开Linux5.7.1内核源码
2.1 首先修改设备树文件arch/arm/boot/dts/suniv-f1c100s.dtsi文件
在soc节点下增加
usb_otg: usb@1c13000 {
compatible = "allwinner,suniv-musb";
reg = <0x01c13000 0x0400>;
clocks = <&ccu CLK_BUS_OTG>;
resets = <&ccu RST_BUS_OTG>;
interrupts = <26>;
interrupt-names = "mc";
phys = <&usbphy 0>;
phy-names = "usb";
extcon = <&usbphy 0>;
allwinner,sram = <&otg_sram 1>;
status = "disabled";
};
usbphy: phy@1c13400 {
compatible = "allwinner,suniv-usb-phy";
reg = <0x01c13400 0x10>;
reg-names = "phy_ctrl";
clocks = <&ccu CLK_USB_PHY0>;
clock-names = "usb0_phy";
resets = <&ccu RST_USB_PHY0>;
reset-names = "usb0_reset";
#phy-cells = <1>;
status = "disabled";
};
2.2 修改arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts文件
在文件里面添加
&otg_sram {
status = "okay";
};
&usb_otg {
dr_mode = "host"; /* 三个可选项: otg / host / peripheral 我在这里指定为host模式*/
status = "okay";
};
&usbphy {
usb0_id_det-gpio = <&pio 4 2 GPIO_ACTIVE_HIGH>; /* PE2 */
status = "okay";
};
2.3 修改drivers/phy/allwinner/phy-sun4i-usb.c文件
因为我们在设备树中定义的驱动是suniv-usb-phy,所以我们需要添加这部分代码。
enum sun4i_usb_phy_type {
suniv_phy, //新增枚举值
sun4i_a10_phy,
sun6i_a31_phy,
sun8i_a33_phy,
sun8i_a83t_phy,
sun8i_h3_phy,
sun8i_r40_phy,
sun8i_v3s_phy,
sun50i_a64_phy,
sun50i_h6_phy,
};
//新增以下结构
static const struct sun4i_usb_phy_cfg suniv_cfg = {
.num_phys = 1,
.type = suniv_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = true,
};
static const struct of_device_id sun4i_usb_phy_of_match[] = {
{ .compatible = "allwinner,suniv-usb-phy", .data = &suniv_cfg }, //新增配置项
{ .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
{ .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
{ .compatible = "allwinner,sun6i-a31-usb-phy", .data = &sun6i_a31_cfg },
{ .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
{ .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
{ .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg },
{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
{ .compatible = "allwinner,sun8i-r40-usb-phy", .data = &sun8i_r40_cfg },
{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
{ .compatible = "allwinner,sun50i-a64-usb-phy",
.data = &sun50i_a64_cfg},
{ .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
{ },
};
2.4 修改drivers/usb/musb/sunxi.c文件
这里主要处理设备树中定义的驱动suniv-musb。
static int sunxi_musb_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data pdata;
struct platform_device_info pinfo;
struct sunxi_glue *glue;
struct device_node *np = pdev->dev.of_node;
int ret; if (!np) {
dev_err(&pdev->dev, "Error no device tree node found\n");
return -EINVAL;
} glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM; memset(&pdata, 0, sizeof(pdata));
switch (usb_get_dr_mode(&pdev->dev)) {
#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
case USB_DR_MODE_HOST:
pdata.mode = MUSB_HOST;
glue->phy_mode = PHY_MODE_USB_HOST;
break;
#endif
#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_GADGET
case USB_DR_MODE_PERIPHERAL:
pdata.mode = MUSB_PERIPHERAL;
glue->phy_mode = PHY_MODE_USB_DEVICE;
break;
#endif
#ifdef CONFIG_USB_MUSB_DUAL_ROLE
case USB_DR_MODE_OTG:
pdata.mode = MUSB_OTG;
glue->phy_mode = PHY_MODE_USB_OTG;
break;
#endif
default:
dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n");
return -EINVAL;
}
pdata.platform_ops = &sunxi_musb_ops;
if (!of_device_is_compatible(np, "allwinner,sun8i-h3-musb"))
pdata.config = &sunxi_musb_hdrc_config;
else
pdata.config = &sunxi_musb_hdrc_config_h3; glue->dev = &pdev->dev;
INIT_WORK(&glue->work, sunxi_musb_work);
glue->host_nb.notifier_call = sunxi_musb_host_notifier; if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb")||
of_device_is_compatible(np, "allwinner,suniv-musb")){ //新增判断项代码
set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
}
if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb") ||
of_device_is_compatible(np, "allwinner,sun8i-h3-musb") ||
of_device_is_compatible(np, "allwinner,suniv-musb")) { //新增判断项代码
set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags);
} glue->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(glue->clk)) {
dev_err(&pdev->dev, "Error getting clock: %ld\n",
PTR_ERR(glue->clk));
return PTR_ERR(glue->clk);
} if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
glue->rst = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(glue->rst)) {
if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "Error getting reset %ld\n",
PTR_ERR(glue->rst));
return PTR_ERR(glue->rst);
}
} …………
static const struct of_device_id sunxi_musb_match[] = {
{ .compatible = "allwinner,suniv-musb", }, //新增代码
{ .compatible = "allwinner,sun4i-a10-musb", },
{ .compatible = "allwinner,sun6i-a31-musb", },
{ .compatible = "allwinner,sun8i-a33-musb", },
{ .compatible = "allwinner,sun8i-h3-musb", },
{}
};
2.5 通过menuconfig配置usb相关的选项
进入:Device Drivers - USB support


进行配置,当然可以根据自己实际情况进行开启与配置。
接下载编译Linux编译内核和设备树,就可以得到内核文件和设备树文件了。
3. 测试USB键盘
这里我默认设置开发板为host模式,然后我要通过usb连接键盘进行输入操作:
[ 31.653231] cfg80211: failed to load regulatory.db
[ 31.696053] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[ 31.707915] VFS: Mounted root (ext4 filesystem) on device 179:2.
[ 31.726584] devtmpfs: mounted
[ 31.736031] Freeing unused kernel memory: 1024K
[ 31.746083] Run /sbin/init as init process
[ 32.023410] usb 1-1: new high-speed USB device number 2 using musb-hdrc
[ 32.215728] hub 1-1:1.0: USB hub found
[ 32.221496] hub 1-1:1.0: 4 ports detected
启动日志中我们可以看到usb已经被检测到,并且检测到4个端口,但是我们只用到两个。
插入键盘。
拔出键盘。
键盘操作开发板:

如果想要进一步了解usb相关的操作,可以借助usbutils相关组件。
首先安装usbutils组件
apt-get install usbutils
安装完成后执行:
lsusb
就可以查看相关usb设备信息了。

4 通过LINUX方式更改USB属性
首先更改设备树,改为otg模式
&usb_otg {
dr_mode = "otg"; /* 三个可选项: otg / host / peripheral */
status = "okay";
};
进入Linux系统,执行,usb将会被设置成为host模式
echo host > /sys/devices/platform/soc/1c13000.usb/musb-hdrc.1.auto/mode
运行结果如下,此时可以插入键盘,就可以使用键盘操作Linux了。
# echo host > /sys/devices/platform/soc/1c13000.usb/musb-hdrc.1.auto/mode
# [117.758152] phy phy-1c13400.phy.0: Changing dr_mode to 1
[ 118.414817] usb 1-1: new high-speed USB device number 3 using musb-hdrc
[ 118.598193] usb-storage 1-1:1.0: USB Mass Storage device detected
[ 118.611789] scsi host0: usb-storage 1-1:1.0
[ 119.686198] scsi 0:0:0:0: Direct-Access Mass Storage Device 1.00 PQ: 0 ANSI: 0 CCS
[ 119.703976] sd 0:0:0:0: [sda] 3842048 512-byte logical blocks: (1.97 GB/1.83 GiB)
[ 119.725260] sd 0:0:0:0: Attached scsi generic sg0 type 0
[ 119.739844] sd 0:0:0:0: [sda] Write Protect is off
[ 119.771819] sd 0:0:0:0: [sda] No Caching mode page found
[ 119.777288] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 119.801571] sda: sda1 sda2 sda3
[ 119.817224] sd 0:0:0:0: [sda] Attached SCSI removable disk
如果执行如下命令,则进入设备模式
#
##切换到device模式:
# echo peripheral > /sys/devices/platform/soc/1c13000.usb/musb-hdrc.1.auto/mode
[ 123.880272] phy phy-1c13400.phy.0: Changing dr_mode to 2
# [ 123.890905] usb 1-1: USB disconnect, device number 3
后记
在论坛中用有测试表明,在这个方案配置完USB后,可能无法同时运行两个控制设备,墨云没做相关测试,如果有相关需求的还请注意核实。谢谢
小白自制Linux开发板 七. USB驱动配置的更多相关文章
- 小白自制Linux开发板 二. u-boot移植
上一篇:小白自制Linux开发板 一. 瞎抄原理图与乱画PCB 中我们做了一个小型而没用的开发板,用的是Licheepi Nano的镜像,那从本篇开始我们开始自己构建它的灵魂吧. 我们都知道,PC在 ...
- 小白自制Linux开发板 三. Linux内核与文件系统移植
上一篇完成了uboot的移植,但是想要愉快的在开发板上玩耍还需要移植Linux内核和文件系统. 1.Linux内核 事实上对于F1C100S/F1C200S,Linux官方源码已经对licheepi ...
- 小白自制Linux开发板 八. Linux音频驱动配置
不知不觉小白自制开发板系列已经到第八篇了,本篇要配置的是音频驱动,也算是硬件部分的最后一片了,积攒的文章也差不多全放完了,后续更新可能会放缓,还请见谅. 对于F1C200s是自带了多媒体处理功能的,所 ...
- 小白自制Linux开发板 番外篇 一 modprobe加载驱动问题(转载整理)
使用modprobe加载驱动 转载地址:https://blog.csdn.net/qq_39101111/article/details/78773362 前面我们提到,modprobe并不需要指定 ...
- 小白自制Linux开发板 一. 瞎抄原理图与乱画PCB
因为墨云是基于高中物理水平的电路知识来学习.而且此前也就玩过树莓派.Esp8266之类的开发板,水平基础趋近于零,所以在写这个系列的时候抱着记录的心态.还望不足之处还望大佬们指正. <论语> ...
- 小白自制Linux开发板 四. 通过SPI使用ESP8266做无线网卡
本文章基于 WhyCan Forum(哇酷开发者社区) https://whycan.com/t_4149.htmlhttps://whycan.com/t_5870.html整理而成. 为了尊重原作 ...
- 小白自制Linux开发板(第二季 V3s篇) 一. 换个核心再来一次
1.前言 大家心心念念(个人认为)的小白自制开发板全新系列正式来了,之前我们使用全志的F1C200s芯片制作了一个小电脑,众所周知,调试很艰难,坑也很多,以至于墨云到现在还是没找到对应的补救方案,为了 ...
- 小白自制Linux开发板 十. NES游戏玩起来
本篇基于我们制作的Debian文件系统而展开,而且我们这会玩一些高级的操作方式--用我们的小电脑进行程序编译. 所以本篇操作全部都在我们个的开发板上完成. 1. 开发环境搭建 首先安装gcc, ...
- 小白自制Linux开发板 六. SPI TFT屏幕修改与移植
本文章参考:https://www.bilibili.com/read/cv9947785?spm_id_from=333.999.0.0 本篇通过SPI接口,使用ST7789V TFT焊接屏(13p ...
随机推荐
- Docker(42)- 镜像原理之联合文件系统
前言 学习狂神老师的 Docker 系列课程,并总结 镜像是什么 镜像是一种轻量级.可执行的独立软件保,用来打包软件运行环境和基于运行环境开发的软件 他包含运行某个软件所需的所有内容,包括代码.运行时 ...
- 如果还是看不懂container_of()函数,那算我输
在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义 ...
- python模块--glob, fnmatch
包/方法 返回值 参数 说明 glob Unix shell样式的路径扩展 .glob() list 匹配满足规则的所有路径(默认以 . 开头的文件不会匹配到, 可以用 .* 来匹配) pat ...
- Java 简介与安装、语法说明、数据类型
目录 Java 介绍 Java 简介 Java 语言跨平台原理 JRE 和 JDK JDK 下载/安装说明 Java 语法说明 注释 关键字 标识符 数据类型 基本数据类型 引用数据类型 隐式类型转换 ...
- 一文带你了解.Net读写锁
本文主要讲解.Net基于ReaderWriterLockSlim讲解读写锁 基础概念 读写锁是一个具有特殊用途的线程锁,适用于频繁读取且读取需要一定时间的场景,共享资源的读取操作通常是可以同时执行的, ...
- docker 搭建 zipkin
1.拉镜像 docker pull openzipkin/zipkin 2.运行镜像 docker run -d --restart always -p 9411:9411 --name zipkin ...
- 深入xLua实现原理之Lua如何调用C#
xLua是腾讯的一个开源项目,为Unity. .Net. Mono等C#环境增加Lua脚本编程的能力.本文主要是探讨xLua下Lua调用C#的实现原理. Lua与C#数据通信机制 无论是Lua调用C# ...
- Dockerfile 自动制作 Docker 镜像(一)—— 基本命令
Dockerfile 自动制作 Docker 镜像(一)-- 基本命令 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云服务器 c. 上一篇:手动制作Do ...
- Eclipse中快速生成Javabean的方法
总结一下: 先写出属性 无参构造器:Alt+/ 再按回车 全参构造器:Alt+Shift+S 再按字母O键 再按回车 toString方法:Alt+Shift+S 再按字母S键 再按回车 get/se ...
- 学习PHP中的目录操作
对于编程语言来说,文件和目录的操作是其最最基础的功能.就像我们日常中最常见的图片上传.文件上传之类的功能,都需要文件和目录操作的支持.今天我们先来简单地学习一下 PHP 中关于目录操作的一些类和函数. ...