^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (C) 2011 Samsung Electronics Co.Ltd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // Author: Joonyoung Shim <jy0922.shim@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "map.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "cpu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "usb-phy.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "regs-sys-s3c64xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "regs-usb-hsotg-phy-s3c64xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) enum samsung_usb_phy_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) USB_PHY_TYPE_DEVICE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) USB_PHY_TYPE_HOST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int s3c_usb_otgphy_init(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct clk *xusbxti;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u32 phyclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /* set clock frequency for PLL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) xusbxti = clk_get(&pdev->dev, "xusbxti");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (!IS_ERR(xusbxti)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) switch (clk_get_rate(xusbxti)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) case 12 * MHZ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) phyclk |= S3C_PHYCLK_CLKSEL_12M;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) case 24 * MHZ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) phyclk |= S3C_PHYCLK_CLKSEL_24M;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) case 48 * MHZ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* default reference clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) clk_put(xusbxti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* TODO: select external clock/oscillator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* set to normal OTG PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* reset OTG PHY and Link */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) S3C_RSTCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) udelay(20); /* at-least 10uS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) writel(0, S3C_RSTCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int s3c_usb_otgphy_exit(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int s3c_usb_phy_init(struct platform_device *pdev, int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (type == USB_PHY_TYPE_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return s3c_usb_otgphy_init(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int s3c_usb_phy_exit(struct platform_device *pdev, int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (type == USB_PHY_TYPE_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return s3c_usb_otgphy_exit(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }