diff options
Diffstat (limited to 'drivers/spi/spi-mt65xx.c')
-rw-r--r-- | drivers/spi/spi-mt65xx.c | 129 |
1 files changed, 83 insertions, 46 deletions
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index ecb6c58238c4..563954a61424 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_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: |