开发环境:win10 64位 + VMware12 + Ubuntu14.04 32位
工具链:linaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-gnueabi
要移植的kernel版本:linux-4.4
Tiny4412开发板硬件版本为:
底板: Tiny4412SDK 1312B
核心板:Tiny4412 - 1306
——————————————————————————————————————————————————————————
1,查看原理图
与整个DM9621相连的有三个口,DP1+和DM1-与USB4640连接传输数据。另有一个复位口,控制网卡使能,低电平有效。所以我们在配置设备树USB-HUB时, 需要将GPM2_4拉低。
2,Patch
diff --git a/include/linux/platform_data/usb4640.h b/include/linux/platform_data/usb4640.h new file mode 100644 index 0000000..062a50c --- /dev/null +++ b/include/linux/platform_data/usb4640.h @@ -0,0 +1,24 @@ +#ifndef __USB4640_H__ +#define __USB4640_H__ + +#define USB4640_NAME "usb4640" +enum usb4640_mode { + USB4640_MODE_UNKNOWN = 1, + USB4640_MODE_HUB, + USB4640_MODE_STANDBY, +}; + +struct usb4640_platform_data { + enum usb4640_mode initial_mode; +#define USB4640_NAME "usb4640" +enum usb4640_mode { + USB4640_MODE_UNKNOWN = 1, + USB4640_MODE_HUB, + USB4640_MODE_STANDBY, +}; + +struct usb4640_platform_data { + enum usb4640_mode initial_mode; + int gpio_reset; +}; + +#endif
diff --git a/include/dt-bindings/usb4640/usb4640.h b/include/dt-bindings/usb4640/usb4640.h new file mode 100644 index 0000000..ef3e1e1 --- /dev/null +++ b/include/dt-bindings/usb4640/usb4640.h @@ -0,0 +1,7 @@ +#ifndef _DT_BINDINGS_USB4640 +#define _DT_BINDINGS_USB4640 + +#define USB4640_MODE_UNKNOWN 1 +#define USB4640_MODE_HUB 2 +#define USB4640_MODE_STANDBY 3 +#endif
diff --git a/drivers/usb/misc/usb4640.c b/drivers/usb/misc/usb4640.c new file mode 100644 index 0000000..b7bc085 --- /dev/null +++ b/drivers/usb/misc/usb4640.c @@ -0,0 +1,157 @@ +/* + * Driver for SMSC USB4640 USB 2.0 hub controller driver + * + */ + +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/platform_data/usb4640.h> + +struct usb4640 { + enum usb4640_mode mode; + struct device *dev; + int gpio_reset; +}; + +static int usb4640_reset(struct usb4640 *hub, int state) +{ + if (gpio_is_valid(hub->gpio_reset)) + gpio_set_value_cansleep(hub->gpio_reset, state); + + /* Wait 1ms for hub logic to stabilize */ + if (state) + usleep_range(1, 10); + + return 0; +} + +static int usb4640_connect(struct usb4640 *hub) +{ + struct device *dev = hub->dev; + + usb4640_reset(hub, 1); + hub->mode = USB4640_MODE_HUB; + dev_info(dev, "switched to HUB mode "); + + return 0; +} + +static int usb4640_switch_mode(struct usb4640 *hub, enum usb4640_mode mode) +{ + struct device *dev = hub->dev; + int err = 0; + + switch (mode) { + case USB4640_MODE_HUB: + err = usb4640_connect(hub); + break; + + case USB4640_MODE_STANDBY: + usb4640_reset(hub, 0); + dev_info(dev, "switched to STANDBY mode "); + break; + + default: + dev_err(dev, "unknown mode is requested "); + err = -EINVAL; + break; + } + + return err; +} + + +static int usb4640_probe(struct usb4640 *hub) +{ + struct device *dev = hub->dev; + struct usb4640_platform_data *pdata = dev_get_platdata(dev); + struct device_node *np = dev->of_node; + int err; + u32 mode = USB4640_MODE_HUB; + + if (pdata) { + hub->gpio_reset = pdata->gpio_reset; + hub->mode = pdata->initial_mode; + } else if (np) { + hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0); + if (hub->gpio_reset == -EPROBE_DEFER) + return -EPROBE_DEFER; + of_property_read_u32(np, "initial-mode", &mode); + hub->mode = mode; + } + + if (gpio_is_valid(hub->gpio_reset)) { + err = devm_gpio_request_one(dev, hub->gpio_reset, + GPIOF_OUT_INIT_LOW, "usb4640 reset"); + if (err) { + dev_err(dev, + "unable to request GPIO %d as reset pin (%d) ", + hub->gpio_reset, err); + return err; + } + } else + dev_err(dev, "reset gpio is invalid: %d ", hub->gpio_reset); + + usb4640_switch_mode(hub, hub->mode); + + dev_info(dev, "%s: probed in %s mode ", __func__, + (hub->mode == USB4640_MODE_HUB) ? "hub" : "standby"); + + return 0; +} + +static int usb4640_platform_probe(struct platform_device *pdev) +{ + struct usb4640 *hub; + + hub = devm_kzalloc(&pdev->dev, sizeof(struct usb4640), GFP_KERNEL); + if (!hub) + return -ENOMEM; + hub->dev = &pdev->dev; + + return usb4640_probe(hub); +} + +#ifdef CONFIG_OF +static const struct of_device_id usb4640_of_match[] = { + { .compatible = "smsc,usb4640", }, + {}, +}; +MODULE_DEVICE_TABLE(of, usb4640_of_match); +#endif + +static struct platform_driver usb4640_platform_driver = { + .driver = { + .name = USB4640_NAME, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(usb4640_of_match), +#endif + }, + .probe = usb4640_platform_probe, +}; + +static int __init usb4640_init(void) +{ + int err; + + err = platform_driver_register(&usb4640_platform_driver); + if (err != 0) + pr_err("usb4640: Failed to register platform driver: %d ", + err); + + return 0; +} +module_init(usb4640_init); + +static void __exit usb4640_exit(void) +{ + platform_driver_unregister(&usb4640_platform_driver); +} +module_exit(usb4640_exit); + +MODULE_DESCRIPTION("USB4640 USB HUB driver"); +MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 45fd4ac..98f81ed 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -25,6 +25,9 @@ obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o + +obj-$(CONFIG_USB_HSIC_USB4640) += usb4640.o + obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index f7a7fc2..9692ca5 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -249,6 +249,11 @@ config USB_HSIC_USB3503 help This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. +config USB_HSIC_USB4640 + tristate "USB4640 HSIC to USB20 Driver" + help + This option enables support for SMSC USB4640 HSIC to USB 2.0 Driver. + config USB_LINK_LAYER_TEST tristate "USB Link Layer Test driver" help
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos index 048ae67..948f2d9 100644 --- a/arch/arm/boot/dts/exynos4412-tiny4412.dts +++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "exynos4412.dtsi" #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/usb4640/usb4640.h> / { model = "FriendlyARM TINY4412 board based on Exynos4412"; @@ -21,13 +22,16 @@ chosen { stdout-path = &serial_0; - bootargs="root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init= - }; + bootargs="root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 et hmac=1C:6F:65:34:51:7E init=/linuxrc ignore_loglevel earlyprink";
+ + }; + memory { + device_type = "memory"; reg = <0x40000000 0x40000000>; }; - + leds { compatible = "gpio-leds"; @@ -69,8 +73,17 @@ clock-frequency = <24000000>; }; }; + + usb-hub { + compatible = "smsc,usb4640"; + reset-gpios = <&gpm2 4 GPIO_ACTIVE_LOW>; + initial-mode = <USB4640_MODE_HUB>; + status = "okay"; + }; }; + + &rtc { status = "okay"; }; @@ -98,3 +111,47 @@ &serial_3 { status = "okay"; }; + +&mshc_0 { + pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>; + pinctrl-names = "default"; + status = "okay"; + + num-slots = <1>; + broken-cd; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + bus-width = <8>; + cap-mmc-highspeed; +}; + + +&exynos_usbphy { + status = "okay"; +}; + +&ehci { + status = "okay"; + port@0 { + status = "okay"; + }; + port@1 { + status = "okay"; + }; + port@2 { + status = "okay"; + }; +}; + +&ohci { + status = "okay"; + port@0 { + status = "okay"; + }; +}; + +&hsotg { + status = "okay"; +}; +
diff --git a/tiny4412_defconfig b/tiny4412_defconfig index 91cba5b..178cea8 100644 --- a/tiny4412_defconfig +++ b/tiny4412_defconfig @@ -1160,7 +1160,7 @@ CONFIG_USB_NET_CDCETHER=y CONFIG_USB_NET_CDC_NCM=y # CONFIG_USB_NET_HUAWEI_CDC_NCM is not set # CONFIG_USB_NET_CDC_MBIM is not set -# CONFIG_USB_NET_DM9601 is not set +CONFIG_USB_NET_DM9601=y # CONFIG_USB_NET_SR9700 is not set # CONFIG_USB_NET_SR9800 is not set CONFIG_USB_NET_SMSC75XX=y @@ -2628,7 +2628,8 @@ CONFIG_USB_DWC2_DUAL_ROLE=y # CONFIG_USB_ISIGHTFW is not set # CONFIG_USB_YUREX is not set # CONFIG_USB_EZUSB_FX2 is not set -CONFIG_USB_HSIC_USB3503=y +# CONFIG_USB_HSIC_USB3503 is not set +CONFIG_USB_HSIC_USB4640=y # CONFIG_USB_LINK_LAYER_TEST is not set # CONFIG_USB_CHAOSKEY is not set
结果:
发现缺少IP地址
[root@tiny4412:/]#ifconfig eth0 192.168.1.130
完成。