All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.