Re: [PATCH v6 3/3] spi: Add spi driver for Socionext Synquacer platform

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Ard,

Thank you for your comments.

On Thu, 30 May 2019 at 16:17, Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> wrote:
>
> On Tue, 28 May 2019 at 11:27, Masahisa Kojima
> <masahisa.kojima@xxxxxxxxxx> wrote:
> >
> > This patch adds support for controller found on synquacer platforms.
> >
> > Signed-off-by: Masahisa Kojima <masahisa.kojima@xxxxxxxxxx>
> > Signed-off-by: Jassi Brar <jaswinder.singh@xxxxxxxxxx>
> > ---
> >  drivers/spi/Kconfig         |  11 +
> >  drivers/spi/Makefile        |   1 +
> >  drivers/spi/spi-synquacer.c | 826 ++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 838 insertions(+)
> >  create mode 100644 drivers/spi/spi-synquacer.c
> >
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index 0fba8f400c59..24a3eac72d12 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -732,6 +732,17 @@ config SPI_SUN6I
> >         help
> >           This enables using the SPI controller on the Allwinner A31 SoCs.
> >
> > +config SPI_SYNQUACER
> > +       tristate "Socionext's Synquacer HighSpeed SPI controller"
> > +       depends on ARCH_SYNQUACER || COMPILE_TEST
> > +       select SPI_BITBANG
>
> Do we really need this dependency?

No, I remove dependency to SPI_BITBANG.

I will also fix other comments.

