aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-mt65xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-mt65xx.c')
-rw-r--r--drivers/spi/spi-mt65xx.c139
1 files changed, 93 insertions, 46 deletions
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index ecb6c58238c4..7840067062a8 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -20,6 +20,7 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/platform_data/spi-mt65xx.h>
#include <linux/pm_runtime.h>
@@ -84,7 +85,8 @@ struct mtk_spi_compatible {
struct mtk_spi {
void __iomem *base;
u32 state;
- u32 pad_sel;
+ int pad_num;
+ u32 *pad_sel;
struct clk *parent_clk, *sel_clk, *spi_clk;
struct spi_transfer *cur_transfer;
u32 xfer_len;
@@ -131,10 +133,28 @@ static void mtk_spi_reset(struct mtk_spi *mdata)
writel(reg_val, mdata->base + SPI_CMD_REG);
}
-static void mtk_spi_config(struct mtk_spi *mdata,
- struct mtk_chip_config *chip_config)
+static int mtk_spi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
+ u16 cpha, cpol;
u32 reg_val;
+ struct spi_device *spi = msg->spi;
+ struct mtk_chip_config *chip_config = spi->controller_data;
+ struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+ cpha = spi->mode & SPI_CPHA ? 1 : 0;
+ cpol = spi->mode & SPI_CPOL ? 1 : 0;
+
+ reg_val = readl(mdata->base + SPI_CMD_REG);
+ 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);
reg_val = readl(mdata->base + SPI_CMD_REG);
@@ -170,38 +190,8 @@ static void mtk_spi_config(struct mtk_spi *mdata,
/* pad select */
if (mdata->dev_comp->need_pad_sel)
- writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG);
-}
-
-static int mtk_spi_prepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- u32 reg_val;
- u8 cpha, cpol;
- struct mtk_chip_config *chip_config;
- struct spi_device *spi = msg->spi;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
-
- cpha = spi->mode & SPI_CPHA ? 1 : 0;
- cpol = spi->mode & SPI_CPOL ? 1 : 0;
-
- reg_val = readl(mdata->base + SPI_CMD_REG);
- 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;
- if (!chip_config) {
- chip_config = (void *)&mtk_default_chip_info;
- spi->controller_data = chip_config;
- }
- mtk_spi_config(mdata, chip_config);
+ writel(mdata->pad_sel[spi->chip_select],
+ mdata->base + SPI_PAD_SEL_REG);
return 0;
}
@@ -413,6 +403,19 @@ static bool mtk_spi_can_dma(struct spi_master *master,
return xfer->len > MTK_SPI_MAX_FIFO_SIZE;
}
+static int mtk_spi_setup(struct spi_device *spi)
+{
+ struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+
+ if (!spi->controller_data)
+ spi->controller_data = (void *)&mtk_default_chip_info;
+
+ if (mdata->dev_comp->need_pad_sel && gpio_is_valid(spi->cs_gpio))
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
+
+ return 0;
+}
+
static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
{
u32 cmd, reg_val, cnt;
@@ -484,7 +487,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
struct mtk_spi *mdata;
const struct of_device_id *of_id;
struct resource *res;
- int irq, ret;
+ int i, irq, ret;
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
if (!master) {
@@ -500,6 +503,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
master->prepare_message = mtk_spi_prepare_message;
master->transfer_one = mtk_spi_transfer_one;
master->can_dma = mtk_spi_can_dma;
+ master->setup = mtk_spi_setup;
of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
if (!of_id) {
@@ -514,21 +518,34 @@ static int mtk_spi_probe(struct platform_device *pdev)
master->flags = SPI_MASTER_MUST_TX;
if (mdata->dev_comp->need_pad_sel) {
- ret = of_property_read_u32(pdev->dev.of_node,
- "mediatek,pad-select",
- &mdata->pad_sel);
- if (ret) {
- dev_err(&pdev->dev, "failed to read pad select: %d\n",
- ret);
+ mdata->pad_num = of_property_count_u32_elems(
+ pdev->dev.of_node,
+ "mediatek,pad-select");
+ if (mdata->pad_num < 0) {
+ dev_err(&pdev->dev,
+ "No 'mediatek,pad-select' property\n");
+ ret = -EINVAL;
goto err_put_master;
}
- if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) {
- dev_err(&pdev->dev, "wrong pad-select: %u\n",
- mdata->pad_sel);
- ret = -EINVAL;
+ mdata->pad_sel = devm_kmalloc_array(&pdev->dev, mdata->pad_num,
+ sizeof(u32), GFP_KERNEL);
+ if (!mdata->pad_sel) {
+ ret = -ENOMEM;
goto err_put_master;
}
+
+ for (i = 0; i < mdata->pad_num; i++) {
+ of_property_read_u32_index(pdev->dev.of_node,
+ "mediatek,pad-select",
+ i, &mdata->pad_sel[i]);
+ if (mdata->pad_sel[i] > MT8173_SPI_MAX_PAD_SEL) {
+ dev_err(&pdev->dev, "wrong pad-sel[%d]: %u\n",
+ i, mdata->pad_sel[i]);
+ ret = -EINVAL;
+ goto err_put_master;
+ }
+ }
}
platform_set_drvdata(pdev, master);
@@ -606,6 +623,36 @@ static int mtk_spi_probe(struct platform_device *pdev)
goto err_put_master;
}
+ if (mdata->dev_comp->need_pad_sel) {
+ if (mdata->pad_num != master->num_chipselect) {
+ dev_err(&pdev->dev,
+ "pad_num does not match num_chipselect(%d != %d)\n",
+ mdata->pad_num, master->num_chipselect);
+ ret = -EINVAL;
+ goto err_put_master;
+ }
+
+ if (!master->cs_gpios && master->num_chipselect > 1) {
+ dev_err(&pdev->dev,
+ "cs_gpios not specified and num_chipselect > 1\n");
+ ret = -EINVAL;
+ goto err_put_master;
+ }
+
+ if (master->cs_gpios) {
+ for (i = 0; i < master->num_chipselect; i++) {
+ ret = devm_gpio_request(&pdev->dev,
+ master->cs_gpios[i],
+ dev_name(&pdev->dev));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "can't get CS GPIO %i\n", i);
+ goto err_put_master;
+ }
+ }
+ }
+ }
+
return 0;
err_disable_clk: