linuxOS_D21X/source/linux-5.10/drivers/spi/spi-artinchip.c
2025-08-14 15:17:16 +08:00

2202 lines
56 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021-2025, Artinchip Technology Co., Ltd
* Author: Dehuang Wu <dehuang.wu@artinchip.com>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <asm/cacheflush.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/spi/spi-mem.h>
#include "../dma/artinchip-dma.h"
#include "internals.h"
#include "spi-artinchip.h"
enum spi_mode_type {
SINGLE_HALF_DUPLEX_RX,
SINGLE_HALF_DUPLEX_TX,
SINGLE_FULL_DUPLEX_RX_TX,
DUAL_HALF_DUPLEX_RX,
DUAL_HALF_DUPLEX_TX,
QUAD_HALF_DUPLEX_RX,
QUAD_HALF_DUPLEX_TX,
MODE_TYPE_NULL,
};
#define SINGLE_MODE 0x01010101U
#define DUAL_OUTPUT_MODE 0x01010102U
#define DUAL_IO_MODE 0x01020202U
#define QUAD_OUTPUT_MODE 0x01010104U
#define QUAD_IO_MODE 0x01040404U
#define QPI_MODE 0x04040404U
#define SPI_DUAL_MODE 1
#define SPI_QUAD_MODE 2
#define SPI_SINGLE_MODE 4
#define SPI_DMA_RX BIT(0)
#define SPI_DMA_TX BIT(1)
#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
#define RX_SAMP_DLY_AUTO 0
#define RX_SAMP_DLY_NONE 1
#define RX_SAMP_DLY_HALF_CYCLE 2
#define RX_SAMP_DLY_ONE_CYCLE 3
/* The port only used for request DDMA, and maybe different in different SoC */
#define DMA_SPI0 10
struct aic_spi {
struct device *dev;
struct spi_controller *ctlr;
void __iomem *base_addr;
struct clk *mclk;
struct reset_control *rst;
struct dma_chan *dma_rx;
struct dma_chan *dma_tx;
dma_addr_t dma_addr_rx;
dma_addr_t dma_addr_tx;
enum spi_mode_type mode_type;
unsigned int irq;
u32 id;
char dev_name[48];
spinlock_t lock;
bool bit_mode;
u32 rx_samp_dly;
u32 freq;
u32 freq_dividor;
};
struct aic_spi_platform_data {
int cs_num;
char regulator_id[16];
struct regulator *regulator;
};
static ssize_t aic_spi_status_show(struct device *dev,
struct device_attribute *attr, char *buf);
static s32 spi_ctlr_set_cs_num(u32 chipselect, void __iomem *base_addr)
{
u32 val;
val = readl(base_addr + SPI_REG_TCR);
val &= ~TCR_BIT_SS_SEL_MSK;
val |= (chipselect << TCR_BIT_SS_SEL_OFF);
writel(val, base_addr + SPI_REG_TCR);
return 0;
}
static inline void spi_cltr_cfg_tc(u32 mode, void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_TCR);
/* only support mode0 & mode2 */
if ((mode & SPI_CPHA) && !(mode & SPI_CPOL)) {
val &= ~TCR_BIT_CPHA;
val |= TCR_BIT_CPOL;
} else if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) {
val &= ~TCR_BIT_CPHA;
val &= ~TCR_BIT_CPOL;
} else {
if (mode & SPI_CPOL)
val |= TCR_BIT_CPOL;
else
val &= ~TCR_BIT_CPOL;
if (mode & SPI_CPHA)
val |= TCR_BIT_CPHA;
else
val &= ~TCR_BIT_CPHA;
}
if (mode & SPI_CS_HIGH)
val &= ~TCR_BIT_SPOL;
else
val |= TCR_BIT_SPOL;
if (mode & SPI_LSB_FIRST)
val |= TCR_BIT_FBS;
else
val &= ~TCR_BIT_FBS;
if (mode & SPI_DUMMY_FILL_ONE)
val |= TCR_BIT_DDB;
else
val &= ~TCR_BIT_DDB;
if (mode & SPI_RECEIVE_ALL_BURST)
val &= ~TCR_BIT_DHB;
else
val |= TCR_BIT_DHB;
#ifndef SUPPORT_SPI_3WIRE_IN_BIT_MODE
if (mode & SPI_3WIRE) {
val |= TCR_BIT_3WIRE;
val |= 0xFF << 16;
} else
val &= ~TCR_BIT_3WIRE;
#endif
val &= ~TCR_BIT_SSCTL;
writel(val, base_addr + SPI_REG_TCR);
}
static u32 spi_get_best_div_param(u32 spiclk, u32 mclk, u32 *div)
{
u32 cdr1_clk, cdr2_clk, cdr1_clkt, cdr2_clkt;
s32 cdr2, cdr1;
/* Get the best cdr1 param if going to use cdr1 */
cdr1 = 0;
while ((mclk >> cdr1) > spiclk)
cdr1++;
if (cdr1 > 0xF)
cdr1 = 0xF;
/* Get the best cdr1 value around bus clk*/
cdr1_clk = mclk >> cdr1;
if (cdr1 > 0 && (cdr1_clk < spiclk)) {
cdr1_clkt = mclk >> (cdr1 - 1);
if ((cdr1_clkt - spiclk) < (spiclk - cdr1_clk))
cdr1--;
}
/* Get the best cdr2 param if going to use cdr2 */
cdr2 = (s32)(mclk / (spiclk * 2)) - 1;
if (cdr2 < 0)
cdr2 = 0;
if (cdr2 > 0xFF)
cdr2 = 0xFF;
cdr2_clk = mclk / (2 * cdr2 + 1);
if ((cdr2 < 0xFF) && (cdr2_clk > spiclk)) {
cdr2_clkt = mclk / (2 * (cdr2 + 1) + 1);
if ((spiclk - cdr2_clkt) < (cdr2_clk - spiclk))
cdr2++;
}
/* cdr1 param vs cdr2 param, use the best */
cdr1_clk = mclk >> cdr1;
cdr2_clk = mclk / (2 * cdr2 + 1);
if (cdr1_clk == spiclk) {
*div = cdr1;
return 0;
} else if (cdr2_clk == spiclk) {
*div = cdr2;
return 1;
} else if ((cdr2_clk < spiclk) && (cdr1_clk < spiclk)) {
/* Two clks less than expect clk, use the larger one */
if (cdr2_clk > cdr1_clk) {
*div = cdr2;
return 1;
}
*div = cdr1;
return 0;
}
/*
* 1. Two clks great than expect clk, use least one
* 2. There is one clk less than expect clk, use it
*/
if (cdr2_clk < cdr1_clk) {
*div = cdr2;
return 1;
}
*div = cdr1;
return 0;
}
static void spi_ctlr_set_work_mode(void __iomem *base_addr, int mode)
{
u32 val;
val = readl(base_addr + SPI_REG_BTC);
val &= ~(BTC_BIT_WM_MSK);
val |= (mode & BTC_BIT_WM_MSK);
writel(val, base_addr + SPI_REG_BTC);
}
static s32 spi_ctlr_bit_mode_set_cs_num(u32 chipselect, void __iomem *base_addr)
{
u32 val;
if (chipselect != 0)
return -EINVAL;
val = readl(base_addr + SPI_REG_BTC);
val &= ~BTC_BIT_SS_SEL_MSK;
val |= (chipselect << BTC_BIT_SS_SEL_OFS);
writel(val, base_addr + SPI_REG_BTC);
return 0;
}
static inline void spi_ctlr_bit_mode_set_clk(u32 spiclk, u32 mclk,
void __iomem *base_addr)
{
u32 div;
/*
* mclk: module source clock
* spiclk: expected spi working clock
*/
if (spiclk == 0)
spiclk = 1;
div = mclk / (2 * spiclk) - 1;
writel(div, base_addr + SPI_REG_BCLK);
}
static inline void spi_ctlr_bit_mode_start_xfer(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_BTC);
val |= BTC_BIT_XFER_EN_MSK;
writel(val, base_addr + SPI_REG_BTC);
}
static inline void spi_ctlr_bit_mode_set_cs(struct aic_spi *aicspi, u32 high)
{
u32 reg_val = readl(aicspi->base_addr + SPI_REG_BTC);
if (high)
reg_val |= BTC_BIT_SS_LEVEL_MSK;
else
reg_val &= ~BTC_BIT_SS_LEVEL_MSK;
writel(reg_val, aicspi->base_addr + SPI_REG_BTC);
}
static inline void spi_ctlr_bit_mode_set_cs_level(struct aic_spi *aicspi,
bool level)
{
u32 reg_val = readl(aicspi->base_addr + SPI_REG_BTC);
if (level)
reg_val |= BTC_BIT_SS_LEVEL_MSK;
else
reg_val &= ~BTC_BIT_SS_LEVEL_MSK;
writel(reg_val, aicspi->base_addr + SPI_REG_BTC);
}
static inline void spi_ctlr_bit_mode_set_cs_pol(struct aic_spi *aicspi,
bool high_active)
{
u32 reg_val = readl(aicspi->base_addr + SPI_REG_BTC);
if (high_active)
reg_val &= ~BTC_BIT_SPOL_MSK;
else
reg_val |= BTC_BIT_SPOL_MSK;
writel(reg_val, aicspi->base_addr + SPI_REG_BTC);
}
static inline void spi_ctlr_bit_mode_set_ss_owner(void __iomem *base_addr,
bool soft_ctrl)
{
u32 val = readl(base_addr + SPI_REG_BTC);
if (soft_ctrl)
val |= BTC_BIT_SS_OWNER_MSK;
else
val &= ~BTC_BIT_SS_OWNER_MSK;
writel(val, base_addr + SPI_REG_BTC);
}
static inline bool spi_ctlr_bit_mode_xfer_done(void __iomem *base_addr)
{
u32 val;
val = readl(base_addr + SPI_REG_BTC);
if (val & BTC_BIT_XFER_EN_MSK)
return false;
if ((val & BTC_BIT_XFER_COMP_MSK) == 0)
return false;
return true;
}
static inline bool spi_ctlr_bit_mode_rxsts_clear(void __iomem *base_addr)
{
u32 val;
val = readl(base_addr + SPI_REG_BTC);
val &= ~(BTC_BIT_RX_BIT_LEN_MSK);
val |= BTC_BIT_XFER_COMP_MSK;
writel(val, base_addr + SPI_REG_BTC);
udelay(1);
val = readl(base_addr + SPI_REG_BTC);
if (val & BTC_BIT_XFER_COMP_MSK)
return false;
return true;
}
static inline bool spi_ctlr_bit_mode_txsts_clear(void __iomem *base_addr)
{
u32 val;
val = readl(base_addr + SPI_REG_BTC);
val &= ~(BTC_BIT_TX_BIT_LEN_MSK);
val |= BTC_BIT_XFER_COMP_MSK;
writel(val, base_addr + SPI_REG_BTC);
udelay(1);
val = readl(base_addr + SPI_REG_BTC);
if (val & BTC_BIT_XFER_COMP_MSK)
return false;
return true;
}
static int spi_ctlr_bit_mode_read(struct aic_spi *aicspi, unsigned char *rx_buf,
unsigned int rx_len, unsigned long speed_hz,
unsigned char bits_per_word)
{
int dolen, remain, i;
u32 val, rxbits;
unsigned char *p;
val = readl(aicspi->base_addr + SPI_REG_BTC);
val |= BTC_BIT_XFER_COMP_MSK;
writel(val, aicspi->base_addr + SPI_REG_BTC);
p = rx_buf;
remain = rx_len;
while (remain) {
rxbits = 0;
dolen = remain;
if (dolen > 4)
dolen = 4;
/* Configre rx length and start transfer */
val = readl(aicspi->base_addr + SPI_REG_BTC);
val |= bits_per_word << BTC_BIT_RX_BIT_LEN_OFS;
val |= BTC_BIT_XFER_EN_MSK;
writel(val, aicspi->base_addr + SPI_REG_BTC);
while (!spi_ctlr_bit_mode_xfer_done(aicspi->base_addr))
;
while (!spi_ctlr_bit_mode_rxsts_clear(aicspi->base_addr))
;
/* Read rx bits */
rxbits = readl(aicspi->base_addr + SPI_REG_RBR);
for (i = 0; i < dolen; i++)
p[i] = (rxbits >> (i * 8)) & 0xFF;
p += dolen;
remain -= dolen;
}
if (remain == 0)
spi_finalize_current_transfer(aicspi->ctlr);
return rx_len;
}
static int spi_ctlr_bit_mode_write(struct aic_spi *aicspi,
unsigned char *tx_buf, unsigned int tx_len,
unsigned long speed_hz,
unsigned char bits_per_word)
{
int dolen, remain, i;
u32 val, txbits;
unsigned char *p;
val = readl(aicspi->base_addr + SPI_REG_BTC);
val |= BTC_BIT_XFER_COMP_MSK;
writel(val, aicspi->base_addr + SPI_REG_BTC);
p = tx_buf;
remain = tx_len;
while (remain) {
txbits = 0;
dolen = remain;
if (dolen > 4)
dolen = 4;
/* Prepare and write tx bits */
for (i = 0; i < dolen; i++)
txbits |= p[i] << (i * 8);
writel(txbits, aicspi->base_addr + SPI_REG_TBR);
/* Configure tx length and start transfer */
val = readl(aicspi->base_addr + SPI_REG_BTC);
val |= bits_per_word << BTC_BIT_TX_BIT_LEN_OFS;
val |= BTC_BIT_XFER_EN_MSK;
writel(val, aicspi->base_addr + SPI_REG_BTC);
while (!spi_ctlr_bit_mode_xfer_done(aicspi->base_addr))
;
while (!spi_ctlr_bit_mode_txsts_clear(aicspi->base_addr))
;
p += dolen;
remain -= dolen;
}
if (remain == 0)
spi_finalize_current_transfer(aicspi->ctlr);
return tx_len;
}
static int aic_spi_bit_mode_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *t)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->controller);
void __iomem *base_addr = aicspi->base_addr;
u8 *tx_buf = (u8 *)t->tx_buf;
u8 *rx_buf = (u8 *)t->rx_buf;
u8 bits_per_word = t->bits_per_word;
dev_dbg(aicspi->dev,
"spi-%d: begin bit transfer, txbuf 0x%lx, rxbuf 0x%lx, len %d\n",
spi->controller->bus_num, (unsigned long)tx_buf,
(unsigned long)rx_buf, t->len);
if ((!t->tx_buf && !t->rx_buf) || !t->len) {
dev_err(aicspi->dev, "invalid bit mode parameters\n");
return -EINVAL;
}
spi_ctlr_bit_mode_set_clk(t->speed_hz, clk_get_rate(aicspi->mclk),
base_addr);
if (t->tx_buf)
spi_ctlr_bit_mode_write(aicspi, (unsigned char *)t->tx_buf,
t->len, t->speed_hz, bits_per_word);
if (t->rx_buf)
spi_ctlr_bit_mode_read(aicspi, t->rx_buf, t->len, t->speed_hz,
bits_per_word);
return 1; /* In progress */
}
static inline u32 spi_ctlr_set_clk(u32 spiclk, u32 mclk, void __iomem *base_addr)
{
u32 val, cdr, div;
u32 freq = 0;
/*
* mclk: module source clock
* spiclk: expected spi working clock
*
* Need to calculate divider parameter to generate spiclk in spi
* controller
*/
cdr = spi_get_best_div_param(spiclk, mclk, &div);
val = readl(base_addr + SPI_REG_CCR);
val &= ~CCR_BIT_MSK;
if (cdr == 0) {
val &= ~(CCR_BIT_CDR1_MSK | CCR_BIT_DRS);
val |= (div << CCR_BIT_CDR1_OFF);
freq = mclk >> div;
} else {
val &= ~CCR_BIT_CDR2_MSK;
val |= CCR_BIT_DRS;
freq = mclk / (2 * (div + 1));
}
writel(val, base_addr + SPI_REG_CCR);
return freq;
}
static inline void spi_ctlr_start_xfer(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_TCR);
val |= TCR_BIT_XCH;
writel(val, base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_enable_bus(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_GCR);
val |= GCR_BIT_EN;
writel(val, base_addr + SPI_REG_GCR);
}
static inline void spi_ctlr_disable_bus(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_GCR);
val &= ~GCR_BIT_EN;
writel(val, base_addr + SPI_REG_GCR);
}
static inline void spi_ctlr_set_master_mode(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_GCR);
val |= GCR_BIT_MODE;
writel(val, base_addr + SPI_REG_GCR);
}
static inline void spi_ctlr_enable_tp(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_GCR);
val |= GCR_BIT_PAUSE;
writel(val, base_addr + SPI_REG_GCR);
}
static inline void spi_ctlr_set_cs_level(struct aic_spi *aicspi, bool level)
{
u32 reg_val = readl(aicspi->base_addr + SPI_REG_TCR);
if (level)
reg_val |= TCR_BIT_SS_LEVEL;
else
reg_val &= ~TCR_BIT_SS_LEVEL;
writel(reg_val, aicspi->base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_set_cs_enable(struct aic_spi *aicspi, bool enable)
{
u32 reg_val = readl(aicspi->base_addr + SPI_REG_TCR);
bool high_active, level;
high_active = !(reg_val & TCR_BIT_SPOL);
if (high_active)
level = enable;
else
level = !enable;
if (level)
reg_val |= TCR_BIT_SS_LEVEL;
else
reg_val &= ~TCR_BIT_SS_LEVEL;
writel(reg_val, aicspi->base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_set_cs_pol(struct aic_spi *aicspi, bool high_active)
{
u32 reg_val = readl(aicspi->base_addr + SPI_REG_TCR);
if (high_active)
reg_val &= ~TCR_BIT_SPOL;
else
reg_val |= TCR_BIT_SPOL;
writel(reg_val, aicspi->base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_soft_reset(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_GCR);
val |= GCR_BIT_SRST;
writel(val, base_addr + SPI_REG_GCR);
}
static inline void spi_ctlr_irq_enable(u32 bitmap, void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_ICR);
bitmap &= ICR_BIT_ALL_MSK;
val |= bitmap;
writel(val, base_addr + SPI_REG_ICR);
}
static inline void spi_ctlr_irq_disable(u32 bitmap, void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_ICR);
bitmap &= ICR_BIT_ALL_MSK;
val &= ~bitmap;
writel(val, base_addr + SPI_REG_ICR);
}
static inline void spi_ctlr_dma_tx_enable(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_FCR);
val |= FCR_BIT_TX_DMA_EN;
writel(val, base_addr + SPI_REG_FCR);
}
static inline void spi_ctlr_dma_rx_enable(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_FCR);
val |= FCR_BIT_RX_DMA_EN;
writel(val, base_addr + SPI_REG_FCR);
}
static inline void spi_ctlr_dma_irq_disable(u32 bitmap, void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_FCR);
bitmap &= FCR_BIT_DMA_EN_MSK;
val &= ~bitmap;
writel(val, base_addr + SPI_REG_FCR);
}
static inline u32 spi_ctlr_pending_irq_query(void __iomem *base_addr)
{
return (ISR_BIT_ALL_MSK & readl(base_addr + SPI_REG_ISR));
}
static inline void spi_ctlr_pending_irq_clr(u32 pending_bit,
void __iomem *base_addr)
{
pending_bit &= ISR_BIT_ALL_MSK;
writel(pending_bit, base_addr + SPI_REG_ISR);
}
static inline u32 spi_ctlr_txfifo_query(void __iomem *base_addr)
{
u32 val = (FSR_BIT_TX_CNT_MSK & readl(base_addr + SPI_REG_FSR));
val >>= FSR_BIT_TXCNT_OFF;
return val;
}
static inline u32 spi_ctlr_rxfifo_query(void __iomem *base_addr)
{
u32 val = (FSR_BIT_RX_CNT_MSK & readl(base_addr + SPI_REG_FSR));
val >>= FSR_BIT_RXCNT_OFF;
return val;
}
static inline void spi_ctlr_reset_fifo(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_FCR);
val |= (FCR_BIT_RX_RST | FCR_BIT_TX_RST);
/* Set the trigger level of RxFIFO/TxFIFO. */
val &= ~(FCR_BIT_RX_LEVEL_MSK | FCR_BIT_TX_LEVEL_MSK);
val |= (0x10 << 16) | 0x30;
writel(val, base_addr + SPI_REG_FCR);
}
static inline void spi_ctlr_set_xfer_cnt(void __iomem *base_addr, u32 tx_len,
u32 rx_len, u32 single_len, u32 dummy_cnt)
{
u32 val = readl(base_addr + SPI_REG_BCR);
/* Total transfer length */
val &= ~BCR_BIT_CNT_MSK;
val |= (BCR_BIT_CNT_MSK & (tx_len + rx_len + dummy_cnt));
writel(val, base_addr + SPI_REG_BCR);
/* Total send data length */
val = readl(base_addr + SPI_REG_MTC);
val &= ~MTC_BIT_CNT_MSK;
val |= (MTC_BIT_CNT_MSK & tx_len);
writel(val, base_addr + SPI_REG_MTC);
/*
* Special configuration:
* # Data length need to send in single mode
* - If the transfer is already single mode, the STC length should be
* the same with total send data length
* - If the transfer is DUAL/QUAD mode, the STC specifies the length
* that need to send out in single mode, usually for cmd,addr,...
* # Dummy count for DUAL/QUAD mode
* - DBC specifies how many dummy burst should be sent before receive
* data in DUAL/QUAD mode
*/
val = readl(base_addr + SPI_REG_BCC);
val &= ~BCC_BIT_STC_MSK;
val |= (BCC_BIT_STC_MSK & single_len);
val &= ~(0xf << 24);
val |= (dummy_cnt << 24);
writel(val, base_addr + SPI_REG_BCC);
}
static inline void spi_ctlr_set_ss_owner(void __iomem *base_addr,
bool soft_ctrl)
{
u32 val = readl(base_addr + SPI_REG_TCR);
if (soft_ctrl)
val |= TCR_BIT_SS_OWNER;
else
val &= ~TCR_BIT_SS_OWNER;
writel(val, base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_set_receive_all_burst(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_TCR);
val &= ~TCR_BIT_DHB;
writel(val, base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_dual_disable(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_BCC);
val &= ~BCC_BIT_DUAL_MODE;
writel(val, base_addr + SPI_REG_BCC);
}
static inline void spi_ctlr_dual_enable(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_BCC);
val |= BCC_BIT_DUAL_MODE;
writel(val, base_addr + SPI_REG_BCC);
}
static inline void spi_ctlr_quad_disable(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_BCC);
val &= ~BCC_BIT_QUAD_MODE;
writel(val, base_addr + SPI_REG_BCC);
}
static inline void spi_ctlr_set_tx_delay_mode(void __iomem *base_addr, bool en)
{
u32 val = readl(base_addr + SPI_REG_TCR);
if (en)
val |= (TCR_BIT_SDDM);
else
val &= ~(TCR_BIT_SDDM);
writel(val, base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_set_rx_delay_mode(void __iomem *base_addr, int mode)
{
u32 val = readl(base_addr + SPI_REG_TCR);
val &= ~TCR_RX_SAMPDLY_MSK;
if (mode == RX_SAMP_DLY_NONE) {
val |= TCR_RX_SAMPDLY_NONE;
} else if (mode == RX_SAMP_DLY_HALF_CYCLE) {
val |= TCR_RX_SAMPDLY_HALF;
} else {
val |= TCR_RX_SAMPDLY_ONE;
}
writel(val, base_addr + SPI_REG_TCR);
}
static inline void spi_ctlr_quad_enable(void __iomem *base_addr)
{
u32 val = readl(base_addr + SPI_REG_BCC);
val |= BCC_BIT_QUAD_MODE;
writel(val, base_addr + SPI_REG_BCC);
}
static int spi_regulator_request(struct aic_spi_platform_data *pdata)
{
struct regulator *regu = NULL;
if (pdata->regulator != NULL)
return 0;
/* Consider "n*" as nocare. Support "none", "nocare", "null", "" etc. */
if ((pdata->regulator_id[0] == 'n') || (pdata->regulator_id[0] == 0))
return 0;
regu = regulator_get(NULL, pdata->regulator_id);
if (IS_ERR(regu))
return -1;
pdata->regulator = regu;
return 0;
}
static void spi_regulator_release(struct aic_spi_platform_data *pdata)
{
if (pdata->regulator == NULL)
return;
regulator_put(pdata->regulator);
pdata->regulator = NULL;
}
static int spi_regulator_enable(struct aic_spi_platform_data *pdata)
{
if (pdata->regulator == NULL)
return 0;
if (regulator_enable(pdata->regulator) != 0)
return -1;
return 0;
}
static int spi_regulator_disable(struct aic_spi_platform_data *pdata)
{
if (pdata->regulator == NULL)
return 0;
if (regulator_disable(pdata->regulator) != 0)
return -1;
return 0;
}
static void aic_spi_dma_cb_rx(void *data)
{
struct aic_spi *aicspi = (struct aic_spi *)data;
spi_ctlr_dma_irq_disable(FCR_BIT_RX_DMA_EN, aicspi->base_addr);
spi_finalize_current_transfer(aicspi->ctlr);
}
static void aic_spi_dma_cb_tx(void *data)
{
/* do nothing */
}
static int aic_spi_dma_rx_cfg(struct aic_spi *aicspi, struct scatterlist *sgl,
unsigned int sg_len)
{
struct dma_async_tx_descriptor *dma_desc = NULL;
struct dma_slave_config dma_conf = {0};
dma_conf.direction = DMA_DEV_TO_MEM;
dma_conf.src_addr = aicspi->dma_addr_rx;
dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_conf.src_maxburst = 1;
dma_conf.dst_maxburst = 1;
dmaengine_slave_config(aicspi->dma_rx, &dma_conf);
dma_desc = dmaengine_prep_slave_sg(aicspi->dma_rx, sgl, sg_len,
dma_conf.direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc) {
dev_err(aicspi->dev, "spi-%d prepare slave sg failed.\n",
aicspi->ctlr->bus_num);
return -EINVAL;
}
dma_desc->callback = aic_spi_dma_cb_rx;
dma_desc->callback_param = (void *)aicspi;
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id > 0)
#endif
dmaengine_submit(dma_desc);
return 0;
}
static int aic_spi_dma_tx_cfg(struct aic_spi *aicspi, struct scatterlist *sgl,
unsigned int sg_len)
{
struct dma_async_tx_descriptor *dma_desc = NULL;
struct dma_slave_config dma_conf = {0};
dma_conf.direction = DMA_MEM_TO_DEV;
dma_conf.dst_addr = aicspi->dma_addr_tx;
dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_conf.src_maxburst = 1;
dma_conf.dst_maxburst = 1;
dmaengine_slave_config(aicspi->dma_tx, &dma_conf);
dma_desc = dmaengine_prep_slave_sg(aicspi->dma_tx, sgl, sg_len,
dma_conf.direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc) {
dev_err(aicspi->dev, "spi-%d prepare slave sg failed.\n",
aicspi->ctlr->bus_num);
return -EINVAL;
}
dma_desc->callback = aic_spi_dma_cb_tx;
dma_desc->callback_param = (void *)aicspi;
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id > 0)
#endif
dmaengine_submit(dma_desc);
return 0;
}
static int spi_ctlr_cfg_single(struct aic_spi *aicspi, struct spi_transfer *t)
{
unsigned long flags = 0;
pr_debug("%s, xfer len %d\n", __func__, t->len);
spin_lock_irqsave(&aicspi->lock, flags);
spi_ctlr_dual_disable(aicspi->base_addr);
spi_ctlr_quad_disable(aicspi->base_addr);
if (t->tx_buf && t->rx_buf) {
/* full duplex */
spi_ctlr_set_receive_all_burst(aicspi->base_addr);
spi_ctlr_set_xfer_cnt(aicspi->base_addr, t->len, 0, t->len, 0);
aicspi->mode_type = SINGLE_FULL_DUPLEX_RX_TX;
} else if (t->tx_buf) {
/* half duplex transmit(single mode) */
spi_ctlr_set_xfer_cnt(aicspi->base_addr, t->len, 0, t->len, 0);
aicspi->mode_type = SINGLE_HALF_DUPLEX_TX;
} else if (t->rx_buf) {
/* half duplex receive(single mode) */
spi_ctlr_set_xfer_cnt(aicspi->base_addr, 0, t->len, 0, 0);
aicspi->mode_type = SINGLE_HALF_DUPLEX_RX;
}
spin_unlock_irqrestore(&aicspi->lock, flags);
return 0;
}
static int spi_ctlr_cfg_dual(struct aic_spi *aicspi, struct spi_transfer *t)
{
unsigned long flags = 0;
pr_debug("%s, xfer len %d\n", __func__, t->len);
spin_lock_irqsave(&aicspi->lock, flags);
spi_ctlr_dual_enable(aicspi->base_addr);
if (t->tx_buf) {
spi_ctlr_set_xfer_cnt(aicspi->base_addr, t->len, 0, 0, 0);
aicspi->mode_type = DUAL_HALF_DUPLEX_TX;
} else if (t->rx_buf) {
spi_ctlr_set_xfer_cnt(aicspi->base_addr, 0, t->len, 0, 0);
aicspi->mode_type = DUAL_HALF_DUPLEX_RX;
}
spin_unlock_irqrestore(&aicspi->lock, flags);
return 0;
}
static int spi_ctlr_cfg_quad(struct aic_spi *aicspi, struct spi_transfer *t)
{
unsigned long flags = 0;
pr_debug("%s, xfer len %d\n", __func__, t->len);
spin_lock_irqsave(&aicspi->lock, flags);
spi_ctlr_quad_enable(aicspi->base_addr);
if (t->tx_buf) {
spi_ctlr_set_xfer_cnt(aicspi->base_addr, t->len, 0, 0, 0);
aicspi->mode_type = QUAD_HALF_DUPLEX_TX;
} else if (t->rx_buf) {
spi_ctlr_set_xfer_cnt(aicspi->base_addr, 0, t->len, 0, 0);
aicspi->mode_type = QUAD_HALF_DUPLEX_RX;
}
spin_unlock_irqrestore(&aicspi->lock, flags);
return 0;
}
static void spi_ctlr_set_rx_delay(struct aic_spi *aicspi, u32 speed_hz)
{
void __iomem *base_addr = aicspi->base_addr;
int rxdlymode = RX_SAMP_DLY_NONE;
if (aicspi->rx_samp_dly == RX_SAMP_DLY_AUTO) {
if (speed_hz <= 24000000)
rxdlymode = RX_SAMP_DLY_NONE;
else if (speed_hz <= 60000000)
rxdlymode = RX_SAMP_DLY_HALF_CYCLE;
else
rxdlymode = RX_SAMP_DLY_ONE_CYCLE;
} else if (aicspi->rx_samp_dly == RX_SAMP_DLY_NONE) {
rxdlymode = RX_SAMP_DLY_NONE;
} else if (aicspi->rx_samp_dly == RX_SAMP_DLY_HALF_CYCLE) {
rxdlymode = RX_SAMP_DLY_HALF_CYCLE;
} else {
rxdlymode = RX_SAMP_DLY_ONE_CYCLE;
}
spi_ctlr_set_rx_delay_mode(base_addr, rxdlymode);
}
static int spi_ctlr_cfg_xfer(struct aic_spi *aicspi, struct spi_device *spi,
struct spi_transfer *t)
{
void __iomem *base_addr = aicspi->base_addr;
if (aicspi->mode_type != MODE_TYPE_NULL)
return -EINVAL;
/* DUPLEX_TX_RX mode, use TX setting */
if (t->tx_buf) {
if ((spi->mode & SPI_TX_DUAL) && (t->tx_nbits == 2))
spi_ctlr_cfg_dual(aicspi, t);
else if ((spi->mode & SPI_TX_QUAD) && (t->tx_nbits == 4))
spi_ctlr_cfg_quad(aicspi, t);
else
spi_ctlr_cfg_single(aicspi, t);
} else if (t->rx_buf) {
if ((spi->mode & SPI_RX_DUAL) && (t->rx_nbits == 2))
spi_ctlr_cfg_dual(aicspi, t);
else if ((spi->mode & SPI_RX_QUAD) && (t->rx_nbits == 4))
spi_ctlr_cfg_quad(aicspi, t);
else
spi_ctlr_cfg_single(aicspi, t);
}
if (aicspi->freq_dividor != 0)
aicspi->freq = spi_ctlr_set_clk(aicspi->freq, clk_get_rate(aicspi->mclk),
base_addr);
else
aicspi->freq = spi_ctlr_set_clk(t->speed_hz, clk_get_rate(aicspi->mclk),
base_addr);
spi_ctlr_set_rx_delay(aicspi, aicspi->freq);
return 0;
}
static bool spi_check_timeout_one_seconed(unsigned long jiffies0)
{
unsigned long timeout;
timeout = jiffies0 + msecs_to_jiffies(1000);
return time_after(jiffies, timeout);
}
#define check_timeout_1s(a) \
do { \
if (spi_check_timeout_one_seconed(a)) { \
dev_err(aicspi->dev, "%d cpu transfer data time out!\n", __LINE__); \
return -1; \
} \
} while (0)
static int spi_ctlr_fifo_read(struct aic_spi *aicspi, unsigned char *rx_buf,
unsigned int rx_len)
{
void __iomem *base_addr = aicspi->base_addr;
unsigned long jiffies0;
unsigned int dolen;
while (rx_len) {
jiffies0 = jiffies;
while (!spi_ctlr_rxfifo_query(base_addr))
check_timeout_1s(jiffies0);
dolen = spi_ctlr_rxfifo_query(base_addr);
while (dolen) {
*rx_buf++ = readb(base_addr + SPI_REG_RXDATA);
--dolen;
--rx_len;
}
}
return 0;
}
static int spi_ctlr_fifo_write(struct aic_spi *aicspi,
const unsigned char *tx_buf, unsigned int tx_len)
{
void __iomem *base_addr = aicspi->base_addr;
unsigned long flags = 0;
unsigned long jiffies0;
unsigned int fifo_len;
unsigned int dolen;
spin_lock_irqsave(&aicspi->lock, flags);
while (tx_len) {
jiffies0 = jiffies;
while (spi_ctlr_txfifo_query(base_addr) > (SPI_FIFO_DEPTH / 2))
check_timeout_1s(jiffies0);
fifo_len = SPI_FIFO_DEPTH - spi_ctlr_txfifo_query(base_addr);
dolen = min(fifo_len, tx_len);
while (dolen) {
writeb(*tx_buf++, base_addr + SPI_REG_TXDATA);
tx_len--;
dolen--;
}
}
spin_unlock_irqrestore(&aicspi->lock, flags);
jiffies0 = jiffies;
while (spi_ctlr_txfifo_query(base_addr))
check_timeout_1s(jiffies0);
return 0;
}
static int spi_ctlr_fifo_write_read(struct aic_spi *aicspi,
const unsigned char *tx_buf, unsigned char *rx_buf, unsigned int len)
{
void __iomem *base_addr = aicspi->base_addr;
unsigned int dolen, temp_cnt;
unsigned long flags = 0;
unsigned long jiffies0;
unsigned int free_len;
spin_lock_irqsave(&aicspi->lock, flags);
while (len) {
jiffies0 = jiffies;
while (spi_ctlr_txfifo_query(base_addr) > (SPI_FIFO_DEPTH / 2))
check_timeout_1s(jiffies0);
free_len = SPI_FIFO_DEPTH - spi_ctlr_txfifo_query(base_addr);
dolen = min(free_len, len);
temp_cnt = dolen;
while (temp_cnt) {
writeb(*tx_buf++, base_addr + SPI_REG_TXDATA);
temp_cnt--;
}
temp_cnt = dolen;
jiffies0 = jiffies;
while (spi_ctlr_rxfifo_query(base_addr) != dolen)
check_timeout_1s(jiffies0);
while (temp_cnt) {
*rx_buf++ = readb(base_addr + SPI_REG_RXDATA);
temp_cnt--;
len--;
}
}
spin_unlock_irqrestore(&aicspi->lock, flags);
jiffies0 = jiffies;
while (spi_ctlr_txfifo_query(base_addr))
check_timeout_1s(jiffies0);
return 0;
}
static int aic_spi_dma_rx_start(struct aic_spi *aicspi, struct scatterlist *sgl,
unsigned int sg_len)
{
int ret = 0;
spi_ctlr_dma_rx_enable(aicspi->base_addr);
ret = aic_spi_dma_rx_cfg(aicspi, sgl, sg_len);
if (ret < 0)
return ret;
dma_async_issue_pending(aicspi->dma_rx);
return ret;
}
static int aic_spi_dma_tx_start(struct aic_spi *aicspi, struct scatterlist *sgl,
unsigned int sg_len)
{
int ret = 0;
spi_ctlr_dma_tx_enable(aicspi->base_addr);
ret = aic_spi_dma_tx_cfg(aicspi, sgl, sg_len);
if (ret < 0)
return ret;
dma_async_issue_pending(aicspi->dma_tx);
return ret;
}
static bool aic_spi_use_dma(struct aic_spi *aicspi, const void *tx_buf,
void *rx_buf, unsigned int len)
{
/* Data length with DMA, should be 4 byte aligned. */
if ((len <= SPI_FIFO_DEPTH) || (len % 4))
return false;
/* Buffers for DMA transactions must be 8 Byte aligned */
if ((unsigned long)tx_buf % 8 != 0 || (unsigned long)rx_buf % 8 != 0)
return false;
if (!aicspi->dma_rx || !aicspi->dma_tx)
return false;
return true;
}
static bool aic_spi_can_dma(struct spi_controller *ctlr, struct spi_device *spi,
struct spi_transfer *t)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->master);
return aic_spi_use_dma(aicspi, t->tx_buf, t->rx_buf, t->len);
}
static int aic_spi_data_xfer(struct spi_device *spi, struct spi_transfer *t)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->master);
void __iomem *base_addr = aicspi->base_addr;
unsigned int tx_len = t->len;
unsigned int rx_len = t->len;
switch (aicspi->mode_type) {
case SINGLE_HALF_DUPLEX_RX:
case DUAL_HALF_DUPLEX_RX:
case QUAD_HALF_DUPLEX_RX:
{
if (aic_spi_use_dma(aicspi, t->tx_buf, t->rx_buf, t->len)) {
dev_dbg(aicspi->dev, "rx -> by dma, len %d\n", rx_len);
spi_ctlr_irq_disable(ICR_BIT_TC, base_addr);
aic_spi_dma_rx_start(aicspi, t->rx_sg.sgl, t->rx_sg.nents);
spi_ctlr_start_xfer(base_addr);
} else {
dev_dbg(aicspi->dev, "rx -> by fifo, len %d\n", rx_len);
spi_ctlr_start_xfer(base_addr);
spi_ctlr_fifo_read(aicspi, t->rx_buf, t->len);
}
break;
}
case SINGLE_HALF_DUPLEX_TX:
case DUAL_HALF_DUPLEX_TX:
case QUAD_HALF_DUPLEX_TX:
{
if (aic_spi_use_dma(aicspi, t->tx_buf, t->rx_buf, t->len)) {
dev_dbg(aicspi->dev, "tx -> by dma, len %d\n", tx_len);
spi_ctlr_start_xfer(base_addr);
aic_spi_dma_tx_start(aicspi, t->tx_sg.sgl, t->tx_sg.nents);
} else {
dev_dbg(aicspi->dev, "tx -> by fifo, len %d\n", tx_len);
spi_ctlr_start_xfer(base_addr);
spi_ctlr_fifo_write(aicspi, t->tx_buf, t->len);
}
break;
}
case SINGLE_FULL_DUPLEX_RX_TX:
{
if ((rx_len == 0) || (tx_len == 0))
return -EINVAL;
if (aic_spi_use_dma(aicspi, t->tx_buf, t->rx_buf, t->len)) {
dev_dbg(aicspi->dev, "rx and tx -> by dma\n");
spi_ctlr_irq_disable(ICR_BIT_TC, base_addr);
aic_spi_dma_tx_start(aicspi, t->tx_sg.sgl, t->tx_sg.nents);
spi_ctlr_start_xfer(base_addr);
aic_spi_dma_rx_start(aicspi, t->rx_sg.sgl, t->rx_sg.nents);
} else {
dev_dbg(aicspi->dev, "rx and tx -> by fifo\n");
spi_ctlr_start_xfer(base_addr);
spi_ctlr_fifo_write_read(aicspi, t->tx_buf, t->rx_buf, t->len);
}
break;
}
default:
return -1;
}
return 0;
}
static irqreturn_t aic_spi_handle_irq(int irq, void *dev_id)
{
struct aic_spi *aicspi = (struct aic_spi *)dev_id;
void __iomem *base_addr = aicspi->base_addr;
unsigned int status = 0;
unsigned long flags = 0;
spin_lock_irqsave(&aicspi->lock, flags);
status = spi_ctlr_pending_irq_query(base_addr);
spi_ctlr_pending_irq_clr(status, base_addr);
dev_dbg(aicspi->dev, "spi-%d: irq status = %x\n", aicspi->ctlr->bus_num,
status);
/* master mode, Transfer Complete Interrupt */
if (status & ISR_BIT_TC) {
dev_dbg(aicspi->dev, "spi-%d: SPI TC comes\n",
aicspi->ctlr->bus_num);
spi_ctlr_irq_disable(ISR_BIT_TC | ISR_BIT_ERRS, base_addr);
/* the callback of tx dma done is slower disable TF_DREQ_EN now */
spi_ctlr_dma_irq_disable(FCR_BIT_TX_DMA_EN, aicspi->base_addr);
spi_finalize_current_transfer(aicspi->ctlr);
spin_unlock_irqrestore(&aicspi->lock, flags);
return IRQ_HANDLED;
} else if (status & ISR_BIT_ERRS) {
dev_err(aicspi->dev, "spi-%d: SPI ERR 0x%x comes\n",
aicspi->ctlr->bus_num, status);
spi_ctlr_irq_disable(ISR_BIT_TC | ISR_BIT_ERRS, base_addr);
spi_ctlr_soft_reset(base_addr);
spi_finalize_current_transfer(aicspi->ctlr);
spin_unlock_irqrestore(&aicspi->lock, flags);
return IRQ_HANDLED;
}
dev_dbg(aicspi->dev, "spi-%d: SPI interrupt comes\n",
aicspi->ctlr->bus_num);
spin_unlock_irqrestore(&aicspi->lock, flags);
return IRQ_NONE;
}
static size_t aic_spi_max_transfer_size(struct spi_device *spi)
{
return AIC_SPI_MAX_XFER_SIZE - 1;
}
static int aic_spi_byte_mode_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *t)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->controller);
void __iomem *base_addr = aicspi->base_addr;
u8 *tx_buf = (u8 *)t->tx_buf;
u8 *rx_buf = (u8 *)t->rx_buf;
dev_dbg(aicspi->dev,
"spi-%d: begin transfer, txbuf 0x%lx, rxbuf 0x%lx, len %d\n",
spi->controller->bus_num, (unsigned long)tx_buf,
(unsigned long)rx_buf, t->len);
if ((!t->tx_buf && !t->rx_buf) || !t->len) {
dev_err(aicspi->dev, "invalid parameters\n");
return -EINVAL;
}
spi_ctlr_pending_irq_clr(ISR_BIT_ALL_MSK, base_addr);
spi_ctlr_dma_irq_disable(FCR_BIT_DMA_EN_MSK, base_addr);
spi_ctlr_reset_fifo(base_addr);
if (spi_ctlr_cfg_xfer(aicspi, spi, t)) {
dev_err(aicspi->dev, "transfer configuration failed.\n");
return -EINVAL;
}
spi_ctlr_irq_enable(ICR_BIT_TC | ICR_BIT_ERRS, base_addr);
aic_spi_data_xfer(spi, t);
if (aicspi->mode_type != MODE_TYPE_NULL)
aicspi->mode_type = MODE_TYPE_NULL;
return 1; /* In progress */
}
static int aic_spi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *t)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->controller);
if (aicspi->bit_mode)
return aic_spi_bit_mode_transfer_one(ctlr, spi, t);
else
return aic_spi_byte_mode_transfer_one(ctlr, spi, t);
}
static void aic_spi_set_cs(struct spi_device *spi, bool high)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->controller);
if (aicspi->bit_mode)
spi_ctlr_bit_mode_set_cs_level(aicspi, high);
else
spi_ctlr_set_cs_level(aicspi, high);
}
static int aic_spi_setup(struct spi_device *spi)
{
struct aic_spi *aicspi = spi_controller_get_devdata(spi->master);
unsigned long flags;
u32 val;
/* Only support 8 bits per word */
if (spi->bits_per_word != 8) {
dev_err(aicspi->dev, "bits_per_word is not supportted.\n");
return -EINVAL;
}
if (spi->max_speed_hz > SPI_MAX_FREQUENCY) {
dev_err(aicspi->dev, "max_speed_hz is too large %d.\n",
spi->max_speed_hz);
return -EINVAL;
}
val = (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL));
if ((val > 0) && val != (SPI_TX_DUAL | SPI_RX_DUAL)) {
dev_warn(aicspi->dev, "TX RX bus width should be the same.\n");
spi->mode &= ~(SPI_TX_DUAL | SPI_RX_DUAL);
}
val = (spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD));
if ((val > 0) && val != (SPI_TX_QUAD | SPI_RX_QUAD)) {
dev_warn(aicspi->dev, "TX RX bus width should be the same.\n");
spi->mode &= ~(SPI_TX_QUAD | SPI_RX_QUAD);
}
#ifdef SUPPORT_SPI_3WIRE_IN_BIT_MODE
if (spi->mode & SPI_3WIRE)
aicspi->bit_mode = true;
else
aicspi->bit_mode = false;
#endif
spin_lock_irqsave(&aicspi->lock, flags);
if (aicspi->bit_mode) {
spi_ctlr_set_work_mode(aicspi->base_addr, BTC_BIT_WM_BIT_3WIRE);
/* set chip select number */
spi_ctlr_bit_mode_set_cs_num(spi->chip_select,
aicspi->base_addr);
if (spi->mode & SPI_CS_HIGH)
spi_ctlr_bit_mode_set_cs_pol(aicspi, true);
else
spi_ctlr_bit_mode_set_cs_pol(aicspi, false);
} else {
spi_ctlr_set_work_mode(aicspi->base_addr, BTC_BIT_WM_BYTE);
spi_cltr_cfg_tc(spi->mode, aicspi->base_addr);
/* set chip select number */
spi_ctlr_set_cs_num(spi->chip_select, aicspi->base_addr);
if (spi->mode & SPI_CS_HIGH)
spi_ctlr_set_cs_pol(aicspi, true);
else
spi_ctlr_set_cs_pol(aicspi, false);
}
spin_unlock_irqrestore(&aicspi->lock, flags);
return 0;
}
static int aic_spi_clk_init(struct aic_spi *aicspi, u32 src_clk)
{
long rate = 0;
aicspi->mclk = of_clk_get(aicspi->dev->of_node, 0);
if (IS_ERR_OR_NULL(aicspi->mclk)) {
dev_err(aicspi->dev, "spi-%d Unable to acquire module clock\n",
aicspi->ctlr->bus_num);
return -1;
}
rate = clk_round_rate(aicspi->mclk, src_clk);
if (clk_set_rate(aicspi->mclk, rate)) {
dev_err(aicspi->dev, "spi-%d spi clk_set_rate failed\n",
aicspi->ctlr->bus_num);
return -1;
}
dev_dbg(aicspi->dev, "spi-%d mclk %u\n", aicspi->ctlr->bus_num,
(unsigned int)clk_get_rate(aicspi->mclk));
if (clk_prepare_enable(aicspi->mclk)) {
dev_err(aicspi->dev, "spi-%d enable module clock failed.\n",
aicspi->ctlr->bus_num);
return -EBUSY;
}
return clk_get_rate(aicspi->mclk);
}
static int aic_spi_clk_exit(struct aic_spi *aicspi)
{
if (IS_ERR_OR_NULL(aicspi->mclk)) {
dev_err(aicspi->dev, "spi-%d SPI mclk handle is invalid.\n",
aicspi->ctlr->bus_num);
return -1;
}
clk_disable_unprepare(aicspi->mclk);
clk_put(aicspi->mclk);
aicspi->mclk = NULL;
return 0;
}
static int aic_spi_hw_init(struct aic_spi *aicspi,
struct aic_spi_platform_data *pdata)
{
void __iomem *base_addr = aicspi->base_addr;
u32 src_clk = 0;
int ret;
if (spi_regulator_request(pdata) < 0) {
dev_err(aicspi->dev, "spi-%d request regulator failed!\n",
aicspi->ctlr->bus_num);
return -1;
}
spi_regulator_enable(pdata);
ret = of_property_read_u32(aicspi->dev->of_node, "spi-max-frequency",
&src_clk);
if (ret) {
dev_err(aicspi->dev, "spi-%d Get spi-max-frequency failed\n",
aicspi->ctlr->bus_num);
return -1;
}
src_clk = aic_spi_clk_init(aicspi, src_clk);
if (src_clk < 0) {
dev_err(aicspi->dev, "spi-%d aic_spi_clk_init(%s) failed.\n",
aicspi->ctlr->bus_num, aicspi->dev_name);
return -1;
}
aicspi->rst = devm_reset_control_get_exclusive(aicspi->dev, NULL);
if (!IS_ERR(aicspi->rst)) {
reset_control_assert(aicspi->rst);
udelay(2);
reset_control_deassert(aicspi->rst);
}
spi_ctlr_enable_bus(base_addr);
spi_ctlr_set_cs_num(0, base_addr);
spi_ctlr_set_master_mode(base_addr);
aicspi->freq = spi_ctlr_set_clk(24000000, src_clk, base_addr);
spi_cltr_cfg_tc(SPI_MODE_0, base_addr);
spi_ctlr_set_tx_delay_mode(base_addr, true);
spi_ctlr_enable_tp(base_addr);
spi_ctlr_set_ss_owner(base_addr, true);
spi_ctlr_bit_mode_set_ss_owner(aicspi->base_addr, true);
spi_ctlr_reset_fifo(base_addr);
return 0;
}
static int aic_spi_hw_exit(struct aic_spi *aicspi,
struct aic_spi_platform_data *pdata)
{
spi_ctlr_disable_bus(aicspi->base_addr);
aic_spi_clk_exit(aicspi);
spi_regulator_disable(pdata);
spi_regulator_release(pdata);
return 0;
}
static ssize_t aic_spi_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aic_spi_platform_data *pdata;
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
pdata = dev->platform_data;
return snprintf(buf, PAGE_SIZE,
"pdev->id = %d\n"
"pdev->name = %s\n"
"pdev->num_resources = %u\n"
"pdev->resource.mem = [%pa, %pa]\n"
"pdev->resource.irq = %pa\n"
"pdev->dev.platform_data.cs_num = %d\n"
"pdev->dev.platform_data.regulator = 0x%p\n"
"pdev->dev.platform_data.regulator_id = %s\n",
pdev->id, pdev->name, pdev->num_resources,
&pdev->resource[0].start, &pdev->resource[0].end,
&pdev->resource[1].start, pdata->cs_num,
pdata->regulator, pdata->regulator_id);
}
static struct device_attribute aic_spi_info_attr =
__ATTR(info, 0444, aic_spi_info_show, NULL);
static ssize_t aic_spi_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct spi_controller *ctlr;
struct aic_spi *aicspi;
char const *spi_mode[] = { "Single mode, half duplex read",
"Single mode, half duplex write",
"Single mode, full duplex read and write",
"Dual mode, half duplex read",
"Dual mode, half duplex write",
"Quad mode, half duplex read",
"Quad mode, half duplex write",
"Null" };
ctlr = spi_controller_get(platform_get_drvdata(pdev));
aicspi = spi_controller_get_devdata(ctlr);
if (ctlr == NULL)
return snprintf(buf, PAGE_SIZE, "%s\n", "controller is NULL!");
return snprintf(buf, PAGE_SIZE,
"ctlr->bus_num = %d\n"
"ctlr->num_chipselect = %d\n"
"ctlr->dma_alignment = %d\n"
"ctlr->mode_bits = %d\n"
"ctlr->flags = 0x%x, ->bus_lock_flag = 0x%x\n"
"ctlr->busy = %d, ->running = %d, ->rt = %d\n"
"aicspi->mode_type = %d [%s]\n"
"aicspi->irq = %d [%s]\n"
"aicspi->base_addr = 0x%lx, the SPI control register:\n"
"[VER] 0x%02x = 0x%08x, [GCR] 0x%02x = 0x%08x\n"
"[TCR] 0x%02x = 0x%08x, [ICR] 0x%02x = 0x%08x\n"
"[ISR] 0x%02x = 0x%08x, [FCR] 0x%02x = 0x%08x\n"
"[FSR] 0x%02x = 0x%08x, [WCR] 0x%02x = 0x%08x\n"
"[CCR] 0x%02x = 0x%08x, [BCR] 0x%02x = 0x%08x\n"
"[MTC] 0x%02x = 0x%08x, [BCC] 0x%02x = 0x%08x\n"
"[DMA] 0x%02x = 0x%08x\n",
ctlr->bus_num, ctlr->num_chipselect,
ctlr->dma_alignment, ctlr->mode_bits, ctlr->flags,
ctlr->bus_lock_flag, ctlr->busy, ctlr->running,
ctlr->rt, aicspi->mode_type,
spi_mode[aicspi->mode_type], aicspi->irq,
aicspi->dev_name, (unsigned long)aicspi->base_addr,
SPI_REG_VER, readl(aicspi->base_addr + SPI_REG_VER),
SPI_REG_GCR, readl(aicspi->base_addr + SPI_REG_GCR),
SPI_REG_TCR, readl(aicspi->base_addr + SPI_REG_TCR),
SPI_REG_ICR, readl(aicspi->base_addr + SPI_REG_ICR),
SPI_REG_ISR, readl(aicspi->base_addr + SPI_REG_ISR),
SPI_REG_FCR, readl(aicspi->base_addr + SPI_REG_FCR),
SPI_REG_FSR, readl(aicspi->base_addr + SPI_REG_FSR),
SPI_REG_WCR, readl(aicspi->base_addr + SPI_REG_WCR),
SPI_REG_CCR, readl(aicspi->base_addr + SPI_REG_CCR),
SPI_REG_BCR, readl(aicspi->base_addr + SPI_REG_BCR),
SPI_REG_MTC, readl(aicspi->base_addr + SPI_REG_MTC),
SPI_REG_BCC, readl(aicspi->base_addr + SPI_REG_BCC),
SPI_REG_DCR, readl(aicspi->base_addr + SPI_REG_DCR));
}
static struct device_attribute aic_spi_status_attr =
__ATTR(status, 0444, aic_spi_status_show, NULL);
static ssize_t freq_dividor_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct spi_controller *ctlr;
struct aic_spi *aicspi;
ctlr = spi_controller_get(platform_get_drvdata(pdev));
aicspi = spi_controller_get_devdata(ctlr);
return sprintf(buf, "%d\n", aicspi->freq_dividor);
}
static ssize_t freq_dividor_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
struct spi_controller *ctlr;
struct aic_spi *aicspi;
int new_val, ret;
ctlr = spi_controller_get(platform_get_drvdata(pdev));
aicspi = spi_controller_get_devdata(ctlr);
ret = kstrtoint(buf, 10, &new_val);
if (ret < 0) {
return ret;
}
if (new_val < 0 || new_val > 10) {
return -EINVAL;
}
if (new_val != aicspi->freq_dividor) {
void __iomem *base_addr = aicspi->base_addr;
u32 freq = 0;
if (new_val == 0)
freq = spi_ctlr_set_clk(clk_get_rate(aicspi->mclk), clk_get_rate(aicspi->mclk), base_addr);
else
freq = spi_ctlr_set_clk(clk_get_rate(aicspi->mclk) / new_val, clk_get_rate(aicspi->mclk), base_addr);
spi_ctlr_set_rx_delay(aicspi, freq);
dev_info(dev, "updata freq: %u Hz, mclk: %lu Hz\n", freq, clk_get_rate(aicspi->mclk));
aicspi->freq_dividor = new_val;
aicspi->freq = freq;
}
return count;
}
static DEVICE_ATTR_RW(freq_dividor);
static void aic_spi_register_sysfs(struct platform_device *_pdev)
{
device_create_file(&_pdev->dev, &aic_spi_info_attr);
device_create_file(&_pdev->dev, &aic_spi_status_attr);
device_create_file(&_pdev->dev, &dev_attr_freq_dividor);
}
static void aic_spi_remove_sysfs(struct platform_device *_pdev)
{
device_remove_file(&_pdev->dev, &aic_spi_info_attr);
device_remove_file(&_pdev->dev, &aic_spi_status_attr);
device_remove_file(&_pdev->dev, &dev_attr_freq_dividor);
}
bool aic_spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
#ifndef CONFIG_SPI_SUPPORT_QUADIO_ARTINCHIP
if ((op->addr.buswidth == 4) && (op->dummy.buswidth == 4) &&
(op->data.buswidth == 4))
return false;
#endif
return spi_mem_default_supports_op(mem, op);
}
/*
* Standard SPI Dual Output Dual I/O Quad Output Quad I/O QPI
* cmd 1 bit 1 bit 1 bit 1 bit 1 bit 4 bit
* addr 1 bit 1 bit 2 bit 1 bit 4 bit 4 bit
* dummy 1 bit 1 bit 2 bit 1 bit 4 bit 4 bit
* data 1 bit 2 bit 2 bit 4 bit 4 bit 4 bit
*/
static int aic_spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
u32 head_len, tx_total, tx_dlen, tx_single, rx_dlen, use_dma;
u8 tx_head[16], *rx_buf;
void __iomem *base_addr;
struct aic_spi *aicspi;
const u8 *tx_buf;
struct sg_table sg;
unsigned long mode;
unsigned long long tmo;
int ret = 0, i;
aicspi = spi_controller_get_devdata(mem->spi->controller);
base_addr = aicspi->base_addr;
head_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
tx_buf = NULL;
tx_dlen = 0;
rx_buf = NULL;
rx_dlen = 0;
if (op->data.dir == SPI_MEM_DATA_IN) {
rx_buf = op->data.buf.in;
rx_dlen = op->data.nbytes;
} else {
tx_buf = op->data.buf.out;
tx_dlen = op->data.nbytes;
}
tx_total = head_len + tx_dlen;
use_dma = aic_spi_use_dma(aicspi, tx_buf, rx_buf, op->data.nbytes);
if (op->cmd.nbytes)
memcpy(tx_head, &op->cmd.opcode, op->cmd.nbytes);
if (op->addr.nbytes) {
for (i = 0; i < op->addr.nbytes; i++)
tx_head[op->cmd.nbytes + i] = op->addr.val >>
(8 * (op->addr.nbytes - i - 1));
}
if (op->dummy.nbytes)
memset(tx_head + op->cmd.nbytes + op->addr.nbytes, 0, op->dummy.nbytes);
if (op->cmd.buswidth == 4)
mode = QPI_MODE;
else if (op->addr.buswidth == 4)
mode = QUAD_IO_MODE;
else if (op->addr.buswidth == 2)
mode = DUAL_IO_MODE;
else if (op->data.buswidth == 4)
mode = QUAD_OUTPUT_MODE;
else if (op->data.buswidth == 2)
mode = DUAL_OUTPUT_MODE;
else
mode = SINGLE_MODE;
#ifndef CONFIG_SPI_SUPPORT_QUADIO_ARTINCHIP
if ((mode == QUAD_IO_MODE) || (mode == QPI_MODE))
return -ENOTSUPP;
#endif
switch (mode) {
case SINGLE_MODE:
dev_dbg(aicspi->dev, "Single mode\n");
tx_single = tx_total;
spi_ctlr_dual_disable(base_addr);
spi_ctlr_quad_disable(base_addr);
spi_ctlr_set_xfer_cnt(base_addr, tx_total, rx_dlen, tx_single, 0);
break;
case DUAL_OUTPUT_MODE:
dev_dbg(aicspi->dev, "DUAL OUTPUT\n");
tx_single = head_len;
spi_ctlr_quad_disable(base_addr);
spi_ctlr_dual_enable(base_addr);
spi_ctlr_set_xfer_cnt(base_addr, tx_total, rx_dlen, tx_single, 0);
break;
case DUAL_IO_MODE:
dev_dbg(aicspi->dev, "DUAL I/O\n");
tx_single = op->cmd.nbytes;
spi_ctlr_quad_disable(base_addr);
spi_ctlr_dual_enable(base_addr);
spi_ctlr_set_xfer_cnt(base_addr, tx_total, rx_dlen, tx_single, 0);
break;
case QUAD_OUTPUT_MODE:
dev_dbg(aicspi->dev, "QUAD OUTPUT\n");
tx_single = head_len;//op->cmd.nbytes + op->addr.nbytes;
spi_ctlr_dual_disable(base_addr);
spi_ctlr_quad_enable(base_addr);
spi_ctlr_set_xfer_cnt(base_addr, tx_total, rx_dlen, tx_single, 0);
break;
case QUAD_IO_MODE:
dev_dbg(aicspi->dev, "QUAD I/O\n");
tx_single = op->cmd.nbytes;
spi_ctlr_dual_disable(base_addr);
spi_ctlr_quad_enable(base_addr);
spi_ctlr_set_xfer_cnt(base_addr, tx_total, rx_dlen, tx_single, 0);
break;
case QPI_MODE:
dev_dbg(aicspi->dev, "QPI\n");
tx_single = 0;
spi_ctlr_dual_disable(base_addr);
spi_ctlr_quad_enable(base_addr);
spi_ctlr_set_xfer_cnt(base_addr, tx_total, rx_dlen, tx_single, 0);
break;
}
if (aicspi->freq_dividor != 0)
aicspi->freq = spi_ctlr_set_clk(aicspi->freq, clk_get_rate(aicspi->mclk),
base_addr);
else
aicspi->freq = spi_ctlr_set_clk(mem->spi->max_speed_hz, clk_get_rate(aicspi->mclk),
base_addr);
spi_ctlr_set_rx_delay(aicspi, aicspi->freq);
spi_ctlr_set_cs_enable(aicspi, true);
spi_ctlr_pending_irq_clr(ISR_BIT_ALL_MSK, base_addr);
reinit_completion(&aicspi->ctlr->xfer_completion);
spi_ctlr_irq_enable(ICR_BIT_TC | ICR_BIT_ERRS, base_addr);
spi_ctlr_reset_fifo(base_addr);
if (use_dma) {
/* Config DMA first */
ret = spi_controller_dma_map_mem_op_data(aicspi->ctlr, op, &sg);
if (ret)
goto out;
spi_ctlr_start_xfer(base_addr);
if (head_len)
spi_ctlr_fifo_write(aicspi, tx_head, head_len);
if (rx_buf) {
/* FIFO mode xfer head, then enalbe dma to xfer data */
spi_ctlr_irq_disable(ICR_BIT_TC, base_addr);
spi_ctlr_dma_rx_enable(aicspi->base_addr);
ret = aic_spi_dma_rx_cfg(aicspi, sg.sgl, sg.nents);
if (ret < 0)
goto out;
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id == 0)
aic_ddma_transfer(aicspi->dma_rx);
else
#endif
dma_async_issue_pending(aicspi->dma_rx);
} else {
spi_ctlr_dma_tx_enable(aicspi->base_addr);
ret = aic_spi_dma_tx_cfg(aicspi, sg.sgl, sg.nents);
if (ret < 0)
goto out;
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id == 0)
aic_ddma_transfer(aicspi->dma_tx);
else
#endif
dma_async_issue_pending(aicspi->dma_tx);
}
} else {
spi_ctlr_start_xfer(base_addr);
if (head_len)
spi_ctlr_fifo_write(aicspi, tx_head, head_len);
if (tx_buf)
spi_ctlr_fifo_write(aicspi, tx_buf, tx_dlen);
if (rx_buf)
spi_ctlr_fifo_read(aicspi, rx_buf, rx_dlen);
}
tmo = 8LL * (tx_total + rx_dlen) * MSEC_PER_SEC;
do_div(tmo, mem->spi->max_speed_hz);
tmo += tmo + 200;
if (tmo > UINT_MAX)
tmo = UINT_MAX;
if (!wait_for_completion_timeout(&aicspi->ctlr->xfer_completion,
msecs_to_jiffies(tmo))) {
dev_err(aicspi->dev, "wait data xfer done timeout.\n");
ret = -ETIMEDOUT;
goto out;
}
out:
if (use_dma)
spi_controller_dma_unmap_mem_op_data(aicspi->ctlr, op, &sg);
spi_ctlr_set_cs_enable(aicspi, false);
return ret;
}
static void aic_spi_release_dma(struct aic_spi *aicspi)
{
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id == 0) {
if (aicspi->dma_rx)
aic_ddma_release_chan(aicspi->dma_rx);
if (aicspi->dma_tx)
aic_ddma_release_chan(aicspi->dma_tx);
return;
}
#endif
if (aicspi->dma_rx)
dma_release_channel(aicspi->dma_rx);
if (aicspi->dma_tx)
dma_release_channel(aicspi->dma_tx);
}
static const struct spi_controller_mem_ops aic_spi_mem_ops = {
.exec_op = aic_spi_mem_exec_op,
.supports_op = aic_spi_mem_supports_op,
};
static int aic_spi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct aic_spi_platform_data *pdata = NULL;
struct spi_controller *ctlr;
int ret = 0, err = 0, irq;
struct resource *mem_res;
struct aic_spi *aicspi;
const char *dly;
u32 num_cs = 0;
if (!np) {
dev_err(&pdev->dev, "failed to get of_node\n");
return -ENODEV;
}
pdev->id = of_alias_get_id(np, "spi");
if (pdev->id < 0) {
dev_err(&pdev->dev, "failed to get alias id\n");
return -EINVAL;
}
pdata = kzalloc(sizeof(struct aic_spi_platform_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdev->dev.platform_data = pdata;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
dev_err(&pdev->dev, "unable to get spi iomem resource\n");
ret = -ENXIO;
goto err0;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq\n");
ret = -ENXIO;
goto err0;
}
err = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
if (err) {
/* Default: only support 1 spi device on bus */
pdata->cs_num = 1;
} else {
pdata->cs_num = num_cs;
}
ctlr = spi_alloc_master(&pdev->dev, sizeof(struct aic_spi));
if (ctlr == NULL) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
ret = -ENOMEM;
goto err0;
}
platform_set_drvdata(pdev, ctlr);
aicspi = spi_controller_get_devdata(ctlr);
memset(aicspi, 0, sizeof(struct aic_spi));
aicspi->id = pdev->id;
aicspi->dev = &pdev->dev;
aicspi->ctlr = ctlr;
aicspi->irq = irq;
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id == 0)
aicspi->dma_rx = aic_ddma_request_chan(aicspi->dev, DMA_SPI0);
else
#endif
aicspi->dma_rx = dma_request_slave_channel(aicspi->dev, "rx");
if (!aicspi->dma_rx)
dev_warn(aicspi->dev, "failed to request rx dma channel\n");
else
ctlr->dma_rx = aicspi->dma_rx;
#ifdef CONFIG_ARTINCHIP_DDMA
if (aicspi->id == 0)
aicspi->dma_tx = aic_ddma_request_chan(aicspi->dev, DMA_SPI0);
else
#endif
aicspi->dma_tx = dma_request_slave_channel(aicspi->dev, "tx");
if (!aicspi->dma_tx)
dev_warn(aicspi->dev, "failed to request tx dma channel\n");
else
ctlr->dma_tx = aicspi->dma_tx;
dly = NULL;
device_property_read_string(&pdev->dev, "aic,rx-samp-dly", &dly);
aicspi->rx_samp_dly = RX_SAMP_DLY_AUTO;
if (dly && !strcmp(dly, "none"))
aicspi->rx_samp_dly = RX_SAMP_DLY_NONE;
if (dly && !strcmp(dly, "half"))
aicspi->rx_samp_dly = RX_SAMP_DLY_HALF_CYCLE;
if (dly && !strcmp(dly, "one"))
aicspi->rx_samp_dly = RX_SAMP_DLY_ONE_CYCLE;
if (aicspi->dma_tx || aicspi->dma_rx)
ctlr->can_dma = aic_spi_can_dma;
aicspi->mode_type = MODE_TYPE_NULL;
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->bus_num = pdev->id;
ctlr->num_chipselect = pdata->cs_num;
ctlr->setup = aic_spi_setup;
ctlr->use_gpio_descriptors = true;
ctlr->set_cs = aic_spi_set_cs;
ctlr->transfer_one = aic_spi_transfer_one;
ctlr->mem_ops = &aic_spi_mem_ops;
ctlr->max_transfer_size = aic_spi_max_transfer_size;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL |
SPI_RX_QUAD | SPI_3WIRE;
if (request_mem_region(mem_res->start, resource_size(mem_res),
pdev->name) == NULL) {
dev_err(&pdev->dev, "Req mem region failed\n");
ret = -ENXIO;
goto err1;
}
aicspi->base_addr = ioremap(mem_res->start, resource_size(mem_res));
if (aicspi->base_addr == NULL) {
dev_err(&pdev->dev, "unable to remap IO\n");
ret = -ENXIO;
goto err2;
}
spin_lock_init(&aicspi->lock);
snprintf(aicspi->dev_name, sizeof(aicspi->dev_name),
AIC_SPI_DEV_NAME "%d", pdev->id);
err = request_irq(aicspi->irq, aic_spi_handle_irq, 0, aicspi->dev_name,
aicspi);
if (err) {
dev_err(&pdev->dev, "request irq failed.\n");
goto err3;
}
aicspi->dma_addr_rx = mem_res->start + SPI_REG_RXDATA;
aicspi->dma_addr_tx = mem_res->start + SPI_REG_TXDATA;
pdev->dev.init_name = aicspi->dev_name;
ret = aic_spi_hw_init(aicspi, pdata);
if (ret != 0) {
dev_err(&pdev->dev, "spi hw init failed!\n");
goto err4;
}
if (spi_register_controller(ctlr)) {
dev_err(&pdev->dev, "cannot register spi controller\n");
ret = -EBUSY;
goto err5;
}
aic_spi_register_sysfs(pdev);
dev_info(&pdev->dev, "spi-%d: driver probe done.\n", ctlr->bus_num);
return 0;
err5:
aic_spi_hw_exit(aicspi, pdata);
err4:
free_irq(aicspi->irq, aicspi);
err3:
iounmap(aicspi->base_addr);
err2:
release_mem_region(mem_res->start, resource_size(mem_res));
err1:
aic_spi_release_dma(aicspi);
platform_set_drvdata(pdev, NULL);
spi_controller_put(ctlr);
err0:
kfree(pdata);
return ret;
}
static int aic_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct resource *mem_res;
struct aic_spi *aicspi;
ctlr = spi_controller_get(platform_get_drvdata(pdev));
aicspi = spi_controller_get_devdata(ctlr);
aic_spi_hw_exit(aicspi, pdev->dev.platform_data);
spi_unregister_controller(ctlr);
iounmap(aicspi->base_addr);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (mem_res != NULL)
release_mem_region(mem_res->start, resource_size(mem_res));
aic_spi_release_dma(aicspi);
platform_set_drvdata(pdev, NULL);
spi_controller_put(ctlr);
aic_spi_remove_sysfs(pdev);
kfree(pdev->dev.platform_data);
return 0;
}
#define AIC_SPI_DEV_PM_OPS NULL
static const struct of_device_id aic_spi_match[] = {
{ .compatible = "artinchip,aic-spi-v1.0", },
{},
};
MODULE_DEVICE_TABLE(of, aic_spi_match);
static struct platform_driver aic_spi_driver = {
.probe = aic_spi_probe,
.remove = aic_spi_remove,
.driver = {
.name = AIC_SPI_DEV_NAME,
.owner = THIS_MODULE,
.pm = AIC_SPI_DEV_PM_OPS,
.of_match_table = aic_spi_match,
},
};
static int __init aic_spi_init(void)
{
return platform_driver_register(&aic_spi_driver);
}
static void __exit aic_spi_exit(void)
{
platform_driver_unregister(&aic_spi_driver);
}
module_init(aic_spi_init);
module_exit(aic_spi_exit);
MODULE_AUTHOR("Dehuang Wu");
MODULE_DESCRIPTION("Artinchip SPI Bus Driver");
MODULE_ALIAS("platform:"AIC_SPI_DEV_NAME);
MODULE_LICENSE("GPL");