[v5,2/7] i3c: split i3c_master_register into init - register pair
diff mbox series

Message ID 1561236905-8901-3-git-send-email-pgaj@cadence.com
State New
Headers show
Series
  • Add the I3C mastership request
Related show

Commit Message

Przemyslaw Gaj June 22, 2019, 8:55 p.m. UTC
This patch is base for mastership takeover where secondary master is
initialized at probe time but register may be postponed till dynamic address is
assigned to our device.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
---
 drivers/i3c/master.c                 | 86 ++++++++++++++++++++----------------
 drivers/i3c/master/dw-i3c-master.c   | 34 +++++++-------
 drivers/i3c/master/i3c-master-cdns.c | 45 ++++++++++---------
 include/linux/i3c/master.h           | 12 ++---
 4 files changed, 94 insertions(+), 83 deletions(-)

Comments

Boris Brezillon July 6, 2019, 8:48 a.m. UTC | #1
On Sat, 22 Jun 2019 21:55:00 +0100
Przemyslaw Gaj <pgaj@cadence.com> wrote:

> This patch is base for mastership takeover where secondary master is
> initialized at probe time but register may be postponed till dynamic address is
> assigned to our device.
> 
> Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> ---
>  drivers/i3c/master.c                 | 86 ++++++++++++++++++++----------------
>  drivers/i3c/master/dw-i3c-master.c   | 34 +++++++-------
>  drivers/i3c/master/i3c-master-cdns.c | 45 ++++++++++---------
>  include/linux/i3c/master.h           | 12 ++---
>  4 files changed, 94 insertions(+), 83 deletions(-)
> 
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 0f7c31e..759078f 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -1528,32 +1528,9 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
>  }
>  EXPORT_SYMBOL_GPL(i3c_master_do_daa);
>  
> -/**
> - * i3c_master_set_info() - set master device information
> - * @master: master used to send frames on the bus
> - * @info: I3C device information
> - *
> - * Set master device info. This should be called from
> - * &i3c_master_controller_ops->bus_init().
> - *
> - * Not all &i3c_device_info fields are meaningful for a master device.
> - * Here is a list of fields that should be properly filled:
> - *
> - * - &i3c_device_info->dyn_addr
> - * - &i3c_device_info->bcr
> - * - &i3c_device_info->dcr
> - * - &i3c_device_info->pid
> - * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in
> - *   &i3c_device_info->bcr
> - *
> - * This function must be called with the bus lock held in maintenance mode.
> - *
> - * Return: 0 if @info contains valid information (not every piece of
> - * information can be checked, but we can at least make sure @info->dyn_addr
> - * and @info->bcr are correct), -EINVAL otherwise.
> - */
> -int i3c_master_set_info(struct i3c_master_controller *master,
> -			const struct i3c_device_info *info)
> +static int i3c_master_set_info(struct i3c_master_controller *master,
> +			       const struct i3c_device_info *info,
> +			       bool secondary)

secondary is not used here, and this can be extracted from
master->secondary anyway. I think you can drop this argument.

