linux/arch/arm/mach-pxa/mfp.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-pxa/mfp.c
   3 *
   4 * PXA3xx Multi-Function Pin Support
   5 *
   6 * Copyright (C) 2007 Marvell Internation Ltd.
   7 *
   8 * 2007-08-21: eric miao <eric.miao@marvell.com>
   9 *             initial version
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License version 2 as
  13 *  published by the Free Software Foundation.
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/kernel.h>
  18#include <linux/init.h>
  19#include <linux/io.h>
  20
  21#include <asm/hardware.h>
  22#include <asm/arch/mfp.h>
  23
  24/* mfp_spin_lock is used to ensure that MFP register configuration
  25 * (most likely a read-modify-write operation) is atomic, and that
  26 * mfp_table[] is consistent
  27 */
  28static DEFINE_SPINLOCK(mfp_spin_lock);
  29
  30static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
  31static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
  32
  33#define mfpr_readl(off)                 \
  34        __raw_readl(mfpr_mmio_base + (off))
  35
  36#define mfpr_writel(off, val)           \
  37        __raw_writel(val, mfpr_mmio_base + (off))
  38
  39/*
  40 * perform a read-back of any MFPR register to make sure the
  41 * previous writings are finished
  42 */
  43#define mfpr_sync()     (void)__raw_readl(mfpr_mmio_base + 0)
  44
  45static inline void __mfp_config(int pin, unsigned long val)
  46{
  47        unsigned long off = mfp_table[pin].mfpr_off;
  48
  49        mfp_table[pin].mfpr_val = val;
  50        mfpr_writel(off, val);
  51}
  52
  53void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
  54{
  55        int i, pin;
  56        unsigned long val, flags;
  57        mfp_cfg_t *mfp_cfg = mfp_cfgs;
  58
  59        spin_lock_irqsave(&mfp_spin_lock, flags);
  60
  61        for (i = 0; i < num; i++, mfp_cfg++) {
  62                pin = MFP_CFG_PIN(*mfp_cfg);
  63                val = MFP_CFG_VAL(*mfp_cfg);
  64
  65                BUG_ON(pin >= MFP_PIN_MAX);
  66
  67                __mfp_config(pin, val);
  68        }
  69
  70        mfpr_sync();
  71        spin_unlock_irqrestore(&mfp_spin_lock, flags);
  72}
  73
  74unsigned long pxa3xx_mfp_read(int mfp)
  75{
  76        unsigned long val, flags;
  77
  78        BUG_ON(mfp >= MFP_PIN_MAX);
  79
  80        spin_lock_irqsave(&mfp_spin_lock, flags);
  81        val = mfpr_readl(mfp_table[mfp].mfpr_off);
  82        spin_unlock_irqrestore(&mfp_spin_lock, flags);
  83
  84        return val;
  85}
  86
  87void pxa3xx_mfp_write(int mfp, unsigned long val)
  88{
  89        unsigned long flags;
  90
  91        BUG_ON(mfp >= MFP_PIN_MAX);
  92
  93        spin_lock_irqsave(&mfp_spin_lock, flags);
  94        mfpr_writel(mfp_table[mfp].mfpr_off, val);
  95        mfpr_sync();
  96        spin_unlock_irqrestore(&mfp_spin_lock, flags);
  97}
  98
  99void pxa3xx_mfp_set_afds(int mfp, int af, int ds)
 100{
 101        uint32_t mfpr_off, mfpr_val;
 102        unsigned long flags;
 103
 104        BUG_ON(mfp >= MFP_PIN_MAX);
 105
 106        spin_lock_irqsave(&mfp_spin_lock, flags);
 107        mfpr_off = mfp_table[mfp].mfpr_off;
 108
 109        mfpr_val = mfpr_readl(mfpr_off);
 110        mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK);
 111        mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) |
 112                     ((ds & 0x7) << MFPR_DRV_OFFSET));
 113
 114        mfpr_writel(mfpr_off, mfpr_val);
 115        mfpr_sync();
 116
 117        spin_unlock_irqrestore(&mfp_spin_lock, flags);
 118}
 119
 120void pxa3xx_mfp_set_rdh(int mfp, int rdh)
 121{
 122        uint32_t mfpr_off, mfpr_val;
 123        unsigned long flags;
 124
 125        BUG_ON(mfp >= MFP_PIN_MAX);
 126
 127        spin_lock_irqsave(&mfp_spin_lock, flags);
 128
 129        mfpr_off = mfp_table[mfp].mfpr_off;
 130
 131        mfpr_val = mfpr_readl(mfpr_off);
 132        mfpr_val &= ~MFPR_RDH_MASK;
 133
 134        if (likely(rdh))
 135                mfpr_val |= (1u << MFPR_SS_OFFSET);
 136
 137        mfpr_writel(mfpr_off, mfpr_val);
 138        mfpr_sync();
 139
 140        spin_unlock_irqrestore(&mfp_spin_lock, flags);
 141}
 142
 143void pxa3xx_mfp_set_lpm(int mfp, int lpm)
 144{
 145        uint32_t mfpr_off, mfpr_val;
 146        unsigned long flags;
 147
 148        BUG_ON(mfp >= MFP_PIN_MAX);
 149
 150        spin_lock_irqsave(&mfp_spin_lock, flags);
 151
 152        mfpr_off = mfp_table[mfp].mfpr_off;
 153        mfpr_val = mfpr_readl(mfpr_off);
 154        mfpr_val &= ~MFPR_LPM_MASK;
 155
 156        if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET;
 157        if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET;
 158        if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET;
 159        if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET;
 160        if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET;
 161
 162        mfpr_writel(mfpr_off, mfpr_val);
 163        mfpr_sync();
 164
 165        spin_unlock_irqrestore(&mfp_spin_lock, flags);
 166}
 167
 168void pxa3xx_mfp_set_pull(int mfp, int pull)
 169{
 170        uint32_t mfpr_off, mfpr_val;
 171        unsigned long flags;
 172
 173        BUG_ON(mfp >= MFP_PIN_MAX);
 174
 175        spin_lock_irqsave(&mfp_spin_lock, flags);
 176
 177        mfpr_off = mfp_table[mfp].mfpr_off;
 178        mfpr_val = mfpr_readl(mfpr_off);
 179        mfpr_val &= ~MFPR_PULL_MASK;
 180        mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET);
 181
 182        mfpr_writel(mfpr_off, mfpr_val);
 183        mfpr_sync();
 184
 185        spin_unlock_irqrestore(&mfp_spin_lock, flags);
 186}
 187
 188void pxa3xx_mfp_set_edge(int mfp, int edge)
 189{
 190        uint32_t mfpr_off, mfpr_val;
 191        unsigned long flags;
 192
 193        BUG_ON(mfp >= MFP_PIN_MAX);
 194
 195        spin_lock_irqsave(&mfp_spin_lock, flags);
 196
 197        mfpr_off = mfp_table[mfp].mfpr_off;
 198        mfpr_val = mfpr_readl(mfpr_off);
 199
 200        mfpr_val &= ~MFPR_EDGE_MASK;
 201        mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET;
 202        mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET;
 203
 204        mfpr_writel(mfpr_off, mfpr_val);
 205        mfpr_sync();
 206
 207        spin_unlock_irqrestore(&mfp_spin_lock, flags);
 208}
 209
 210void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
 211{
 212        struct pxa3xx_mfp_addr_map *p;
 213        unsigned long offset, flags;
 214        int i;
 215
 216        spin_lock_irqsave(&mfp_spin_lock, flags);
 217
 218        for (p = map; p->start != MFP_PIN_INVALID; p++) {
 219                offset = p->offset;
 220                i = p->start;
 221
 222                do {
 223                        mfp_table[i].mfpr_off = offset;
 224                        mfp_table[i].mfpr_val = 0;
 225                        offset += 4; i++;
 226                } while ((i <= p->end) && (p->end != -1));
 227        }
 228
 229        spin_unlock_irqrestore(&mfp_spin_lock, flags);
 230}
 231
 232void __init pxa3xx_init_mfp(void)
 233{
 234        memset(mfp_table, 0, sizeof(mfp_table));
 235}
 236