linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
  • * [PATCH v3] spi: add Renesas RPC-IF driver
           [not found] <ad503d6e-4739-9744-64b4-fd13f44ea6fe@cogentembedded.com>
           [not found] ` <ad503d6e-4739-9744-64b4-fd13f44ea6fe-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
    @ 2020-05-08 19:54 ` Sergei Shtylyov
      2020-06-13 19:18 ` [PATCH v4] " Sergei Shtylyov
      2 siblings, 0 replies; 16+ messages in thread
    From: Sergei Shtylyov @ 2020-05-08 19:54 UTC (permalink / raw)
      To: linux-spi, Mark Brown; +Cc: Mason Yang, Chris Brandt
    
    Add the SPI driver for the Renesas RPC-IF.  It's the "front end" driver
    using the "back end" APIs in the main driver to talk to the real hardware.
    We only implement the 'spi-mem' interface -- there's no need to implement
    the usual SPI driver methods...
    
    Based on the original patch by Mason Yang <masonccyang@mxic.com.tw>.
    
    Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
    
    ---
    This patch is against the 'for-next' branch of Mark Brown's 'spi.git' repo.
    It depends on the memory RPC-IF driver  in order to build/work:
    
    https://patchwork.kernel.org/patch/11521595/
    https://patchwork.kernel.org/patch/11521597/
    
    Changes in version 3:
    - properly set up the direction field in rpcif_spi_mem_prepare() when there's
      no data;
    - renamed rpcif_io_xfer() to rpcif_manual_xfer();
    - extended Cogent Embedded's copyright to this year.
    
    Changes in version 2:
    - removed unneeded transfer_one_message() method and the related code;
    - fixed up #include's as we switch from MFD to the memory core driver;
    - removed unneeded #include <linux/pm_runtime.h>;
    - removed 'struct rpcif_spi', replacing it with 'struct rpcif' everywhere;
    - added spi_mem_default_supports_op() call to rpcif_spi_mem_supports_op();
    - added rpcif_sw_init() call in rpcif_spi_probe();
    - set SPI_CONTROLLER_HALF_DUPLEX flag in rpcif_spi_probe();
    - added a new variable 'struct device *parent' and renamed the 'ret' variable
      to 'error' in rpcif_spi_probe();
    - changed the order of calls in the error path of rpcif_spi_probe() and in
      rpcif_spi_remove();
    - changed from 'select' to 'depends on' the main driver Kconfig symbol,
      removed 'depends on ARCH_RENESAS || COMPILE TEST';
    - renamed rpcif_spi_mem_set_prep_op_cfg() to rpcif_spi_mem_prepare(), updated
      the rpcif_io_xfer() call there to match the RPC-IF core driver, changed
      'rpc_op' there from parameter into the local variable;
    - changed the platform driver's name to "rpc-if-spi";
    - fixed whitespace in rpcif_spi_mem_exec_op()'s prototype; 
    - beautified the whitespace in the initializers of 'rpcif_spi_mem_ops' and
      'rpcif_spi_driver';
    - changed the heading comment from /* */ to //;
    - updated the patch description with more details.
    
     drivers/spi/Kconfig      |    6 +
     drivers/spi/Makefile     |    1 
     drivers/spi/spi-rpc-if.c |  216 +++++++++++++++++++++++++++++++++++++++++++++++
     3 files changed, 223 insertions(+)
    
    Index: spi/drivers/spi/Kconfig
    ===================================================================
    --- spi.orig/drivers/spi/Kconfig
    +++ spi/drivers/spi/Kconfig
    @@ -602,6 +602,12 @@ config SPI_RB4XX
     	help
     	  SPI controller driver for the Mikrotik RB4xx series boards.
     
    +config SPI_RPCIF
    +	tristate "Renesas RPC-IF SPI driver"
    +	depends on RENESAS_RPCIF
    +	help
    +	  SPI driver for Renesas R-Car Gen3 RPC-IF.
    +
     config SPI_RSPI
     	tristate "Renesas RSPI/QSPI controller"
     	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
    Index: spi/drivers/spi/Makefile
    ===================================================================
    --- spi.orig/drivers/spi/Makefile
    +++ spi/drivers/spi/Makefile
    @@ -91,6 +91,7 @@ obj-$(CONFIG_SPI_QCOM_QSPI)		+= spi-qcom
     obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
     obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
     obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
    +obj-$(CONFIG_SPI_RPCIF)			+= spi-rpc-if.o
     obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
     obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o
     spi-s3c24xx-hw-y			:= spi-s3c24xx.o
    Index: spi/drivers/spi/spi-rpc-if.c
    ===================================================================
    --- /dev/null
    +++ spi/drivers/spi/spi-rpc-if.c
    @@ -0,0 +1,216 @@
    +// SPDX-License-Identifier: GPL-2.0
    +//
    +// RPC-IF SPI/QSPI/Octa driver
    +//
    +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
    +// Copyright (C) 2019 Macronix International Co., Ltd.
    +// Copyright (C) 2019 - 2020 Cogent Embedded, Inc.
    +//
    +
    +#include <linux/module.h>
    +#include <linux/platform_device.h>
    +#include <linux/spi/spi.h>
    +#include <linux/spi/spi-mem.h>
    +
    +#include <memory/renesas-rpc-if.h>
    +
    +#include <asm/unaligned.h>
    +
    +static void rpcif_spi_mem_prepare(struct spi_device *spi_dev,
    +				  const struct spi_mem_op *spi_op,
    +				  u64 *offs, size_t *len)
    +{
    +	struct rpcif *rpc = spi_controller_get_devdata(spi_dev->controller);
    +	struct rpcif_op rpc_op = { };
    +
    +	rpc_op.cmd.opcode = spi_op->cmd.opcode;
    +	rpc_op.cmd.buswidth = spi_op->cmd.buswidth;
    +
    +	if (spi_op->addr.nbytes) {
    +		rpc_op.addr.buswidth = spi_op->addr.buswidth;
    +		rpc_op.addr.nbytes = spi_op->addr.nbytes;
    +		rpc_op.addr.val = spi_op->addr.val;
    +	}
    +
    +	if (spi_op->dummy.nbytes) {
    +		rpc_op.dummy.buswidth = spi_op->dummy.buswidth;
    +		rpc_op.dummy.ncycles  = spi_op->dummy.nbytes * 8 /
    +					spi_op->dummy.buswidth;
    +	}
    +
    +	if (spi_op->data.nbytes || (offs && len)) {
    +		rpc_op.data.buswidth = spi_op->data.buswidth;
    +		rpc_op.data.nbytes = spi_op->data.nbytes;
    +		switch (spi_op->data.dir) {
    +		case SPI_MEM_DATA_IN:
    +			rpc_op.data.dir = RPCIF_DATA_IN;
    +			rpc_op.data.buf.in = spi_op->data.buf.in;
    +			break;
    +		case SPI_MEM_DATA_OUT:
    +			rpc_op.data.dir = RPCIF_DATA_OUT;
    +			rpc_op.data.buf.out = spi_op->data.buf.out;
    +			break;
    +		case SPI_MEM_NO_DATA:
    +			rpc_op.data.dir = RPCIF_NO_DATA;
    +			break;
    +		}
    +	} else	{
    +		rpc_op.data.dir = RPCIF_NO_DATA;
    +	}
    +
    +	rpcif_prepare(rpc, &rpc_op, offs, len);
    +}
    +
    +static bool rpcif_spi_mem_supports_op(struct spi_mem *mem,
    +				      const struct spi_mem_op *op)
    +{
    +	if (!spi_mem_default_supports_op(mem, op))
    +		return false;
    +
    +	if (op->data.buswidth > 4 || op->addr.buswidth > 4 ||
    +	    op->dummy.buswidth > 4 || op->cmd.buswidth > 4 ||
    +	    op->addr.nbytes > 4)
    +		return false;
    +
    +	return true;
    +}
    +
    +static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
    +					 u64 offs, size_t len, void *buf)
    +{
    +	struct rpcif *rpc =
    +		spi_controller_get_devdata(desc->mem->spi->controller);
    +
    +	if (offs + desc->info.offset + len > U32_MAX)
    +		return -EINVAL;
    +
    +	rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len);
    +
    +	return rpcif_dirmap_read(rpc, offs, len, buf);
    +}
    +
    +static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
    +{
    +	struct rpcif *rpc =
    +		spi_controller_get_devdata(desc->mem->spi->controller);
    +
    +	if (desc->info.offset + desc->info.length > U32_MAX)
    +		return -ENOTSUPP;
    +
    +	if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
    +		return -ENOTSUPP;
    +
    +	if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
    +		return -ENOTSUPP;
    +
    +	if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
    +		return -ENOTSUPP;
    +
    +	return 0;
    +}
    +
    +static int rpcif_spi_mem_exec_op(struct spi_mem *mem,
    +				 const struct spi_mem_op *op)
    +{
    +	struct rpcif *rpc =
    +		spi_controller_get_devdata(mem->spi->controller);
    +
    +	rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL);
    +
    +	return rpcif_manual_xfer(rpc);
    +}
    +
    +static const struct spi_controller_mem_ops rpcif_spi_mem_ops = {
    +	.supports_op	= rpcif_spi_mem_supports_op,
    +	.exec_op	= rpcif_spi_mem_exec_op,
    +	.dirmap_create	= rpcif_spi_mem_dirmap_create,
    +	.dirmap_read	= rpcif_spi_mem_dirmap_read,
    +};
    +
    +static int rpcif_spi_probe(struct platform_device *pdev)
    +{
    +	struct device *parent = pdev->dev.parent;
    +	struct spi_controller *ctlr;
    +	struct rpcif *rpc;
    +	int error;
    +
    +	ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc));
    +	if (!ctlr)
    +		return -ENOMEM;
    +
    +	rpc = spi_controller_get_devdata(ctlr);
    +	rpcif_sw_init(rpc, parent);
    +
    +	platform_set_drvdata(pdev, ctlr);
    +
    +	ctlr->dev.of_node = parent->of_node;
    +
    +	rpcif_enable_rpm(rpc);
    +
    +	ctlr->num_chipselect = 1;
    +	ctlr->mem_ops = &rpcif_spi_mem_ops;
    +
    +	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
    +	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
    +	ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
    +
    +	rpcif_hw_init(rpc, false);
    +
    +	error = spi_register_controller(ctlr);
    +	if (error) {
    +		dev_err(&pdev->dev, "spi_register_controller failed\n");
    +		goto err_put_ctlr;
    +	}
    +	return 0;
    +
    +err_put_ctlr:
    +	rpcif_disable_rpm(rpc);
    +	spi_controller_put(ctlr);
    +
    +	return error;
    +}
    +
    +static int rpcif_spi_remove(struct platform_device *pdev)
    +{
    +	struct spi_controller *ctlr = platform_get_drvdata(pdev);
    +	struct rpcif *rpc = spi_controller_get_devdata(ctlr);
    +
    +	spi_unregister_controller(ctlr);
    +	rpcif_disable_rpm(rpc);
    +
    +	return 0;
    +}
    +
    +#ifdef CONFIG_PM_SLEEP
    +static int rpcif_spi_suspend(struct device *dev)
    +{
    +	struct spi_controller *ctlr = dev_get_drvdata(dev);
    +
    +	return spi_controller_suspend(ctlr);
    +}
    +
    +static int rpcif_spi_resume(struct device *dev)
    +{
    +	struct spi_controller *ctlr = dev_get_drvdata(dev);
    +
    +	return spi_controller_resume(ctlr);
    +}
    +
    +static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
    +#define DEV_PM_OPS	(&rpcif_spi_pm_ops)
    +#else
    +#define DEV_PM_OPS	NULL
    +#endif
    +
    +static struct platform_driver rpcif_spi_driver = {
    +	.probe	= rpcif_spi_probe,
    +	.remove	= rpcif_spi_remove,
    +	.driver = {
    +		.name	= "rpc-if-spi",
    +		.pm	= DEV_PM_OPS,
    +	},
    +};
    +module_platform_driver(rpcif_spi_driver);
    +
    +MODULE_DESCRIPTION("Renesas RPC-IF SPI driver");
    +MODULE_LICENSE("GPL v2");
    
    ^ permalink raw reply	[flat|nested] 16+ messages in thread
  • * [PATCH v4] spi: add Renesas RPC-IF driver
           [not found] <ad503d6e-4739-9744-64b4-fd13f44ea6fe@cogentembedded.com>
           [not found] ` <ad503d6e-4739-9744-64b4-fd13f44ea6fe-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
      2020-05-08 19:54 ` [PATCH v3] " Sergei Shtylyov
    @ 2020-06-13 19:18 ` Sergei Shtylyov
      2020-06-15 23:41   ` Mark Brown
      2 siblings, 1 reply; 16+ messages in thread
    From: Sergei Shtylyov @ 2020-06-13 19:18 UTC (permalink / raw)
      To: linux-spi, Mark Brown; +Cc: Mason Yang, Chris Brandt, linux-renesas-soc
    
    Add the SPI driver for the Renesas RPC-IF.  It's the "front end" driver
    using the "back end" APIs in the main driver to talk to the real hardware.
    We only implement the 'spi-mem' interface -- there's no need to implement
    the usual SPI driver methods...
    
    Based on the original patch by Mason Yang <masonccyang@mxic.com.tw>.
    
    Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
    
    ---
    Changes in version 4:
    - refreshed the patch.
    
    Changes in version 3:
    - properly set up the direction field in rpcif_spi_mem_prepare() when there's
      no data;
    - renamed rpcif_io_xfer() to rpcif_manual_xfer();
    - extended Cogent Embedded's copyright to this year.
    
    Changes in version 2:
    - removed unneeded transfer_one_message() method and the related code;
    - fixed up #include's as we switch from MFD to the memory core driver;
    - removed unneeded #include <linux/pm_runtime.h>;
    - removed 'struct rpcif_spi', replacing it with 'struct rpcif' everywhere;
    - added spi_mem_default_supports_op() call to rpcif_spi_mem_supports_op();
    - added rpcif_sw_init() call in rpcif_spi_probe();
    - set SPI_CONTROLLER_HALF_DUPLEX flag in rpcif_spi_probe();
    - added a new variable 'struct device *parent' and renamed the 'ret' variable
      to 'error' in rpcif_spi_probe();
    - changed the order of calls in the error path of rpcif_spi_probe() and in
      rpcif_spi_remove();
    - changed from 'select' to 'depends on' the main driver Kconfig symbol,
      removed 'depends on ARCH_RENESAS || COMPILE TEST';
    - renamed rpcif_spi_mem_set_prep_op_cfg() to rpcif_spi_mem_prepare(), updated
      the rpcif_io_xfer() call there to match the RPC-IF core driver, changed
      'rpc_op' there from parameter into the local variable;
    - changed the platform driver's name to "rpc-if-spi";
    - fixed whitespace in rpcif_spi_mem_exec_op()'s prototype; 
    - beautified the whitespace in the initializers of 'rpcif_spi_mem_ops' and
      'rpcif_spi_driver';
    - changed the heading comment from /* */ to //;
    - updated the patch description with more details.
    
     drivers/spi/Kconfig      |    6 +
     drivers/spi/Makefile     |    1 
     drivers/spi/spi-rpc-if.c |  216 +++++++++++++++++++++++++++++++++++++++++++++++
     3 files changed, 223 insertions(+)
    
    Index: spi/drivers/spi/Kconfig
    ===================================================================
    --- spi.orig/drivers/spi/Kconfig
    +++ spi/drivers/spi/Kconfig
    @@ -605,6 +605,12 @@ config SPI_RB4XX
     	help
     	  SPI controller driver for the Mikrotik RB4xx series boards.
     
    +config SPI_RPCIF
    +	tristate "Renesas RPC-IF SPI driver"
    +	depends on RENESAS_RPCIF
    +	help
    +	  SPI driver for Renesas R-Car Gen3 RPC-IF.
    +
     config SPI_RSPI
     	tristate "Renesas RSPI/QSPI controller"
     	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
    Index: spi/drivers/spi/Makefile
    ===================================================================
    --- spi.orig/drivers/spi/Makefile
    +++ spi/drivers/spi/Makefile
    @@ -92,6 +92,7 @@ obj-$(CONFIG_SPI_QCOM_QSPI)		+= spi-qcom
     obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
     obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
     obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
    +obj-$(CONFIG_SPI_RPCIF)			+= spi-rpc-if.o
     obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
     obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o
     spi-s3c24xx-hw-y			:= spi-s3c24xx.o
    Index: spi/drivers/spi/spi-rpc-if.c
    ===================================================================
    --- /dev/null
    +++ spi/drivers/spi/spi-rpc-if.c
    @@ -0,0 +1,216 @@
    +// SPDX-License-Identifier: GPL-2.0
    +//
    +// RPC-IF SPI/QSPI/Octa driver
    +//
    +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
    +// Copyright (C) 2019 Macronix International Co., Ltd.
    +// Copyright (C) 2019 - 2020 Cogent Embedded, Inc.
    +//
    +
    +#include <linux/module.h>
    +#include <linux/platform_device.h>
    +#include <linux/spi/spi.h>
    +#include <linux/spi/spi-mem.h>
    +
    +#include <memory/renesas-rpc-if.h>
    +
    +#include <asm/unaligned.h>
    +
    +static void rpcif_spi_mem_prepare(struct spi_device *spi_dev,
    +				  const struct spi_mem_op *spi_op,
    +				  u64 *offs, size_t *len)
    +{
    +	struct rpcif *rpc = spi_controller_get_devdata(spi_dev->controller);
    +	struct rpcif_op rpc_op = { };
    +
    +	rpc_op.cmd.opcode = spi_op->cmd.opcode;
    +	rpc_op.cmd.buswidth = spi_op->cmd.buswidth;
    +
    +	if (spi_op->addr.nbytes) {
    +		rpc_op.addr.buswidth = spi_op->addr.buswidth;
    +		rpc_op.addr.nbytes = spi_op->addr.nbytes;
    +		rpc_op.addr.val = spi_op->addr.val;
    +	}
    +
    +	if (spi_op->dummy.nbytes) {
    +		rpc_op.dummy.buswidth = spi_op->dummy.buswidth;
    +		rpc_op.dummy.ncycles  = spi_op->dummy.nbytes * 8 /
    +					spi_op->dummy.buswidth;
    +	}
    +
    +	if (spi_op->data.nbytes || (offs && len)) {
    +		rpc_op.data.buswidth = spi_op->data.buswidth;
    +		rpc_op.data.nbytes = spi_op->data.nbytes;
    +		switch (spi_op->data.dir) {
    +		case SPI_MEM_DATA_IN:
    +			rpc_op.data.dir = RPCIF_DATA_IN;
    +			rpc_op.data.buf.in = spi_op->data.buf.in;
    +			break;
    +		case SPI_MEM_DATA_OUT:
    +			rpc_op.data.dir = RPCIF_DATA_OUT;
    +			rpc_op.data.buf.out = spi_op->data.buf.out;
    +			break;
    +		case SPI_MEM_NO_DATA:
    +			rpc_op.data.dir = RPCIF_NO_DATA;
    +			break;
    +		}
    +	} else	{
    +		rpc_op.data.dir = RPCIF_NO_DATA;
    +	}
    +
    +	rpcif_prepare(rpc, &rpc_op, offs, len);
    +}
    +
    +static bool rpcif_spi_mem_supports_op(struct spi_mem *mem,
    +				      const struct spi_mem_op *op)
    +{
    +	if (!spi_mem_default_supports_op(mem, op))
    +		return false;
    +
    +	if (op->data.buswidth > 4 || op->addr.buswidth > 4 ||
    +	    op->dummy.buswidth > 4 || op->cmd.buswidth > 4 ||
    +	    op->addr.nbytes > 4)
    +		return false;
    +
    +	return true;
    +}
    +
    +static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
    +					 u64 offs, size_t len, void *buf)
    +{
    +	struct rpcif *rpc =
    +		spi_controller_get_devdata(desc->mem->spi->controller);
    +
    +	if (offs + desc->info.offset + len > U32_MAX)
    +		return -EINVAL;
    +
    +	rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len);
    +
    +	return rpcif_dirmap_read(rpc, offs, len, buf);
    +}
    +
    +static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
    +{
    +	struct rpcif *rpc =
    +		spi_controller_get_devdata(desc->mem->spi->controller);
    +
    +	if (desc->info.offset + desc->info.length > U32_MAX)
    +		return -ENOTSUPP;
    +
    +	if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
    +		return -ENOTSUPP;
    +
    +	if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
    +		return -ENOTSUPP;
    +
    +	if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
    +		return -ENOTSUPP;
    +
    +	return 0;
    +}
    +
    +static int rpcif_spi_mem_exec_op(struct spi_mem *mem,
    +				 const struct spi_mem_op *op)
    +{
    +	struct rpcif *rpc =
    +		spi_controller_get_devdata(mem->spi->controller);
    +
    +	rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL);
    +
    +	return rpcif_manual_xfer(rpc);
    +}
    +
    +static const struct spi_controller_mem_ops rpcif_spi_mem_ops = {
    +	.supports_op	= rpcif_spi_mem_supports_op,
    +	.exec_op	= rpcif_spi_mem_exec_op,
    +	.dirmap_create	= rpcif_spi_mem_dirmap_create,
    +	.dirmap_read	= rpcif_spi_mem_dirmap_read,
    +};
    +
    +static int rpcif_spi_probe(struct platform_device *pdev)
    +{
    +	struct device *parent = pdev->dev.parent;
    +	struct spi_controller *ctlr;
    +	struct rpcif *rpc;
    +	int error;
    +
    +	ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc));
    +	if (!ctlr)
    +		return -ENOMEM;
    +
    +	rpc = spi_controller_get_devdata(ctlr);
    +	rpcif_sw_init(rpc, parent);
    +
    +	platform_set_drvdata(pdev, ctlr);
    +
    +	ctlr->dev.of_node = parent->of_node;
    +
    +	rpcif_enable_rpm(rpc);
    +
    +	ctlr->num_chipselect = 1;
    +	ctlr->mem_ops = &rpcif_spi_mem_ops;
    +
    +	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
    +	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
    +	ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
    +
    +	rpcif_hw_init(rpc, false);
    +
    +	error = spi_register_controller(ctlr);
    +	if (error) {
    +		dev_err(&pdev->dev, "spi_register_controller failed\n");
    +		goto err_put_ctlr;
    +	}
    +	return 0;
    +
    +err_put_ctlr:
    +	rpcif_disable_rpm(rpc);
    +	spi_controller_put(ctlr);
    +
    +	return error;
    +}
    +
    +static int rpcif_spi_remove(struct platform_device *pdev)
    +{
    +	struct spi_controller *ctlr = platform_get_drvdata(pdev);
    +	struct rpcif *rpc = spi_controller_get_devdata(ctlr);
    +
    +	spi_unregister_controller(ctlr);
    +	rpcif_disable_rpm(rpc);
    +
    +	return 0;
    +}
    +
    +#ifdef CONFIG_PM_SLEEP
    +static int rpcif_spi_suspend(struct device *dev)
    +{
    +	struct spi_controller *ctlr = dev_get_drvdata(dev);
    +
    +	return spi_controller_suspend(ctlr);
    +}
    +
    +static int rpcif_spi_resume(struct device *dev)
    +{
    +	struct spi_controller *ctlr = dev_get_drvdata(dev);
    +
    +	return spi_controller_resume(ctlr);
    +}
    +
    +static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
    +#define DEV_PM_OPS	(&rpcif_spi_pm_ops)
    +#else
    +#define DEV_PM_OPS	NULL
    +#endif
    +
    +static struct platform_driver rpcif_spi_driver = {
    +	.probe	= rpcif_spi_probe,
    +	.remove	= rpcif_spi_remove,
    +	.driver = {
    +		.name	= "rpc-if-spi",
    +		.pm	= DEV_PM_OPS,
    +	},
    +};
    +module_platform_driver(rpcif_spi_driver);
    +
    +MODULE_DESCRIPTION("Renesas RPC-IF SPI driver");
    +MODULE_LICENSE("GPL v2");
    
    ^ permalink raw reply	[flat|nested] 16+ messages in thread

  • end of thread, other threads:[~2020-06-16 14:32 UTC | newest]
    
    Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
    -- links below jump to the message on this page --
         [not found] <ad503d6e-4739-9744-64b4-fd13f44ea6fe@cogentembedded.com>
         [not found] ` <ad503d6e-4739-9744-64b4-fd13f44ea6fe-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
    2020-01-15 20:46   ` [PATCH v2] spi: add Renesas RPC-IF driver Sergei Shtylyov
         [not found]     ` <6515c5ec-8432-0b20-426d-0428bbdf3712-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
    2020-02-07 22:36       ` Chris Brandt
         [not found]         ` <TY1PR01MB1562509AEBD0B4460D3FEC798A1C0-5SGCI54O2uKy/kJTUOSl63colHNk5qUtvxpqHgZTriW3zl9H0oFU5g@public.gmane.org>
    2020-02-10 18:43           ` Sergei Shtylyov
    2020-02-10 18:06       ` Chris Brandt
         [not found]         ` <TYXPR01MB1568E8BCB6B80A77C91D98998A190-enDngAEzY3rnUoU5SHyUhXcolHNk5qUtvxpqHgZTriW3zl9H0oFU5g@public.gmane.org>
    2020-02-10 19:34           ` Chris Brandt
    2020-05-08 19:54 ` [PATCH v3] " Sergei Shtylyov
    2020-06-13 19:18 ` [PATCH v4] " Sergei Shtylyov
    2020-06-15 23:41   ` Mark Brown
    2020-06-16  8:24     ` Sergei Shtylyov
    2020-06-16  8:38       ` Mark Brown
    2020-06-16  8:48         ` Sergei Shtylyov
    2020-06-16  9:34           ` Mark Brown
    2020-06-16 12:55             ` Sergei Shtylyov
    2020-06-16 14:32               ` Mark Brown
    2020-06-16  9:26         ` Sergei Shtylyov
    2020-06-16  9:34           ` Mark Brown
    

    This is a public inbox, see mirroring instructions
    for how to clone and mirror all data and code used for this inbox;
    as well as URLs for NNTP newsgroup(s).