0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/delay.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/platform_device.h>
0011 #include "map.h"
0012 #include "cpu.h"
0013 #include "usb-phy.h"
0014
0015 #include "regs-sys-s3c64xx.h"
0016 #include "regs-usb-hsotg-phy-s3c64xx.h"
0017
0018 enum samsung_usb_phy_type {
0019 USB_PHY_TYPE_DEVICE,
0020 USB_PHY_TYPE_HOST,
0021 };
0022
0023 static int s3c_usb_otgphy_init(struct platform_device *pdev)
0024 {
0025 struct clk *xusbxti;
0026 u32 phyclk;
0027
0028 writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
0029
0030
0031 phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
0032
0033 xusbxti = clk_get(&pdev->dev, "xusbxti");
0034 if (!IS_ERR(xusbxti)) {
0035 switch (clk_get_rate(xusbxti)) {
0036 case 12 * MHZ:
0037 phyclk |= S3C_PHYCLK_CLKSEL_12M;
0038 break;
0039 case 24 * MHZ:
0040 phyclk |= S3C_PHYCLK_CLKSEL_24M;
0041 break;
0042 default:
0043 case 48 * MHZ:
0044
0045 break;
0046 }
0047 clk_put(xusbxti);
0048 }
0049
0050
0051 writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
0052
0053
0054 writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
0055 mdelay(1);
0056
0057
0058 writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
0059 S3C_RSTCON);
0060 udelay(20);
0061 writel(0, S3C_RSTCON);
0062
0063 return 0;
0064 }
0065
0066 static int s3c_usb_otgphy_exit(struct platform_device *pdev)
0067 {
0068 writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
0069 S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
0070
0071 writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
0072
0073 return 0;
0074 }
0075
0076 int s3c_usb_phy_init(struct platform_device *pdev, int type)
0077 {
0078 if (type == USB_PHY_TYPE_DEVICE)
0079 return s3c_usb_otgphy_init(pdev);
0080
0081 return -EINVAL;
0082 }
0083
0084 int s3c_usb_phy_exit(struct platform_device *pdev, int type)
0085 {
0086 if (type == USB_PHY_TYPE_DEVICE)
0087 return s3c_usb_otgphy_exit(pdev);
0088
0089 return -EINVAL;
0090 }