S5PV210 主機控制器驅動的移植
移植 ohci-s5p 驅動
- 拷貝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>
- 打開內核目錄 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
- 添加 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
- 添加平臺設備
打開 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
- 移植 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
- 創建 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;
}
- 編寫 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