root/arch/arm/plat-pxa/mfp.c

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

DEFINITIONS

This source file includes following definitions.
  1. __mfp_config_run
  2. __mfp_config_lpm
  3. mfp_config
  4. mfp_read
  5. mfp_write
  6. mfp_init_base
  7. mfp_init_addr
  8. mfp_config_lpm
  9. mfp_config_run

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/arch/arm/plat-pxa/mfp.c
   4  *
   5  *   Multi-Function Pin Support
   6  *
   7  * Copyright (C) 2007 Marvell Internation Ltd.
   8  *
   9  * 2007-08-21: eric miao <eric.miao@marvell.com>
  10  *             initial version
  11  */
  12 
  13 #include <linux/module.h>
  14 #include <linux/kernel.h>
  15 #include <linux/init.h>
  16 #include <linux/io.h>
  17 
  18 #include <plat/mfp.h>
  19 
  20 #define MFPR_SIZE       (PAGE_SIZE)
  21 
  22 /* MFPR register bit definitions */
  23 #define MFPR_PULL_SEL           (0x1 << 15)
  24 #define MFPR_PULLUP_EN          (0x1 << 14)
  25 #define MFPR_PULLDOWN_EN        (0x1 << 13)
  26 #define MFPR_SLEEP_SEL          (0x1 << 9)
  27 #define MFPR_SLEEP_OE_N         (0x1 << 7)
  28 #define MFPR_EDGE_CLEAR         (0x1 << 6)
  29 #define MFPR_EDGE_FALL_EN       (0x1 << 5)
  30 #define MFPR_EDGE_RISE_EN       (0x1 << 4)
  31 
  32 #define MFPR_SLEEP_DATA(x)      ((x) << 8)
  33 #define MFPR_DRIVE(x)           (((x) & 0x7) << 10)
  34 #define MFPR_AF_SEL(x)          (((x) & 0x7) << 0)
  35 
  36 #define MFPR_EDGE_NONE          (0)
  37 #define MFPR_EDGE_RISE          (MFPR_EDGE_RISE_EN)
  38 #define MFPR_EDGE_FALL          (MFPR_EDGE_FALL_EN)
  39 #define MFPR_EDGE_BOTH          (MFPR_EDGE_RISE | MFPR_EDGE_FALL)
  40 
  41 /*
  42  * Table that determines the low power modes outputs, with actual settings
  43  * used in parentheses for don't-care values. Except for the float output,
  44  * the configured driven and pulled levels match, so if there is a need for
  45  * non-LPM pulled output, the same configuration could probably be used.
  46  *
  47  * Output value  sleep_oe_n  sleep_data  pullup_en  pulldown_en  pull_sel
  48  *                 (bit 7)    (bit 8)    (bit 14)     (bit 13)   (bit 15)
  49  *
  50  * Input            0          X(0)        X(0)        X(0)       0
  51  * Drive 0          0          0           0           X(1)       0
  52  * Drive 1          0          1           X(1)        0          0
  53  * Pull hi (1)      1          X(1)        1           0          0
  54  * Pull lo (0)      1          X(0)        0           1          0
  55  * Z (float)        1          X(0)        0           0          0
  56  */
  57 #define MFPR_LPM_INPUT          (0)
  58 #define MFPR_LPM_DRIVE_LOW      (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN)
  59 #define MFPR_LPM_DRIVE_HIGH     (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN)
  60 #define MFPR_LPM_PULL_LOW       (MFPR_LPM_DRIVE_LOW  | MFPR_SLEEP_OE_N)
  61 #define MFPR_LPM_PULL_HIGH      (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N)
  62 #define MFPR_LPM_FLOAT          (MFPR_SLEEP_OE_N)
  63 #define MFPR_LPM_MASK           (0xe080)
  64 
  65 /*
  66  * The pullup and pulldown state of the MFP pin at run mode is by default
  67  * determined by the selected alternate function. In case that some buggy
  68  * devices need to override this default behavior,  the definitions below
  69  * indicates the setting of corresponding MFPR bits
  70  *
  71  * Definition       pull_sel  pullup_en  pulldown_en
  72  * MFPR_PULL_NONE       0         0        0
  73  * MFPR_PULL_LOW        1         0        1
  74  * MFPR_PULL_HIGH       1         1        0
  75  * MFPR_PULL_BOTH       1         1        1
  76  * MFPR_PULL_FLOAT      1         0        0
  77  */
  78 #define MFPR_PULL_NONE          (0)
  79 #define MFPR_PULL_LOW           (MFPR_PULL_SEL | MFPR_PULLDOWN_EN)
  80 #define MFPR_PULL_BOTH          (MFPR_PULL_LOW | MFPR_PULLUP_EN)
  81 #define MFPR_PULL_HIGH          (MFPR_PULL_SEL | MFPR_PULLUP_EN)
  82 #define MFPR_PULL_FLOAT         (MFPR_PULL_SEL)
  83 
  84 /* mfp_spin_lock is used to ensure that MFP register configuration
  85  * (most likely a read-modify-write operation) is atomic, and that
  86  * mfp_table[] is consistent
  87  */
  88 static DEFINE_SPINLOCK(mfp_spin_lock);
  89 
  90 static void __iomem *mfpr_mmio_base;
  91 
  92 struct mfp_pin {
  93         unsigned long   config;         /* -1 for not configured */
  94         unsigned long   mfpr_off;       /* MFPRxx Register offset */
  95         unsigned long   mfpr_run;       /* Run-Mode Register Value */
  96         unsigned long   mfpr_lpm;       /* Low Power Mode Register Value */
  97 };
  98 
  99 static struct mfp_pin mfp_table[MFP_PIN_MAX];
 100 
 101 /* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */
 102 static const unsigned long mfpr_lpm[] = {
 103         MFPR_LPM_INPUT,
 104         MFPR_LPM_DRIVE_LOW,
 105         MFPR_LPM_DRIVE_HIGH,
 106         MFPR_LPM_PULL_LOW,
 107         MFPR_LPM_PULL_HIGH,
 108         MFPR_LPM_FLOAT,
 109         MFPR_LPM_INPUT,
 110 };
 111 
 112 /* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */
 113 static const unsigned long mfpr_pull[] = {
 114         MFPR_PULL_NONE,
 115         MFPR_PULL_LOW,
 116         MFPR_PULL_HIGH,
 117         MFPR_PULL_BOTH,
 118         MFPR_PULL_FLOAT,
 119 };
 120 
 121 /* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */
 122 static const unsigned long mfpr_edge[] = {
 123         MFPR_EDGE_NONE,
 124         MFPR_EDGE_RISE,
 125         MFPR_EDGE_FALL,
 126         MFPR_EDGE_BOTH,
 127 };
 128 
 129 #define mfpr_readl(off)                 \
 130         __raw_readl(mfpr_mmio_base + (off))
 131 
 132 #define mfpr_writel(off, val)           \
 133         __raw_writel(val, mfpr_mmio_base + (off))
 134 
 135 #define mfp_configured(p)       ((p)->config != -1)
 136 
 137 /*
 138  * perform a read-back of any valid MFPR register to make sure the
 139  * previous writings are finished
 140  */
 141 static unsigned long mfpr_off_readback;
 142 #define mfpr_sync()     (void)__raw_readl(mfpr_mmio_base + mfpr_off_readback)
 143 
 144 static inline void __mfp_config_run(struct mfp_pin *p)
 145 {
 146         if (mfp_configured(p))
 147                 mfpr_writel(p->mfpr_off, p->mfpr_run);
 148 }
 149 
 150 static inline void __mfp_config_lpm(struct mfp_pin *p)
 151 {
 152         if (mfp_configured(p)) {
 153                 unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR;
 154                 if (mfpr_clr != p->mfpr_run)
 155                         mfpr_writel(p->mfpr_off, mfpr_clr);
 156                 if (p->mfpr_lpm != mfpr_clr)
 157                         mfpr_writel(p->mfpr_off, p->mfpr_lpm);
 158         }
 159 }
 160 
 161 void mfp_config(unsigned long *mfp_cfgs, int num)
 162 {
 163         unsigned long flags;
 164         int i;
 165 
 166         spin_lock_irqsave(&mfp_spin_lock, flags);
 167 
 168         for (i = 0; i < num; i++, mfp_cfgs++) {
 169                 unsigned long tmp, c = *mfp_cfgs;
 170                 struct mfp_pin *p;
 171                 int pin, af, drv, lpm, edge, pull;
 172 
 173                 pin = MFP_PIN(c);
 174                 BUG_ON(pin >= MFP_PIN_MAX);
 175                 p = &mfp_table[pin];
 176 
 177                 af  = MFP_AF(c);
 178                 drv = MFP_DS(c);
 179                 lpm = MFP_LPM_STATE(c);
 180                 edge = MFP_LPM_EDGE(c);
 181                 pull = MFP_PULL(c);
 182 
 183                 /* run-mode pull settings will conflict with MFPR bits of
 184                  * low power mode state,  calculate mfpr_run and mfpr_lpm
 185                  * individually if pull != MFP_PULL_NONE
 186                  */
 187                 tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv);
 188 
 189                 if (likely(pull == MFP_PULL_NONE)) {
 190                         p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
 191                         p->mfpr_lpm = p->mfpr_run;
 192                 } else {
 193                         p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
 194                         p->mfpr_run = tmp | mfpr_pull[pull];
 195                 }
 196 
 197                 p->config = c; __mfp_config_run(p);
 198         }
 199 
 200         mfpr_sync();
 201         spin_unlock_irqrestore(&mfp_spin_lock, flags);
 202 }
 203 
 204 unsigned long mfp_read(int mfp)
 205 {
 206         unsigned long val, flags;
 207 
 208         BUG_ON(mfp < 0 || mfp >= MFP_PIN_MAX);
 209 
 210         spin_lock_irqsave(&mfp_spin_lock, flags);
 211         val = mfpr_readl(mfp_table[mfp].mfpr_off);
 212         spin_unlock_irqrestore(&mfp_spin_lock, flags);
 213 
 214         return val;
 215 }
 216 
 217 void mfp_write(int mfp, unsigned long val)
 218 {
 219         unsigned long flags;
 220 
 221         BUG_ON(mfp < 0 || mfp >= MFP_PIN_MAX);
 222 
 223         spin_lock_irqsave(&mfp_spin_lock, flags);
 224         mfpr_writel(mfp_table[mfp].mfpr_off, val);
 225         mfpr_sync();
 226         spin_unlock_irqrestore(&mfp_spin_lock, flags);
 227 }
 228 
 229 void __init mfp_init_base(void __iomem *mfpr_base)
 230 {
 231         int i;
 232 
 233         /* initialize the table with default - unconfigured */
 234         for (i = 0; i < ARRAY_SIZE(mfp_table); i++)
 235                 mfp_table[i].config = -1;
 236 
 237         mfpr_mmio_base = mfpr_base;
 238 }
 239 
 240 void __init mfp_init_addr(struct mfp_addr_map *map)
 241 {
 242         struct mfp_addr_map *p;
 243         unsigned long offset, flags;
 244         int i;
 245 
 246         spin_lock_irqsave(&mfp_spin_lock, flags);
 247 
 248         /* mfp offset for readback */
 249         mfpr_off_readback = map[0].offset;
 250 
 251         for (p = map; p->start != MFP_PIN_INVALID; p++) {
 252                 offset = p->offset;
 253                 i = p->start;
 254 
 255                 do {
 256                         mfp_table[i].mfpr_off = offset;
 257                         mfp_table[i].mfpr_run = 0;
 258                         mfp_table[i].mfpr_lpm = 0;
 259                         offset += 4; i++;
 260                 } while ((i <= p->end) && (p->end != -1));
 261         }
 262 
 263         spin_unlock_irqrestore(&mfp_spin_lock, flags);
 264 }
 265 
 266 void mfp_config_lpm(void)
 267 {
 268         struct mfp_pin *p = &mfp_table[0];
 269         int pin;
 270 
 271         for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++)
 272                 __mfp_config_lpm(p);
 273 }
 274 
 275 void mfp_config_run(void)
 276 {
 277         struct mfp_pin *p = &mfp_table[0];
 278         int pin;
 279 
 280         for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++)
 281                 __mfp_config_run(p);
 282 }

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