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

📄 dm355_spi_bitbang.c

📁 TI的达芬奇系列dm355使用的spi模块驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
                unsigned cs_change;                int status;                int (*setup_transfer) (struct spi_device *,                                       struct spi_transfer *);                m = container_of(bitbang->queue.next, struct spi_message,                                 queue);                list_del_init(&m->queue);                spin_unlock_irqrestore(&bitbang->lock, flags);                /* FIXME this is made-up ... the correct value is known to                 * word-at-a-time bitbang code, and presumably chipselect()                 * should enforce these requirements too?                 */                nsecs = 100;                spi = m->spi;                tmp = 0;                cs_change = 1;                status = 0;                setup_transfer = NULL;                list_for_each_entry(t, &m->transfers, transfer_list) {                        if (bitbang->shutdown) {                                status = -ESHUTDOWN;                                break;                        }                        /* override or restore speed and wordsize */                        if (t->speed_hz || t->bits_per_word) {                                setup_transfer = bitbang->setup_transfer;                                if (!setup_transfer) {                                        status = -ENOPROTOOPT;                                        break;                                }                        }                        if (setup_transfer) {                                DEBUG_BB("setup_transfer is being called\n");                                status = setup_transfer(spi, t);                                if (status < 0)                                        break;                        }                        /* set up default clock polarity, and activate chip;                         * this implicitly updates clock and spi modes as                         * previously recorded for this device via setup().                         * (and also deselects any other chip that might be                         * selected ...)                         */                        if (cs_change) {                                bitbang->chipselect(spi,                                                    BITBANG_CS_ACTIVE);                                ndelay(nsecs);                        }                        cs_change = t->cs_change;                        if (!t->tx_buf && !t->rx_buf && t->len) {                                status = -EINVAL;                                break;                        }                        /* transfer data.  the lower level code handles any                         * new dma mappings it needs. our caller always gave                         * us dma-safe buffers.                         */                        if (t->len) {                                /* REVISIT dma API still needs a designated                                 * DMA_ADDR_INVALID; ~0 might be better.                                 */                                if (!m->is_dma_mapped)                                        t->rx_dma = t->tx_dma = 0;                                DEBUG_BB("bitbang->txrx_bufs called\n");                                status = bitbang->txrx_bufs(spi, t);                        }                        if (status != t->len) {                                if (status > 0)                                        status = -EMSGSIZE;                                break;                        }                        m->actual_length += status;                        status = 0;                        /* protocol tweaks before next transfer */                        if (t->delay_usecs)                                udelay(t->delay_usecs);                        if (!cs_change)                                continue;                        if (t->transfer_list.next == &m->transfers)                                break;                        /* sometimes a short mid-message deselect of the chip                         * may be needed to terminate a mode or command                         */                        ndelay(nsecs);                        bitbang->chipselect(spi, BITBANG_CS_INACTIVE);                        ndelay(nsecs);                }                m->status = status;                m->complete(m->context);                /* restore speed and wordsize */                if (setup_transfer)                        setup_transfer(spi, NULL);                /* normally deactivate chipselect ... unless no error and                 * cs_change has hinted that the next message will probably                 * be for this chip too.                 */                if (!(status == 0 && cs_change)) {                        ndelay(nsecs);                        bitbang->chipselect(spi, BITBANG_CS_INACTIVE);                        ndelay(nsecs);                }                spin_lock_irqsave(&bitbang->lock, flags);        }        bitbang->busy = 0;        spin_unlock_irqrestore(&bitbang->lock, flags);}/** * dm355_spi_bitbang_transfer - default submit to transfer queue */int dm355_spi_bitbang_transfer(struct spi_device *spi,                               struct spi_message *m){        struct spi_bitbang *bitbang;        unsigned long flags;        int status = 0;        ENTER m->actual_length = 0;        m->status = -EINPROGRESS;        bitbang = spi_master_get_devdata(spi->master);        if (bitbang->shutdown)                return -ESHUTDOWN;        spin_lock_irqsave(&bitbang->lock, flags);        if (!spi->max_speed_hz)                status = -ENETDOWN;        else {                list_add_tail(&m->queue, &bitbang->queue);                queue_work(bitbang->workqueue, &bitbang->work);        }        spin_unlock_irqrestore(&bitbang->lock, flags);        EXIT return status;}EXPORT_SYMBOL_GPL(dm355_spi_bitbang_transfer);/*----------------------------------------------------------------------*//** * dm355_spi_bitbang_start - start up a polled/bitbanging SPI master driver * @bitbang: driver handle * * Caller should have zero-initialized all parts of the structure, and then * provided callbacks for chip selection and I/O loops.  If the master has * a transfer method, its final step should call spi_bitbang_transfer; or, * that's the default if the transfer routine is not initialized.  It should * also set up the bus number and number of chipselects. * * For i/o loops, provide callbacks either per-word (for bitbanging, or for * hardware that basically exposes a shift register) or per-spi_transfer * (which takes better advantage of hardware like fifos or DMA engines). * * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and * spi_bitbang_cleanup to handle those spi master methods.  Those methods are * the defaults if the bitbang->txrx_bufs routine isn't initialized. * * This routine registers the spi_master, which will process requests in a * dedicated task, keeping IRQs unblocked most of the time.  To stop * processing those requests, call spi_bitbang_stop(). */int dm355_spi_bitbang_start(struct spi_bitbang *bitbang){        int status;        if (!bitbang->master || !bitbang->chipselect)                return -EINVAL;        INIT_WORK(&bitbang->work, dm355_bitbang_work, bitbang);        spin_lock_init(&bitbang->lock);        INIT_LIST_HEAD(&bitbang->queue);        if (!bitbang->master->transfer)                bitbang->master->transfer = dm355_spi_bitbang_transfer;        if (!bitbang->txrx_bufs) {                bitbang->use_dma = 0;                bitbang->txrx_bufs = dm355_spi_bitbang_bufs;                if (!bitbang->master->setup) {                        if (!bitbang->setup_transfer)                                bitbang->setup_transfer =                                    dm355_spi_bitbang_setup_transfer;                        bitbang->master->setup = dm355_spi_bitbang_setup;                        bitbang->master->cleanup =                            dm355_spi_bitbang_cleanup;                }        } else if (!bitbang->master->setup)                return -EINVAL;        /* this task is the only thing to touch the SPI bits */        bitbang->busy = 0;        DEBUG_BB("bus_id = %s\n", bitbang->master->cdev.dev->bus_id);        bitbang->workqueue =            create_singlethread_workqueue(bitbang->master->cdev.dev->                                          bus_id);        if (bitbang->workqueue == NULL) {                status = -EBUSY;                goto err1;        }        /* driver may get busy before register() returns, especially         * if someone registered boardinfo for devices         */        status = spi_register_master(bitbang->master);        if (status < 0)                goto err2;        return status;      err2:        destroy_workqueue(bitbang->workqueue);      err1:        return status;}EXPORT_SYMBOL_GPL(dm355_spi_bitbang_start);/** * spi_bitbang_stop - stops the task providing spi communication */int dm355_spi_bitbang_stop(struct spi_bitbang *bitbang){        unsigned limit = 500;        spin_lock_irq(&bitbang->lock);        bitbang->shutdown = 0;        while (!list_empty(&bitbang->queue) && limit--) {                spin_unlock_irq(&bitbang->lock);                dev_dbg(bitbang->master->cdev.dev, "wait for queue\n");                msleep(10);                spin_lock_irq(&bitbang->lock);        }        spin_unlock_irq(&bitbang->lock);        if (!list_empty(&bitbang->queue)) {                dev_err(bitbang->master->cdev.dev, "queue didn't empty\n");                return -EBUSY;        }        destroy_workqueue(bitbang->workqueue);        spi_unregister_master(bitbang->master);        return 0;}EXPORT_SYMBOL_GPL(dm355_spi_bitbang_stop);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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