1. 程式人生 > >linux SPI驅動——spi core(四)

linux SPI驅動——spi core(四)

一:

SPI核心,就是指/drivers/spi/目錄下spi.c檔案中提供給其他檔案的函式,首先看下spi核心的初始化函式spi_init(void)。

1: static int __init spi_init(void)2: {3: int status;4:  5: buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); /* 初始化快取 */6: if (!buf) {7: status = -ENOMEM;8: goto err0;9: }10:  11:status = bus_register(&spi_bus_type); /* 註冊spi匯流排,此步驟之後就會在/sys/bus目錄下生成spi子目錄 */
12: if (status < 0)13: goto err1;14:  15: status = class_register(&spi_master_class);;/* 註冊spi類,此步驟之後就會在/sys/class目錄下生成spi_master子目錄 */16: if (status < 0)17: gotoerr2;18: return 0;19:  20: err2:21: bus_unregister(&spi_bus_type);22: err1:23:kfree(buf);24: buf = NULL;25: err0:26: return status;27: 
}
1: struct bus_type spi_bus_type = {2: .name = "spi",3: .dev_attrs = spi_dev_attrs,4: .match = spi_match_device,5: .uevent = spi_uevent,6: .pm = &spi_pm,7: };1: static struct class spi_master_class = {2: .name = "spi_master",3: .owner = THIS_MODULE,4: .dev_release = spi_master_release,5: };1: postcore_initcall(spi_init); /* 註冊 */

說明:
        1) 由postcore_initcall(spi_init);可以看出,此巨集在系統初始化時是先於module_init()執行的。

        2) 申請的buf空間用於在spi資料傳輸中。

        3) 接下來是匯流排註冊和類註冊。

二:

此函式是半雙工的形式寫then讀

1: int spi_write_then_read(struct spi_device *spi,2: const void *txbuf, unsigned n_tx,3: void *rxbuf, unsigned n_rx)4: {5: static DEFINE_MUTEX(lock);6:  7: int status;8: struct spi_message message;9: struct spi_transfer x[2];10: u8 *local_buf;11:  12: /* Use preallocated DMA-safe buffer. We can't avoid copying here,13: * (as a pure convenience thing), but we can keep heap costs14: * out of the hot path ...15: */16: if ((n_tx + n_rx) > SPI_BUFSIZ)17: return -EINVAL;18:  19: spi_message_init(&message);20: memset(x, 0, sizeof x);21: if (n_tx) {22: x[0].len = n_tx;23: spi_message_add_tail(&x[0], &message);24: }25: if (n_rx) {26: x[1].len = n_rx;27: spi_message_add_tail(&x[1], &message);28: }29:  30: /* ... unless someone else is using the pre-allocated buffer */31: if (!mutex_trylock(&lock)) {32: local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);33: if (!local_buf)34: return -ENOMEM;35: else36: local_buf = buf;37:  38: memcpy(local_buf, txbuf, n_tx);39: x[0].tx_buf = local_buf;40: x[1].rx_buf = local_buf + n_tx;41:  42: /* do the i/o */43: status = spi_sync(spi, &message);44: if (status == 0)45: memcpy(rxbuf, x[1].rx_buf, n_rx);46:  47: if (x[0].tx_buf == buf)48: mutex_unlock(&lock);49: else50: kfree(local_buf);51:  52: return status;53: }1: 對master操作的加鎖與解鎖2: int spi_bus_lock(struct spi_master *master)3: {4: unsigned long flags;5:  6: mutex_lock(&master->bus_lock_mutex);7:  8: spin_lock_irqsave(&master->bus_lock_spinlock, flags);9: master->bus_lock_flag = 1;10: spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);11:  12: /* mutex remains locked until spi_bus_unlock is called */13:  14: return 0;15: }16: int spi_bus_unlock(struct spi_master *master)17: {18: master->bus_lock_flag = 0;19:  20: mutex_unlock(&master->bus_lock_mutex);21:  22: return 0;23: }同步資料互動1: int spi_sync(struct spi_device *spi, struct spi_message *message)2: {3: return__spi_sync(spi, message, 0);4: }5: int spi_sync_locked(struct spi_device *spi, structspi_message *message)6: {7: return __spi_sync(spi, message, 1);8: }非同步資料互動1: int spi_async(struct spi_device *spi, struct spi_message *message)2: {3: structspi_master *master = spi->master;4: int ret;5: unsigned long flags;6:  7:spin_lock_irqsave(&master->bus_lock_spinlock, flags);8:  9: if (master->bus_lock_flag)10:ret = -EBUSY;11: else12: ret = __spi_async(spi, message);13:  14:spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);15:  16: return ret;17: }18:  19: int spi_async_locked(struct spi_device *spi, struct spi_message *message)20: {21: structspi_master *master = spi->master;22: int ret;23: unsigned long flags;24:  25:spin_lock_irqsave(&master->bus_lock_spinlock, flags);26:  27: ret = __spi_async(spi, message);28:  29: spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);30:  31:return ret;32:  33: }//建立master1: struct spi_master *spi_alloc_master(struct device *dev, unsigned size)2: {3: structspi_master *master;4:  5: if (!dev)6: return NULL;7:  8: master = kzalloc(size + sizeof*master, GFP_KERNEL);9: if (!master)10: return NULL;11:  12: device_initialize(&master->dev);13: master->dev.class = &spi_master_class;14: master->dev.parent = get_device(dev);15: spi_master_set_devdata(master, &master[1]);16:  17: return master;18: }//spi_register_master1: int spi_register_master(struct spi_master *master)2: {3: static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);4: struct device *dev = master->dev.parent;5: struct boardinfo *bi;6: int status = -ENODEV;7: int dynamic = 0;8:  9: if (!dev)10: return -ENODEV;11:  12:/* even if it's just one always-selected device, there must13: * be at least one chipselect14: */15: if (master->num_chipselect == 0)16: return -EINVAL;17:  18: /* convention: dynamically assigned bus IDs count down from the max */19: if (master->bus_num < 0) {20: /* FIXME switch to an IDR based scheme, something like21: * I2C now uses, so we can't run out of "dynamic" IDs22: */23: master->bus_num = atomic_dec_return(&dyn_bus_id);24: dynamic = 1;25: }26:  27: spin_lock_init(&master->bus_lock_spinlock);28: mutex_init(&master->bus_lock_mutex);29: master->bus_lock_flag = 0;30:  31: /* register the device, then userspace will see it.32: * registration fails if the bus ID is in use.33: */34:dev_set_name(&master->dev, "spi%u", master->bus_num);35: status = device_add(&master->dev);36: if (status < 0)37: goto done;38: dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),39: dynamic ?