linux/arch/arm/mach-omap2/omap_phy_internal.c
<<
>>
Prefs
   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}
 141