source: trunk/target/linux/cns3xxx/patches-3.1/052-cns3xxx_spi.patch @ 28165

Last change on this file since 28165 was 28165, checked in by kaloz, 5 years ago

[cns3xxx]: upgrade testing kernel support to 3.1

File size: 13.3 KB
  • drivers/spi/Kconfig

    a b config SPI_BUTTERFLY 
    117117          inexpensive battery powered microcontroller evaluation board. 
    118118          This same cable can be used to flash new firmware. 
    119119 
     120config SPI_CNS3XXX 
     121        tristate "CNS3XXX SPI controller" 
     122        depends on ARCH_CNS3XXX && SPI_MASTER 
     123        select SPI_BITBANG 
     124        help 
     125          This enables using the CNS3XXX SPI controller in master mode. 
     126 
    120127config SPI_COLDFIRE_QSPI 
    121128        tristate "Freescale Coldfire QSPI controller" 
    122129        depends on (M520x || M523x || M5249 || M527x || M528x || M532x) 
  • drivers/spi/Makefile

    a b obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx. 
    1818obj-$(CONFIG_SPI_BFIN_SPORT)            += spi-bfin-sport.o 
    1919obj-$(CONFIG_SPI_BITBANG)               += spi-bitbang.o 
    2020obj-$(CONFIG_SPI_BUTTERFLY)             += spi-butterfly.o 
     21obj-$(CONFIG_SPI_CNS3XXX)               += spi_cns3xxx.o 
    2122obj-$(CONFIG_SPI_COLDFIRE_QSPI)         += spi-coldfire-qspi.o 
    2223obj-$(CONFIG_SPI_DAVINCI)               += spi-davinci.o 
    2324obj-$(CONFIG_SPI_DESIGNWARE)            += spi-dw.o 
  • new file drivers/spi/spi_cns3xxx.c

    - +  
     1/******************************************************************************* 
     2 * 
     3 *  CNS3XXX SPI controller driver (master mode only) 
     4 * 
     5 *  Copyright (c) 2008 Cavium Networks 
     6 *  Copyright 2011 Gateworks Corporation 
     7 *                 Chris Lang <clang@gateworks.com> 
     8 * 
     9 *  This file is free software; you can redistribute it and/or modify 
     10 *  it under the terms of the GNU General Public License, Version 2, as 
     11 *  published by the Free Software Foundation. 
     12 * 
     13 *  This file is distributed in the hope that it will be useful, 
     14 *  but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of 
     15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 
     16 *  NONINFRINGEMENT.  See the GNU General Public License for more details. 
     17 * 
     18 *  You should have received a copy of the GNU General Public License 
     19 *  along with this file; if not, write to the Free Software 
     20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or 
     21 *  visit http://www.gnu.org/licenses/. 
     22 * 
     23 *  This file may also be available under a different license from Cavium. 
     24 *  Contact Cavium Networks for more information 
     25 * 
     26 ******************************************************************************/ 
     27 
     28#include <linux/init.h> 
     29#include <linux/spinlock.h> 
     30#include <linux/workqueue.h> 
     31#include <linux/interrupt.h> 
     32#include <linux/delay.h> 
     33#include <linux/errno.h> 
     34#include <linux/err.h> 
     35#include <linux/clk.h> 
     36#include <linux/platform_device.h> 
     37 
     38#include <linux/spi/spi.h> 
     39#include <linux/spi/spi_bitbang.h> 
     40#include <linux/mtd/partitions.h> 
     41#include <linux/dma-mapping.h> 
     42#include <linux/slab.h> 
     43 
     44#include <asm/io.h> 
     45#include <asm/memory.h> 
     46#include <asm/dma.h> 
     47#include <asm/delay.h> 
     48#include <mach/cns3xxx.h> 
     49#include <linux/module.h> 
     50#include <mach/pm.h> 
     51 
     52/* 
     53 * define access macros 
     54 */ 
     55#define SPI_MEM_MAP_VALUE(reg_offset)           (*((u32 volatile *)(CNS3XXX_SSP_BASE_VIRT + reg_offset))) 
     56 
     57#define SPI_CONFIGURATION_REG                   SPI_MEM_MAP_VALUE(0x40) 
     58#define SPI_SERVICE_STATUS_REG                  SPI_MEM_MAP_VALUE(0x44) 
     59#define SPI_BIT_RATE_CONTROL_REG                SPI_MEM_MAP_VALUE(0x48) 
     60#define SPI_TRANSMIT_CONTROL_REG                SPI_MEM_MAP_VALUE(0x4C) 
     61#define SPI_TRANSMIT_BUFFER_REG                 SPI_MEM_MAP_VALUE(0x50) 
     62#define SPI_RECEIVE_CONTROL_REG                 SPI_MEM_MAP_VALUE(0x54) 
     63#define SPI_RECEIVE_BUFFER_REG                  SPI_MEM_MAP_VALUE(0x58) 
     64#define SPI_FIFO_TRANSMIT_CONFIG_REG            SPI_MEM_MAP_VALUE(0x5C) 
     65#define SPI_FIFO_TRANSMIT_CONTROL_REG           SPI_MEM_MAP_VALUE(0x60) 
     66#define SPI_FIFO_RECEIVE_CONFIG_REG             SPI_MEM_MAP_VALUE(0x64) 
     67#define SPI_INTERRUPT_STATUS_REG                SPI_MEM_MAP_VALUE(0x68) 
     68#define SPI_INTERRUPT_ENABLE_REG                SPI_MEM_MAP_VALUE(0x6C) 
     69 
     70#define SPI_TRANSMIT_BUFFER_REG_ADDR            (CNS3XXX_SSP_BASE +0x50) 
     71#define SPI_RECEIVE_BUFFER_REG_ADDR             (CNS3XXX_SSP_BASE +0x58) 
     72 
     73/* Structure for SPI controller of CNS3XXX SOCs */ 
     74struct cns3xxx_spi { 
     75        /* bitbang has to be first */ 
     76        struct spi_bitbang bitbang; 
     77        struct completion done; 
     78        wait_queue_head_t wait; 
     79 
     80        int len; 
     81        int count; 
     82        int last_in_message_list; 
     83 
     84        /* data buffers */ 
     85        const unsigned char *tx; 
     86        unsigned char *rx; 
     87 
     88        struct spi_master *master; 
     89        struct platform_device *pdev; 
     90        struct device *dev; 
     91}; 
     92 
     93static inline u8 cns3xxx_spi_bus_idle(void) 
     94{ 
     95        return ((SPI_SERVICE_STATUS_REG & 0x1) ? 0 : 1); 
     96} 
     97 
     98static inline u8 cns3xxx_spi_tx_buffer_empty(void) 
     99{ 
     100        return ((SPI_INTERRUPT_STATUS_REG & (0x1 << 3)) ? 1 : 0); 
     101} 
     102 
     103static inline u8 cns3xxx_spi_rx_buffer_full(void) 
     104{ 
     105        return ((SPI_INTERRUPT_STATUS_REG & (0x1 << 2)) ? 1 : 0); 
     106} 
     107 
     108u8 cns3xxx_spi_tx_rx(u8 tx_channel, u8 tx_eof, u32 tx_data, 
     109                            u32 * rx_data) 
     110{ 
     111        u8 rx_channel; 
     112        u8 rx_eof; 
     113 
     114        while (!cns3xxx_spi_bus_idle()) ;       // do nothing 
     115 
     116        while (!cns3xxx_spi_tx_buffer_empty()) ;        // do nothing 
     117 
     118        SPI_TRANSMIT_CONTROL_REG &= ~(0x7); 
     119        SPI_TRANSMIT_CONTROL_REG |= (tx_channel & 0x3) | ((tx_eof & 0x1) << 2); 
     120 
     121        SPI_TRANSMIT_BUFFER_REG = tx_data; 
     122 
     123        while (!cns3xxx_spi_rx_buffer_full()) ; // do nothing 
     124 
     125        rx_channel = SPI_RECEIVE_CONTROL_REG & 0x3; 
     126        rx_eof = (SPI_RECEIVE_CONTROL_REG & (0x1 << 2)) ? 1 : 0; 
     127 
     128        *rx_data = SPI_RECEIVE_BUFFER_REG; 
     129 
     130        if ((tx_channel != rx_channel) || (tx_eof != rx_eof)) { 
     131                return 0; 
     132        } else { 
     133                return 1; 
     134        } 
     135} 
     136 
     137u8 cns3xxx_spi_tx(u8 tx_channel, u8 tx_eof, u32 tx_data) 
     138{ 
     139 
     140        while (!cns3xxx_spi_bus_idle()) ;       // do nothing 
     141 
     142        while (!cns3xxx_spi_tx_buffer_empty()) ;        // do nothing 
     143 
     144        SPI_TRANSMIT_CONTROL_REG &= ~(0x7); 
     145        SPI_TRANSMIT_CONTROL_REG |= (tx_channel & 0x3) | ((tx_eof & 0x1) << 2); 
     146 
     147        SPI_TRANSMIT_BUFFER_REG = tx_data; 
     148 
     149        return 1; 
     150} 
     151 
     152static inline struct cns3xxx_spi *to_hw(struct spi_device *sdev) 
     153{ 
     154        return spi_master_get_devdata(sdev->master); 
     155} 
     156 
     157static int cns3xxx_spi_setup_transfer(struct spi_device *spi, 
     158                                      struct spi_transfer *t) 
     159{ 
     160        return 0; 
     161} 
     162 
     163static void cns3xxx_spi_chipselect(struct spi_device *spi, int value) 
     164{ 
     165        unsigned int spi_config; 
     166 
     167        switch (value) { 
     168        case BITBANG_CS_INACTIVE: 
     169                break; 
     170 
     171        case BITBANG_CS_ACTIVE: 
     172                spi_config = SPI_CONFIGURATION_REG; 
     173 
     174                if (spi->mode & SPI_CPHA) 
     175                        spi_config |= (0x1 << 13); 
     176                else 
     177                        spi_config &= ~(0x1 << 13); 
     178 
     179                if (spi->mode & SPI_CPOL) 
     180                        spi_config |= (0x1 << 14); 
     181                else 
     182                        spi_config &= ~(0x1 << 14); 
     183 
     184                /* write new configration */ 
     185                SPI_CONFIGURATION_REG = spi_config; 
     186 
     187                SPI_TRANSMIT_CONTROL_REG &= ~(0x7); 
     188                SPI_TRANSMIT_CONTROL_REG |= (spi->chip_select & 0x3); 
     189 
     190                break; 
     191        } 
     192} 
     193 
     194static int cns3xxx_spi_setup(struct spi_device *spi) 
     195{ 
     196        if (!spi->bits_per_word) 
     197                spi->bits_per_word = 8; 
     198 
     199        return 0; 
     200} 
     201 
     202static int cns3xxx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) 
     203{ 
     204        struct cns3xxx_spi *hw = to_hw(spi); 
     205 
     206        dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", t->tx_buf, t->rx_buf, 
     207                t->len); 
     208 
     209        hw->tx = t->tx_buf; 
     210        hw->rx = t->rx_buf; 
     211        hw->len = t->len; 
     212        hw->count = 0; 
     213        hw->last_in_message_list = t->last_in_message_list; 
     214 
     215        init_completion(&hw->done); 
     216 
     217        if (hw->tx) { 
     218                int i; 
     219                u32 rx_data; 
     220                for (i = 0; i < (hw->len - 1); i++) { 
     221                        dev_dbg(&spi->dev, 
     222                                "[SPI_CNS3XXX_DEBUG] hw->tx[%02d]: 0x%02x\n", i, 
     223                                hw->tx[i]); 
     224                        cns3xxx_spi_tx_rx(spi->chip_select, 0, hw->tx[i], 
     225                                          &rx_data); 
     226                        if (hw->rx) { 
     227                                hw->rx[i] = rx_data; 
     228                                dev_dbg(&spi->dev, 
     229                                        "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n", 
     230                                        i, hw->rx[i]); 
     231                        } 
     232                } 
     233 
     234                if (t->last_in_message_list) { 
     235                        cns3xxx_spi_tx_rx(spi->chip_select, 1, hw->tx[i], 
     236                                          &rx_data); 
     237                        if (hw->rx) { 
     238                                hw->rx[i] = rx_data; 
     239                                dev_dbg(&spi->dev, 
     240                                        "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n", 
     241                                        i, hw->rx[i]); 
     242                        } 
     243                } else { 
     244                        cns3xxx_spi_tx_rx(spi->chip_select, 0, hw->tx[i], 
     245                                          &rx_data); 
     246                } 
     247                goto done; 
     248        } 
     249 
     250        if (hw->rx) { 
     251                int i; 
     252                u32 rx_data; 
     253                for (i = 0; i < (hw->len - 1); i++) { 
     254                        cns3xxx_spi_tx_rx(spi->chip_select, 0, 0xff, &rx_data); 
     255                        hw->rx[i] = rx_data; 
     256                        dev_dbg(&spi->dev, 
     257                                "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n", i, 
     258                                hw->rx[i]); 
     259                } 
     260 
     261                if (t->last_in_message_list) { 
     262                        cns3xxx_spi_tx_rx(spi->chip_select, 1, 0xff, &rx_data); 
     263                } else { 
     264                        cns3xxx_spi_tx_rx(spi->chip_select, 0, 0xff, &rx_data); 
     265                } 
     266                hw->rx[i] = rx_data; 
     267                dev_dbg(&spi->dev, "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n", 
     268                        i, hw->rx[i]); 
     269        } 
     270done: 
     271        return hw->len; 
     272} 
     273 
     274static void __init cns3xxx_spi_initial(void) 
     275{ 
     276        u32 __iomem *gpiob = __io(CNS3XXX_MISC_BASE_VIRT + 0x0018); 
     277        u32 gpiob_pins = __raw_readl(gpiob); 
     278 
     279        /* MMC/SD pins share with GPIOA */ 
     280        gpiob_pins |= 0xf80; 
     281        __raw_writel(gpiob_pins, gpiob); 
     282 
     283        /* share pin config. */ 
     284        //PM_PLL_HM_PD_CTRL_REG &= ~(0x1 << 5); 
     285        //HAL_MISC_ENABLE_SPI_PINS(); 
     286        cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SPI_PCM_I2C)); 
     287        cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SPI_PCM_I2C)); 
     288 
     289        SPI_CONFIGURATION_REG = (((0x0 & 0x3) << 0) |   /* 8bits shift length */ 
     290                                 (0x0 << 9) |   /* SPI mode */ 
     291                                 (0x0 << 10) |  /* disable FIFO */ 
     292                                 (0x1 << 11) |  /* SPI master mode */ 
     293                                 (0x0 << 12) |  /* disable SPI loopback mode */ 
     294                                 (0x1 << 13) |  /* clock phase */ 
     295                                 (0x1 << 14) |  /* clock polarity */ 
     296                                 (0x0 << 24) |  /* disable - SPI data swap */ 
     297                                 (0x1 << 29) |  /* enable - 2IO Read mode */ 
     298                                 (0x0 << 30) |  /* disable - SPI high speed read for system boot up */ 
     299                                 (0x0 << 31));  /* disable - SPI */ 
     300 
     301        /* Set SPI bit rate PCLK/2 */ 
     302        SPI_BIT_RATE_CONTROL_REG = 0x1; 
     303 
     304        /* Set SPI Tx channel 0 */ 
     305        SPI_TRANSMIT_CONTROL_REG = 0x0; 
     306 
     307        /* Set Tx FIFO Threshold, Tx FIFO has 2 words */ 
     308        SPI_FIFO_TRANSMIT_CONFIG_REG &= ~(0x03 << 4); 
     309        SPI_FIFO_TRANSMIT_CONFIG_REG |= ((0x0 & 0x03) << 4); 
     310 
     311        /* Set Rx FIFO Threshold, Rx FIFO has 2 words */ 
     312        SPI_FIFO_RECEIVE_CONFIG_REG &= ~(0x03 << 4); 
     313        SPI_FIFO_RECEIVE_CONFIG_REG |= ((0x0 & 0x03) << 4); 
     314 
     315        /* Disable all interrupt */ 
     316        SPI_INTERRUPT_ENABLE_REG = 0x0; 
     317 
     318        /* Clear spurious interrupt sources */ 
     319        SPI_INTERRUPT_STATUS_REG = (0x0F << 4); 
     320 
     321        /* Enable SPI */ 
     322        SPI_CONFIGURATION_REG |= (0x1 << 31); 
     323 
     324        return; 
     325} 
     326 
     327static int __init cns3xxx_spi_probe(struct platform_device *pdev) 
     328{ 
     329        struct spi_master *master; 
     330        struct cns3xxx_spi *hw; 
     331        int err = 0; 
     332 
     333        printk("%s: setup CNS3XXX SPI Controller\n", __FUNCTION__); 
     334 
     335        /* Allocate master with space for cns3xxx_spi */ 
     336        master = spi_alloc_master(&pdev->dev, sizeof(struct cns3xxx_spi)); 
     337        if (master == NULL) { 
     338                dev_err(&pdev->dev, "No memory for spi_master\n"); 
     339                err = -ENOMEM; 
     340                goto err_nomem; 
     341        } 
     342 
     343        hw = spi_master_get_devdata(master); 
     344        memset(hw, 0, sizeof(struct cns3xxx_spi)); 
     345 
     346        hw->master = spi_master_get(master); 
     347        hw->dev = &pdev->dev; 
     348 
     349        platform_set_drvdata(pdev, hw); 
     350        init_completion(&hw->done); 
     351 
     352        /* setup the master state. */ 
     353 
     354        master->num_chipselect = 4; 
     355        master->bus_num = 1; 
     356 
     357        /* setup the state for the bitbang driver */ 
     358 
     359        hw->bitbang.master = hw->master; 
     360        hw->bitbang.setup_transfer = cns3xxx_spi_setup_transfer; 
     361        hw->bitbang.chipselect = cns3xxx_spi_chipselect; 
     362        hw->bitbang.txrx_bufs = cns3xxx_spi_txrx; 
     363        hw->bitbang.master->setup = cns3xxx_spi_setup; 
     364 
     365        dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); 
     366 
     367        /* SPI controller initializations */ 
     368        cns3xxx_spi_initial(); 
     369 
     370        /* register SPI controller */ 
     371 
     372        err = spi_bitbang_start(&hw->bitbang); 
     373        if (err) { 
     374                dev_err(&pdev->dev, "Failed to register SPI master\n"); 
     375                goto err_register; 
     376        } 
     377 
     378        return 0; 
     379 
     380err_register: 
     381        spi_master_put(hw->master);; 
     382 
     383err_nomem: 
     384        return err; 
     385} 
     386 
     387static int __devexit cns3xxx_spi_remove(struct platform_device *dev) 
     388{ 
     389        struct cns3xxx_spi *hw = platform_get_drvdata(dev); 
     390 
     391        platform_set_drvdata(dev, NULL); 
     392 
     393        spi_unregister_master(hw->master); 
     394 
     395        spi_master_put(hw->master); 
     396        return 0; 
     397} 
     398 
     399#ifdef CONFIG_PM 
     400 
     401static int cns3xxx_spi_suspend(struct platform_device *pdev, pm_message_t msg) 
     402{ 
     403        struct cns3xxx_spi *hw = platform_get_drvdata(pdev); 
     404 
     405        return 0; 
     406} 
     407 
     408static int cns3xxx_spi_resume(struct platform_device *pdev) 
     409{ 
     410        struct cns3xxx_spi *hw = platform_get_drvdata(pdev); 
     411 
     412        return 0; 
     413} 
     414 
     415#else 
     416#define cns3xxx_spi_suspend     NULL 
     417#define cns3xxx_spi_resume      NULL 
     418#endif 
     419 
     420static struct platform_driver cns3xxx_spi_driver = { 
     421        .probe          = cns3xxx_spi_probe, 
     422        .remove         = __devexit_p(cns3xxx_spi_remove), 
     423        .suspend        = cns3xxx_spi_suspend, 
     424        .resume         = cns3xxx_spi_resume, 
     425        .driver         = { 
     426                .name = "cns3xxx_spi", 
     427                .owner = THIS_MODULE, 
     428        }, 
     429}; 
     430 
     431static int __init cns3xxx_spi_init(void) 
     432{ 
     433        return platform_driver_register(&cns3xxx_spi_driver); 
     434} 
     435 
     436static void __exit cns3xxx_spi_exit(void) 
     437{ 
     438        platform_driver_unregister(&cns3xxx_spi_driver); 
     439} 
     440 
     441module_init(cns3xxx_spi_init); 
     442module_exit(cns3xxx_spi_exit); 
     443 
     444MODULE_AUTHOR("Cavium Networks"); 
     445MODULE_DESCRIPTION("CNS3XXX SPI Controller Driver"); 
     446MODULE_LICENSE("GPL"); 
     447MODULE_ALIAS("platform:cns3xxx_spi"); 
     448 
     449EXPORT_SYMBOL_GPL(cns3xxx_spi_tx_rx); 
  • include/linux/spi/spi.h

    a b struct spi_transfer { 
    446446        u32             speed_hz; 
    447447 
    448448        struct list_head transfer_list; 
     449 
     450#ifdef CONFIG_ARCH_CNS3XXX 
     451        unsigned        last_in_message_list; 
     452#ifdef CONFIG_SPI_CNS3XXX_2IOREAD 
     453        u8              dio_read; 
     454#endif 
     455#endif 
    449456}; 
    450457 
    451458/** 
  • drivers/spi/spi-bitbang.c

    a b static void bitbang_work(struct work_str 
    329329                                 */ 
    330330                                if (!m->is_dma_mapped) 
    331331                                        t->rx_dma = t->tx_dma = 0; 
     332 
     333                                if (t->transfer_list.next == &m->transfers) 
     334                                        t->last_in_message_list = 1; 
     335                                else 
     336                                        t->last_in_message_list = 0; 
     337 
    332338                                status = bitbang->txrx_bufs(spi, t); 
    333339                        } 
    334340                        if (status > 0) 
Note: See TracBrowser for help on using the repository browser.