diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 23:08:50 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 23:08:50 (GMT) |
commit | 65a6ec0d72a07f16719e9b7a96e1c4bae044b591 (patch) | |
tree | 344e03a5039a44982c1b78d6113633b21b434820 /arch/arm/mach-pxa/mfp.c | |
parent | 541010e4b8921cd781ff02ae68028501457045b6 (diff) | |
parent | 0181b61a988424b5cc44fe09e6968142359c815e (diff) | |
download | linux-65a6ec0d72a07f16719e9b7a96e1c4bae044b591.tar.xz |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (95 commits)
[ARM] 4578/1: CM-x270: PCMCIA support
[ARM] 4577/1: ITE 8152 PCI bridge support
[ARM] 4576/1: CM-X270 machine support
[ARM] pxa: Avoid pxa_gpio_mode() in gpio_direction_{in,out}put()
[ARM] pxa: move pxa_set_mode() from pxa2xx_mainstone.c to mainstone.c
[ARM] pxa: move pxa_set_mode() from pxa2xx_lubbock.c to lubbock.c
[ARM] pxa: Make cpu_is_pxaXXX dependent on configuration symbols
[ARM] pxa: PXA3xx base support
[NET] smc91x: fix PXA DMA support code
[SERIAL] Fix console initialisation ordering
[ARM] pxa: tidy up arch/arm/mach-pxa/Makefile
[ARM] Update arch/arm/Kconfig for drivers/Kconfig changes
[ARM] 4600/1: fix kernel build failure with build-id-supporting binutils
[ARM] 4599/1: Preserve ATAG list for use with kexec (2.6.23)
[ARM] Rename consistent_sync() as dma_cache_maint()
[ARM] 4572/1: ep93xx: add cirrus logic edb9307 support
[ARM] 4596/1: S3C2412: Correct IRQs for SDI+CF and add decoding support
[ARM] 4595/1: ns9xxx: define registers as void __iomem * instead of volatile u32
[ARM] 4594/1: ns9xxx: use the new gpio functions
[ARM] 4593/1: ns9xxx: implement generic clockevents
...
Diffstat (limited to 'arch/arm/mach-pxa/mfp.c')
-rw-r--r-- | arch/arm/mach-pxa/mfp.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c new file mode 100644 index 0000000..5cd3cad --- /dev/null +++ b/arch/arm/mach-pxa/mfp.c @@ -0,0 +1,235 @@ +/* + * linux/arch/arm/mach-pxa/mfp.c + * + * PXA3xx Multi-Function Pin Support + * + * Copyright (C) 2007 Marvell Internation Ltd. + * + * 2007-08-21: eric miao <eric.y.miao@gmail.com> + * initial version + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/hardware.h> +#include <asm/arch/mfp.h> + +/* mfp_spin_lock is used to ensure that MFP register configuration + * (most likely a read-modify-write operation) is atomic, and that + * mfp_table[] is consistent + */ +static DEFINE_SPINLOCK(mfp_spin_lock); + +static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE); +static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX]; + +#define mfpr_readl(off) \ + __raw_readl(mfpr_mmio_base + (off)) + +#define mfpr_writel(off, val) \ + __raw_writel(val, mfpr_mmio_base + (off)) + +/* + * perform a read-back of any MFPR register to make sure the + * previous writings are finished + */ +#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) + +static inline void __mfp_config(int pin, unsigned long val) +{ + unsigned long off = mfp_table[pin].mfpr_off; + + mfp_table[pin].mfpr_val = val; + mfpr_writel(off, val); +} + +void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num) +{ + int i, pin; + unsigned long val, flags; + mfp_cfg_t *mfp_cfg = mfp_cfgs; + + spin_lock_irqsave(&mfp_spin_lock, flags); + + for (i = 0; i < num; i++, mfp_cfg++) { + pin = MFP_CFG_PIN(*mfp_cfg); + val = MFP_CFG_VAL(*mfp_cfg); + + BUG_ON(pin >= MFP_PIN_MAX); + + __mfp_config(pin, val); + } + + mfpr_sync(); + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +unsigned long pxa3xx_mfp_read(int mfp) +{ + unsigned long val, flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + val = mfpr_readl(mfp_table[mfp].mfpr_off); + spin_unlock_irqrestore(&mfp_spin_lock, flags); + + return val; +} + +void pxa3xx_mfp_write(int mfp, unsigned long val) +{ + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + mfpr_writel(mfp_table[mfp].mfpr_off, val); + mfpr_sync(); + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void pxa3xx_mfp_set_afds(int mfp, int af, int ds) +{ + uint32_t mfpr_off, mfpr_val; + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + mfpr_off = mfp_table[mfp].mfpr_off; + + mfpr_val = mfpr_readl(mfpr_off); + mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK); + mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) | + ((ds & 0x7) << MFPR_DRV_OFFSET)); + + mfpr_writel(mfpr_off, mfpr_val); + mfpr_sync(); + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void pxa3xx_mfp_set_rdh(int mfp, int rdh) +{ + uint32_t mfpr_off, mfpr_val; + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + + mfpr_off = mfp_table[mfp].mfpr_off; + + mfpr_val = mfpr_readl(mfpr_off); + mfpr_val &= ~MFPR_RDH_MASK; + + if (likely(rdh)) + mfpr_val |= (1u << MFPR_SS_OFFSET); + + mfpr_writel(mfpr_off, mfpr_val); + mfpr_sync(); + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void pxa3xx_mfp_set_lpm(int mfp, int lpm) +{ + uint32_t mfpr_off, mfpr_val; + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + + mfpr_off = mfp_table[mfp].mfpr_off; + mfpr_val = mfpr_readl(mfpr_off); + mfpr_val &= ~MFPR_LPM_MASK; + + if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET; + if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET; + if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET; + if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET; + if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET; + + mfpr_writel(mfpr_off, mfpr_val); + mfpr_sync(); + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void pxa3xx_mfp_set_pull(int mfp, int pull) +{ + uint32_t mfpr_off, mfpr_val; + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + + mfpr_off = mfp_table[mfp].mfpr_off; + mfpr_val = mfpr_readl(mfpr_off); + mfpr_val &= ~MFPR_PULL_MASK; + mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET); + + mfpr_writel(mfpr_off, mfpr_val); + mfpr_sync(); + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void pxa3xx_mfp_set_edge(int mfp, int edge) +{ + uint32_t mfpr_off, mfpr_val; + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + + mfpr_off = mfp_table[mfp].mfpr_off; + mfpr_val = mfpr_readl(mfpr_off); + + mfpr_val &= ~MFPR_EDGE_MASK; + mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET; + mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET; + + mfpr_writel(mfpr_off, mfpr_val); + mfpr_sync(); + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) +{ + struct pxa3xx_mfp_addr_map *p; + unsigned long offset, flags; + int i; + + spin_lock_irqsave(&mfp_spin_lock, flags); + + for (p = map; p->start != MFP_PIN_INVALID; p++) { + offset = p->offset; + i = p->start; + + do { + mfp_table[i].mfpr_off = offset; + mfp_table[i].mfpr_val = 0; + offset += 4; i++; + } while ((i <= p->end) && (p->end != -1)); + } + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void __init pxa3xx_init_mfp(void) +{ + memset(mfp_table, 0, sizeof(mfp_table)); +} |