#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
#define SPI_CFG1_PACKET_LOOP_MASK 0xff00
#define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000
-#define SPI_CMD_ACT_OFFSET 0
-#define SPI_CMD_RESUME_OFFSET 1
-#define SPI_CMD_CPHA_OFFSET 8
-#define SPI_CMD_CPOL_OFFSET 9
-#define SPI_CMD_TXMSBF_OFFSET 12
-#define SPI_CMD_RXMSBF_OFFSET 13
-#define SPI_CMD_RX_ENDIAN_OFFSET 14
-#define SPI_CMD_TX_ENDIAN_OFFSET 15
-
+#define SPI_CMD_ACT BIT(0)
+#define SPI_CMD_RESUME BIT(1)
#define SPI_CMD_RST BIT(2)
#define SPI_CMD_PAUSE_EN BIT(4)
#define SPI_CMD_DEASSERT BIT(5)
#define MT8173_SPI_MAX_PAD_SEL 3
+#define MTK_SPI_PAUSE_INT_STATUS 0x2
+
#define MTK_SPI_IDLE 0
#define MTK_SPI_PAUSED 1
reg_val = readl(mdata->base + SPI_CMD_REG);
/* set the mlsbx and mlsbtx */
- reg_val &= ~(SPI_CMD_TXMSBF | SPI_CMD_RXMSBF);
- reg_val |= (chip_config->tx_mlsb << SPI_CMD_TXMSBF_OFFSET);
- reg_val |= (chip_config->rx_mlsb << SPI_CMD_RXMSBF_OFFSET);
+ if (chip_config->tx_mlsb)
+ reg_val |= SPI_CMD_TXMSBF;
+ else
+ reg_val &= ~SPI_CMD_TXMSBF;
+ if (chip_config->rx_mlsb)
+ reg_val |= SPI_CMD_RXMSBF;
+ else
+ reg_val &= ~SPI_CMD_RXMSBF;
/* set the tx/rx endian */
#ifdef __LITTLE_ENDIAN
#endif
/* set finish and pause interrupt always enable */
- reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_EN;
+ reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE;
/* disable dma mode */
reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA);
trans = list_first_entry(&msg->transfers, struct spi_transfer,
transfer_list);
- if (trans->cs_change == 0) {
+ if (!trans->cs_change) {
mdata->state = MTK_SPI_IDLE;
mtk_spi_reset(mdata);
}
cpol = spi->mode & SPI_CPOL ? 1 : 0;
reg_val = readl(mdata->base + SPI_CMD_REG);
- reg_val &= ~(SPI_CMD_CPHA | SPI_CMD_CPOL);
- reg_val |= (cpha << SPI_CMD_CPHA_OFFSET);
- reg_val |= (cpol << SPI_CMD_CPOL_OFFSET);
+ if (cpha)
+ reg_val |= SPI_CMD_CPHA;
+ else
+ reg_val &= ~SPI_CMD_CPHA;
+ if (cpol)
+ reg_val |= SPI_CMD_CPOL;
+ else
+ reg_val &= ~SPI_CMD_CPOL;
writel(reg_val, mdata->base + SPI_CMD_REG);
chip_config = spi->controller_data;
static void mtk_spi_prepare_transfer(struct spi_master *master,
struct spi_transfer *xfer)
{
- u32 spi_clk_hz, div, high_time, low_time, holdtime,
- setuptime, cs_idletime, reg_val = 0;
+ u32 spi_clk_hz, div, sck_time, cs_time, reg_val = 0;
struct mtk_spi *mdata = spi_master_get_devdata(master);
spi_clk_hz = clk_get_rate(mdata->spi_clk);
else
div = 1;
- high_time = (div + 1) / 2;
- low_time = (div + 1) / 2;
- holdtime = (div + 1) / 2 * 2;
- setuptime = (div + 1) / 2 * 2;
- cs_idletime = (div + 1) / 2 * 2;
+ sck_time = (div + 1) / 2;
+ cs_time = sck_time * 2;
- reg_val |= (((high_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET);
- reg_val |= (((low_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
- reg_val |= (((holdtime - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
- reg_val |= (((setuptime - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
+ reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET);
+ reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
+ reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
+ reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
writel(reg_val, mdata->base + SPI_CFG0_REG);
reg_val = readl(mdata->base + SPI_CFG1_REG);
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
- reg_val |= (((cs_idletime - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
+ reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
writel(reg_val, mdata->base + SPI_CFG1_REG);
}
u32 packet_size, packet_loop, reg_val;
struct mtk_spi *mdata = spi_master_get_devdata(master);
- packet_size = min_t(unsigned, mdata->xfer_len, MTK_SPI_PACKET_SIZE);
+ packet_size = min_t(u32, mdata->xfer_len, MTK_SPI_PACKET_SIZE);
packet_loop = mdata->xfer_len / packet_size;
reg_val = readl(mdata->base + SPI_CFG1_REG);
- reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK + SPI_CFG1_PACKET_LOOP_MASK);
+ reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK);
reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
writel(reg_val, mdata->base + SPI_CFG1_REG);
static void mtk_spi_enable_transfer(struct spi_master *master)
{
- int cmd;
+ u32 cmd;
struct mtk_spi *mdata = spi_master_get_devdata(master);
cmd = readl(mdata->base + SPI_CMD_REG);
if (mdata->state == MTK_SPI_IDLE)
- cmd |= 1 << SPI_CMD_ACT_OFFSET;
+ cmd |= SPI_CMD_ACT;
else
- cmd |= 1 << SPI_CMD_RESUME_OFFSET;
+ cmd |= SPI_CMD_RESUME;
writel(cmd, mdata->base + SPI_CMD_REG);
}
-static int mtk_spi_get_mult_delta(int xfer_len)
+static int mtk_spi_get_mult_delta(u32 xfer_len)
{
- int mult_delta;
+ u32 mult_delta;
if (xfer_len > MTK_SPI_PACKET_SIZE)
mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
struct spi_transfer *trans = mdata->cur_transfer;
reg_val = readl(mdata->base + SPI_STATUS0_REG);
- if (reg_val & 0x2)
+ if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
mdata->state = MTK_SPI_PAUSED;
else
mdata->state = MTK_SPI_IDLE;
struct mtk_spi *mdata;
const struct of_device_id *of_id;
struct resource *res;
- int irq, ret;
+ int irq, ret;
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
if (!master) {
if (!pm_runtime_suspended(dev)) {
ret = clk_prepare_enable(mdata->spi_clk);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
return ret;
+ }
}
ret = spi_master_resume(master);
{
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(mdata->spi_clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+ return ret;
+ }
- return clk_prepare_enable(mdata->spi_clk);
+ return 0;
}
#endif /* CONFIG_PM */