> > +       help
> > +         SPI driver for Socionext's High speed SPI controller which provides
> > +         various operating modes for interfacing to serial peripheral devices
> > +         that use the de-facto standard SPI protocol.
> > +
> > +         It also supports the new dual-bit and quad-bit SPI protocol.
> > +
> >  config SPI_MXIC
> >          tristate "Macronix MX25F0A SPI controller"
> >          depends on SPI_MASTER
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> > index f2f78d03dc28..63dcab552bcb 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_STM32_QSPI)                += spi-stm32-qspi.o
> >  obj-$(CONFIG_SPI_ST_SSC4)              += spi-st-ssc4.o
> >  obj-$(CONFIG_SPI_SUN4I)                        += spi-sun4i.o
> >  obj-$(CONFIG_SPI_SUN6I)                        += spi-sun6i.o
> > +obj-$(CONFIG_SPI_SYNQUACER)            += spi-synquacer.o
> >  obj-$(CONFIG_SPI_TEGRA114)             += spi-tegra114.o
> >  obj-$(CONFIG_SPI_TEGRA20_SFLASH)       += spi-tegra20-sflash.o
> >  obj-$(CONFIG_SPI_TEGRA20_SLINK)                += spi-tegra20-slink.o
> > diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
> > new file mode 100644
> > index 000000000000..27a9babaffc0
> > --- /dev/null
> > +++ b/drivers/spi/spi-synquacer.c
> > @@ -0,0 +1,826 @@
> ...
> > +static int synquacer_spi_probe(struct platform_device *pdev)
> > +{
> > +       struct device_node *np = pdev->dev.of_node;
> > +       struct spi_master *master;
> > +       struct synquacer_spi *sspi;
> > +       int ret;
> > +       int rx_irq, tx_irq;
> > +
> > +       master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
> > +       if (!master)
> > +               return -ENOMEM;
> > +
> > +       platform_set_drvdata(pdev, master);
> > +
> > +       sspi = spi_master_get_devdata(master);
> > +       sspi->dev = &pdev->dev;
> > +
> > +       init_completion(&sspi->transfer_done);
> > +
> > +       sspi->regs = devm_platform_ioremap_resource(pdev, 0);
> > +       if (IS_ERR(sspi->regs)) {
> > +               ret = PTR_ERR(sspi->regs);
> > +               goto put_spi;
> > +       }
> > +
> > +       sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
> > +       device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
> > +                                &master->max_speed_hz); /* for ACPI */
> > +
> > +       if (dev_of_node(&pdev->dev)) {
> > +               if (device_property_match_string(&pdev->dev,
> > +                                        "clock-names", "iHCLK") >= 0) {
> > +                       sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK;
> > +                       sspi->clk = devm_clk_get(sspi->dev, "iHCLK");
> > +               } else if (device_property_match_string(&pdev->dev,
> > +                                               "clock-names", "iPCLK") >= 0) {
> > +                       sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK;
> > +                       sspi->clk = devm_clk_get(sspi->dev, "iPCLK");
> > +               } else {
> > +                       dev_err(&pdev->dev, "specified wrong clock source\n");
> > +                       ret = -EINVAL;
> > +                       goto put_spi;
> > +               }
> > +               if (IS_ERR(sspi->clk)) {
>
> You could have received an -EPROBE_DEFER return value here, in which
> case you should not print an error and just return.
>
> > +                       dev_err(&pdev->dev, "clock not found\n");
> > +                       ret = PTR_ERR(sspi->clk);
> > +                       goto put_spi;
> > +               }
> > +
> > +               ret = clk_prepare_enable(sspi->clk);
> > +               if (ret) {
> > +                       dev_err(&pdev->dev, "failed to enable clock (%d)\n",
> > +                               ret);
> > +                       goto put_spi;
> > +               }
> > +
> > +               master->max_speed_hz = clk_get_rate(sspi->clk);
> > +       }
> > +
> > +       if (!master->max_speed_hz) {
> > +               dev_err(&pdev->dev, "missing clock source\n");
> > +               return -EINVAL;
> > +       }
> > +       master->min_speed_hz = master->max_speed_hz / 254;
> > +
> > +       sspi->aces = device_property_read_bool(&pdev->dev,
> > +                                              "socionext,set-aces");
> > +       sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
> > +
> > +       master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
> > +
> > +       rx_irq = platform_get_irq(pdev, 0);
> > +       if (rx_irq < 0) {
>
> <= 0
>
> > +               dev_err(&pdev->dev, "get rx_irq failed (%d)\n", rx_irq);
> > +               ret = rx_irq;
> > +               goto put_spi;
> > +       }
> > +       snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-%s",
>
> Why not just use "%s-rx" as the format string?
>
> > +                dev_name(&pdev->dev), "rx");
> > +       ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler,
> > +                               0, sspi->rx_irq_name, sspi);
> > +       if (ret) {
> > +               dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
> > +               goto put_spi;
> > +       }
> > +
> > +       tx_irq = platform_get_irq(pdev, 1);
> > +       if (tx_irq < 0) {
>
> <= 0
>
> > +               dev_err(&pdev->dev, "get tx_irq failed (%d)\n", tx_irq);
> > +               ret = tx_irq;
> > +               goto put_spi;
> > +       }
> > +       snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-%s",
>
> Likewise
>
> > +                dev_name(&pdev->dev), "tx");
> > +       ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler,
> > +                               0, sspi->tx_irq_name, sspi);
> > +       if (ret) {
> > +               dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
> > +               goto put_spi;
> > +       }
> > +
> > +       master->dev.of_node = np;
>
> please add
>
> master->dev.fwnode = pdev->dev.fwnode;
>
> here as well
>
> > +       master->auto_runtime_pm = true;
> > +       master->bus_num = pdev->id;
> > +
> > +       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
> > +                           SPI_TX_QUAD | SPI_RX_QUAD;
> > +       master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
> > +                                    SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
> > +
> > +       master->set_cs = synquacer_spi_set_cs;
> > +       master->transfer_one = synquacer_spi_transfer_one;
> > +
> > +       ret = synquacer_spi_enable(master);
> > +       if (ret)
> > +               goto fail_enable;
> > +
> > +       pm_runtime_set_active(sspi->dev);
> > +       pm_runtime_enable(sspi->dev);
> > +
> > +       ret = devm_spi_register_master(sspi->dev, master);
> > +       if (ret)
> > +               goto disable_pm;
> > +
> > +       return 0;
> > +
> > +disable_pm:
> > +       pm_runtime_disable(sspi->dev);
> > +fail_enable:
> > +       if (!IS_ERR(sspi->clk))
>
> You can drop this check: clk_disable_unprepare() already ignores NULL
> or ERR values.
>
> > +               clk_disable_unprepare(sspi->clk);
> > +put_spi:
> > +       spi_master_put(master);
> > +
> > +       return ret;
> > +}
> > +
> > +static int synquacer_spi_remove(struct platform_device *pdev)
> > +{
> > +       struct spi_master *master = platform_get_drvdata(pdev);
> > +       struct synquacer_spi *sspi = spi_master_get_devdata(master);
> > +
> > +       pm_runtime_disable(sspi->dev);
> > +
> > +       if (!IS_ERR(sspi->clk))
> > +               clk_disable_unprepare(sspi->clk);
> > +
>
> Same here
>
> > +       return 0;
> > +}
> > +
> > +static int __maybe_unused synquacer_spi_suspend(struct device *dev)
> > +{
> > +       struct spi_master *master = dev_get_drvdata(dev);
> > +       struct synquacer_spi *sspi = spi_master_get_devdata(master);
> > +       int ret;
> > +
> > +       ret = spi_master_suspend(master);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (!pm_runtime_suspended(dev))
> > +               if (!IS_ERR(sspi->clk))
> > +                       clk_disable_unprepare(sspi->clk);
> > +
>
> ... and here
>
> > +       return ret;
> > +}
> > +
> > +static int __maybe_unused synquacer_spi_resume(struct device *dev)
> > +{
> > +       struct spi_master *master = dev_get_drvdata(dev);
> > +       struct synquacer_spi *sspi = spi_master_get_devdata(master);
> > +       int ret;
> > +
> > +       if (!pm_runtime_suspended(dev)) {
> > +               /* Ensure reconfigure during next xfer */
> > +               sspi->speed = 0;
> > +
> > +               if (!IS_ERR(sspi->clk)) {
>
> ... and here
>
> > +                       ret = clk_prepare_enable(sspi->clk);
> > +                       if (ret < 0) {
> > +                               dev_err(dev, "failed to enable clk (%d)\n",
> > +                                       ret);
> > +                               return ret;
> > +                       }
> > +               }
> > +
> > +               ret = synquacer_spi_enable(master);
> > +               if (ret) {
> > +                       dev_err(dev, "failed to enable spi (%d)\n", ret);
> > +                       return ret;
> > +               }
> > +       }
> > +
> > +       ret = spi_master_resume(master);
> > +       if (ret < 0) {
> > +               if (!IS_ERR(sspi->clk))
> > +                       clk_disable_unprepare(sspi->clk);
>
> .. and here
>
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend,
> > +                        synquacer_spi_resume);
> > +
> > +static const struct of_device_id synquacer_spi_of_match[] = {
> > +       {.compatible = "socionext,synquacer-spi"},
> > +       {}
> > +};
> > +MODULE_DEVICE_TABLE(of, synquacer_spi_of_match);
> > +
> > +#ifdef CONFIG_ACPI
> > +static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = {
> > +       { "SCX0004" },
> > +       { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids);
> > +#endif
> > +
> > +static struct platform_driver synquacer_spi_driver = {
> > +       .driver = {
> > +               .name = "synquacer-spi",
> > +               .pm = &synquacer_spi_pm_ops,
> > +               .of_match_table = synquacer_spi_of_match,
> > +               .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids),
> > +       },
> > +       .probe = synquacer_spi_probe,
> > +       .remove = synquacer_spi_remove,
> > +};
> > +module_platform_driver(synquacer_spi_driver);
> > +
> > +MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver");
> > +MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@xxxxxxxxxx>");
> > +MODULE_AUTHOR("Jassi Brar <jaswinder.singh@xxxxxxxxxx>");
> > +MODULE_LICENSE("GPL v2");
> > --
> > 2.14.2
> >
>
> With the changes above,
>
> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
>
> but someone else has to review the SPI bits.



[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux