mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-05-09 16:53:48 +00:00
spi: spi-davinci: convert to DMA engine API
Removes use of the DaVinci EDMA private DMA API and replaces it with use of the DMA engine API. Signed-off-by: Matt Porter <mporter@ti.com> Tested-by: Tom Rini <trini@ti.com> Tested-by: Sekhar Nori <nsekhar@ti.com> Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
This commit is contained in:
parent
b5daabbd3d
commit
048177ce3b
1 changed files with 126 additions and 158 deletions
|
@ -25,13 +25,14 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/edma.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/spi_bitbang.h>
|
#include <linux/spi/spi_bitbang.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include <mach/spi.h>
|
#include <mach/spi.h>
|
||||||
#include <mach/edma.h>
|
|
||||||
|
|
||||||
#define SPI_NO_RESOURCE ((resource_size_t)-1)
|
#define SPI_NO_RESOURCE ((resource_size_t)-1)
|
||||||
|
|
||||||
|
@ -113,14 +114,6 @@
|
||||||
#define SPIDEF 0x4c
|
#define SPIDEF 0x4c
|
||||||
#define SPIFMT0 0x50
|
#define SPIFMT0 0x50
|
||||||
|
|
||||||
/* We have 2 DMA channels per CS, one for RX and one for TX */
|
|
||||||
struct davinci_spi_dma {
|
|
||||||
int tx_channel;
|
|
||||||
int rx_channel;
|
|
||||||
int dummy_param_slot;
|
|
||||||
enum dma_event_q eventq;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* SPI Controller driver's private data. */
|
/* SPI Controller driver's private data. */
|
||||||
struct davinci_spi {
|
struct davinci_spi {
|
||||||
struct spi_bitbang bitbang;
|
struct spi_bitbang bitbang;
|
||||||
|
@ -134,11 +127,14 @@ struct davinci_spi {
|
||||||
|
|
||||||
const void *tx;
|
const void *tx;
|
||||||
void *rx;
|
void *rx;
|
||||||
#define SPI_TMP_BUFSZ (SMP_CACHE_BYTES + 1)
|
|
||||||
u8 rx_tmp_buf[SPI_TMP_BUFSZ];
|
|
||||||
int rcount;
|
int rcount;
|
||||||
int wcount;
|
int wcount;
|
||||||
struct davinci_spi_dma dma;
|
|
||||||
|
struct dma_chan *dma_rx;
|
||||||
|
struct dma_chan *dma_tx;
|
||||||
|
int dma_rx_chnum;
|
||||||
|
int dma_tx_chnum;
|
||||||
|
|
||||||
struct davinci_spi_platform_data *pdata;
|
struct davinci_spi_platform_data *pdata;
|
||||||
|
|
||||||
void (*get_rx)(u32 rx_data, struct davinci_spi *);
|
void (*get_rx)(u32 rx_data, struct davinci_spi *);
|
||||||
|
@ -496,21 +492,23 @@ out:
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
|
static void davinci_spi_dma_rx_callback(void *data)
|
||||||
{
|
{
|
||||||
struct davinci_spi *dspi = data;
|
struct davinci_spi *dspi = (struct davinci_spi *)data;
|
||||||
struct davinci_spi_dma *dma = &dspi->dma;
|
|
||||||
|
|
||||||
edma_stop(lch);
|
dspi->rcount = 0;
|
||||||
|
|
||||||
if (status == DMA_COMPLETE) {
|
if (!dspi->wcount && !dspi->rcount)
|
||||||
if (lch == dma->rx_channel)
|
complete(&dspi->done);
|
||||||
dspi->rcount = 0;
|
}
|
||||||
if (lch == dma->tx_channel)
|
|
||||||
dspi->wcount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!dspi->wcount && !dspi->rcount) || (status != DMA_COMPLETE))
|
static void davinci_spi_dma_tx_callback(void *data)
|
||||||
|
{
|
||||||
|
struct davinci_spi *dspi = (struct davinci_spi *)data;
|
||||||
|
|
||||||
|
dspi->wcount = 0;
|
||||||
|
|
||||||
|
if (!dspi->wcount && !dspi->rcount)
|
||||||
complete(&dspi->done);
|
complete(&dspi->done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,20 +524,20 @@ static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
|
||||||
static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
struct davinci_spi *dspi;
|
struct davinci_spi *dspi;
|
||||||
int data_type, ret;
|
int data_type, ret = -ENOMEM;
|
||||||
u32 tx_data, spidat1;
|
u32 tx_data, spidat1;
|
||||||
u32 errors = 0;
|
u32 errors = 0;
|
||||||
struct davinci_spi_config *spicfg;
|
struct davinci_spi_config *spicfg;
|
||||||
struct davinci_spi_platform_data *pdata;
|
struct davinci_spi_platform_data *pdata;
|
||||||
unsigned uninitialized_var(rx_buf_count);
|
unsigned uninitialized_var(rx_buf_count);
|
||||||
struct device *sdev;
|
void *dummy_buf = NULL;
|
||||||
|
struct scatterlist sg_rx, sg_tx;
|
||||||
|
|
||||||
dspi = spi_master_get_devdata(spi->master);
|
dspi = spi_master_get_devdata(spi->master);
|
||||||
pdata = dspi->pdata;
|
pdata = dspi->pdata;
|
||||||
spicfg = (struct davinci_spi_config *)spi->controller_data;
|
spicfg = (struct davinci_spi_config *)spi->controller_data;
|
||||||
if (!spicfg)
|
if (!spicfg)
|
||||||
spicfg = &davinci_spi_default_cfg;
|
spicfg = &davinci_spi_default_cfg;
|
||||||
sdev = dspi->bitbang.master->dev.parent;
|
|
||||||
|
|
||||||
/* convert len to words based on bits_per_word */
|
/* convert len to words based on bits_per_word */
|
||||||
data_type = dspi->bytes_per_word[spi->chip_select];
|
data_type = dspi->bytes_per_word[spi->chip_select];
|
||||||
|
@ -567,112 +565,83 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
spidat1 |= tx_data & 0xFFFF;
|
spidat1 |= tx_data & 0xFFFF;
|
||||||
iowrite32(spidat1, dspi->base + SPIDAT1);
|
iowrite32(spidat1, dspi->base + SPIDAT1);
|
||||||
} else {
|
} else {
|
||||||
struct davinci_spi_dma *dma;
|
struct dma_slave_config dma_rx_conf = {
|
||||||
unsigned long tx_reg, rx_reg;
|
.direction = DMA_DEV_TO_MEM,
|
||||||
struct edmacc_param param;
|
.src_addr = (unsigned long)dspi->pbase + SPIBUF,
|
||||||
void *rx_buf;
|
.src_addr_width = data_type,
|
||||||
int b, c;
|
.src_maxburst = 1,
|
||||||
|
};
|
||||||
|
struct dma_slave_config dma_tx_conf = {
|
||||||
|
.direction = DMA_MEM_TO_DEV,
|
||||||
|
.dst_addr = (unsigned long)dspi->pbase + SPIDAT1,
|
||||||
|
.dst_addr_width = data_type,
|
||||||
|
.dst_maxburst = 1,
|
||||||
|
};
|
||||||
|
struct dma_async_tx_descriptor *rxdesc;
|
||||||
|
struct dma_async_tx_descriptor *txdesc;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
dma = &dspi->dma;
|
dummy_buf = kzalloc(t->len, GFP_KERNEL);
|
||||||
|
if (!dummy_buf)
|
||||||
|
goto err_alloc_dummy_buf;
|
||||||
|
|
||||||
tx_reg = (unsigned long)dspi->pbase + SPIDAT1;
|
dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf);
|
||||||
rx_reg = (unsigned long)dspi->pbase + SPIBUF;
|
dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf);
|
||||||
|
|
||||||
/*
|
sg_init_table(&sg_rx, 1);
|
||||||
* Transmit DMA setup
|
if (!t->rx_buf)
|
||||||
*
|
buf = dummy_buf;
|
||||||
* If there is transmit data, map the transmit buffer, set it
|
|
||||||
* as the source of data and set the source B index to data
|
|
||||||
* size. If there is no transmit data, set the transmit register
|
|
||||||
* as the source of data, and set the source B index to zero.
|
|
||||||
*
|
|
||||||
* The destination is always the transmit register itself. And
|
|
||||||
* the destination never increments.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (t->tx_buf) {
|
|
||||||
t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf,
|
|
||||||
t->len, DMA_TO_DEVICE);
|
|
||||||
if (dma_mapping_error(&spi->dev, t->tx_dma)) {
|
|
||||||
dev_dbg(sdev, "Unable to DMA map %d bytes"
|
|
||||||
"TX buffer\n", t->len);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If number of words is greater than 65535, then we need
|
|
||||||
* to configure a 3 dimension transfer. Use the BCNTRLD
|
|
||||||
* feature to allow for transfers that aren't even multiples
|
|
||||||
* of 65535 (or any other possible b size) by first transferring
|
|
||||||
* the remainder amount then grabbing the next N blocks of
|
|
||||||
* 65535 words.
|
|
||||||
*/
|
|
||||||
|
|
||||||
c = dspi->wcount / (SZ_64K - 1); /* N 65535 Blocks */
|
|
||||||
b = dspi->wcount - c * (SZ_64K - 1); /* Remainder */
|
|
||||||
if (b)
|
|
||||||
c++;
|
|
||||||
else
|
else
|
||||||
b = SZ_64K - 1;
|
buf = t->rx_buf;
|
||||||
|
t->rx_dma = dma_map_single(&spi->dev, buf,
|
||||||
param.opt = TCINTEN | EDMA_TCC(dma->tx_channel);
|
t->len, DMA_FROM_DEVICE);
|
||||||
param.src = t->tx_buf ? t->tx_dma : tx_reg;
|
if (!t->rx_dma) {
|
||||||
param.a_b_cnt = b << 16 | data_type;
|
ret = -EFAULT;
|
||||||
param.dst = tx_reg;
|
goto err_rx_map;
|
||||||
param.src_dst_bidx = t->tx_buf ? data_type : 0;
|
|
||||||
param.link_bcntrld = 0xffffffff;
|
|
||||||
param.src_dst_cidx = t->tx_buf ? data_type : 0;
|
|
||||||
param.ccnt = c;
|
|
||||||
edma_write_slot(dma->tx_channel, ¶m);
|
|
||||||
edma_link(dma->tx_channel, dma->dummy_param_slot);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Receive DMA setup
|
|
||||||
*
|
|
||||||
* If there is receive buffer, use it to receive data. If there
|
|
||||||
* is none provided, use a temporary receive buffer. Set the
|
|
||||||
* destination B index to 0 so effectively only one byte is used
|
|
||||||
* in the temporary buffer (address does not increment).
|
|
||||||
*
|
|
||||||
* The source of receive data is the receive data register. The
|
|
||||||
* source address never increments.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (t->rx_buf) {
|
|
||||||
rx_buf = t->rx_buf;
|
|
||||||
rx_buf_count = t->len;
|
|
||||||
} else {
|
|
||||||
rx_buf = dspi->rx_tmp_buf;
|
|
||||||
rx_buf_count = sizeof(dspi->rx_tmp_buf);
|
|
||||||
}
|
}
|
||||||
|
sg_dma_address(&sg_rx) = t->rx_dma;
|
||||||
|
sg_dma_len(&sg_rx) = t->len;
|
||||||
|
|
||||||
t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count,
|
sg_init_table(&sg_tx, 1);
|
||||||
DMA_FROM_DEVICE);
|
if (!t->tx_buf)
|
||||||
if (dma_mapping_error(&spi->dev, t->rx_dma)) {
|
buf = dummy_buf;
|
||||||
dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
|
else
|
||||||
rx_buf_count);
|
buf = (void *)t->tx_buf;
|
||||||
if (t->tx_buf)
|
t->tx_dma = dma_map_single(&spi->dev, buf,
|
||||||
dma_unmap_single(&spi->dev, t->tx_dma, t->len,
|
t->len, DMA_FROM_DEVICE);
|
||||||
DMA_TO_DEVICE);
|
if (!t->tx_dma) {
|
||||||
return -ENOMEM;
|
ret = -EFAULT;
|
||||||
|
goto err_tx_map;
|
||||||
}
|
}
|
||||||
|
sg_dma_address(&sg_tx) = t->tx_dma;
|
||||||
|
sg_dma_len(&sg_tx) = t->len;
|
||||||
|
|
||||||
param.opt = TCINTEN | EDMA_TCC(dma->rx_channel);
|
rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx,
|
||||||
param.src = rx_reg;
|
&sg_rx, 1, DMA_DEV_TO_MEM,
|
||||||
param.a_b_cnt = b << 16 | data_type;
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
param.dst = t->rx_dma;
|
if (!rxdesc)
|
||||||
param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16;
|
goto err_desc;
|
||||||
param.link_bcntrld = 0xffffffff;
|
|
||||||
param.src_dst_cidx = (t->rx_buf ? data_type : 0) << 16;
|
txdesc = dmaengine_prep_slave_sg(dspi->dma_tx,
|
||||||
param.ccnt = c;
|
&sg_tx, 1, DMA_MEM_TO_DEV,
|
||||||
edma_write_slot(dma->rx_channel, ¶m);
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
if (!txdesc)
|
||||||
|
goto err_desc;
|
||||||
|
|
||||||
|
rxdesc->callback = davinci_spi_dma_rx_callback;
|
||||||
|
rxdesc->callback_param = (void *)dspi;
|
||||||
|
txdesc->callback = davinci_spi_dma_tx_callback;
|
||||||
|
txdesc->callback_param = (void *)dspi;
|
||||||
|
|
||||||
if (pdata->cshold_bug)
|
if (pdata->cshold_bug)
|
||||||
iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2);
|
iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2);
|
||||||
|
|
||||||
edma_start(dma->rx_channel);
|
dmaengine_submit(rxdesc);
|
||||||
edma_start(dma->tx_channel);
|
dmaengine_submit(txdesc);
|
||||||
|
|
||||||
|
dma_async_issue_pending(dspi->dma_rx);
|
||||||
|
dma_async_issue_pending(dspi->dma_tx);
|
||||||
|
|
||||||
set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
|
set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,15 +659,13 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
|
|
||||||
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
|
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
|
||||||
if (spicfg->io_type == SPI_IO_TYPE_DMA) {
|
if (spicfg->io_type == SPI_IO_TYPE_DMA) {
|
||||||
|
|
||||||
if (t->tx_buf)
|
|
||||||
dma_unmap_single(&spi->dev, t->tx_dma, t->len,
|
|
||||||
DMA_TO_DEVICE);
|
|
||||||
|
|
||||||
dma_unmap_single(&spi->dev, t->rx_dma, rx_buf_count,
|
|
||||||
DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
|
clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
|
||||||
|
|
||||||
|
dma_unmap_single(&spi->dev, t->rx_dma,
|
||||||
|
t->len, DMA_FROM_DEVICE);
|
||||||
|
dma_unmap_single(&spi->dev, t->tx_dma,
|
||||||
|
t->len, DMA_TO_DEVICE);
|
||||||
|
kfree(dummy_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
|
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
|
||||||
|
@ -716,11 +683,20 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dspi->rcount != 0 || dspi->wcount != 0) {
|
if (dspi->rcount != 0 || dspi->wcount != 0) {
|
||||||
dev_err(sdev, "SPI data transfer error\n");
|
dev_err(&spi->dev, "SPI data transfer error\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return t->len;
|
return t->len;
|
||||||
|
|
||||||
|
err_desc:
|
||||||
|
dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE);
|
||||||
|
err_tx_map:
|
||||||
|
dma_unmap_single(&spi->dev, t->rx_dma, t->len, DMA_FROM_DEVICE);
|
||||||
|
err_rx_map:
|
||||||
|
kfree(dummy_buf);
|
||||||
|
err_alloc_dummy_buf:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -751,39 +727,33 @@ static irqreturn_t davinci_spi_irq(s32 irq, void *data)
|
||||||
|
|
||||||
static int davinci_spi_request_dma(struct davinci_spi *dspi)
|
static int davinci_spi_request_dma(struct davinci_spi *dspi)
|
||||||
{
|
{
|
||||||
|
dma_cap_mask_t mask;
|
||||||
|
struct device *sdev = dspi->bitbang.master->dev.parent;
|
||||||
int r;
|
int r;
|
||||||
struct davinci_spi_dma *dma = &dspi->dma;
|
|
||||||
|
|
||||||
r = edma_alloc_channel(dma->rx_channel, davinci_spi_dma_callback, dspi,
|
dma_cap_zero(mask);
|
||||||
dma->eventq);
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
if (r < 0) {
|
|
||||||
pr_err("Unable to request DMA channel for SPI RX\n");
|
dspi->dma_rx = dma_request_channel(mask, edma_filter_fn,
|
||||||
r = -EAGAIN;
|
&dspi->dma_rx_chnum);
|
||||||
|
if (!dspi->dma_rx) {
|
||||||
|
dev_err(sdev, "request RX DMA channel failed\n");
|
||||||
|
r = -ENODEV;
|
||||||
goto rx_dma_failed;
|
goto rx_dma_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = edma_alloc_channel(dma->tx_channel, davinci_spi_dma_callback, dspi,
|
dspi->dma_tx = dma_request_channel(mask, edma_filter_fn,
|
||||||
dma->eventq);
|
&dspi->dma_tx_chnum);
|
||||||
if (r < 0) {
|
if (!dspi->dma_tx) {
|
||||||
pr_err("Unable to request DMA channel for SPI TX\n");
|
dev_err(sdev, "request TX DMA channel failed\n");
|
||||||
r = -EAGAIN;
|
r = -ENODEV;
|
||||||
goto tx_dma_failed;
|
goto tx_dma_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = edma_alloc_slot(EDMA_CTLR(dma->tx_channel), EDMA_SLOT_ANY);
|
|
||||||
if (r < 0) {
|
|
||||||
pr_err("Unable to request SPI TX DMA param slot\n");
|
|
||||||
r = -EAGAIN;
|
|
||||||
goto param_failed;
|
|
||||||
}
|
|
||||||
dma->dummy_param_slot = r;
|
|
||||||
edma_link(dma->dummy_param_slot, dma->dummy_param_slot);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
param_failed:
|
|
||||||
edma_free_channel(dma->tx_channel);
|
|
||||||
tx_dma_failed:
|
tx_dma_failed:
|
||||||
edma_free_channel(dma->rx_channel);
|
dma_release_channel(dspi->dma_rx);
|
||||||
rx_dma_failed:
|
rx_dma_failed:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -898,9 +868,8 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
|
||||||
dspi->bitbang.txrx_bufs = davinci_spi_bufs;
|
dspi->bitbang.txrx_bufs = davinci_spi_bufs;
|
||||||
if (dma_rx_chan != SPI_NO_RESOURCE &&
|
if (dma_rx_chan != SPI_NO_RESOURCE &&
|
||||||
dma_tx_chan != SPI_NO_RESOURCE) {
|
dma_tx_chan != SPI_NO_RESOURCE) {
|
||||||
dspi->dma.rx_channel = dma_rx_chan;
|
dspi->dma_rx_chnum = dma_rx_chan;
|
||||||
dspi->dma.tx_channel = dma_tx_chan;
|
dspi->dma_tx_chnum = dma_tx_chan;
|
||||||
dspi->dma.eventq = pdata->dma_event_q;
|
|
||||||
|
|
||||||
ret = davinci_spi_request_dma(dspi);
|
ret = davinci_spi_request_dma(dspi);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -955,9 +924,8 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
free_dma:
|
free_dma:
|
||||||
edma_free_channel(dspi->dma.tx_channel);
|
dma_release_channel(dspi->dma_rx);
|
||||||
edma_free_channel(dspi->dma.rx_channel);
|
dma_release_channel(dspi->dma_tx);
|
||||||
edma_free_slot(dspi->dma.dummy_param_slot);
|
|
||||||
free_clk:
|
free_clk:
|
||||||
clk_disable(dspi->clk);
|
clk_disable(dspi->clk);
|
||||||
clk_put(dspi->clk);
|
clk_put(dspi->clk);
|
||||||
|
|
Loading…
Add table
Reference in a new issue