]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/spi/spi-mt65xx.c
Merge remote-tracking branch 'spi/for-next'
[karo-tx-linux.git] / drivers / spi / spi-mt65xx.c
index ecb6c58238c4f56867e73e3f074ddf90f1b04ee3..563954a614242718bd125f16f9a3549f783346b8 100644 (file)
@@ -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_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,26 @@ 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;
+               }
+
+               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: