linux-i3c.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Boris Brezillon <bbrezillon@kernel.org>
To: Przemyslaw Gaj <pgaj@cadence.com>
Cc: linux-i3c@lists.infradead.org, psroka@cadence.com,
	rafalc@cadence.com, vitor.soares@synopsys.com
Subject: Re: [PATCH v2 2/3] i3c: master: cdns: add support for mastership request to Cadence I3C master driver.
Date: Tue, 15 Jan 2019 22:36:50 +0100	[thread overview]
Message-ID: <20190115223650.03e0f435@bbrezillon> (raw)
In-Reply-To: <bbf21a32340d06d48b98204921b1007ca5ec569e.1547227861.git.pgaj@cadence.com>

On Fri, 11 Jan 2019 17:43:36 +0000
Przemyslaw Gaj <pgaj@cadence.com> wrote:

> This patch adds support for mastership request to Cadence I3C master driver.
> 
> Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> 
> Changes in v2:
> - Add work structs for mastership purpose
> - Add missing mastership disable feature
> ---
>  drivers/i3c/master/i3c-master-cdns.c | 385 ++++++++++++++++++++++++++++++-----
>  1 file changed, 339 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
> index 02a8297..578fc1e 100644
> --- a/drivers/i3c/master/i3c-master-cdns.c
> +++ b/drivers/i3c/master/i3c-master-cdns.c
> @@ -157,6 +157,7 @@
>  #define SLV_IMR				0x48
>  #define SLV_ICR				0x4c
>  #define SLV_ISR				0x50
> +#define SLV_INT_DEFSLVS			BIT(21)
>  #define SLV_INT_TM			BIT(20)
>  #define SLV_INT_ERROR			BIT(19)
>  #define SLV_INT_EVENT_UP		BIT(18)
> @@ -390,6 +391,12 @@ struct cdns_i3c_xfer {
>  
>  struct cdns_i3c_master {
>  	struct work_struct hj_work;
> +	struct {
> +		struct work_struct handover_work;
> +		struct work_struct takeover_work;
> +		struct work_struct request_work;

Can't we use the same work for all of them and just have a state or
type field reflecting the kind of MR request?

> +		u32 ibir;
> +	} mastership;
>  	struct i3c_master_controller base;
>  	u32 free_rr_slots;
>  	unsigned int maxdevs;
> @@ -664,6 +671,89 @@ static void cdns_i3c_master_unqueue_xfer(struct cdns_i3c_master *master,
>  	spin_unlock_irqrestore(&master->xferqueue.lock, flags);
>  }
>  
> +static void
> +cdns_i3c_master_i3c_dev_rr_to_info(struct cdns_i3c_master *master,
> +				   unsigned int slot,
> +				   struct i3c_device_info *info)
> +{
> +	u32 rr;
> +
> +	memset(info, 0, sizeof(*info));
> +	rr = readl(master->regs + DEV_ID_RR0(slot));
> +	info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
> +	rr = readl(master->regs + DEV_ID_RR2(slot));
> +	info->dcr = rr;
> +	info->bcr = rr >> 8;
> +	info->pid = rr >> 16;
> +	info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16;
> +}
> +
> +static void
> +cdns_i3c_master_i2c_dev_rr_to_boardinfo(struct cdns_i3c_master *master,
> +					unsigned int slot,
> +					struct i2c_dev_boardinfo *info)
> +{
> +	u32 rr;
> +
> +	memset(info, 0, sizeof(*info));
> +	rr = readl(master->regs + DEV_ID_RR0(slot));
> +	info->base.addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
> +	rr = readl(master->regs + DEV_ID_RR2(slot));
> +	info->lvr = rr;
> +}
> +
> +static
> +int cdns_i3c_sec_master_request_mastership(struct i3c_master_controller *m)
> +{
> +	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
> +	u32 status;
> +	int ret;
> +
> +	status = readl(master->regs + MST_STATUS0);
> +	if (status & MST_STATUS0_MASTER_MODE)
> +		return -EEXIST;

This deserves a WARN_ON() as we should not hit that case unless the
driver or core is buggy.

> +
> +	status = readl(master->regs + SLV_STATUS1);
> +	if (status & SLV_STATUS1_MR_DIS)
> +		return -EBUSY;

Maybe EACCES instead of EBUSY.

> +
> +	writel(readl(master->regs + CTRL) | CTRL_MST_INIT | CTRL_MST_ACK,
> +	       master->regs + CTRL);
> +
> +	writel(SLV_INT_MR_DONE, master->regs + SLV_IER);
> +
> +	ret = readl_poll_timeout(master->regs + MST_STATUS0, status,
> +				 status & MST_STATUS0_MASTER_MODE, 100,
> +				 1000000);
> +
> +	return ret;
> +}
> +
> +static void cdns_i3c_master_update_devs(struct i3c_master_controller *m)
> +{
> +	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
> +	u32 val, newdevs;
> +	int slot;
> +	struct i3c_device_info i3c_info;
> +	struct i2c_dev_boardinfo i2c_info;
> +
> +	newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
> +	for (slot = 1; slot <= master->maxdevs; slot++) {
> +		val = readl(master->regs + DEV_ID_RR0(slot));
> +
> +		if ((newdevs & BIT(slot)) && (val & DEV_ID_RR0_IS_I3C)) {
> +			cdns_i3c_master_i3c_dev_rr_to_info(master, slot,
> +							   &i3c_info);
> +			i3c_master_add_i3c_dev_locked(m, i3c_info.dyn_addr);
> +		} else if ((newdevs & BIT(slot)) &&
> +			   !(val & DEV_ID_RR0_IS_I3C)) {
> +			cdns_i3c_master_i2c_dev_rr_to_boardinfo(master, slot,
> +								&i2c_info);
> +			i3c_master_add_i2c_dev(m, &i2c_info);
> +		}
> +	}
> +}
> +
>  static enum i3c_error_code cdns_i3c_cmd_get_err(struct cdns_i3c_cmd *cmd)
>  {
>  	switch (cmd->error) {
> @@ -1045,22 +1135,6 @@ static void cdns_i3c_master_bus_cleanup(struct i3c_master_controller *m)
>  	cdns_i3c_master_disable(master);
>  }
>  
> -static void cdns_i3c_master_dev_rr_to_info(struct cdns_i3c_master *master,
> -					   unsigned int slot,
> -					   struct i3c_device_info *info)
> -{
> -	u32 rr;
> -
> -	memset(info, 0, sizeof(*info));
> -	rr = readl(master->regs + DEV_ID_RR0(slot));
> -	info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
> -	rr = readl(master->regs + DEV_ID_RR2(slot));
> -	info->dcr = rr;
> -	info->bcr = rr >> 8;
> -	info->pid = rr >> 16;
> -	info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16;
> -}
> -
>  static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
>  {
>  	struct i3c_master_controller *m = &master->base;
> @@ -1259,15 +1333,17 @@ 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;
> +	if (!m->secondary) {
> +		/* 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));
> +		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);
> +	cdns_i3c_master_i3c_dev_rr_to_info(master, 0, &info);
>  	if (info.bcr & I3C_BCR_HDR_CAP)
>  		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
>  
> @@ -1289,6 +1365,23 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
>  	return 0;
>  }
>  
> +static
> +struct i3c_dev_desc *cdns_i3c_get_ibi_device(struct cdns_i3c_master *master,
> +					     u32 ibir)
> +{
> +	struct i3c_dev_desc *dev;
> +	u32 id = IBIR_SLVID(ibir);
> +
> +	if (id >= master->ibi.num_slots || (ibir & IBIR_ERROR))
> +		return NULL;
> +
> +	dev = master->ibi.slots[id];
> +	if (!dev)
> +		return NULL;
> +
> +	return dev;
> +}
> +
>  static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
>  				       u32 ibir)
>  {
> @@ -1366,27 +1459,105 @@ static void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master)
>  
>  		case IBIR_TYPE_MR:
>  			WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
> +			master->mastership.ibir = ibir;
> +			queue_work(master->base.wq,
> +				   &master->mastership.handover_work);
> +			break;
>  		default:
>  			break;
>  		}
>  	}
>  }
>  
> +static void cdns_i3c_master_bus_handoff(struct cdns_i3c_master *master)
> +{
> +	struct i3c_dev_desc *dev;
> +
> +	dev = cdns_i3c_get_ibi_device(master, master->mastership.ibir);
> +
> +	writel(MST_INT_MR_DONE, master->regs + MST_ICR);
> +
> +	master->base.bus.cur_master = dev;
> +}
> +
> +static void cdns_i3c_master_mastership_takeover(struct work_struct *work)
> +{
> +	struct cdns_i3c_master *master = container_of(work,
> +						      struct cdns_i3c_master,
> +						      mastership.takeover_work);
> +
> +	writel(SLV_INT_MR_DONE, master->regs + SLV_ICR);
> +
> +	master->base.bus.cur_master = master->base.this;
> +
> +	if (master->base.init_done)
> +		i3c_master_bus_takeover(&master->base);
> +
> +	writel(readl(master->regs + CTRL) & ~CTRL_MST_ACK, master->regs + CTRL);
> +}
> +
> +static void cdns_i3c_sec_master_mastership_request(struct work_struct *work)
> +{
> +	struct cdns_i3c_master *master = container_of(work,
> +						      struct cdns_i3c_master,
> +						      mastership.request_work);
> +
> +	if (cdns_i3c_sec_master_request_mastership(&master->base))
> +		dev_err(&master->base.dev, "Mastership takeover failed\n");
> +	else
> +		dev_err(&master->base.dev, "Mastership takeover succeed\n");
> +}
> +
> +static void cdns_i3c_sec_master_event_up(struct cdns_i3c_master *master)
> +{
> +	u32 status;
> +
> +	writel(SLV_INT_EVENT_UP, master->regs + SLV_ICR);
> +	status = readl(master->regs + SLV_STATUS1);
> +	if (!(status & SLV_STATUS1_MR_DIS) &&
> +	    !master->base.bus.cur_master) {

Hm, don't we need to make sure we actually have something to do? I
mean, we could receive ENEC(MR) event for the second time and actually
have no devices to register. In this case we probably don't want to
send an MR event...

> +		queue_work(master->base.wq, &master->mastership.request_work);
> +	}
> +}
> +
> +static void cdns_i3c_sec_mastership_done(struct cdns_i3c_master *master)
> +{
> +	writel(SLV_INT_MR_DONE, master->regs + SLV_ICR);
> +
> +	queue_work(master->base.wq, &master->mastership.takeover_work);
> +}
> +
>  static irqreturn_t cdns_i3c_master_interrupt(int irq, void *data)
>  {
>  	struct cdns_i3c_master *master = data;
>  	u32 status;
>  
> -	status = readl(master->regs + MST_ISR);
> -	if (!(status & readl(master->regs + MST_IMR)))
> -		return IRQ_NONE;
> +	if (master->base.bus.cur_master != master->base.this) {
> +		status = readl(master->regs + SLV_ISR);
>  
> -	spin_lock(&master->xferqueue.lock);
> -	cdns_i3c_master_end_xfer_locked(master, status);
> -	spin_unlock(&master->xferqueue.lock);
> +		if (!(status & readl(master->regs + SLV_IMR)))
> +			return IRQ_NONE;
> +
> +		if (status & SLV_INT_MR_DONE)
> +			cdns_i3c_sec_mastership_done(master);
> +
> +		if (status & SLV_INT_EVENT_UP)
> +			cdns_i3c_sec_master_event_up(master);
> +	} else {
> +		status = readl(master->regs + MST_ISR);
> +		if (!(status & readl(master->regs + MST_IMR)))
> +			return IRQ_NONE;
>  
> -	if (status & MST_INT_IBIR_THR)
> -		cnds_i3c_master_demux_ibis(master);
> +		spin_lock(&master->xferqueue.lock);
> +		cdns_i3c_master_end_xfer_locked(master, status);
> +		spin_unlock(&master->xferqueue.lock);
> +
> +		if (status & MST_INT_IBIR_THR)
> +			cnds_i3c_master_demux_ibis(master);
> +
> +		if (status & MST_INT_MR_DONE)
> +			cdns_i3c_master_bus_handoff(master);
> +	}
>  
>  	return IRQ_HANDLED;
>  }
> @@ -1455,30 +1626,46 @@ static int cdns_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
>  	return ret;
>  }
>  
> -static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
> -				       const struct i3c_ibi_setup *req)
> +static int cdns_i3c_master_find_ibi_slot(struct cdns_i3c_master *master,
> +					 struct i3c_dev_desc *dev,
> +					 s16 *slot)
>  {
> -	struct i3c_master_controller *m = i3c_dev_get_master(dev);
> -	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
> -	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
>  	unsigned long flags;
>  	unsigned int i;
> -
> -	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
> -	if (IS_ERR(data->ibi_pool))
> -		return PTR_ERR(data->ibi_pool);
> +	int ret = -ENOENT;
>  
>  	spin_lock_irqsave(&master->ibi.lock, flags);
>  	for (i = 0; i < master->ibi.num_slots; i++) {
> -		if (!master->ibi.slots[i]) {
> -			data->ibi = i;
> +		/*
> +		 * We only need 'SIR' slots to describe IBI-capable devices.
> +		 * This slot may be used by mastership request interrupt,
> +		 * We can ruse the same 'SIR' map entry.
> +		 */
> +		if (!master->ibi.slots[i] ||
> +		    master->ibi.slots[i] == dev) {

Doesn't work if you have empty slots in the middle. You should first
iterate over all entries searching for slots[i] == dev and if there's
no match, pick the first empty entry.

>  			master->ibi.slots[i] = dev;
> +			*slot = i;
> +			ret = 0;
>  			break;
>  		}
>  	}
>  	spin_unlock_irqrestore(&master->ibi.lock, flags);
>  
> -	if (i < master->ibi.num_slots)
> +	return ret;
> +}
> +
> +static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
> +				       const struct i3c_ibi_setup *req)
> +{
> +	struct i3c_master_controller *m = i3c_dev_get_master(dev);
> +	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
> +	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
> +
> +	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
> +	if (IS_ERR(data->ibi_pool))
> +		return PTR_ERR(data->ibi_pool);
> +
> +	if (cdns_i3c_master_find_ibi_slot(master, dev, &data->ibi) == 0)

	if (!....)

>  		return 0;
>  
>  	i3c_generic_ibi_free_pool(data->ibi_pool);
> @@ -1487,6 +1674,37 @@ static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
>  	return -ENOSPC;
>  }
>  
> +static int cdns_i3c_master_enable_mastership_events(struct i3c_dev_desc *dev)
> +{
> +	struct i3c_master_controller *m = i3c_dev_get_master(dev);
> +	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
> +	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
> +	unsigned long flags;
> +	u32 sircfg, sirmap;
> +	int ret;
> +
> +	ret = cdns_i3c_master_find_ibi_slot(master, dev, &data->ibi);
> +	if (ret)
> +		return -ENOSPC;

Please propagate the error instead of returning ENOSPC.

> +
> +	spin_lock_irqsave(&master->ibi.lock, flags);
> +	sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
> +	sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
> +	sircfg = SIR_MAP_DEV_ROLE(dev->info.bcr >> 6) |
> +		 SIR_MAP_DEV_DA(dev->info.dyn_addr) |
> +		 SIR_MAP_DEV_PL(dev->info.max_ibi_len) |
> +		 SIR_MAP_DEV_ACK;
> +
> +	if (dev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM)
> +		sircfg |= SIR_MAP_DEV_SLOW;
> +
> +	sirmap |= SIR_MAP_DEV_CONF(data->ibi, sircfg);
> +	writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
> +	spin_unlock_irqrestore(&master->ibi.lock, flags);
> +

Where is i3c_master_enec_locked() called?

> +	return 0;
> +}
> +
>  static void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev)
>  {
>  	struct i3c_master_controller *m = i3c_dev_get_master(dev);
> @@ -1502,6 +1720,39 @@ static void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev)
>  	i3c_generic_ibi_free_pool(data->ibi_pool);
>  }
>  
> +static int cdns_i3c_master_disable_mastership_events(struct i3c_dev_desc *dev)
> +{
> +	struct i3c_master_controller *m = i3c_dev_get_master(dev);
> +	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
> +	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
> +	unsigned long flags;
> +	u32 sirmap;
> +	int ret;
> +
> +	ret = i3c_master_disec_locked(m, dev->info.dyn_addr,
> +				      I3C_CCC_EVENT_MR);
> +	if (ret)
> +		return ret;
> +
> +	if (data->ibi < 0)
> +		return -ENOENT;
> +
> +	if (master->ibi.slots[data->ibi]->ibi->handler)
> +		return 0;
> +
> +	spin_lock_irqsave(&master->ibi.lock, flags);
> +	sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
> +	sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
> +	sirmap |= SIR_MAP_DEV_CONF(data->ibi,
> +				   SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR));
> +	writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
> +	spin_unlock_irqrestore(&master->ibi.lock, flags);
> +
> +	cdns_i3c_master_free_ibi(dev);

Looks like you're also disabling regular IBIs here, is that really
what you want?

> +
> +	return ret;
> +}
> +
>  static void cdns_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
>  					     struct i3c_ibi_slot *slot)
>  {
> @@ -1529,6 +1780,10 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = {
>  	.request_ibi = cdns_i3c_master_request_ibi,
>  	.free_ibi = cdns_i3c_master_free_ibi,
>  	.recycle_ibi_slot = cdns_i3c_master_recycle_ibi_slot,
> +	.request_mastership = cdns_i3c_sec_master_request_mastership,
> +	.update_devs = cdns_i3c_master_update_devs,
> +	.enable_mr_events = cdns_i3c_master_enable_mastership_events,
> +	.disable_mr_events = cdns_i3c_master_disable_mastership_events
>  };
>  
>  static void cdns_i3c_master_hj(struct work_struct *work)
> @@ -1537,13 +1792,31 @@ static void cdns_i3c_master_hj(struct work_struct *work)
>  						      struct cdns_i3c_master,
>  						      hj_work);
>  
> -	i3c_master_do_daa(&master->base);
> +	if (!master->base.secondary)
> +		i3c_master_do_daa(&master->base);
> +}
> +
> +static void cdns_i3c_master_mastership_handover(struct work_struct *work)
> +{
> +	struct cdns_i3c_master *master = container_of(work,
> +						      struct cdns_i3c_master,
> +						      mastership.handover_work);
> +	struct i3c_dev_desc *dev;
> +	u32 ibir = master->mastership.ibir;
> +
> +	dev = cdns_i3c_get_ibi_device(master, ibir);
> +	if (!dev)
> +		return;
> +
> +	if (i3c_master_mastership_ack(&master->base, dev->info.dyn_addr))
> +		dev_err(&master->base.dev, "Mastership handover failed\n");
>  }
>  
>  static int cdns_i3c_master_probe(struct platform_device *pdev)
>  {
>  	struct cdns_i3c_master *master;
>  	struct resource *res;
> +	bool secondary = false;
>  	int ret, irq;
>  	u32 val;
>  
> @@ -1585,15 +1858,27 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
>  	INIT_LIST_HEAD(&master->xferqueue.list);
>  
>  	INIT_WORK(&master->hj_work, cdns_i3c_master_hj);
> +	INIT_WORK(&master->mastership.handover_work,
> +		  cdns_i3c_master_mastership_handover);
> +	INIT_WORK(&master->mastership.takeover_work,
> +		  cdns_i3c_master_mastership_takeover);
> +	INIT_WORK(&master->mastership.request_work,
> +		  cdns_i3c_sec_master_mastership_request);
> +
>  	writel(0xffffffff, master->regs + MST_IDR);
>  	writel(0xffffffff, master->regs + SLV_IDR);
>  	ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
>  			       dev_name(&pdev->dev), master);
> +

