linux/arch/mips/bcm63xx/cs.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/errno.h>
  11#include <linux/export.h>
  12#include <linux/spinlock.h>
  13#include <linux/log2.h>
  14#include <bcm63xx_cpu.h>
  15#include <bcm63xx_io.h>
  16#include <bcm63xx_regs.h>
  17#include <bcm63xx_cs.h>
  18
  19static DEFINE_SPINLOCK(bcm63xx_cs_lock);
  20
  21/*
  22 * check if given chip select exists
  23 */
  24static int is_valid_cs(unsigned int cs)
  25{
  26        if (cs > 6)
  27                return 0;
  28        return 1;
  29}
  30
  31/*
  32 * Configure chipselect base address and size (bytes).
  33 * Size must be a power of two between 8k and 256M.
  34 */
  35int bcm63xx_set_cs_base(unsigned int cs, u32 base, unsigned int size)
  36{
  37        unsigned long flags;
  38        u32 val;
  39
  40        if (!is_valid_cs(cs))
  41                return -EINVAL;
  42
  43        /* sanity check on size */
  44        if (size != roundup_pow_of_two(size))
  45                return -EINVAL;
  46
  47        if (size < 8 * 1024 || size > 256 * 1024 * 1024)
  48                return -EINVAL;
  49
  50        val = (base & MPI_CSBASE_BASE_MASK);
  51        /* 8k => 0 - 256M => 15 */
  52        val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT;
  53
  54        spin_lock_irqsave(&bcm63xx_cs_lock, flags);
  55        bcm_mpi_writel(val, MPI_CSBASE_REG(cs));
  56        spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
  57
  58        return 0;
  59}
  60
  61EXPORT_SYMBOL(bcm63xx_set_cs_base);
  62
  63/*
  64 * configure chipselect timing (ns)
  65 */
  66int bcm63xx_set_cs_timing(unsigned int cs, unsigned int wait,
  67                           unsigned int setup, unsigned int hold)
  68{
  69        unsigned long flags;
  70        u32 val;
  71
  72        if (!is_valid_cs(cs))
  73                return -EINVAL;
  74
  75        spin_lock_irqsave(&bcm63xx_cs_lock, flags);
  76        val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
  77        val &= ~(MPI_CSCTL_WAIT_MASK);
  78        val &= ~(MPI_CSCTL_SETUP_MASK);
  79        val &= ~(MPI_CSCTL_HOLD_MASK);
  80        val |= wait << MPI_CSCTL_WAIT_SHIFT;
  81        val |= setup << MPI_CSCTL_SETUP_SHIFT;
  82        val |= hold << MPI_CSCTL_HOLD_SHIFT;
  83        bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
  84        spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
  85
  86        return 0;
  87}
  88
  89EXPORT_SYMBOL(bcm63xx_set_cs_timing);
  90
  91/*
  92 * configure other chipselect parameter (data bus size, ...)
  93 */
  94int bcm63xx_set_cs_param(unsigned int cs, u32 params)
  95{
  96        unsigned long flags;
  97        u32 val;
  98
  99        if (!is_valid_cs(cs))
 100                return -EINVAL;
 101
 102        /* none of this fields apply to pcmcia */
 103        if (cs == MPI_CS_PCMCIA_COMMON ||
 104            cs == MPI_CS_PCMCIA_ATTR ||
 105            cs == MPI_CS_PCMCIA_IO)
 106                return -EINVAL;
 107
 108        spin_lock_irqsave(&bcm63xx_cs_lock, flags);
 109        val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
 110        val &= ~(MPI_CSCTL_DATA16_MASK);
 111        val &= ~(MPI_CSCTL_SYNCMODE_MASK);
 112        val &= ~(MPI_CSCTL_TSIZE_MASK);
 113        val &= ~(MPI_CSCTL_ENDIANSWAP_MASK);
 114        val |= params;
 115        bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
 116        spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
 117
 118        return 0;
 119}
 120
 121EXPORT_SYMBOL(bcm63xx_set_cs_param);
 122
 123/*
 124 * set cs status (enable/disable)
 125 */
 126int bcm63xx_set_cs_status(unsigned int cs, int enable)
 127{
 128        unsigned long flags;
 129        u32 val;
 130
 131        if (!is_valid_cs(cs))
 132                return -EINVAL;
 133
 134        spin_lock_irqsave(&bcm63xx_cs_lock, flags);
 135        val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
 136        if (enable)
 137                val |= MPI_CSCTL_ENABLE_MASK;
 138        else
 139                val &= ~MPI_CSCTL_ENABLE_MASK;
 140        bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
 141        spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
 142        return 0;
 143}
 144
 145EXPORT_SYMBOL(bcm63xx_set_cs_status);
 146