omap_phy_internal.c (3355B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * This file configures the internal USB PHY in OMAP4430. Used 4 * with TWL6030 transceiver and MUSB on OMAP4430. 5 * 6 * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com 7 * Author: Hema HK <hemahk@ti.com> 8 */ 9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 12#include <linux/types.h> 13#include <linux/delay.h> 14#include <linux/clk.h> 15#include <linux/io.h> 16#include <linux/err.h> 17#include <linux/usb.h> 18#include <linux/usb/musb.h> 19 20#include "soc.h" 21#include "control.h" 22#include "usb.h" 23 24#define CONTROL_DEV_CONF 0x300 25#define PHY_PD 0x1 26 27/** 28 * omap4430_phy_power_down: disable MUSB PHY during early init 29 * 30 * OMAP4 MUSB PHY module is enabled by default on reset, but this will 31 * prevent core retention if not disabled by SW. USB driver will 32 * later on enable this, once and if the driver needs it. 33 */ 34static int __init omap4430_phy_power_down(void) 35{ 36 void __iomem *ctrl_base; 37 38 if (!cpu_is_omap44xx()) 39 return 0; 40 41 ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K); 42 if (!ctrl_base) { 43 pr_err("control module ioremap failed\n"); 44 return -ENOMEM; 45 } 46 47 /* Power down the phy */ 48 writel_relaxed(PHY_PD, ctrl_base + CONTROL_DEV_CONF); 49 50 iounmap(ctrl_base); 51 52 return 0; 53} 54omap_early_initcall(omap4430_phy_power_down); 55 56void am35x_musb_reset(void) 57{ 58 u32 regval; 59 60 /* Reset the musb interface */ 61 regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); 62 63 regval |= AM35XX_USBOTGSS_SW_RST; 64 omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); 65 66 regval &= ~AM35XX_USBOTGSS_SW_RST; 67 omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); 68 69 regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); 70} 71 72void am35x_musb_phy_power(u8 on) 73{ 74 unsigned long timeout = jiffies + msecs_to_jiffies(100); 75 u32 devconf2; 76 77 if (on) { 78 /* 79 * Start the on-chip PHY and its PLL. 80 */ 81 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); 82 83 devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN); 84 devconf2 |= CONF2_PHY_PLLON; 85 86 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); 87 88 pr_info("Waiting for PHY clock good...\n"); 89 while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2) 90 & CONF2_PHYCLKGD)) { 91 cpu_relax(); 92 93 if (time_after(jiffies, timeout)) { 94 pr_err("musb PHY clock good timed out\n"); 95 break; 96 } 97 } 98 } else { 99 /* 100 * Power down the on-chip PHY. 101 */ 102 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); 103 104 devconf2 &= ~CONF2_PHY_PLLON; 105 devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN; 106 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); 107 } 108} 109 110void am35x_musb_clear_irq(void) 111{ 112 u32 regval; 113 114 regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); 115 regval |= AM35XX_USBOTGSS_INT_CLR; 116 omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR); 117 regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); 118} 119 120void am35x_set_mode(u8 musb_mode) 121{ 122 u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); 123 124 devconf2 &= ~CONF2_OTGMODE; 125 switch (musb_mode) { 126 case MUSB_HOST: /* Force VBUS valid, ID = 0 */ 127 devconf2 |= CONF2_FORCE_HOST; 128 break; 129 case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */ 130 devconf2 |= CONF2_FORCE_DEVICE; 131 break; 132 case MUSB_OTG: /* Don't override the VBUS/ID comparators */ 133 devconf2 |= CONF2_NO_OVERRIDE; 134 break; 135 default: 136 pr_info("Unsupported mode %u\n", musb_mode); 137 } 138 139 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); 140}