Please do not add blank lines between ret assignments and the following
ret check.

>  	if (ret)
>  		goto err_disable_sysclk;
>  
>  	platform_set_drvdata(pdev, master);
>  
> +	val = readl(master->regs + MST_STATUS0);
> +	if (!(val & MST_STATUS0_MASTER_MODE))
> +		secondary = true;
> +
>  	val = readl(master->regs + CONF_STATUS0);
>  
>  	/* Device ID0 is reserved to describe this master. */
> @@ -1609,6 +1894,7 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
>  
>  	spin_lock_init(&master->ibi.lock);
>  	master->ibi.num_slots = CONF_STATUS1_IBI_HW_RES(val);
> +
>  	master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
>  					 sizeof(*master->ibi.slots),
>  					 GFP_KERNEL);
> @@ -1617,13 +1903,19 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
>  
>  	writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
>  	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
> -	writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
> +
> +	if (!secondary)
> +		writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
>  
>  	ret = i3c_master_register(&master->base, &pdev->dev,
> -				  &cdns_i3c_master_ops, false);
> +				  &cdns_i3c_master_ops, secondary);
>  	if (ret)
>  		goto err_disable_sysclk;
>  
> +	if (secondary)
> +		writel(SLV_INT_EVENT_UP,
> +		       master->regs + SLV_IER);
> +
>  	return 0;
>  
>  err_disable_sysclk:
> @@ -1666,6 +1958,7 @@ static struct platform_driver cdns_i3c_master = {
>  module_platform_driver(cdns_i3c_master);
>  
>  MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
> +MODULE_AUTHOR("Przemyslaw Gaj <pgaj@cadence.com>");
>  MODULE_DESCRIPTION("Cadence I3C master driver");
>  MODULE_LICENSE("GPL v2");
>  MODULE_ALIAS("platform:cdns-i3c-master");


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

  reply	other threads:[~2019-01-15 21:37 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-11 17:43 [PATCH v2 0/3] Add the I3C mastership request Przemyslaw Gaj
2019-01-11 17:43 ` [PATCH v2 1/3] i3c: Add support for mastership request to I3C subsystem Przemyslaw Gaj
2019-01-15 21:09   ` Boris Brezillon
2019-01-28 10:37     ` Przemyslaw Gaj
2019-01-28 12:08       ` Boris Brezillon
2019-01-29 18:13     ` Przemyslaw Gaj
2019-01-30  7:56       ` Boris Brezillon
2019-01-30  8:29         ` Przemyslaw Gaj
2019-01-30  8:38           ` Boris Brezillon
2019-01-11 17:43 ` [PATCH v2 2/3] i3c: master: cdns: add support for mastership request to Cadence I3C master driver Przemyslaw Gaj
2019-01-15 21:36   ` Boris Brezillon [this message]
2019-01-11 17:43 ` [PATCH v2 3/3] i3c: master: Add module author Przemyslaw Gaj
2019-01-15 21:11   ` Boris Brezillon
2019-01-15 21:40     ` Boris Brezillon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190115223650.03e0f435@bbrezillon \
    --to=bbrezillon@kernel.org \
    --cc=linux-i3c@lists.infradead.org \
    --cc=pgaj@cadence.com \
    --cc=psroka@cadence.com \
    --cc=rafalc@cadence.com \
    --cc=vitor.soares@synopsys.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).