07. Linux USB主機控制器和設備驅動

S5PV210 主機控制器驅動的移植

移植 ohci-s5p 驅動

  1. 拷貝drivers\usb\host\目錄下的 ohci-exynos.c 爲 ohci-s5p.c。 然後將所有 exynos 字符串替換成 s5p, 由於有些地方是 exynos4,所以還需要將 s5p4 替換爲 s5p。最後還需要修改下頭文件,將#include <linux/platform_data/usb-exynos.h>修改爲#include <linux/platform_data/usb-ohci-s5p.h>
  2. 打開內核目錄 include\linux\platform_data\,然後拷貝 usb-exynos.h 爲usb-ohci-s5p.h。將所有的 exynos4 字符串替換爲 s5p, 將 EXYNOS 替換爲 S5P。爲了以後支持 EHCI 還添加 echi 的平臺數據,最後 usb-ohci-s5p.h 修改爲:
#ifndef __MACH_S5P_OHCI_H
#define __MACH_S5P_OHCI_H

#ifdef CONFIG_S5P_DEV_USB_EHCI
static struct s5p_ehci_platdata s5p_ehci_platdata;
#endif
static struct s5p_ohci_platdata s5p_ohci_platdata;

struct s5p_ohci_platdata {
	int (*phy_init)(struct platform_device *pdev, int type);
	int (*phy_exit)(struct platform_device *pdev, int type);
};
extern void s5p_ohci_set_platdata(struct s5p_ohci_platdata *pd);
#endif
  1. 添加 s5p_ohci_driver 到 ohci-hcd.c
    打開 drivers\usb\host\ ohci-hcd.c,在 CONFIG_USB_OHCI_EXYNOS 前面添加如下代碼:
#ifdef CONFIG_USB_OHCI_S5P
#include "ohci-s5p.c"
#define PLATFORM_DRIVER s5p_ohci_driver
#endif
  1. 添加平臺設備
    打開 arch\arm\mach-s5pv210\mach-smdkv210.c,在 smdkv210_devices[ ]前,添加如下代碼:
#include <linux/platform_data/usb-ohci-s5p.h>
static struct resource s5p_ohci_resource[] = {
	[0] = DEFINE_RES_MEM(0xEC300000, SZ_256),
	[1] = DEFINE_RES_IRQ(S5P_IRQ_VIC1(23)),
};
static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
struct platform_device s5p_device_ohci = {
	.name = "s5p-ohci",
	.id = -1,
	.num_resources = ARRAY_SIZE(s5p_ohci_resource),
	.resource = s5p_ohci_resource,
	.dev = {
		.dma_mask = &samsung_device_dma_mask,
		.coherent_dma_mask = DMA_BIT_MASK(32),
	}
};
void __init s5p_ohci_set_platdata(struct s5p_ohci_platdata *pd)
{
	struct s5p_ohci_platdata *npd;
	npd = s3c_set_platdata(pd, sizeof(struct s5p_ohci_platdata), &s5p_device_ohci);
	if (!npd->phy_init)
		npd->phy_init = s5p_usb_phy_init;
	if (!npd->phy_exit)
		npd->phy_exit = s5p_usb_phy_exit;
}

然後將定義設置好的 s5p_device_ohci 添加到 smdkv210_devices[ ]

static struct platform_device *smdkv210_devices[] __initdata = {
	&s5p_device_ohci,
	......
};

最後在smdkv210_machine_init 函數中添加平臺數據的設置函數。

#ifdef CONFIG_S5P_DEV_USB_OHCI
	s5p_ohci_set_platdata(&s5p_ohci_platdata);
#endif
  1. 移植 Kconfig
    打開 drivers\usb\host\目錄下的 Kconfig,在 USB_OHCI_EXYNOS 前面添加 USB_OHCI_S5P 的配置支持。
config USB_OHCI_S5P
	boolean "OHCI support for Samsung S5P SoC Series"
	depends on USB_OHCI_HCD && PLAT_S5P
	select S5P_DEV_USB_OHCI
	help
	    Enable support for the Samsung S5P SOC's on-chip OHCI controller.

打開 arch\arm\plat-samsung 目錄下的 Kconfig,在 S5P_DEV_USB_EHCI後面添加 S5P_DEV_USB_OHCI 的配置支持

config S5P_DEV_USB_OHCI
	bool
	help
	    Compile in platform device definition for USB OHCI

打開 drivers\usb\目錄下的 Kconfig,在 USB_ARCH_HAS_OHCI 模塊下添加如下內容:

default y if PLAT_S5P
  1. 創建 setup-usb-phy.c 文件
    在 arch\arm\mach-s5pv210\目錄下創建 setup-usb-phy.c 文件
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <mach/regs-clock.h>
#include <mach/gpio.h>
#include <mach/regs-sys.h>
#include <plat/regs-usb-hsotg-phy.h>
#include <plat/usb-phy.h>
#include <plat/clock.h>
#include <plat/gpio-cfg.h>
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
	int err;
	struct clk *otg_clk;
	if (type != S5P_USB_PHY_HOST)
		return -EINVAL;
	otg_clk = clk_get(&pdev->dev, "otg");
	if (IS_ERR(otg_clk)) 
	{
		dev_err(&pdev->dev, "Failed to get otg clock\n");
		return PTR_ERR(otg_clk);
	}
	
	err = clk_enable(otg_clk);
	if (err)
	 {
		clk_put(otg_clk);
		return err;
	}
	
	if (readl(S5PV210_USB_PHY_CON) & (0x1<<1)) 
	{
		clk_disable(otg_clk);
		clk_put(otg_clk);
		return 0;
	}
	__raw_writel(__raw_readl(S5PV210_USB_PHY_CON) | (0x1<<1), S5PV210_USB_PHY_CON);
	__raw_writel((__raw_readl(S3C_PHYPWR) & ~(0x1<<7) & ~(0x1<<6)) 
				| (0x1<<8) | (0x1<<5) | (0x1<<4), S3C_PHYPWR);
	__raw_writel((__raw_readl(S3C_PHYCLK) & ~(0x1<<7)) | (0x3<<0), S3C_PHYCLK);
	__raw_writel((__raw_readl(S3C_RSTCON)) | (0x1<<4) | (0x1<<3), S3C_RSTCON);
	__raw_writel(__raw_readl(S3C_RSTCON) & ~(0x1<<4) & ~(0x1<<3), S3C_RSTCON);
	
	/* "at least 10uS" for PHY reset elsewhere, 20 not enough here... */
	udelay(50);
	clk_disable(otg_clk);
	clk_put(otg_clk);
	return 0;
}

int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
	if (type != S5P_USB_PHY_HOST)
		return -EINVAL;
	__raw_writel(__raw_readl(S3C_PHYPWR) | (0x1<<7)|(0x1<<6), S3C_PHYPWR);
	__raw_writel(__raw_readl(S5PV210_USB_PHY_CON) & ~(1<<1),S5PV210_USB_PHY_CON);
	return 0;
}
  1. 編寫 setup-usb-phy.h 文件
    在 include/linux/platform_data 目錄下創建 setup-usb-phy.h 文件。
//include/linux/platform_data
#ifndef __SETUP_USB_PHY_H
#define __SETUP_USB_PHY_H

int s5p_usb_phy_init(struct platform_device *pdev, int type);
int s5p_usb_phy_exit(struct platform_device *pdev, int type);

#endif

make menuconfig 配置內核選項

Device Drivers ——>
	SCSI device support ——>
		<*> SCSI device support
		[ * ] legacy /proc/scsi/ support
		<*> SCSI disk support
		<*> SCSI CDROM support
		<*> SCSI generic support
	HID support ——>
		<*> Generic HID driver
	[ * ] USB support ——>
		<*> Support for Host-side USB
		<*> OHCI HCD support
		[ * ] OHCI support for Samsung S5P SoC Series
		[ * ] Generic OHCI driver for a platform device
		<*> USB mass Storage support
		[ * ] USB mass Storage verbose debug
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章