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

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

DEFINITIONS

This source file includes following definitions.
  1. exynos4210_rate_to_clk
  2. exynos4210_isol
  3. exynos4210_phy_pwr
  4. exynos4210_power_on
  5. exynos4210_power_off

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
   4  *
   5  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
   6  * Author: 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 <linux/regmap.h>
  13 #include "phy-samsung-usb2.h"
  14 
  15 /* Exynos USB PHY registers */
  16 
  17 /* PHY power control */
  18 #define EXYNOS_4210_UPHYPWR                     0x0
  19 
  20 #define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND        BIT(0)
  21 #define EXYNOS_4210_UPHYPWR_PHY0_PWR            BIT(3)
  22 #define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR        BIT(4)
  23 #define EXYNOS_4210_UPHYPWR_PHY0_SLEEP          BIT(5)
  24 #define EXYNOS_4210_UPHYPWR_PHY0        ( \
  25         EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
  26         EXYNOS_4210_UPHYPWR_PHY0_PWR | \
  27         EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
  28         EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
  29 
  30 #define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND        BIT(6)
  31 #define EXYNOS_4210_UPHYPWR_PHY1_PWR            BIT(7)
  32 #define EXYNOS_4210_UPHYPWR_PHY1_SLEEP          BIT(8)
  33 #define EXYNOS_4210_UPHYPWR_PHY1 ( \
  34         EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
  35         EXYNOS_4210_UPHYPWR_PHY1_PWR | \
  36         EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
  37 
  38 #define EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND       BIT(9)
  39 #define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP         BIT(10)
  40 #define EXYNOS_4210_UPHYPWR_HSIC0 ( \
  41         EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
  42         EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
  43 
  44 #define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND       BIT(11)
  45 #define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP         BIT(12)
  46 #define EXYNOS_4210_UPHYPWR_HSIC1 ( \
  47         EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
  48         EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
  49 
  50 /* PHY clock control */
  51 #define EXYNOS_4210_UPHYCLK                     0x4
  52 
  53 #define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK        (0x3 << 0)
  54 #define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET      0
  55 #define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ       (0x0 << 0)
  56 #define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ       (0x3 << 0)
  57 #define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ       (0x2 << 0)
  58 
  59 #define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP      BIT(2)
  60 #define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON      BIT(4)
  61 #define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON      BIT(7)
  62 
  63 /* PHY reset control */
  64 #define EXYNOS_4210_UPHYRST                     0x8
  65 
  66 #define EXYNOS_4210_URSTCON_PHY0                BIT(0)
  67 #define EXYNOS_4210_URSTCON_OTG_HLINK           BIT(1)
  68 #define EXYNOS_4210_URSTCON_OTG_PHYLINK         BIT(2)
  69 #define EXYNOS_4210_URSTCON_PHY1_ALL            BIT(3)
  70 #define EXYNOS_4210_URSTCON_PHY1_P0             BIT(4)
  71 #define EXYNOS_4210_URSTCON_PHY1_P1P2           BIT(5)
  72 #define EXYNOS_4210_URSTCON_HOST_LINK_ALL       BIT(6)
  73 #define EXYNOS_4210_URSTCON_HOST_LINK_P0        BIT(7)
  74 #define EXYNOS_4210_URSTCON_HOST_LINK_P1        BIT(8)
  75 #define EXYNOS_4210_URSTCON_HOST_LINK_P2        BIT(9)
  76 
  77 /* Isolation, configured in the power management unit */
  78 #define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET      0x704
  79 #define EXYNOS_4210_USB_ISOL_DEVICE             BIT(0)
  80 #define EXYNOS_4210_USB_ISOL_HOST_OFFSET        0x708
  81 #define EXYNOS_4210_USB_ISOL_HOST               BIT(0)
  82 
  83 /* USBYPHY1 Floating prevention */
  84 #define EXYNOS_4210_UPHY1CON                    0x34
  85 #define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION   0x1
  86 
  87 /* Mode switching SUB Device <-> Host */
  88 #define EXYNOS_4210_MODE_SWITCH_OFFSET          0x21c
  89 #define EXYNOS_4210_MODE_SWITCH_MASK            1
  90 #define EXYNOS_4210_MODE_SWITCH_DEVICE          0
  91 #define EXYNOS_4210_MODE_SWITCH_HOST            1
  92 
  93 enum exynos4210_phy_id {
  94         EXYNOS4210_DEVICE,
  95         EXYNOS4210_HOST,
  96         EXYNOS4210_HSIC0,
  97         EXYNOS4210_HSIC1,
  98         EXYNOS4210_NUM_PHYS,
  99 };
 100 
 101 /*
 102  * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
 103  * can be written to the phy register.
 104  */
 105 static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
 106 {
 107         switch (rate) {
 108         case 12 * MHZ:
 109                 *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
 110                 break;
 111         case 24 * MHZ:
 112                 *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
 113                 break;
 114         case 48 * MHZ:
 115                 *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
 116                 break;
 117         default:
 118                 return -EINVAL;
 119         }
 120 
 121         return 0;
 122 }
 123 
 124 static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
 125 {
 126         struct samsung_usb2_phy_driver *drv = inst->drv;
 127         u32 offset;
 128         u32 mask;
 129 
 130         switch (inst->cfg->id) {
 131         case EXYNOS4210_DEVICE:
 132                 offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
 133                 mask = EXYNOS_4210_USB_ISOL_DEVICE;
 134                 break;
 135         case EXYNOS4210_HOST:
 136                 offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
 137                 mask = EXYNOS_4210_USB_ISOL_HOST;
 138                 break;
 139         default:
 140                 return;
 141         }
 142 
 143         regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
 144 }
 145 
 146 static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
 147 {
 148         struct samsung_usb2_phy_driver *drv = inst->drv;
 149         u32 rstbits = 0;
 150         u32 phypwr = 0;
 151         u32 rst;
 152         u32 pwr;
 153         u32 clk;
 154 
 155         switch (inst->cfg->id) {
 156         case EXYNOS4210_DEVICE:
 157                 phypwr =        EXYNOS_4210_UPHYPWR_PHY0;
 158                 rstbits =       EXYNOS_4210_URSTCON_PHY0;
 159                 break;
 160         case EXYNOS4210_HOST:
 161                 phypwr =        EXYNOS_4210_UPHYPWR_PHY1;
 162                 rstbits =       EXYNOS_4210_URSTCON_PHY1_ALL |
 163                                 EXYNOS_4210_URSTCON_PHY1_P0 |
 164                                 EXYNOS_4210_URSTCON_PHY1_P1P2 |
 165                                 EXYNOS_4210_URSTCON_HOST_LINK_ALL |
 166                                 EXYNOS_4210_URSTCON_HOST_LINK_P0;
 167                 writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
 168                 break;
 169         case EXYNOS4210_HSIC0:
 170                 phypwr =        EXYNOS_4210_UPHYPWR_HSIC0;
 171                 rstbits =       EXYNOS_4210_URSTCON_PHY1_P1P2 |
 172                                 EXYNOS_4210_URSTCON_HOST_LINK_P1;
 173                 break;
 174         case EXYNOS4210_HSIC1:
 175                 phypwr =        EXYNOS_4210_UPHYPWR_HSIC1;
 176                 rstbits =       EXYNOS_4210_URSTCON_PHY1_P1P2 |
 177                                 EXYNOS_4210_URSTCON_HOST_LINK_P2;
 178                 break;
 179         }
 180 
 181         if (on) {
 182                 clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
 183                 clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
 184                 clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
 185                 writel(clk, drv->reg_phy + EXYNOS_4210_UPHYCLK);
 186 
 187                 pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
 188                 pwr &= ~phypwr;
 189                 writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
 190 
 191                 rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
 192                 rst |= rstbits;
 193                 writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
 194                 udelay(10);
 195                 rst &= ~rstbits;
 196                 writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
 197                 /* The following delay is necessary for the reset sequence to be
 198                  * completed */
 199                 udelay(80);
 200         } else {
 201                 pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
 202                 pwr |= phypwr;
 203                 writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
 204         }
 205 }
 206 
 207 static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
 208 {
 209         /* Order of initialisation is important - first power then isolation */
 210         exynos4210_phy_pwr(inst, 1);
 211         exynos4210_isol(inst, 0);
 212 
 213         return 0;
 214 }
 215 
 216 static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
 217 {
 218         exynos4210_isol(inst, 1);
 219         exynos4210_phy_pwr(inst, 0);
 220 
 221         return 0;
 222 }
 223 
 224 
 225 static const struct samsung_usb2_common_phy exynos4210_phys[] = {
 226         {
 227                 .label          = "device",
 228                 .id             = EXYNOS4210_DEVICE,
 229                 .power_on       = exynos4210_power_on,
 230                 .power_off      = exynos4210_power_off,
 231         },
 232         {
 233                 .label          = "host",
 234                 .id             = EXYNOS4210_HOST,
 235                 .power_on       = exynos4210_power_on,
 236                 .power_off      = exynos4210_power_off,
 237         },
 238         {
 239                 .label          = "hsic0",
 240                 .id             = EXYNOS4210_HSIC0,
 241                 .power_on       = exynos4210_power_on,
 242                 .power_off      = exynos4210_power_off,
 243         },
 244         {
 245                 .label          = "hsic1",
 246                 .id             = EXYNOS4210_HSIC1,
 247                 .power_on       = exynos4210_power_on,
 248                 .power_off      = exynos4210_power_off,
 249         },
 250 };
 251 
 252 const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
 253         .has_mode_switch        = 0,
 254         .num_phys               = EXYNOS4210_NUM_PHYS,
 255         .phys                   = exynos4210_phys,
 256         .rate_to_clk            = exynos4210_rate_to_clk,
 257 };

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