>  {
>  	struct i3c_dev_desc *i3cdev;
>  	int ret;
> @@ -1586,7 +1563,6 @@ int i3c_master_set_info(struct i3c_master_controller *master,
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL_GPL(i3c_master_set_info);
>  
>  static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
>  {
> @@ -2403,7 +2379,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>  }
>  
>  /**
> - * i3c_master_register() - register an I3C master
> + * i3c_master_init() - initializes all the structures required by I3C master
>   * @master: master used to send frames on the bus
>   * @parent: the parent device (the one that provides this I3C master
>   *	    controller)
> @@ -2417,16 +2393,14 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>   * - creates and initializes the I3C bus
>   * - populates the bus with static I2C devs if @parent->of_node is not
>   *   NULL
> - * - registers all I3C devices added by the controller during bus
> - *   initialization
> - * - registers the I2C adapter and all I2C devices
> + * - set bus mode when registering I2C devices.
>   *
>   * Return: 0 in case of success, a negative error code otherwise.
>   */
> -int i3c_master_register(struct i3c_master_controller *master,
> -			struct device *parent,
> -			const struct i3c_master_controller_ops *ops,
> -			bool secondary)
> +int i3c_master_init(struct i3c_master_controller *master,
> +		    struct device *parent,
> +		    const struct i3c_master_controller_ops *ops,
> +		    bool secondary)

Can we have i3c_primary_master_init() and i3c_secondary_master_init()
instead of this secondary arg? You can provide them as wrappers around a
generic i3c_master_init() if that make sense.

>  {
>  	struct i3c_bus *i3cbus = i3c_master_get_bus(master);
>  	enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
> @@ -2488,10 +2462,47 @@ int i3c_master_register(struct i3c_master_controller *master,
>  		ret = -ENOMEM;
>  		goto err_put_dev;
>  	}
> +	return 0;
> +
> +err_put_dev:
> +	put_device(&master->dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_init);

Patch
diff mbox series

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 0f7c31e..759078f 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1528,32 +1528,9 @@  int i3c_master_do_daa(struct i3c_master_controller *master)
 }
 EXPORT_SYMBOL_GPL(i3c_master_do_daa);
 
-/**
- * i3c_master_set_info() - set master device information
- * @master: master used to send frames on the bus
- * @info: I3C device information
- *
- * Set master device info. This should be called from
- * &i3c_master_controller_ops->bus_init().
- *
- * Not all &i3c_device_info fields are meaningful for a master device.
- * Here is a list of fields that should be properly filled:
- *
- * - &i3c_device_info->dyn_addr
- * - &i3c_device_info->bcr
- * - &i3c_device_info->dcr
- * - &i3c_device_info->pid
- * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in
- *   &i3c_device_info->bcr
- *
- * This function must be called with the bus lock held in maintenance mode.
- *
- * Return: 0 if @info contains valid information (not every piece of
- * information can be checked, but we can at least make sure @info->dyn_addr
- * and @info->bcr are correct), -EINVAL otherwise.
- */
-int i3c_master_set_info(struct i3c_master_controller *master,
-			const struct i3c_device_info *info)
+static int i3c_master_set_info(struct i3c_master_controller *master,
+			       const struct i3c_device_info *info,
+			       bool secondary)
 {
 	struct i3c_dev_desc *i3cdev;
 	int ret;
@@ -1586,7 +1563,6 @@  int i3c_master_set_info(struct i3c_master_controller *master,
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(i3c_master_set_info);
 
 static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
 {
@@ -2403,7 +2379,7 @@  static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
 }
 
 /**
- * i3c_master_register() - register an I3C master
+ * i3c_master_init() - initializes all the structures required by I3C master
  * @master: master used to send frames on the bus
  * @parent: the parent device (the one that provides this I3C master
  *	    controller)
@@ -2417,16 +2393,14 @@  static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
  * - creates and initializes the I3C bus
  * - populates the bus with static I2C devs if @parent->of_node is not
  *   NULL
- * - registers all I3C devices added by the controller during bus
- *   initialization
- * - registers the I2C adapter and all I2C devices
+ * - set bus mode when registering I2C devices.
  *
  * Return: 0 in case of success, a negative error code otherwise.
  */
-int i3c_master_register(struct i3c_master_controller *master,
-			struct device *parent,
-			const struct i3c_master_controller_ops *ops,
-			bool secondary)
+int i3c_master_init(struct i3c_master_controller *master,
+		    struct device *parent,
+		    const struct i3c_master_controller_ops *ops,
+		    bool secondary)
 {
 	struct i3c_bus *i3cbus = i3c_master_get_bus(master);
 	enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
@@ -2488,10 +2462,47 @@  int i3c_master_register(struct i3c_master_controller *master,
 		ret = -ENOMEM;
 		goto err_put_dev;
 	}
+	return 0;
+
+err_put_dev:
+	put_device(&master->dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_init);
+
+void i3c_master_cleanup(struct i3c_master_controller *master)
+{
+	put_device(&master->dev);
+}
+EXPORT_SYMBOL_GPL(i3c_master_cleanup);
+
+/**
+ * i3c_master_register() - register an primary I3C master
+ * @master: master used to send frames on the bus
+ * @info: master info, describes this device
+ *
+ * This function takes care of everything for you:
+ *
+ * - updates this master info
+ * - registers all I3C devices added by the controller during bus
+ *   initialization
+ * - registers the I2C adapter and all I2C devices
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int i3c_master_register(struct i3c_master_controller *master,
+			struct i3c_device_info *info)
+{
+	int ret;
+
+	ret = i3c_master_set_info(master, info, master->secondary);
+	if (ret)
+		return ret;
 
 	ret = i3c_master_bus_init(master);
 	if (ret)
-		goto err_put_dev;
+		return ret;
 
 	ret = device_add(&master->dev);
 	if (ret)
@@ -2522,9 +2533,6 @@  int i3c_master_register(struct i3c_master_controller *master,
 err_cleanup_bus:
 	i3c_master_bus_cleanup(master);
 
-err_put_dev:
-	put_device(&master->dev);
-
 	return ret;
 }
 EXPORT_SYMBOL_GPL(i3c_master_register);
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 22ac305..8e91364 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -593,7 +593,6 @@  static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 {
 	struct dw_i3c_master *master = to_dw_i3c_master(m);
 	struct i3c_bus *bus = i3c_master_get_bus(m);
-	struct i3c_device_info info = { };
 	u32 thld_ctrl;
 	int ret;
 
@@ -623,20 +622,6 @@  static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 	writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
 	writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
 
-	ret = i3c_master_get_free_addr(m, 0);
-	if (ret < 0)
-		return ret;
-
-	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
-	       master->regs + DEVICE_ADDR);
-
-	memset(&info, 0, sizeof(info));
-	info.dyn_addr = ret;
-
-	ret = i3c_master_set_info(&master->base, &info);
-	if (ret)
-		return ret;
-
 	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT);
 	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
 
@@ -1109,6 +1094,7 @@  static int dw_i3c_probe(struct platform_device *pdev)
 {
 	struct dw_i3c_master *master;
 	struct resource *res;
+	struct i3c_device_info info = { };
 	int ret, irq;
 
 	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
@@ -1160,8 +1146,22 @@  static int dw_i3c_probe(struct platform_device *pdev)
 	master->maxdevs = ret >> 16;
 	master->free_pos = GENMASK(master->maxdevs - 1, 0);
 
-	ret = i3c_master_register(&master->base, &pdev->dev,
-				  &dw_mipi_i3c_ops, false);
+	ret = i3c_master_init(&master->base, &pdev->dev,
+			      &dw_mipi_i3c_ops, false);
+	if (ret)
+		goto err_assert_rst;
+
+	ret = i3c_master_get_free_addr(&master->base, 0);
+	if (ret < 0)
+		goto err_assert_rst;
+
+	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
+	       master->regs + DEVICE_ADDR);
+
+	memset(&info, 0, sizeof(info));
+	info.dyn_addr = ret;
+
+	ret = i3c_master_register(&master->base, &info);
 	if (ret)
 		goto err_assert_rst;
 
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 5aee315..9706426 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -1193,8 +1193,7 @@  static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 	unsigned long pres_step, sysclk_rate, max_i2cfreq;
 	struct i3c_bus *bus = i3c_master_get_bus(m);
 	u32 ctrl, prescl0, prescl1, pres, low;
-	struct i3c_device_info info = { };
-	int ret, ncycles;
+	int ncycles;
 
 	switch (bus->mode) {
 	case I3C_BUS_MODE_PURE:
@@ -1247,22 +1246,6 @@  static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 	prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
 	writel(prescl1, master->regs + PRESCL_CTRL1);
 
-	/* Get an address for the master. */
-	ret = i3c_master_get_free_addr(m, 0);
-	if (ret < 0)
-		return ret;
-
-	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
-	       master->regs + DEV_ID_RR0(0));
-
-	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
-	if (info.bcr & I3C_BCR_HDR_CAP)
-		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
-
-	ret = i3c_master_set_info(&master->base, &info);
-	if (ret)
-		return ret;
-
 	/*
 	 * Enable Hot-Join, and, when a Hot-Join request happens, disable all
 	 * events coming from this device.
@@ -1531,6 +1514,7 @@  static int cdns_i3c_master_probe(struct platform_device *pdev)
 {
 	struct cdns_i3c_master *master;
 	struct resource *res;
+	struct i3c_device_info info = { };
 	int ret, irq;
 	u32 val;
 
@@ -1606,13 +1590,32 @@  static int cdns_i3c_master_probe(struct platform_device *pdev)
 	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
 	writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
 
-	ret = i3c_master_register(&master->base, &pdev->dev,
-				  &cdns_i3c_master_ops, false);
+	ret = i3c_master_init(&master->base, &pdev->dev, &cdns_i3c_master_ops, false);
 	if (ret)
-		goto err_disable_sysclk;
+	goto err_disable_sysclk;
+
+	/* Get an address for the master. */
+	ret = i3c_master_get_free_addr(&master->base, 0);
+	if (ret < 0)
+		return ret;
+
+	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
+	       master->regs + DEV_ID_RR0(0));
+
+	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
+	if (info.bcr & I3C_BCR_HDR_CAP)
+		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
+
+	ret = i3c_master_register(&master->base, &info);
+
+	if (ret)
+		goto err_cleanup;
 
 	return 0;
 
+err_cleanup:
+	i3c_master_cleanup(&master->base);
+
 err_disable_sysclk:
 	clk_disable_unprepare(master->sysclk);
 
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 42bb215..df3d769 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -530,13 +530,13 @@  int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
 				  u8 addr);
 int i3c_master_do_daa(struct i3c_master_controller *master);
 
-int i3c_master_set_info(struct i3c_master_controller *master,
-			const struct i3c_device_info *info);
-
+int i3c_master_init(struct i3c_master_controller *master,
+		    struct device *parent,
+		    const struct i3c_master_controller_ops *ops,
+		    bool secondary);
+void i3c_master_cleanup(struct i3c_master_controller *master);
 int i3c_master_register(struct i3c_master_controller *master,
-			struct device *parent,
-			const struct i3c_master_controller_ops *ops,
-			bool secondary);
+			struct i3c_device_info *info);
 int i3c_master_unregister(struct i3c_master_controller *master);
 
 /**