diff options
author | Leilk Liu <leilk.liu@mediatek.com> | 2015-10-26 04:09:44 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-10-27 00:33:42 -0400 |
commit | 37457607ecaffe56718a0e423548edeb3d4a11b7 (patch) | |
tree | e37b60c5ff7f4e83cd76eaaf05640c146088669f /drivers/spi/spi-mt65xx.c | |
parent | 58a984c79a68d508ccfccf4b82c0eaf7f487c399 (diff) |
spi: mediatek: mt8173 spi multiple devices support
mt8173 IC spi HW has 4 gpio group, it's possible to support
max <= 4 slave devices, even mtk spi HW is not congruent to spi core.
1. When a device do a spi_message transfer, spi HW should know
which pad-group this device is on, and then writes pad-select
register.
2. Mtk pad-select register just selects which MISO pin HW will
receive data. For example, pad-select=1(select spi1 pins), HW just
receives data from spi1 MISO, but it still send waveform to all 4
group cs/clk/mosi. If cs pin in other groups is still spi mode,
after spi1 is selected(by active cs pin), devices on other group
will also be selected.
Signed-off-by: Leilk Liu <leilk.liu@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-mt65xx.c')
-rw-r--r-- | drivers/spi/spi-mt65xx.c | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 406695a42e19..563954a61424 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/ioport.h> | 20 | #include <linux/ioport.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | #include <linux/of_gpio.h> | ||
23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
24 | #include <linux/platform_data/spi-mt65xx.h> | 25 | #include <linux/platform_data/spi-mt65xx.h> |
25 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
@@ -84,7 +85,8 @@ struct mtk_spi_compatible { | |||
84 | struct mtk_spi { | 85 | struct mtk_spi { |
85 | void __iomem *base; | 86 | void __iomem *base; |
86 | u32 state; | 87 | u32 state; |
87 | u32 pad_sel; | 88 | int pad_num; |
89 | u32 *pad_sel; | ||
88 | struct clk *parent_clk, *sel_clk, *spi_clk; | 90 | struct clk *parent_clk, *sel_clk, *spi_clk; |
89 | struct spi_transfer *cur_transfer; | 91 | struct spi_transfer *cur_transfer; |
90 | u32 xfer_len; | 92 | u32 xfer_len; |
@@ -188,7 +190,8 @@ static int mtk_spi_prepare_message(struct spi_master *master, | |||
188 | 190 | ||
189 | /* pad select */ | 191 | /* pad select */ |
190 | if (mdata->dev_comp->need_pad_sel) | 192 | if (mdata->dev_comp->need_pad_sel) |
191 | writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG); | 193 | writel(mdata->pad_sel[spi->chip_select], |
194 | mdata->base + SPI_PAD_SEL_REG); | ||
192 | 195 | ||
193 | return 0; | 196 | return 0; |
194 | } | 197 | } |
@@ -407,6 +410,9 @@ static int mtk_spi_setup(struct spi_device *spi) | |||
407 | if (!spi->controller_data) | 410 | if (!spi->controller_data) |
408 | spi->controller_data = (void *)&mtk_default_chip_info; | 411 | spi->controller_data = (void *)&mtk_default_chip_info; |
409 | 412 | ||
413 | if (mdata->dev_comp->need_pad_sel) | ||
414 | gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); | ||
415 | |||
410 | return 0; | 416 | return 0; |
411 | } | 417 | } |
412 | 418 | ||
@@ -481,7 +487,7 @@ static int mtk_spi_probe(struct platform_device *pdev) | |||
481 | struct mtk_spi *mdata; | 487 | struct mtk_spi *mdata; |
482 | const struct of_device_id *of_id; | 488 | const struct of_device_id *of_id; |
483 | struct resource *res; | 489 | struct resource *res; |
484 | int irq, ret; | 490 | int i, irq, ret; |
485 | 491 | ||
486 | master = spi_alloc_master(&pdev->dev, sizeof(*mdata)); | 492 | master = spi_alloc_master(&pdev->dev, sizeof(*mdata)); |
487 | if (!master) { | 493 | if (!master) { |
@@ -512,21 +518,34 @@ static int mtk_spi_probe(struct platform_device *pdev) | |||
512 | master->flags = SPI_MASTER_MUST_TX; | 518 | master->flags = SPI_MASTER_MUST_TX; |
513 | 519 | ||
514 | if (mdata->dev_comp->need_pad_sel) { | 520 | if (mdata->dev_comp->need_pad_sel) { |
515 | ret = of_property_read_u32(pdev->dev.of_node, | 521 | mdata->pad_num = of_property_count_u32_elems( |
516 | "mediatek,pad-select", | 522 | pdev->dev.of_node, |
517 | &mdata->pad_sel); | 523 | "mediatek,pad-select"); |
518 | if (ret) { | 524 | if (mdata->pad_num < 0) { |
519 | dev_err(&pdev->dev, "failed to read pad select: %d\n", | 525 | dev_err(&pdev->dev, |
520 | ret); | 526 | "No 'mediatek,pad-select' property\n"); |
527 | ret = -EINVAL; | ||
521 | goto err_put_master; | 528 | goto err_put_master; |
522 | } | 529 | } |
523 | 530 | ||
524 | if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) { | 531 | mdata->pad_sel = devm_kmalloc_array(&pdev->dev, mdata->pad_num, |
525 | dev_err(&pdev->dev, "wrong pad-select: %u\n", | 532 | sizeof(u32), GFP_KERNEL); |
526 | mdata->pad_sel); | 533 | if (!mdata->pad_sel) { |
527 | ret = -EINVAL; | 534 | ret = -ENOMEM; |
528 | goto err_put_master; | 535 | goto err_put_master; |
529 | } | 536 | } |
537 | |||
538 | for (i = 0; i < mdata->pad_num; i++) { | ||
539 | of_property_read_u32_index(pdev->dev.of_node, | ||
540 | "mediatek,pad-select", | ||
541 | i, &mdata->pad_sel[i]); | ||
542 | if (mdata->pad_sel[i] > MT8173_SPI_MAX_PAD_SEL) { | ||
543 | dev_err(&pdev->dev, "wrong pad-sel[%d]: %u\n", | ||
544 | i, mdata->pad_sel[i]); | ||
545 | ret = -EINVAL; | ||
546 | goto err_put_master; | ||
547 | } | ||
548 | } | ||
530 | } | 549 | } |
531 | 550 | ||
532 | platform_set_drvdata(pdev, master); | 551 | platform_set_drvdata(pdev, master); |
@@ -604,6 +623,26 @@ static int mtk_spi_probe(struct platform_device *pdev) | |||
604 | goto err_put_master; | 623 | goto err_put_master; |
605 | } | 624 | } |
606 | 625 | ||
626 | if (mdata->dev_comp->need_pad_sel) { | ||
627 | if (mdata->pad_num != master->num_chipselect) { | ||
628 | dev_err(&pdev->dev, | ||
629 | "pad_num does not match num_chipselect(%d != %d)\n", | ||
630 | mdata->pad_num, master->num_chipselect); | ||
631 | ret = -EINVAL; | ||
632 | goto err_put_master; | ||
633 | } | ||
634 | |||
635 | for (i = 0; i < master->num_chipselect; i++) { | ||
636 | ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], | ||
637 | dev_name(&pdev->dev)); | ||
638 | if (ret) { | ||
639 | dev_err(&pdev->dev, | ||
640 | "can't get CS GPIO %i\n", i); | ||
641 | goto err_put_master; | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | |||
607 | return 0; | 646 | return 0; |
608 | 647 | ||
609 | err_disable_clk: | 648 | err_disable_clk: |