mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-16 03:06:58 +07:00
spi: lpspi: add dma mode support
Add dma mode support for LPSPI. Any frame longer than half txfifosize will be sent by dma mode. For now, there are some limits: 1. The maximum transfer speed in master mode depends on the slave device, at least 40MHz(tested by spi-nor on 8qm-lpddr4-arm2 base board); 2. The maximum transfer speed in slave mode is 15MHz(imx7ulp), 22MHz(8qm/qxp). In order to reach the maximum speed which is mentioned in datasheet, the load of connect wires between master and slave should be less than 15pF. Signed-off-by: Clark Wang <xiaoning.wang@nxp.com> Acked-by: Fugang Duan <Fugang.duan@nxp.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
c7a4025995
commit
09c04466ce
@ -8,6 +8,8 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/dmaengine.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
@ -20,6 +22,7 @@
|
|||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/platform_data/dma-imx.h>
|
||||||
#include <linux/platform_data/spi-imx.h>
|
#include <linux/platform_data/spi-imx.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@ -31,6 +34,9 @@
|
|||||||
|
|
||||||
#define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
|
#define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
|
||||||
|
|
||||||
|
/* The maximum bytes that edma can transfer once.*/
|
||||||
|
#define FSL_LPSPI_MAX_EDMA_BYTES ((1 << 15) - 1)
|
||||||
|
|
||||||
/* i.MX7ULP LPSPI registers */
|
/* i.MX7ULP LPSPI registers */
|
||||||
#define IMX7ULP_VERID 0x0
|
#define IMX7ULP_VERID 0x0
|
||||||
#define IMX7ULP_PARAM 0x4
|
#define IMX7ULP_PARAM 0x4
|
||||||
@ -64,6 +70,8 @@
|
|||||||
#define IER_FCIE BIT(9)
|
#define IER_FCIE BIT(9)
|
||||||
#define IER_RDIE BIT(1)
|
#define IER_RDIE BIT(1)
|
||||||
#define IER_TDIE BIT(0)
|
#define IER_TDIE BIT(0)
|
||||||
|
#define DER_RDDE BIT(1)
|
||||||
|
#define DER_TDDE BIT(0)
|
||||||
#define CFGR1_PCSCFG BIT(27)
|
#define CFGR1_PCSCFG BIT(27)
|
||||||
#define CFGR1_PINCFG (BIT(24)|BIT(25))
|
#define CFGR1_PINCFG (BIT(24)|BIT(25))
|
||||||
#define CFGR1_PCSPOL BIT(8)
|
#define CFGR1_PCSPOL BIT(8)
|
||||||
@ -91,6 +99,7 @@ struct lpspi_config {
|
|||||||
struct fsl_lpspi_data {
|
struct fsl_lpspi_data {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
unsigned long base_phys;
|
||||||
struct clk *clk_ipg;
|
struct clk *clk_ipg;
|
||||||
struct clk *clk_per;
|
struct clk *clk_per;
|
||||||
bool is_slave;
|
bool is_slave;
|
||||||
@ -111,6 +120,11 @@ struct fsl_lpspi_data {
|
|||||||
|
|
||||||
bool slave_aborted;
|
bool slave_aborted;
|
||||||
|
|
||||||
|
/* DMA */
|
||||||
|
bool usedma;
|
||||||
|
struct completion dma_rx_completion;
|
||||||
|
struct completion dma_tx_completion;
|
||||||
|
|
||||||
int chipselect[0];
|
int chipselect[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -158,6 +172,35 @@ static void fsl_lpspi_intctrl(struct fsl_lpspi_data *fsl_lpspi,
|
|||||||
writel(enable, fsl_lpspi->base + IMX7ULP_IER);
|
writel(enable, fsl_lpspi->base + IMX7ULP_IER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fsl_lpspi_bytes_per_word(const int bpw)
|
||||||
|
{
|
||||||
|
return DIV_ROUND_UP(bpw, BITS_PER_BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fsl_lpspi_can_dma(struct spi_controller *controller,
|
||||||
|
struct spi_device *spi,
|
||||||
|
struct spi_transfer *transfer)
|
||||||
|
{
|
||||||
|
unsigned int bytes_per_word;
|
||||||
|
|
||||||
|
if (!controller->dma_rx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bytes_per_word = fsl_lpspi_bytes_per_word(transfer->bits_per_word);
|
||||||
|
|
||||||
|
switch (bytes_per_word)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
|
static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
|
||||||
{
|
{
|
||||||
struct fsl_lpspi_data *fsl_lpspi =
|
struct fsl_lpspi_data *fsl_lpspi =
|
||||||
@ -245,11 +288,13 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
|
|||||||
* For the first transfer, clear TCR_CONTC to assert SS.
|
* For the first transfer, clear TCR_CONTC to assert SS.
|
||||||
* For subsequent transfer, set TCR_CONTC to keep SS asserted.
|
* For subsequent transfer, set TCR_CONTC to keep SS asserted.
|
||||||
*/
|
*/
|
||||||
temp |= TCR_CONT;
|
if (!fsl_lpspi->usedma) {
|
||||||
if (fsl_lpspi->is_first_byte)
|
temp |= TCR_CONT;
|
||||||
temp &= ~TCR_CONTC;
|
if (fsl_lpspi->is_first_byte)
|
||||||
else
|
temp &= ~TCR_CONTC;
|
||||||
temp |= TCR_CONTC;
|
else
|
||||||
|
temp |= TCR_CONTC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
|
writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
|
||||||
|
|
||||||
@ -260,7 +305,11 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
|
|||||||
{
|
{
|
||||||
u32 temp;
|
u32 temp;
|
||||||
|
|
||||||
temp = fsl_lpspi->watermark >> 1 | (fsl_lpspi->watermark >> 1) << 16;
|
if (!fsl_lpspi->usedma)
|
||||||
|
temp = fsl_lpspi->watermark >> 1 |
|
||||||
|
(fsl_lpspi->watermark >> 1) << 16;
|
||||||
|
else
|
||||||
|
temp = fsl_lpspi->watermark >> 1;
|
||||||
|
|
||||||
writel(temp, fsl_lpspi->base + IMX7ULP_FCR);
|
writel(temp, fsl_lpspi->base + IMX7ULP_FCR);
|
||||||
|
|
||||||
@ -302,6 +351,53 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fsl_lpspi_dma_configure(struct spi_controller *controller)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
enum dma_slave_buswidth buswidth;
|
||||||
|
struct dma_slave_config rx = {}, tx = {};
|
||||||
|
struct fsl_lpspi_data *fsl_lpspi =
|
||||||
|
spi_controller_get_devdata(controller);
|
||||||
|
|
||||||
|
switch (fsl_lpspi_bytes_per_word(fsl_lpspi->config.bpw)) {
|
||||||
|
case 4:
|
||||||
|
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.direction = DMA_MEM_TO_DEV;
|
||||||
|
tx.dst_addr = fsl_lpspi->base_phys + IMX7ULP_TDR;
|
||||||
|
tx.dst_addr_width = buswidth;
|
||||||
|
tx.dst_maxburst = 1;
|
||||||
|
ret = dmaengine_slave_config(controller->dma_tx, &tx);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(fsl_lpspi->dev, "TX dma configuration failed with %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx.direction = DMA_DEV_TO_MEM;
|
||||||
|
rx.src_addr = fsl_lpspi->base_phys + IMX7ULP_RDR;
|
||||||
|
rx.src_addr_width = buswidth;
|
||||||
|
rx.src_maxburst = 1;
|
||||||
|
ret = dmaengine_slave_config(controller->dma_rx, &rx);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(fsl_lpspi->dev, "RX dma configuration failed with %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
|
static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
|
||||||
{
|
{
|
||||||
u32 temp;
|
u32 temp;
|
||||||
@ -327,10 +423,16 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
|
|||||||
temp |= CR_RRF | CR_RTF | CR_MEN;
|
temp |= CR_RRF | CR_RTF | CR_MEN;
|
||||||
writel(temp, fsl_lpspi->base + IMX7ULP_CR);
|
writel(temp, fsl_lpspi->base + IMX7ULP_CR);
|
||||||
|
|
||||||
|
temp = 0;
|
||||||
|
if (fsl_lpspi->usedma)
|
||||||
|
temp = DER_TDDE | DER_RDDE;
|
||||||
|
writel(temp, fsl_lpspi->base + IMX7ULP_DER);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsl_lpspi_setup_transfer(struct spi_device *spi,
|
static int fsl_lpspi_setup_transfer(struct spi_controller *controller,
|
||||||
|
struct spi_device *spi,
|
||||||
struct spi_transfer *t)
|
struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
struct fsl_lpspi_data *fsl_lpspi =
|
struct fsl_lpspi_data *fsl_lpspi =
|
||||||
@ -363,6 +465,11 @@ static int fsl_lpspi_setup_transfer(struct spi_device *spi,
|
|||||||
else
|
else
|
||||||
fsl_lpspi->watermark = fsl_lpspi->txfifosize;
|
fsl_lpspi->watermark = fsl_lpspi->txfifosize;
|
||||||
|
|
||||||
|
if (fsl_lpspi_can_dma(controller, spi, t))
|
||||||
|
fsl_lpspi->usedma = 1;
|
||||||
|
else
|
||||||
|
fsl_lpspi->usedma = 0;
|
||||||
|
|
||||||
return fsl_lpspi_config(fsl_lpspi);
|
return fsl_lpspi_config(fsl_lpspi);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,8 +508,10 @@ static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
|
|||||||
{
|
{
|
||||||
u32 temp;
|
u32 temp;
|
||||||
|
|
||||||
/* Disable all interrupt */
|
if (!fsl_lpspi->usedma) {
|
||||||
fsl_lpspi_intctrl(fsl_lpspi, 0);
|
/* Disable all interrupt */
|
||||||
|
fsl_lpspi_intctrl(fsl_lpspi, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* W1C for all flags in SR */
|
/* W1C for all flags in SR */
|
||||||
temp = 0x3F << 8;
|
temp = 0x3F << 8;
|
||||||
@ -415,6 +524,176 @@ static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fsl_lpspi_dma_rx_callback(void *cookie)
|
||||||
|
{
|
||||||
|
struct fsl_lpspi_data *fsl_lpspi = (struct fsl_lpspi_data *)cookie;
|
||||||
|
|
||||||
|
complete(&fsl_lpspi->dma_rx_completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fsl_lpspi_dma_tx_callback(void *cookie)
|
||||||
|
{
|
||||||
|
struct fsl_lpspi_data *fsl_lpspi = (struct fsl_lpspi_data *)cookie;
|
||||||
|
|
||||||
|
complete(&fsl_lpspi->dma_tx_completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fsl_lpspi_calculate_timeout(struct fsl_lpspi_data *fsl_lpspi,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
unsigned long timeout = 0;
|
||||||
|
|
||||||
|
/* Time with actual data transfer and CS change delay related to HW */
|
||||||
|
timeout = (8 + 4) * size / fsl_lpspi->config.speed_hz;
|
||||||
|
|
||||||
|
/* Add extra second for scheduler related activities */
|
||||||
|
timeout += 1;
|
||||||
|
|
||||||
|
/* Double calculated timeout */
|
||||||
|
return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
|
||||||
|
struct fsl_lpspi_data *fsl_lpspi,
|
||||||
|
struct spi_transfer *transfer)
|
||||||
|
{
|
||||||
|
struct dma_async_tx_descriptor *desc_tx, *desc_rx;
|
||||||
|
unsigned long transfer_timeout;
|
||||||
|
unsigned long timeout;
|
||||||
|
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = fsl_lpspi_dma_configure(controller);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
|
||||||
|
rx->sgl, rx->nents, DMA_DEV_TO_MEM,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
if (!desc_rx)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
desc_rx->callback = fsl_lpspi_dma_rx_callback;
|
||||||
|
desc_rx->callback_param = (void *)fsl_lpspi;
|
||||||
|
dmaengine_submit(desc_rx);
|
||||||
|
reinit_completion(&fsl_lpspi->dma_rx_completion);
|
||||||
|
dma_async_issue_pending(controller->dma_rx);
|
||||||
|
|
||||||
|
desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
|
||||||
|
tx->sgl, tx->nents, DMA_MEM_TO_DEV,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
if (!desc_tx) {
|
||||||
|
dmaengine_terminate_all(controller->dma_tx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_tx->callback = fsl_lpspi_dma_tx_callback;
|
||||||
|
desc_tx->callback_param = (void *)fsl_lpspi;
|
||||||
|
dmaengine_submit(desc_tx);
|
||||||
|
reinit_completion(&fsl_lpspi->dma_tx_completion);
|
||||||
|
dma_async_issue_pending(controller->dma_tx);
|
||||||
|
|
||||||
|
fsl_lpspi->slave_aborted = false;
|
||||||
|
|
||||||
|
if (!fsl_lpspi->is_slave) {
|
||||||
|
transfer_timeout = fsl_lpspi_calculate_timeout(fsl_lpspi,
|
||||||
|
transfer->len);
|
||||||
|
|
||||||
|
/* Wait eDMA to finish the data transfer.*/
|
||||||
|
timeout = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion,
|
||||||
|
transfer_timeout);
|
||||||
|
if (!timeout) {
|
||||||
|
dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n");
|
||||||
|
dmaengine_terminate_all(controller->dma_tx);
|
||||||
|
dmaengine_terminate_all(controller->dma_rx);
|
||||||
|
fsl_lpspi_reset(fsl_lpspi);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion,
|
||||||
|
transfer_timeout);
|
||||||
|
if (!timeout) {
|
||||||
|
dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n");
|
||||||
|
dmaengine_terminate_all(controller->dma_tx);
|
||||||
|
dmaengine_terminate_all(controller->dma_rx);
|
||||||
|
fsl_lpspi_reset(fsl_lpspi);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wait_for_completion_interruptible(&fsl_lpspi->dma_tx_completion) ||
|
||||||
|
fsl_lpspi->slave_aborted) {
|
||||||
|
dev_dbg(fsl_lpspi->dev,
|
||||||
|
"I/O Error in DMA TX interrupted\n");
|
||||||
|
dmaengine_terminate_all(controller->dma_tx);
|
||||||
|
dmaengine_terminate_all(controller->dma_rx);
|
||||||
|
fsl_lpspi_reset(fsl_lpspi);
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_for_completion_interruptible(&fsl_lpspi->dma_rx_completion) ||
|
||||||
|
fsl_lpspi->slave_aborted) {
|
||||||
|
dev_dbg(fsl_lpspi->dev,
|
||||||
|
"I/O Error in DMA RX interrupted\n");
|
||||||
|
dmaengine_terminate_all(controller->dma_tx);
|
||||||
|
dmaengine_terminate_all(controller->dma_rx);
|
||||||
|
fsl_lpspi_reset(fsl_lpspi);
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fsl_lpspi_reset(fsl_lpspi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fsl_lpspi_dma_exit(struct spi_controller *controller)
|
||||||
|
{
|
||||||
|
if (controller->dma_rx) {
|
||||||
|
dma_release_channel(controller->dma_rx);
|
||||||
|
controller->dma_rx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller->dma_tx) {
|
||||||
|
dma_release_channel(controller->dma_tx);
|
||||||
|
controller->dma_tx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fsl_lpspi_dma_init(struct device *dev,
|
||||||
|
struct fsl_lpspi_data *fsl_lpspi,
|
||||||
|
struct spi_controller *controller)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prepare for TX DMA: */
|
||||||
|
controller->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||||
|
if (IS_ERR(controller->dma_tx)) {
|
||||||
|
ret = PTR_ERR(controller->dma_tx);
|
||||||
|
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
||||||
|
controller->dma_tx = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare for RX DMA: */
|
||||||
|
controller->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||||
|
if (IS_ERR(controller->dma_rx)) {
|
||||||
|
ret = PTR_ERR(controller->dma_rx);
|
||||||
|
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||||
|
controller->dma_rx = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_completion(&fsl_lpspi->dma_rx_completion);
|
||||||
|
init_completion(&fsl_lpspi->dma_tx_completion);
|
||||||
|
controller->can_dma = fsl_lpspi_can_dma;
|
||||||
|
controller->max_dma_len = FSL_LPSPI_MAX_EDMA_BYTES;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
fsl_lpspi_dma_exit(controller);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int fsl_lpspi_pio_transfer(struct spi_controller *controller,
|
static int fsl_lpspi_pio_transfer(struct spi_controller *controller,
|
||||||
struct spi_transfer *t)
|
struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
@ -449,14 +728,17 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fsl_lpspi->is_first_byte = true;
|
fsl_lpspi->is_first_byte = true;
|
||||||
ret = fsl_lpspi_setup_transfer(spi, t);
|
ret = fsl_lpspi_setup_transfer(controller, spi, t);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fsl_lpspi_set_cmd(fsl_lpspi);
|
fsl_lpspi_set_cmd(fsl_lpspi);
|
||||||
fsl_lpspi->is_first_byte = false;
|
fsl_lpspi->is_first_byte = false;
|
||||||
|
|
||||||
ret = fsl_lpspi_pio_transfer(controller, t);
|
if (fsl_lpspi->usedma)
|
||||||
|
ret = fsl_lpspi_dma_transfer(controller, fsl_lpspi, t);
|
||||||
|
else
|
||||||
|
ret = fsl_lpspi_pio_transfer(controller, t);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -606,6 +888,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
|||||||
ret = PTR_ERR(fsl_lpspi->base);
|
ret = PTR_ERR(fsl_lpspi->base);
|
||||||
goto out_controller_put;
|
goto out_controller_put;
|
||||||
}
|
}
|
||||||
|
fsl_lpspi->base_phys = res->start;
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
if (irq < 0) {
|
if (irq < 0) {
|
||||||
@ -647,6 +930,13 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
|||||||
fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
|
fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
|
||||||
fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
|
fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
|
||||||
|
|
||||||
|
ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
|
||||||
|
if (ret == -EPROBE_DEFER)
|
||||||
|
goto out_controller_put;
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret);
|
||||||
|
|
||||||
ret = devm_spi_register_controller(&pdev->dev, controller);
|
ret = devm_spi_register_controller(&pdev->dev, controller);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "spi_register_controller error.\n");
|
dev_err(&pdev->dev, "spi_register_controller error.\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user