⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm355_spi_bitbang.c

📁 TI的达芬奇系列dm355使用的spi模块驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * dm355_spi_bitbang.c - polling/bitbanging TI dm355 SPI master controller driver utilities * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <linux/init.h>#include <linux/spinlock.h>#include <linux/workqueue.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/device.h>#include <linux/device.h>#include <linux/spi/spi.h>#include <linux/spi/dm355_spi_bitbang.h>#if defined(CONFIG_SPI_DEBUG)#define DEBUG_BB(fmt,arg...)  printk(KERN_EMERG fmt , ##arg);#else#define DEBUG_BB(fmt,arg...)#endif#define ENTER DEBUG_BB("[Ei %s-%d] \n", __FUNCTION__, __LINE__);#define EXIT  DEBUG_BB("[Ex %s-%d] \n", __FUNCTION__, __LINE__);/*----------------------------------------------------------------------*//* * FIRST PART (OPTIONAL):  word-at-a-time spi_transfer support. * Use this for GPIO or shift-register level hardware APIs. * * spi_bitbang_cs is in spi_device->controller_state, which is unavailable * to glue code.  These bitbang setup() and cleanup() routines are always * used, though maybe they're called from controller-aware code. * * chipselect() and friends may use use spi_device->controller_data and * controller registers as appropriate. * * * NOTE:  SPI controller pins can often be used as GPIO pins instead, * which means you could use a bitbang driver either to get hardware * working quickly, or testing for differences that aren't speed related. */struct spi_bitbang_cs {        unsigned nsecs;         /* (clock cycle time)/2 */         u32(*txrx_word) (struct spi_device * spi, unsigned nsecs,                          u32 word, u8 bits);        unsigned (*txrx_bufs) (struct spi_device *,                               u32(*txrx_word) (struct spi_device * spi,                                                unsigned nsecs,                                                u32 word, u8 bits),                               unsigned, struct spi_transfer *);};static unsigned bitbang_txrx_8(struct spi_device *spi,                               u32(*txrx_word) (struct spi_device * spi,                                                unsigned nsecs,                                                u32 word, u8 bits),                               unsigned ns, struct spi_transfer *t){        unsigned bits = spi->bits_per_word;        unsigned count = t->len;        const u8 *tx = t->tx_buf;        u8 *rx = t->rx_buf;        while (likely(count > 0)) {                u8 word = 0;                if (tx)                        word = *tx++;                word = txrx_word(spi, ns, word, bits);                if (rx)                        *rx++ = word;                count -= 1;        }        return t->len - count;}static unsigned bitbang_txrx_16(struct spi_device *spi,                                u32(*txrx_word) (struct spi_device * spi,                                                 unsigned nsecs,                                                 u32 word, u8 bits),                                unsigned ns, struct spi_transfer *t){        unsigned bits = spi->bits_per_word;        unsigned count = t->len;        const u16 *tx = t->tx_buf;        u16 *rx = t->rx_buf;        while (likely(count > 1)) {                u16 word = 0;                if (tx)                        word = *tx++;                word = txrx_word(spi, ns, word, bits);                if (rx)                        *rx++ = word;                count -= 2;        }        return t->len - count;}int dm355_spi_bitbang_setup_transfer(struct spi_device *spi,                                     struct spi_transfer *t){        struct spi_bitbang_cs *cs = spi->controller_state;        u8 bits_per_word;        u32 hz;        ENTER if (t) {                bits_per_word = t->bits_per_word;                hz = t->speed_hz;        } else {                bits_per_word = 0;                hz = 0;        }        /* spi_transfer level calls that work per-word */        if (!bits_per_word)                bits_per_word = spi->bits_per_word;        if (bits_per_word <= 8 && bits_per_word >= 2) {                cs->txrx_bufs = bitbang_txrx_8;                DEBUG_BB("word = %d\n", bits_per_word);        } else if (bits_per_word <= 16 && bits_per_word >= 2) {                cs->txrx_bufs = bitbang_txrx_16;                DEBUG_BB("word = %d\n", bits_per_word);        }        /*else if (bits_per_word <= 32)           cs->txrx_bufs = bitbang_txrx_32; */        else                return -EINVAL;        /* nsecs = (clock period)/2 */        if (!hz)                hz = spi->max_speed_hz;        if (hz) {                cs->nsecs = (1000000000 / 2) / hz;                if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))                        return -EINVAL;        }        EXIT return 0;}EXPORT_SYMBOL_GPL(dm355_spi_bitbang_setup_transfer);/** * dm355_spi_bitbang_setup - default setup for per-word I/O loops */int dm355_spi_bitbang_setup(struct spi_device *spi){        struct spi_bitbang_cs *cs = spi->controller_state;        struct spi_bitbang *bitbang;        int retval;        bitbang = spi_master_get_devdata(spi->master);        /* REVISIT: some systems will want to support devices using lsb-first         * bit encodings on the wire.  In pure software that would be trivial,         * just bitbang_txrx_le_cphaX() routines shifting the other way, and         * some hardware controllers also have this support.         */        if ((spi->mode & SPI_LSB_FIRST) != 0)                return -EINVAL;        if (!cs) {                cs = kzalloc(sizeof *cs, SLAB_KERNEL);                if (!cs)                        return -ENOMEM;                spi->controller_state = cs;        }        if (!spi->bits_per_word)                spi->bits_per_word = 8;        /* per-word shift register access, in hardware or bitbanging */        cs->txrx_word =            bitbang->txrx_word[spi->mode & (SPI_CPOL | SPI_CPHA)];        if (!cs->txrx_word)                return -EINVAL;        retval = dm355_spi_bitbang_setup_transfer(spi, NULL);        if (retval < 0)                return retval;        dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",                __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),                spi->bits_per_word, 2 * cs->nsecs);        /* NOTE we _need_ to call chipselect() early, ideally with adapter         * setup, unless the hardware defaults cooperate to avoid confusion         * between normal (active low) and inverted chipselects.         */        /* deselect chip (low or high) */        spin_lock(&bitbang->lock);        if (!bitbang->busy) {                bitbang->chipselect(spi, BITBANG_CS_INACTIVE);                ndelay(cs->nsecs);        }        spin_unlock(&bitbang->lock);        return 0;}EXPORT_SYMBOL_GPL(dm355_spi_bitbang_setup);/** * dm355_spi_bitbang_cleanup - default cleanup for per-word I/O loops */void dm355_spi_bitbang_cleanup(const struct spi_device *spi){        kfree(spi->controller_state);}EXPORT_SYMBOL_GPL(dm355_spi_bitbang_cleanup);static int dm355_spi_bitbang_bufs(struct spi_device *spi,                                  struct spi_transfer *t){        struct spi_bitbang_cs *cs = spi->controller_state;        unsigned nsecs = cs->nsecs;        return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);}/*----------------------------------------------------------------------*//* * SECOND PART ... simple transfer queue runner. * * This costs a task context per controller, running the queue by * performing each transfer in sequence.  Smarter hardware can queue * several DMA transfers at once, and process several controller queues * in parallel; this driver doesn't match such hardware very well. * * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */static void dm355_bitbang_work(void *_bitbang){        struct spi_bitbang *bitbang = _bitbang;        unsigned long flags;        ENTER spin_lock_irqsave(&bitbang->lock, flags);        bitbang->busy = 1;        while (!list_empty(&bitbang->queue)) {                struct spi_message *m;                struct spi_device *spi;                unsigned nsecs;                struct spi_transfer *t = NULL;                unsigned tmp;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -