source: trunk/target/linux/brcm63xx/patches-2.6.37/240-spi.patch @ 26801

Last change on this file since 26801 was 26801, checked in by hauke, 5 years ago

brcm47xx: add fallback sprom for pci devices without an own sprom.

If there is no sprom on an ssb based pci device on the brcm47xx
architecture ssb now asks the architecture code to look into the nvram
to get some sprom data for this device. Now we are able to read out
pci/1/1/ foo or pci/1/3/ foo config options.

This will fix some problems where the wireless devices does not got an
mac address and the following message was show:
ssb: WARNING: Invalid SPROM CRC (corrupt SPROM)

File size: 26.9 KB
  • arch/mips/bcm63xx/cpu.c

    a b static const unsigned long bcm96338_regs 
    5858 
    5959static const int bcm96338_irqs[] = { 
    6060        [IRQ_TIMER]             = BCM_6338_TIMER_IRQ, 
     61        [IRQ_SPI]               = BCM_6338_SPI_IRQ, 
    6162        [IRQ_UART0]             = BCM_6338_UART0_IRQ, 
    6263        [IRQ_DSL]               = BCM_6338_DSL_IRQ, 
    6364        [IRQ_ENET0]             = BCM_6338_ENET0_IRQ, 
    static const unsigned long bcm96348_regs 
    132133 
    133134static const int bcm96348_irqs[] = { 
    134135        [IRQ_TIMER]             = BCM_6348_TIMER_IRQ, 
     136        [IRQ_SPI]               = BCM_6348_SPI_IRQ, 
    135137        [IRQ_UART0]             = BCM_6348_UART0_IRQ, 
    136138        [IRQ_DSL]               = BCM_6348_DSL_IRQ, 
    137139        [IRQ_ENET0]             = BCM_6348_ENET0_IRQ, 
    static const unsigned long bcm96358_regs 
    175177 
    176178static const int bcm96358_irqs[] = { 
    177179        [IRQ_TIMER]             = BCM_6358_TIMER_IRQ, 
     180        [IRQ_SPI]               = BCM_6358_SPI_IRQ, 
    178181        [IRQ_UART0]             = BCM_6358_UART0_IRQ, 
    179182        [IRQ_UART1]             = BCM_6358_UART1_IRQ, 
    180183        [IRQ_DSL]               = BCM_6358_DSL_IRQ, 
  • new file arch/mips/bcm63xx/dev-spi.c

    - +  
     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) 2009 Florian Fainelli <florian@openwrt.org> 
     7 * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com> 
     8 */ 
     9 
     10#include <linux/init.h> 
     11#include <linux/kernel.h> 
     12#include <linux/platform_device.h> 
     13 
     14#include <bcm63xx_cpu.h> 
     15#include <bcm63xx_dev_spi.h> 
     16#include <bcm63xx_regs.h> 
     17 
     18#ifdef BCMCPU_RUNTIME_DETECT 
     19/* 
     20 * register offsets 
     21 */ 
     22static const unsigned long bcm96338_regs_spi[] = { 
     23        [SPI_CMD]               = SPI_BCM_6338_SPI_CMD, 
     24        [SPI_INT_STATUS]        = SPI_BCM_6338_SPI_INT_STATUS, 
     25        [SPI_INT_MASK_ST]       = SPI_BCM_6338_SPI_MASK_INT_ST, 
     26        [SPI_INT_MASK]          = SPI_BCM_6338_SPI_INT_MASK, 
     27        [SPI_ST]                = SPI_BCM_6338_SPI_ST, 
     28        [SPI_CLK_CFG]           = SPI_BCM_6338_SPI_CLK_CFG, 
     29        [SPI_FILL_BYTE]         = SPI_BCM_6338_SPI_FILL_BYTE, 
     30        [SPI_MSG_TAIL]          = SPI_BCM_6338_SPI_MSG_TAIL, 
     31        [SPI_RX_TAIL]           = SPI_BCM_6338_SPI_RX_TAIL, 
     32        [SPI_MSG_CTL]           = SPI_BCM_6338_SPI_MSG_CTL, 
     33        [SPI_MSG_DATA]          = SPI_BCM_6338_SPI_MSG_DATA, 
     34        [SPI_RX_DATA]           = SPI_BCM_6338_SPI_RX_DATA, 
     35}; 
     36 
     37static const unsigned long bcm96348_regs_spi[] = { 
     38        [SPI_CMD]               = SPI_BCM_6348_SPI_CMD, 
     39        [SPI_INT_STATUS]        = SPI_BCM_6348_SPI_INT_STATUS, 
     40        [SPI_INT_MASK_ST]       = SPI_BCM_6348_SPI_MASK_INT_ST, 
     41        [SPI_INT_MASK]          = SPI_BCM_6348_SPI_INT_MASK, 
     42        [SPI_ST]                = SPI_BCM_6348_SPI_ST, 
     43        [SPI_CLK_CFG]           = SPI_BCM_6348_SPI_CLK_CFG, 
     44        [SPI_FILL_BYTE]         = SPI_BCM_6348_SPI_FILL_BYTE, 
     45        [SPI_MSG_TAIL]          = SPI_BCM_6348_SPI_MSG_TAIL, 
     46        [SPI_RX_TAIL]           = SPI_BCM_6348_SPI_RX_TAIL, 
     47        [SPI_MSG_CTL]           = SPI_BCM_6348_SPI_MSG_CTL, 
     48        [SPI_MSG_DATA]          = SPI_BCM_6348_SPI_MSG_DATA, 
     49        [SPI_RX_DATA]           = SPI_BCM_6348_SPI_RX_DATA, 
     50}; 
     51 
     52static const unsigned long bcm96358_regs_spi[] = { 
     53        [SPI_CMD]               = SPI_BCM_6358_SPI_CMD, 
     54        [SPI_INT_STATUS]        = SPI_BCM_6358_SPI_INT_STATUS, 
     55        [SPI_INT_MASK_ST]       = SPI_BCM_6358_SPI_MASK_INT_ST, 
     56        [SPI_INT_MASK]          = SPI_BCM_6358_SPI_INT_MASK, 
     57        [SPI_ST]                = SPI_BCM_6358_SPI_STATUS, 
     58        [SPI_CLK_CFG]           = SPI_BCM_6358_SPI_CLK_CFG, 
     59        [SPI_FILL_BYTE]         = SPI_BCM_6358_SPI_FILL_BYTE, 
     60        [SPI_MSG_TAIL]          = SPI_BCM_6358_SPI_MSG_TAIL, 
     61        [SPI_RX_TAIL]           = SPI_BCM_6358_SPI_RX_TAIL, 
     62        [SPI_MSG_CTL]           = SPI_BCM_6358_MSG_CTL, 
     63        [SPI_MSG_DATA]          = SPI_BCM_6358_SPI_MSG_DATA, 
     64        [SPI_RX_DATA]           = SPI_BCM_6358_SPI_RX_DATA, 
     65}; 
     66 
     67const unsigned long *bcm63xx_regs_spi; 
     68EXPORT_SYMBOL(bcm63xx_regs_spi); 
     69 
     70static __init void bcm63xx_spi_regs_init(void) 
     71{ 
     72        if (BCMCPU_IS_6338()) 
     73                bcm63xx_regs_spi = bcm96338_regs_spi; 
     74        if (BCMCPU_IS_6348()) 
     75                bcm63xx_regs_spi = bcm96348_regs_spi; 
     76        if (BCMCPU_IS_6358()) 
     77                bcm63xx_regs_spi = bcm96358_regs_spi; 
     78} 
     79#else 
     80static __init void bcm63xx_spi_regs_init(void) { } 
     81#endif 
     82 
     83static struct resource spi_resources[] = { 
     84        { 
     85                .start          = -1, /* filled at runtime */ 
     86                .end            = -1, /* filled at runtime */ 
     87                .flags          = IORESOURCE_MEM, 
     88        }, 
     89        { 
     90                .start          = -1, /* filled at runtime */ 
     91                .flags          = IORESOURCE_IRQ, 
     92        }, 
     93}; 
     94 
     95static struct bcm63xx_spi_pdata spi_pdata = { 
     96        .bus_num                = 0, 
     97        .num_chipselect         = 8, 
     98        .speed_hz               = 50000000,     /* Fclk */ 
     99}; 
     100 
     101static struct platform_device bcm63xx_spi_device = { 
     102        .name           = "bcm63xx-spi", 
     103        .id             = 0, 
     104        .num_resources  = ARRAY_SIZE(spi_resources), 
     105        .resource       = spi_resources, 
     106        .dev            = { 
     107                .platform_data = &spi_pdata, 
     108        }, 
     109}; 
     110 
     111int __init bcm63xx_spi_register(void) 
     112{ 
     113        spi_resources[0].start = bcm63xx_regset_address(RSET_SPI); 
     114        spi_resources[0].end = spi_resources[0].start; 
     115        spi_resources[0].end += RSET_SPI_SIZE - 1; 
     116        spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI); 
     117 
     118        /* Fill in platform data */ 
     119        if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) 
     120                spi_pdata.fifo_size = SPI_BCM_6338_SPI_MSG_DATA_SIZE; 
     121 
     122        if (BCMCPU_IS_6358()) 
     123                spi_pdata.fifo_size = SPI_BCM_6358_SPI_MSG_DATA_SIZE; 
     124 
     125        bcm63xx_spi_regs_init(); 
     126 
     127        return platform_device_register(&bcm63xx_spi_device); 
     128} 
  • arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h

    a b enum bcm63xx_regs_set { 
    109109#define RSET_WDT_SIZE                   12 
    110110#define RSET_ENET_SIZE                  2048 
    111111#define RSET_ENETDMA_SIZE               2048 
     112#define RSET_SPI_SIZE                   256 
    112113#define RSET_UART_SIZE                  24 
    113114#define RSET_UDC_SIZE                   256 
    114115#define RSET_OHCI_SIZE                  256 
    enum bcm63xx_regs_set { 
    214215#define BCM_6358_UART0_BASE             (0xfffe0100) 
    215216#define BCM_6358_UART1_BASE             (0xfffe0120) 
    216217#define BCM_6358_GPIO_BASE              (0xfffe0080) 
    217 #define BCM_6358_SPI_BASE               (0xdeadbeef) 
     218#define BCM_6358_SPI_BASE               (0xfffe0800) 
    218219#define BCM_6358_UDC0_BASE              (0xfffe0400) 
    219220#define BCM_6358_OHCI0_BASE             (0xfffe1400) 
    220221#define BCM_6358_OHCI_PRIV_BASE         (0xdeadbeef) 
    static inline unsigned long bcm63xx_regs 
    441442 */ 
    442443enum bcm63xx_irq { 
    443444        IRQ_TIMER = 0, 
     445        IRQ_SPI, 
    444446        IRQ_UART0, 
    445447        IRQ_UART1, 
    446448        IRQ_DSL, 
    enum bcm63xx_irq { 
    507509 * 6348 irqs 
    508510 */ 
    509511#define BCM_6348_TIMER_IRQ              (IRQ_INTERNAL_BASE + 0) 
     512#define BCM_6348_SPI_IRQ                (IRQ_INTERNAL_BASE + 1) 
    510513#define BCM_6348_UART0_IRQ              (IRQ_INTERNAL_BASE + 2) 
    511514#define BCM_6348_DSL_IRQ                (IRQ_INTERNAL_BASE + 4) 
    512515#define BCM_6348_UDC0_IRQ               (IRQ_INTERNAL_BASE + 6) 
    enum bcm63xx_irq { 
    531534 * 6358 irqs 
    532535 */ 
    533536#define BCM_6358_TIMER_IRQ              (IRQ_INTERNAL_BASE + 0) 
     537#define BCM_6358_SPI_IRQ                (IRQ_INTERNAL_BASE + 1) 
    534538#define BCM_6358_UART0_IRQ              (IRQ_INTERNAL_BASE + 2) 
    535539#define BCM_6358_UART1_IRQ              (IRQ_INTERNAL_BASE + 3) 
    536540#define BCM_6358_OHCI0_IRQ              (IRQ_INTERNAL_BASE + 5) 
  • arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h

    a b  
    769769#define DMIPSPLLCFG_N2_SHIFT            29 
    770770#define DMIPSPLLCFG_N2_MASK             (0x7 << DMIPSPLLCFG_N2_SHIFT) 
    771771 
     772/************************************************************************* 
     773 * _REG relative to RSET_SPI 
     774 *************************************************************************/ 
     775 
     776/* BCM 6338 SPI core */ 
     777#define SPI_BCM_6338_SPI_CMD            0x00    /* 16-bits register */ 
     778#define SPI_BCM_6338_SPI_INT_STATUS     0x02 
     779#define SPI_BCM_6338_SPI_MASK_INT_ST    0x03 
     780#define SPI_BCM_6338_SPI_INT_MASK       0x04 
     781#define SPI_BCM_6338_SPI_ST             0x05 
     782#define SPI_BCM_6338_SPI_CLK_CFG        0x06 
     783#define SPI_BCM_6338_SPI_FILL_BYTE      0x07 
     784#define SPI_BCM_6338_SPI_MSG_TAIL       0x09 
     785#define SPI_BCM_6338_SPI_RX_TAIL        0x0b 
     786#define SPI_BCM_6338_SPI_MSG_CTL        0x40 
     787#define SPI_BCM_6338_SPI_MSG_DATA       0x41 
     788#define SPI_BCM_6338_SPI_MSG_DATA_SIZE  0x3f 
     789#define SPI_BCM_6338_SPI_RX_DATA        0x80 
     790#define SPI_BCM_6338_SPI_RX_DATA_SIZE   0x3f 
     791 
     792/* BCM 6348 SPI core */ 
     793#define SPI_BCM_6348_SPI_MASK_INT_ST    0x00 
     794#define SPI_BCM_6348_SPI_INT_STATUS     0x01 
     795#define SPI_BCM_6348_SPI_CMD            0x02    /* 16-bits register */ 
     796#define SPI_BCM_6348_SPI_FILL_BYTE      0x04 
     797#define SPI_BCM_6348_SPI_CLK_CFG        0x05 
     798#define SPI_BCM_6348_SPI_ST             0x06 
     799#define SPI_BCM_6348_SPI_INT_MASK       0x07 
     800#define SPI_BCM_6348_SPI_RX_TAIL        0x08 
     801#define SPI_BCM_6348_SPI_MSG_TAIL       0x10 
     802#define SPI_BCM_6348_SPI_MSG_DATA       0x40 
     803#define SPI_BCM_6348_SPI_MSG_CTL        0x42 
     804#define SPI_BCM_6348_SPI_MSG_DATA_SIZE  0x3f 
     805#define SPI_BCM_6348_SPI_RX_DATA        0x80 
     806#define SPI_BCM_6348_SPI_RX_DATA_SIZE   0x3f 
     807 
     808/* BCM 6358 SPI core */ 
     809#define SPI_BCM_6358_MSG_CTL            0x00    /* 16-bits register */ 
     810 
     811#define SPI_BCM_6358_SPI_MSG_DATA       0x02 
     812#define SPI_BCM_6358_SPI_MSG_DATA_SIZE  0x21e 
     813 
     814#define SPI_BCM_6358_SPI_RX_DATA        0x400 
     815#define SPI_BCM_6358_SPI_RX_DATA_SIZE   0x220 
     816 
     817#define SPI_BCM_6358_SPI_CMD            0x700   /* 16-bits register */ 
     818 
     819#define SPI_BCM_6358_SPI_INT_STATUS     0x702 
     820#define SPI_BCM_6358_SPI_MASK_INT_ST    0x703 
     821 
     822#define SPI_BCM_6358_SPI_INT_MASK       0x704 
     823 
     824#define SPI_BCM_6358_SPI_STATUS         0x705 
     825 
     826#define SPI_BCM_6358_SPI_CLK_CFG        0x706 
     827 
     828#define SPI_BCM_6358_SPI_FILL_BYTE      0x707 
     829#define SPI_BCM_6358_SPI_MSG_TAIL       0x709 
     830#define SPI_BCM_6358_SPI_RX_TAIL        0x70B 
     831 
     832/* Shared SPI definitions */ 
     833 
     834/* Message configuration */ 
     835#define SPI_FD_RW                       0x00 
     836#define SPI_HD_W                        0x01 
     837#define SPI_HD_R                        0x02 
     838#define SPI_BYTE_CNT_SHIFT              0 
     839#define SPI_MSG_TYPE_SHIFT              14 
     840 
     841/* Command */ 
     842#define SPI_CMD_NOOP                    0x01 
     843#define SPI_CMD_SOFT_RESET              0x02 
     844#define SPI_CMD_HARD_RESET              0x04 
     845#define SPI_CMD_START_IMMEDIATE         0x08 
     846#define SPI_CMD_COMMAND_SHIFT           0 
     847#define SPI_CMD_COMMAND_MASK            0x000f 
     848#define SPI_CMD_DEVICE_ID_SHIFT         4 
     849#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT  8 
     850#define SPI_CMD_ONE_BYTE_SHIFT          11 
     851#define SPI_CMD_ONE_WIRE_SHIFT          12 
     852#define SPI_DEV_ID_0                    0 
     853#define SPI_DEV_ID_1                    1 
     854#define SPI_DEV_ID_2                    2 
     855#define SPI_DEV_ID_3                    3 
     856 
     857/* Interrupt mask */ 
     858#define SPI_INTR_CMD_DONE               0x01 
     859#define SPI_INTR_RX_OVERFLOW            0x02 
     860#define SPI_INTR_TX_UNDERFLOW           0x04 
     861#define SPI_INTR_TX_OVERFLOW            0x08 
     862#define SPI_INTR_RX_UNDERFLOW           0x10 
     863#define SPI_INTR_CLEAR_ALL              0x1f 
     864 
     865/* Status */ 
     866#define SPI_RX_EMPTY                    0x02 
     867#define SPI_CMD_BUSY                    0x04 
     868#define SPI_SERIAL_BUSY                 0x08 
     869 
     870/* Clock configuration */ 
     871#define SPI_CLK_20MHZ                   0x00 
     872#define SPI_CLK_0_391MHZ                0x01 
     873#define SPI_CLK_0_781MHZ                0x02 /* default */ 
     874#define SPI_CLK_1_563MHZ                0x03 
     875#define SPI_CLK_3_125MHZ                0x04 
     876#define SPI_CLK_6_250MHZ                0x05 
     877#define SPI_CLK_12_50MHZ                0x06 
     878#define SPI_CLK_25MHZ                   0x07 
     879#define SPI_CLK_MASK                    0x07 
     880#define SPI_SSOFFTIME_MASK              0x38 
     881#define SPI_SSOFFTIME_SHIFT             3 
     882#define SPI_BYTE_SWAP                   0x80 
     883 
    772884#endif /* BCM63XX_REGS_H_ */ 
  • new file drivers/spi/bcm63xx_spi.c

    - +  
     1/* 
     2 * Broadcom BCM63xx SPI controller support 
     3 * 
     4 * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org> 
     5 * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com> 
     6 * 
     7 * This program is free software; you can redistribute it and/or 
     8 * modify it under the terms of the GNU General Public License 
     9 * as published by the Free Software Foundation; either version 2 
     10 * of the License, or (at your option) any later version. 
     11 * 
     12 * This program is distributed in the hope that it will be useful, 
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     15 * GNU General Public License for more details. 
     16 * 
     17 * You should have received a copy of the GNU General Public License 
     18 * along with this program; if not, write to the 
     19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
     20 */ 
     21 
     22#include <linux/kernel.h> 
     23#include <linux/init.h> 
     24#include <linux/clk.h> 
     25#include <linux/module.h> 
     26#include <linux/platform_device.h> 
     27#include <linux/delay.h> 
     28#include <linux/interrupt.h> 
     29#include <linux/spi/spi.h> 
     30#include <linux/completion.h> 
     31#include <linux/err.h> 
     32 
     33#include <bcm63xx_dev_spi.h> 
     34 
     35#define PFX             KBUILD_MODNAME 
     36#define DRV_VER         "0.1.2" 
     37 
     38struct bcm63xx_spi { 
     39        spinlock_t              lock; 
     40        int                     stopping; 
     41        struct completion       done; 
     42 
     43        void __iomem            *regs; 
     44        int                     irq; 
     45 
     46        /* Platform data */ 
     47        u32                     speed_hz; 
     48        unsigned                fifo_size; 
     49 
     50        /* Data buffers */ 
     51        const unsigned char     *tx_ptr; 
     52        unsigned char           *rx_ptr; 
     53 
     54        /* data iomem */ 
     55        u8 __iomem              *tx_io; 
     56        const u8 __iomem        *rx_io; 
     57 
     58        int                     remaining_bytes; 
     59 
     60        struct clk              *clk; 
     61        struct platform_device  *pdev; 
     62}; 
     63 
     64static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs, 
     65                                unsigned int offset) 
     66{ 
     67        return bcm_readw(bs->regs + bcm63xx_spireg(offset)); 
     68} 
     69 
     70static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs, 
     71                                unsigned int offset) 
     72{ 
     73        return bcm_readw(bs->regs + bcm63xx_spireg(offset)); 
     74} 
     75 
     76static inline void bcm_spi_writeb(struct bcm63xx_spi *bs, 
     77                                  u8 value, unsigned int offset) 
     78{ 
     79        bcm_writeb(value, bs->regs + bcm63xx_spireg(offset)); 
     80} 
     81 
     82static inline void bcm_spi_writew(struct bcm63xx_spi *bs, 
     83                                  u16 value, unsigned int offset) 
     84{ 
     85        bcm_writew(value, bs->regs + bcm63xx_spireg(offset)); 
     86} 
     87 
     88static int bcm63xx_spi_setup_transfer(struct spi_device *spi, 
     89                                      struct spi_transfer *t) 
     90{ 
     91        u8 bits_per_word; 
     92        u8 clk_cfg; 
     93        u32 hz; 
     94        unsigned int div; 
     95 
     96        struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); 
     97 
     98        bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; 
     99        hz = (t) ? t->speed_hz : spi->max_speed_hz; 
     100        if (bits_per_word != 8) { 
     101                dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", 
     102                        __func__, bits_per_word); 
     103                return -EINVAL; 
     104        } 
     105 
     106        if (spi->chip_select > spi->master->num_chipselect) { 
     107                dev_err(&spi->dev, "%s, unsupported slave %d\n", 
     108                        __func__, spi->chip_select); 
     109                return -EINVAL; 
     110        } 
     111 
     112        /* Check clock setting */ 
     113        div = (bs->speed_hz / hz); 
     114        switch (div) { 
     115        case 2: 
     116                clk_cfg = SPI_CLK_25MHZ; 
     117                break; 
     118        case 4: 
     119                clk_cfg = SPI_CLK_12_50MHZ; 
     120                break; 
     121        case 8: 
     122                clk_cfg = SPI_CLK_6_250MHZ; 
     123                break; 
     124        case 16: 
     125                clk_cfg = SPI_CLK_3_125MHZ; 
     126                break; 
     127        case 32: 
     128                clk_cfg = SPI_CLK_1_563MHZ; 
     129                break; 
     130        case 64: 
     131                clk_cfg = SPI_CLK_0_781MHZ; 
     132                break; 
     133        case 128: 
     134        default: 
     135                /* Set to slowest mode for compatibility */ 
     136                clk_cfg = SPI_CLK_0_391MHZ; 
     137                break; 
     138        } 
     139 
     140        bcm_spi_writeb(bs, clk_cfg, SPI_CLK_CFG); 
     141        dev_dbg(&spi->dev, "Setting clock register to %d (hz %d, cmd %02x)\n", 
     142                div, hz, clk_cfg); 
     143 
     144        return 0; 
     145} 
     146 
     147/* the spi->mode bits understood by this driver: */ 
     148#define MODEBITS (SPI_CPOL | SPI_CPHA) 
     149 
     150static int bcm63xx_spi_setup(struct spi_device *spi) 
     151{ 
     152        struct bcm63xx_spi *bs; 
     153        int ret; 
     154 
     155        bs = spi_master_get_devdata(spi->master); 
     156 
     157        if (bs->stopping) 
     158                return -ESHUTDOWN; 
     159 
     160        if (!spi->bits_per_word) 
     161                spi->bits_per_word = 8; 
     162 
     163        if (spi->mode & ~MODEBITS) { 
     164                dev_err(&spi->dev, "%s, unsupported mode bits %x\n", 
     165                        __func__, spi->mode & ~MODEBITS); 
     166                return -EINVAL; 
     167        } 
     168 
     169        ret = bcm63xx_spi_setup_transfer(spi, NULL); 
     170        if (ret < 0) { 
     171                dev_err(&spi->dev, "setup: unsupported mode bits %x\n", 
     172                        spi->mode & ~MODEBITS); 
     173                return ret; 
     174        } 
     175 
     176        dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", 
     177                __func__, spi->mode & MODEBITS, spi->bits_per_word, 0); 
     178 
     179        return 0; 
     180} 
     181 
     182/* Fill the TX FIFO with as many bytes as possible */ 
     183static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) 
     184{ 
     185        u8 size; 
     186 
     187        /* Fill the Tx FIFO with as many bytes as possible */ 
     188        size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes : 
     189                bs->fifo_size; 
     190        memcpy_toio(bs->tx_io, bs->tx_ptr, size); 
     191        bs->remaining_bytes -= size; 
     192} 
     193 
     194static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) 
     195{ 
     196        struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); 
     197        u16 msg_ctl; 
     198        u16 cmd; 
     199 
     200        dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", 
     201                t->tx_buf, t->rx_buf, t->len); 
     202 
     203        /* Transmitter is inhibited */ 
     204        bs->tx_ptr = t->tx_buf; 
     205        bs->rx_ptr = t->rx_buf; 
     206        init_completion(&bs->done); 
     207 
     208        if (t->tx_buf) { 
     209                bs->remaining_bytes = t->len; 
     210                bcm63xx_spi_fill_tx_fifo(bs); 
     211        } 
     212 
     213        /* Enable the command done interrupt which 
     214         * we use to determine completion of a command */ 
     215        bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); 
     216 
     217        /* Fill in the Message control register */ 
     218        msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT); 
     219 
     220        if (t->rx_buf && t->tx_buf) 
     221                msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT); 
     222        else if (t->rx_buf) 
     223                msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT); 
     224        else if (t->tx_buf) 
     225                msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT); 
     226 
     227        bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL); 
     228 
     229        /* Issue the transfer */ 
     230        cmd = SPI_CMD_START_IMMEDIATE; 
     231        cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); 
     232        cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT); 
     233        bcm_spi_writew(bs, cmd, SPI_CMD); 
     234        wait_for_completion(&bs->done); 
     235 
     236        /* Disable the CMD_DONE interrupt */ 
     237        bcm_spi_writeb(bs, 0, SPI_INT_MASK); 
     238 
     239        return t->len - bs->remaining_bytes; 
     240} 
     241 
     242static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m) 
     243{ 
     244        struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); 
     245        struct spi_transfer *t; 
     246        int ret = 0; 
     247 
     248        if (unlikely(list_empty(&m->transfers))) 
     249                return -EINVAL; 
     250 
     251        if (bs->stopping) 
     252                return -ESHUTDOWN; 
     253 
     254        list_for_each_entry(t, &m->transfers, transfer_list) { 
     255                ret += bcm63xx_txrx_bufs(spi, t); 
     256        } 
     257 
     258        m->complete(m->context); 
     259 
     260        return ret; 
     261} 
     262 
     263/* This driver supports single master mode only. Hence 
     264 * CMD_DONE is the only interrupt we care about 
     265 */ 
     266static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) 
     267{ 
     268        struct spi_master *master = (struct spi_master *)dev_id; 
     269        struct bcm63xx_spi *bs = spi_master_get_devdata(master); 
     270        u8 intr; 
     271        u16 cmd; 
     272 
     273        /* Read interupts and clear them immediately */ 
     274        intr = bcm_spi_readb(bs, SPI_INT_STATUS); 
     275        bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); 
     276        bcm_spi_writeb(bs, 0, SPI_INT_MASK); 
     277 
     278        /* A tansfer completed */ 
     279        if (intr & SPI_INTR_CMD_DONE) { 
     280                u8 rx_tail; 
     281 
     282                rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL); 
     283 
     284                /* Read out all the data */ 
     285                if (rx_tail) 
     286                        memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail); 
     287 
     288                /* See if there is more data to send */ 
     289                if (bs->remaining_bytes > 0) { 
     290                        bcm63xx_spi_fill_tx_fifo(bs); 
     291 
     292                        /* Start the transfer */ 
     293                        bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT, 
     294                                       SPI_MSG_CTL); 
     295                        cmd = bcm_spi_readw(bs, SPI_CMD); 
     296                        cmd |= SPI_CMD_START_IMMEDIATE; 
     297                        cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); 
     298                        bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); 
     299                        bcm_spi_writew(bs, cmd, SPI_CMD); 
     300                } else { 
     301                        complete(&bs->done); 
     302                } 
     303        } 
     304 
     305        return IRQ_HANDLED; 
     306} 
     307 
     308 
     309static int __init bcm63xx_spi_probe(struct platform_device *pdev) 
     310{ 
     311        struct resource *r; 
     312        struct device *dev = &pdev->dev; 
     313        struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data; 
     314        int irq; 
     315        struct spi_master *master; 
     316        struct clk *clk; 
     317        struct bcm63xx_spi *bs; 
     318        int ret; 
     319 
     320        r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 
     321        if (!r) { 
     322                dev_err(dev, "no iomem\n"); 
     323                ret = -ENXIO; 
     324                goto out; 
     325        } 
     326 
     327        irq = platform_get_irq(pdev, 0); 
     328        if (irq < 0) { 
     329                dev_err(dev, "no irq\n"); 
     330                ret = -ENXIO; 
     331                goto out; 
     332        } 
     333 
     334        clk = clk_get(dev, "spi"); 
     335        if (IS_ERR(clk)) { 
     336                dev_err(dev, "no clock for device\n"); 
     337                ret = -ENODEV; 
     338                goto out; 
     339        } 
     340 
     341        master = spi_alloc_master(dev, sizeof(*bs)); 
     342        if (!master) { 
     343                dev_err(dev, "out of memory\n"); 
     344                ret = -ENOMEM; 
     345                goto out_free; 
     346        } 
     347 
     348        bs = spi_master_get_devdata(master); 
     349        init_completion(&bs->done); 
     350 
     351        platform_set_drvdata(pdev, master); 
     352        bs->pdev = pdev; 
     353 
     354        if (!request_mem_region(r->start, r->end - r->start, PFX)) { 
     355                dev_err(dev, "iomem request failed\n"); 
     356                ret = -ENXIO; 
     357                goto out_put_master; 
     358        } 
     359 
     360        bs->regs = ioremap_nocache(r->start, r->end - r->start); 
     361        if (!bs->regs) { 
     362                dev_err(dev, "unable to ioremap regs\n"); 
     363                ret = -ENOMEM; 
     364                goto out_put_master; 
     365        } 
     366        bs->irq = irq; 
     367        bs->clk = clk; 
     368        bs->fifo_size = pdata->fifo_size; 
     369 
     370        ret = request_irq(irq, bcm63xx_spi_interrupt, 0, pdev->name, master); 
     371        if (ret) { 
     372                dev_err(dev, "unable to request irq\n"); 
     373                goto out_unmap; 
     374        } 
     375 
     376        master->bus_num = pdata->bus_num; 
     377        master->num_chipselect = pdata->num_chipselect; 
     378        master->setup = bcm63xx_spi_setup; 
     379        master->transfer = bcm63xx_transfer; 
     380        bs->speed_hz = pdata->speed_hz; 
     381        bs->stopping = 0; 
     382        bs->tx_io = (u8*)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); 
     383        bs->rx_io = (const u8*)(bs->regs + bcm63xx_spireg(SPI_RX_DATA)); 
     384        spin_lock_init(&bs->lock); 
     385 
     386        /* Initialize hardware */ 
     387        clk_enable(bs->clk); 
     388        bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); 
     389 
     390        /* register and we are done */ 
     391        ret = spi_register_master(master); 
     392        if (ret) { 
     393                dev_err(dev, "spi register failed\n"); 
     394                goto out_reset_hw; 
     395        } 
     396 
     397        dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n", 
     398                 r->start, irq, bs->fifo_size, DRV_VER); 
     399 
     400        return 0; 
     401 
     402out_reset_hw: 
     403        clk_disable(clk); 
     404        free_irq(irq, master); 
     405out_unmap: 
     406        iounmap(bs->regs); 
     407out_put_master: 
     408        spi_master_put(master); 
     409out_free: 
     410        clk_put(clk); 
     411out: 
     412        return ret; 
     413} 
     414 
     415static int __exit bcm63xx_spi_remove(struct platform_device *pdev) 
     416{ 
     417        struct spi_master       *master = platform_get_drvdata(pdev); 
     418        struct bcm63xx_spi      *bs = spi_master_get_devdata(master); 
     419        struct resource         *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 
     420 
     421        /* reset spi block */ 
     422        bcm_spi_writeb(bs, 0, SPI_INT_MASK); 
     423        spin_lock(&bs->lock); 
     424        bs->stopping = 1; 
     425 
     426        /* HW shutdown */ 
     427        clk_disable(bs->clk); 
     428        clk_put(bs->clk); 
     429 
     430        spin_unlock(&bs->lock); 
     431 
     432        free_irq(bs->irq, master); 
     433        iounmap(bs->regs); 
     434        release_mem_region(r->start, r->end - r->start); 
     435        platform_set_drvdata(pdev, 0); 
     436        spi_unregister_master(master); 
     437 
     438        return 0; 
     439} 
     440 
     441#ifdef CONFIG_PM 
     442static int bcm63xx_spi_suspend(struct platform_device *pdev, pm_message_t mesg) 
     443{ 
     444        struct spi_master       *master = platform_get_drvdata(pdev); 
     445        struct bcm63xx_spi      *bs = spi_master_get_devdata(master); 
     446 
     447        clk_disable(bs->clk); 
     448 
     449        return 0; 
     450} 
     451 
     452static int bcm63xx_spi_resume(struct platform_device *pdev) 
     453{ 
     454        struct spi_master       *master = platform_get_drvdata(pdev); 
     455        struct bcm63xx_spi      *bs = spi_master_get_devdata(master); 
     456 
     457        clk_enable(bs->clk); 
     458 
     459        return 0; 
     460} 
     461#else 
     462#define bcm63xx_spi_suspend     NULL 
     463#define bcm63xx_spi_resume      NULL 
     464#endif 
     465 
     466static struct platform_driver bcm63xx_spi_driver = { 
     467        .driver = { 
     468                .name   = "bcm63xx-spi", 
     469                .owner  = THIS_MODULE, 
     470        }, 
     471        .probe          = bcm63xx_spi_probe, 
     472        .remove         = __exit_p(bcm63xx_spi_remove), 
     473        .suspend        = bcm63xx_spi_suspend, 
     474        .resume         = bcm63xx_spi_resume, 
     475}; 
     476 
     477 
     478static int __init bcm63xx_spi_init(void) 
     479{ 
     480        return platform_driver_register(&bcm63xx_spi_driver); 
     481} 
     482 
     483static void __exit bcm63xx_spi_exit(void) 
     484{ 
     485        platform_driver_unregister(&bcm63xx_spi_driver); 
     486} 
     487 
     488module_init(bcm63xx_spi_init); 
     489module_exit(bcm63xx_spi_exit); 
     490 
     491MODULE_ALIAS("platform:bcm63xx_spi"); 
     492MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); 
     493MODULE_AUTHOR("Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>"); 
     494MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver"); 
     495MODULE_LICENSE("GPL"); 
     496MODULE_VERSION(DRV_VER); 
  • drivers/spi/Kconfig

    a b config SPI_ATMEL 
    6060          This selects a driver for the Atmel SPI Controller, present on 
    6161          many AT32 (AVR32) and AT91 (ARM) chips. 
    6262 
     63config SPI_BCM63XX 
     64        tristate "Broadcom BCM63xx SPI controller" 
     65        depends on BCM63XX 
     66        help 
     67          This is the SPI controller master driver for Broadcom BCM63xx SoC. 
     68 
    6369config SPI_BFIN 
    6470        tristate "SPI controller driver for ADI Blackfin5xx" 
    6571        depends on BLACKFIN 
  • drivers/spi/Makefile

    a b obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci. 
    5050obj-$(CONFIG_SPI_SH_MSIOF)              += spi_sh_msiof.o 
    5151obj-$(CONFIG_SPI_STMP3XXX)              += spi_stmp.o 
    5252obj-$(CONFIG_SPI_NUC900)                += spi_nuc900.o 
     53obj-$(CONFIG_SPI_BCM63XX)               += bcm63xx_spi.o 
    5354 
    5455# special build for s3c24xx spi driver with fiq support 
    5556spi_s3c24xx_hw-y                        := spi_s3c24xx.o 
  • new file arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h

    - +  
     1#ifndef BCM63XX_DEV_SPI_H 
     2#define BCM63XX_DEV_SPI_H 
     3 
     4#include <linux/types.h> 
     5#include <bcm63xx_io.h> 
     6#include <bcm63xx_regs.h> 
     7 
     8int __init bcm63xx_spi_register(void); 
     9 
     10struct bcm63xx_spi_pdata { 
     11        unsigned int    fifo_size; 
     12        int             bus_num; 
     13        int             num_chipselect; 
     14        u32             speed_hz; 
     15}; 
     16 
     17enum bcm63xx_regs_spi { 
     18        SPI_CMD, 
     19        SPI_INT_STATUS, 
     20        SPI_INT_MASK_ST, 
     21        SPI_INT_MASK, 
     22        SPI_ST, 
     23        SPI_CLK_CFG, 
     24        SPI_FILL_BYTE, 
     25        SPI_MSG_TAIL, 
     26        SPI_RX_TAIL, 
     27        SPI_MSG_CTL, 
     28        SPI_MSG_DATA, 
     29        SPI_RX_DATA, 
     30}; 
     31 
     32static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg) 
     33{ 
     34#ifdef BCMCPU_RUNTIME_DETECT 
     35        extern const unsigned long *bcm63xx_regs_spi; 
     36        return bcm63xx_regs_spi[reg]; 
     37#else 
     38#ifdef CONFIG_BCM63XX_CPU_6338 
     39switch (reg) { 
     40        case SPI_CMD: 
     41                return SPI_BCM_6338_SPI_CMD; 
     42        case SPI_INT_STATUS: 
     43                return SPI_BCM_6338_SPI_INT_STATUS; 
     44        case SPI_INT_MASK_ST: 
     45                return SPI_BCM_6338_SPI_MASK_INT_ST; 
     46        case SPI_INT_MASK: 
     47                return SPI_BCM_6338_SPI_INT_MASK; 
     48        case SPI_ST: 
     49                return SPI_BCM_6338_SPI_ST; 
     50        case SPI_CLK_CFG: 
     51                return SPI_BCM_6338_SPI_CLK_CFG; 
     52        case SPI_FILL_BYTE: 
     53                return SPI_BCM_6338_SPI_FILL_BYTE; 
     54        case SPI_MSG_TAIL: 
     55                return SPI_BCM_6338_SPI_MSG_TAIL; 
     56        case SPI_RX_TAIL: 
     57                return SPI_BCM_6338_SPI_RX_TAIL; 
     58        case SPI_MSG_CTL: 
     59                return SPI_BCM_6338_SPI_MSG_CTL; 
     60        case SPI_MSG_DATA: 
     61                return SPI_BCM_6338_SPI_MSG_DATA; 
     62        case SPI_RX_DATA: 
     63                return SPI_BCM_6338_SPI_RX_DATA; 
     64} 
     65#endif 
     66#ifdef CONFIG_BCM63XX_CPU_6348 
     67switch (reg) { 
     68        case SPI_CMD: 
     69                return SPI_BCM_6348_SPI_CMD; 
     70        case SPI_INT_MASK_ST: 
     71                return SPI_BCM_6348_SPI_MASK_INT_ST; 
     72        case SPI_INT_MASK: 
     73                return SPI_BCM_6348_SPI_INT_MASK; 
     74        case SPI_INT_STATUS: 
     75                return SPI_BCM_6348_SPI_INT_STATUS; 
     76        case SPI_ST: 
     77                return SPI_BCM_6348_SPI_ST; 
     78        case SPI_CLK_CFG: 
     79                return SPI_BCM_6348_SPI_CLK_CFG; 
     80        case SPI_FILL_BYTE: 
     81                return SPI_BCM_6348_SPI_FILL_BYTE; 
     82        case SPI_MSG_TAIL: 
     83                return SPI_BCM_6348_SPI_MSG_TAIL; 
     84        case SPI_RX_TAIL: 
     85                return SPI_BCM_6348_SPI_RX_TAIL; 
     86        case SPI_MSG_CTL: 
     87                return SPI_BCM_6348_SPI_MSG_CTL; 
     88        case SPI_MSG_DATA: 
     89                return SPI_BCM_6348_SPI_MSG_DATA; 
     90        case SPI_RX_DATA: 
     91                return SPI_BCM_6348_SPI_RX_DATA; 
     92} 
     93#endif 
     94#ifdef CONFIG_BCM63XX_CPU_6358 
     95switch (reg) { 
     96        case SPI_CMD: 
     97                return SPI_BCM_6358_SPI_CMD; 
     98        case SPI_INT_STATUS: 
     99                return SPI_BCM_6358_SPI_INT_STATUS; 
     100        case SPI_INT_MASK_ST: 
     101                return SPI_BCM_6358_SPI_MASK_INT_ST; 
     102        case SPI_INT_MASK: 
     103                return SPI_BCM_6358_SPI_INT_MASK; 
     104        case SPI_ST: 
     105                return SPI_BCM_6358_SPI_STATUS; 
     106        case SPI_CLK_CFG: 
     107                return SPI_BCM_6358_SPI_CLK_CFG; 
     108        case SPI_FILL_BYTE: 
     109                return SPI_BCM_6358_SPI_FILL_BYTE; 
     110        case SPI_MSG_TAIL: 
     111                return SPI_BCM_6358_SPI_MSG_TAIL; 
     112        case SPI_RX_TAIL: 
     113                return SPI_BCM_6358_SPI_RX_TAIL; 
     114        case SPI_MSG_CTL: 
     115                return SPI_BCM_6358_MSG_CTL; 
     116        case SPI_MSG_DATA: 
     117                return SPI_BCM_6358_SPI_MSG_DATA; 
     118        case SPI_RX_DATA: 
     119                return SPI_BCM_6358_SPI_RX_DATA; 
     120} 
     121#endif 
     122#endif 
     123        return 0; 
     124} 
     125 
     126#endif /* BCM63XX_DEV_SPI_H */ 
  • arch/mips/bcm63xx/Makefile

    a b  
    11obj-y           += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \ 
    22                   dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o \ 
    3                    dev-usb-ohci.o dev-usb-ehci.o dev-usb-udc.o 
     3                   dev-usb-ohci.o dev-usb-ehci.o dev-usb-udc.o dev-spi.o 
    44obj-$(CONFIG_EARLY_PRINTK)      += early_printk.o 
    55 
    66obj-y           += boards/ 
  • arch/mips/bcm63xx/boards/board_bcm963xx.c

    a b  
    3333#include <bcm63xx_dev_usb_ohci.h> 
    3434#include <bcm63xx_dev_usb_ehci.h> 
    3535#include <bcm63xx_dev_usb_udc.h> 
     36#include <bcm63xx_dev_spi.h> 
    3637#include <board_bcm963xx.h> 
    3738 
    3839#define PFX     "board_bcm963xx: " 
    int __init board_register_devices(void) 
    15871588        if (board.num_spis) 
    15881589                spi_register_board_info(board.spis, board.num_spis); 
    15891590 
     1591        if (!BCMCPU_IS_6345()) 
     1592                bcm63xx_spi_register(); 
     1593 
    15901594        /* read base address of boot chip select (0) */ 
    15911595        if (BCMCPU_IS_6345()) 
    15921596                val = 0x1fc00000; 
Note: See TracBrowser for help on using the repository browser.