How to initialize DMA channels of SPI master

Hi,

I’m developing a kernel module that is supposed to communicate with a TI ADS1274 ADC via SPI. So far I have a working kernel module that doesn’t use DMA for the SPI communication. Therefore the CPU get’s a hell of a load and I need to fix that. The way to do it presumably is using DMA but that’s where the struggle starts. At first I delved into the SPI interface structures struct spi_device and struct spi_master. From the device tree (am33xx.dtsi) I know that the SPI controller has 2 DMA channels assigned for each CS, namely ‘tx0’, ‘rx0’, ‘tx1’ and ‘rx1’.

I thought these can be used through the struct dma_chan pointers in struct spi_master but the pointers are null (I tried to print out their values within my probing function). The respective dmesg output is.

[ +0.000010] DEBUG /root/Code/kmod/selton.c:970: ads_spi_probe: spi m rx: (null)
[ +0.000008] DEBUG /root/Code/kmod/selton.c:971: ads_spi_probe: spi m tx: (null)

As a next step I tried to figure out how these pointers could get initialized and found that in the TI driver omap2_mcspi.c a function omap2_mcspi_request_dma( struct spi_device *spi) is defined and called by omap2_mcspi_setup( struct spi_device *spi). The latter is assigned to the setup function of the struct spi_master allocated in the drivers probe function omap2_mcspi_probe( struct platform_device *pdev).

So I thought everything left to do is calling the SPI masters setup function (what seems to be done in spi_setup( struct spi_device *spi)) to make the DMA channels accessible but they still remain as null pointers. Here is my probe function.
`

static int
ads_spi_probe(struct spi_device *spi)
{
ads_data_t *ads; //–> driver data struct
int err = 0;

/* Is there a matching device in the device tree? */
if (!of_match_device(ads1274_dt_ids, &spi->dev)) {
err = -ENODEV;
goto error;
}
debug(“Probed compat. devices: %s”, //–> .compatible = “ti,ads1274”,
ads1274_dt_ids[0].compatible);

/* Then allocate the driver data */
ads = (ads_data_t *)kzalloc(sizeof(ads_data_t), GFP_KERNEL);
if (IS_ERR(ads)) {
err = PTR_ERR(ads);
debug(“Could not allocate driver data: ERR %d”, err);
goto error;
}
debug(“Initialized SPI data structure at %p”, ads);

init_waitqueue_head(&ads->wait_read);
spin_lock_init(&ads->spi_lock);

INIT_LIST_HEAD(&device_list);
mutex_lock(&device_list_lock);

/* Request and configure GPIO trigger */
err = ads_gpio_init(&ads->gpio, p9, true, true);
if (err < 0) {
pr_err("%s: Could not initialze GPIO %d", MODNAME, p9);
goto free_driver_data;
}
debug(“GPIO pin %d mapped to irq %d”,
ads->gpio.pin, ads->gpio.irq_number);

/* Request 1 minor device number from the kernel */
if (alloc_chrdev_region(&ads->devt, 0, 1, MODNAME) < 0) {
err = -EIO;
goto free_workqueue;
}
debug(“Requested major/minor %d : %d”, MAJOR(ads->devt), MINOR(ads->devt));

/* SPI setup */
ads->spi = spi;
spi_set_drvdata(spi, ads);
spi_setup(ads->spi); //–> should init dma channels

debug(“spi: %p”, ads->spi);
debug(“spi m: %p”, ads->spi->master);
debug(“spi m rx: %p”, ads->spi->master->dma_rx); //–> NULL
debug(“spi m tx: %p”, ads->spi->master->dma_tx); //–> NULL

/* Create character device */
ads->cdev = cdev_alloc();

if (ads->cdev == NULL)
goto free_chrdev_region;

debug(“Cdev initialized”);

ads->cdev->owner = THIS_MODULE;
ads->cdev->ops = &fops;

if (cdev_add(ads->cdev, ads->devt, 1))
goto free_cdev;

device_create(ads_class, &ads->spi->dev, ads->devt, ads->spi,
“ads1274-spi%d.%d”, ads->spi->master->bus_num, ads->spi->chip_select);

list_add_tail(&(ads->device_entry), &device_list);
mutex_unlock(&device_list_lock);

pr_info("%s: Added SPI device %s-spi%d.%d", MODNAME, spi->modalias,
spi->master->bus_num, spi->chip_select);

/* Should be 0 */
return err;

free_cdev:
kobject_put(&(ads->cdev->kobj));
free_chrdev_region:
unregister_chrdev_region(ads->devt, 1);
free_workqueue:
// ads_workqueue_free(&ads);
//free_gpio:
ads_gpio_free(&(ads->gpio));
free_driver_data:
kfree(ads);
debug(“There was an error while probing devices”);

error:
return err;
}
`

So can anybody tell me how to initialize the DMA channels in spi_master or how to use SPI with DMA generally.

Thx in advance.

Look at how this is done in drivers/mmc/host/mmc_spi.c

Regards,
John