root/drivers/phy/samsung/phy-s5pv210-usb2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s5pv210_rate_to_clk
  2. s5pv210_isol
  3. s5pv210_phy_pwr
  4. s5pv210_power_on
  5. s5pv210_power_off

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
   4  *
   5  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
   6  * Authors: Kamil Debski <k.debski@samsung.com>
   7  */
   8 
   9 #include <linux/delay.h>
  10 #include <linux/io.h>
  11 #include <linux/phy/phy.h>
  12 #include "phy-samsung-usb2.h"
  13 
  14 /* Exynos USB PHY registers */
  15 
  16 /* PHY power control */
  17 #define S5PV210_UPHYPWR                 0x0
  18 
  19 #define S5PV210_UPHYPWR_PHY0_SUSPEND    BIT(0)
  20 #define S5PV210_UPHYPWR_PHY0_PWR        BIT(3)
  21 #define S5PV210_UPHYPWR_PHY0_OTG_PWR    BIT(4)
  22 #define S5PV210_UPHYPWR_PHY0    ( \
  23         S5PV210_UPHYPWR_PHY0_SUSPEND | \
  24         S5PV210_UPHYPWR_PHY0_PWR | \
  25         S5PV210_UPHYPWR_PHY0_OTG_PWR)
  26 
  27 #define S5PV210_UPHYPWR_PHY1_SUSPEND    BIT(6)
  28 #define S5PV210_UPHYPWR_PHY1_PWR        BIT(7)
  29 #define S5PV210_UPHYPWR_PHY1 ( \
  30         S5PV210_UPHYPWR_PHY1_SUSPEND | \
  31         S5PV210_UPHYPWR_PHY1_PWR)
  32 
  33 /* PHY clock control */
  34 #define S5PV210_UPHYCLK                 0x4
  35 
  36 #define S5PV210_UPHYCLK_PHYFSEL_MASK    (0x3 << 0)
  37 #define S5PV210_UPHYCLK_PHYFSEL_48MHZ   (0x0 << 0)
  38 #define S5PV210_UPHYCLK_PHYFSEL_24MHZ   (0x3 << 0)
  39 #define S5PV210_UPHYCLK_PHYFSEL_12MHZ   (0x2 << 0)
  40 
  41 #define S5PV210_UPHYCLK_PHY0_ID_PULLUP  BIT(2)
  42 #define S5PV210_UPHYCLK_PHY0_COMMON_ON  BIT(4)
  43 #define S5PV210_UPHYCLK_PHY1_COMMON_ON  BIT(7)
  44 
  45 /* PHY reset control */
  46 #define S5PV210_UPHYRST                 0x8
  47 
  48 #define S5PV210_URSTCON_PHY0            BIT(0)
  49 #define S5PV210_URSTCON_OTG_HLINK       BIT(1)
  50 #define S5PV210_URSTCON_OTG_PHYLINK     BIT(2)
  51 #define S5PV210_URSTCON_PHY1_ALL        BIT(3)
  52 #define S5PV210_URSTCON_HOST_LINK_ALL   BIT(4)
  53 
  54 /* Isolation, configured in the power management unit */
  55 #define S5PV210_USB_ISOL_OFFSET         0x680c
  56 #define S5PV210_USB_ISOL_DEVICE         BIT(0)
  57 #define S5PV210_USB_ISOL_HOST           BIT(1)
  58 
  59 
  60 enum s5pv210_phy_id {
  61         S5PV210_DEVICE,
  62         S5PV210_HOST,
  63         S5PV210_NUM_PHYS,
  64 };
  65 
  66 /*
  67  * s5pv210_rate_to_clk() converts the supplied clock rate to the value that
  68  * can be written to the phy register.
  69  */
  70 static int s5pv210_rate_to_clk(unsigned long rate, u32 *reg)
  71 {
  72         switch (rate) {
  73         case 12 * MHZ:
  74                 *reg = S5PV210_UPHYCLK_PHYFSEL_12MHZ;
  75                 break;
  76         case 24 * MHZ:
  77                 *reg = S5PV210_UPHYCLK_PHYFSEL_24MHZ;
  78                 break;
  79         case 48 * MHZ:
  80                 *reg = S5PV210_UPHYCLK_PHYFSEL_48MHZ;
  81                 break;
  82         default:
  83                 return -EINVAL;
  84         }
  85 
  86         return 0;
  87 }
  88 
  89 static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on)
  90 {
  91         struct samsung_usb2_phy_driver *drv = inst->drv;
  92         u32 mask;
  93 
  94         switch (inst->cfg->id) {
  95         case S5PV210_DEVICE:
  96                 mask = S5PV210_USB_ISOL_DEVICE;
  97                 break;
  98         case S5PV210_HOST:
  99                 mask = S5PV210_USB_ISOL_HOST;
 100                 break;
 101         default:
 102                 return;
 103         }
 104 
 105         regmap_update_bits(drv->reg_pmu, S5PV210_USB_ISOL_OFFSET,
 106                                                         mask, on ? 0 : mask);
 107 }
 108 
 109 static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
 110 {
 111         struct samsung_usb2_phy_driver *drv = inst->drv;
 112         u32 rstbits = 0;
 113         u32 phypwr = 0;
 114         u32 rst;
 115         u32 pwr;
 116 
 117         switch (inst->cfg->id) {
 118         case S5PV210_DEVICE:
 119                 phypwr =        S5PV210_UPHYPWR_PHY0;
 120                 rstbits =       S5PV210_URSTCON_PHY0;
 121                 break;
 122         case S5PV210_HOST:
 123                 phypwr =        S5PV210_UPHYPWR_PHY1;
 124                 rstbits =       S5PV210_URSTCON_PHY1_ALL |
 125                                 S5PV210_URSTCON_HOST_LINK_ALL;
 126                 break;
 127         }
 128 
 129         if (on) {
 130                 writel(drv->ref_reg_val, drv->reg_phy + S5PV210_UPHYCLK);
 131 
 132                 pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
 133                 pwr &= ~phypwr;
 134                 writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
 135 
 136                 rst = readl(drv->reg_phy + S5PV210_UPHYRST);
 137                 rst |= rstbits;
 138                 writel(rst, drv->reg_phy + S5PV210_UPHYRST);
 139                 udelay(10);
 140                 rst &= ~rstbits;
 141                 writel(rst, drv->reg_phy + S5PV210_UPHYRST);
 142         } else {
 143                 pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
 144                 pwr |= phypwr;
 145                 writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
 146         }
 147 }
 148 
 149 static int s5pv210_power_on(struct samsung_usb2_phy_instance *inst)
 150 {
 151         s5pv210_isol(inst, 0);
 152         s5pv210_phy_pwr(inst, 1);
 153 
 154         return 0;
 155 }
 156 
 157 static int s5pv210_power_off(struct samsung_usb2_phy_instance *inst)
 158 {
 159         s5pv210_phy_pwr(inst, 0);
 160         s5pv210_isol(inst, 1);
 161 
 162         return 0;
 163 }
 164 
 165 static const struct samsung_usb2_common_phy s5pv210_phys[S5PV210_NUM_PHYS] = {
 166         [S5PV210_DEVICE] = {
 167                 .label          = "device",
 168                 .id             = S5PV210_DEVICE,
 169                 .power_on       = s5pv210_power_on,
 170                 .power_off      = s5pv210_power_off,
 171         },
 172         [S5PV210_HOST] = {
 173                 .label          = "host",
 174                 .id             = S5PV210_HOST,
 175                 .power_on       = s5pv210_power_on,
 176                 .power_off      = s5pv210_power_off,
 177         },
 178 };
 179 
 180 const struct samsung_usb2_phy_config s5pv210_usb2_phy_config = {
 181         .num_phys       = ARRAY_SIZE(s5pv210_phys),
 182         .phys           = s5pv210_phys,
 183         .rate_to_clk    = s5pv210_rate_to_clk,
 184 };

/* [<][>][^][v][top][bottom][index][help] */