linux/arch/arm/mach-imx/anatop.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
   4 * Copyright 2017-2018 NXP.
   5 */
   6
   7#include <linux/err.h>
   8#include <linux/io.h>
   9#include <linux/of.h>
  10#include <linux/of_address.h>
  11#include <linux/mfd/syscon.h>
  12#include <linux/regmap.h>
  13#include "common.h"
  14#include "hardware.h"
  15
  16#define REG_SET         0x4
  17#define REG_CLR         0x8
  18
  19#define ANADIG_REG_2P5          0x130
  20#define ANADIG_REG_CORE         0x140
  21#define ANADIG_ANA_MISC0        0x150
  22#define ANADIG_USB1_CHRG_DETECT 0x1b0
  23#define ANADIG_USB2_CHRG_DETECT 0x210
  24#define ANADIG_DIGPROG          0x260
  25#define ANADIG_DIGPROG_IMX6SL   0x280
  26#define ANADIG_DIGPROG_IMX7D    0x800
  27
  28#define SRC_SBMR2               0x1c
  29
  30#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG    0x40000
  31#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN       0x8
  32#define BM_ANADIG_REG_CORE_FET_ODRIVE           0x20000000
  33#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG    0x1000
  34/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
  35#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS    0x2000
  36#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B    0x80000
  37#define BM_ANADIG_USB_CHRG_DETECT_EN_B          0x100000
  38
  39static struct regmap *anatop;
  40
  41static void imx_anatop_enable_weak2p5(bool enable)
  42{
  43        u32 reg, val;
  44
  45        regmap_read(anatop, ANADIG_ANA_MISC0, &val);
  46
  47        /* can only be enabled when stop_mode_config is clear. */
  48        reg = ANADIG_REG_2P5;
  49        reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ?
  50                REG_SET : REG_CLR;
  51        regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG);
  52}
  53
  54static void imx_anatop_enable_fet_odrive(bool enable)
  55{
  56        regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR),
  57                BM_ANADIG_REG_CORE_FET_ODRIVE);
  58}
  59
  60static inline void imx_anatop_enable_2p5_pulldown(bool enable)
  61{
  62        regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR),
  63                BM_ANADIG_REG_2P5_ENABLE_PULLDOWN);
  64}
  65
  66static inline void imx_anatop_disconnect_high_snvs(bool enable)
  67{
  68        regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR),
  69                BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS);
  70}
  71
  72void imx_anatop_pre_suspend(void)
  73{
  74        if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
  75                imx_anatop_enable_2p5_pulldown(true);
  76        else
  77                imx_anatop_enable_weak2p5(true);
  78
  79        imx_anatop_enable_fet_odrive(true);
  80
  81        if (cpu_is_imx6sl())
  82                imx_anatop_disconnect_high_snvs(true);
  83}
  84
  85void imx_anatop_post_resume(void)
  86{
  87        if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
  88                imx_anatop_enable_2p5_pulldown(false);
  89        else
  90                imx_anatop_enable_weak2p5(false);
  91
  92        imx_anatop_enable_fet_odrive(false);
  93
  94        if (cpu_is_imx6sl())
  95                imx_anatop_disconnect_high_snvs(false);
  96
  97}
  98
  99static void imx_anatop_usb_chrg_detect_disable(void)
 100{
 101        regmap_write(anatop, ANADIG_USB1_CHRG_DETECT,
 102                BM_ANADIG_USB_CHRG_DETECT_EN_B
 103                | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
 104        regmap_write(anatop, ANADIG_USB2_CHRG_DETECT,
 105                BM_ANADIG_USB_CHRG_DETECT_EN_B |
 106                BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
 107}
 108
 109void __init imx_init_revision_from_anatop(void)
 110{
 111        struct device_node *np;
 112        void __iomem *anatop_base;
 113        unsigned int revision;
 114        u32 digprog;
 115        u16 offset = ANADIG_DIGPROG;
 116        u8 major_part, minor_part;
 117
 118        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
 119        anatop_base = of_iomap(np, 0);
 120        WARN_ON(!anatop_base);
 121        if (of_device_is_compatible(np, "fsl,imx6sl-anatop"))
 122                offset = ANADIG_DIGPROG_IMX6SL;
 123        if (of_device_is_compatible(np, "fsl,imx7d-anatop"))
 124                offset = ANADIG_DIGPROG_IMX7D;
 125        digprog = readl_relaxed(anatop_base + offset);
 126        iounmap(anatop_base);
 127
 128        /*
 129         * On i.MX7D digprog value match linux version format, so
 130         * it needn't map again and we can use register value directly.
 131         */
 132        if (of_device_is_compatible(np, "fsl,imx7d-anatop")) {
 133                revision = digprog & 0xff;
 134        } else {
 135                /*
 136                 * MAJOR: [15:8], the major silicon revison;
 137                 * MINOR: [7: 0], the minor silicon revison;
 138                 *
 139                 * please refer to the i.MX RM for the detailed
 140                 * silicon revison bit define.
 141                 * format the major part and minor part to match the
 142                 * linux kernel soc version format.
 143                 */
 144                major_part = (digprog >> 8) & 0xf;
 145                minor_part = digprog & 0xf;
 146                revision = ((major_part + 1) << 4) | minor_part;
 147
 148                if ((digprog >> 16) == MXC_CPU_IMX6ULL) {
 149                        void __iomem *src_base;
 150                        u32 sbmr2;
 151
 152                        np = of_find_compatible_node(NULL, NULL,
 153                                                     "fsl,imx6ul-src");
 154                        src_base = of_iomap(np, 0);
 155                        WARN_ON(!src_base);
 156                        sbmr2 = readl_relaxed(src_base + SRC_SBMR2);
 157                        iounmap(src_base);
 158
 159                        /* src_sbmr2 bit 6 is to identify if it is i.MX6ULZ */
 160                        if (sbmr2 & (1 << 6)) {
 161                                digprog &= ~(0xff << 16);
 162                                digprog |= (MXC_CPU_IMX6ULZ << 16);
 163                        }
 164                }
 165        }
 166
 167        mxc_set_cpu_type(digprog >> 16 & 0xff);
 168        imx_set_soc_revision(revision);
 169}
 170
 171void __init imx_anatop_init(void)
 172{
 173        anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
 174        if (IS_ERR(anatop)) {
 175                pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__);
 176                return;
 177        }
 178
 179        imx_anatop_usb_chrg_detect_disable();
 180}
 181