i2c: cadence: Added slave support
Added support for I2C slave functionality Signed-off-by: Chirag Parekh <chirag.parekh@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com> Signed-off-by: Radu Pirea <radu_nicolae.pirea@upb.ro> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
		
							parent
							
								
									35eba185fd
								
							
						
					
					
						commit
						1a351b10b9
					
				| @ -23,6 +23,7 @@ | ||||
| #define CDNS_I2C_ISR_OFFSET		0x10 /* IRQ Status Register, RW */ | ||||
| #define CDNS_I2C_XFER_SIZE_OFFSET	0x14 /* Transfer Size Register, RW */ | ||||
| #define CDNS_I2C_TIME_OUT_OFFSET	0x1C /* Time Out Register, RW */ | ||||
| #define CDNS_I2C_IMR_OFFSET		0x20 /* IRQ Mask Register, RO */ | ||||
| #define CDNS_I2C_IER_OFFSET		0x24 /* IRQ Enable Register, WO */ | ||||
| #define CDNS_I2C_IDR_OFFSET		0x28 /* IRQ Disable Register, WO */ | ||||
| 
 | ||||
| @ -40,9 +41,17 @@ | ||||
| #define CDNS_I2C_CR_DIVB_SHIFT		8 | ||||
| #define CDNS_I2C_CR_DIVB_MASK		(0x3f << CDNS_I2C_CR_DIVB_SHIFT) | ||||
| 
 | ||||
| #define CDNS_I2C_CR_MASTER_EN_MASK	(CDNS_I2C_CR_NEA | \ | ||||
| 					 CDNS_I2C_CR_ACK_EN | \ | ||||
| 					 CDNS_I2C_CR_MS) | ||||
| 
 | ||||
| #define CDNS_I2C_CR_SLAVE_EN_MASK	~CDNS_I2C_CR_MASTER_EN_MASK | ||||
| 
 | ||||
| /* Status Register Bit mask definitions */ | ||||
| #define CDNS_I2C_SR_BA		BIT(8) | ||||
| #define CDNS_I2C_SR_TXDV	BIT(6) | ||||
| #define CDNS_I2C_SR_RXDV	BIT(5) | ||||
| #define CDNS_I2C_SR_RXRW	BIT(3) | ||||
| 
 | ||||
| /*
 | ||||
|  * I2C Address Register Bit mask definitions | ||||
| @ -91,6 +100,14 @@ | ||||
| 					 CDNS_I2C_IXR_DATA | \ | ||||
| 					 CDNS_I2C_IXR_COMP) | ||||
| 
 | ||||
| #define CDNS_I2C_IXR_SLAVE_INTR_MASK	(CDNS_I2C_IXR_RX_UNF | \ | ||||
| 					 CDNS_I2C_IXR_TX_OVF | \ | ||||
| 					 CDNS_I2C_IXR_RX_OVF | \ | ||||
| 					 CDNS_I2C_IXR_TO | \ | ||||
| 					 CDNS_I2C_IXR_NACK | \ | ||||
| 					 CDNS_I2C_IXR_DATA | \ | ||||
| 					 CDNS_I2C_IXR_COMP) | ||||
| 
 | ||||
| #define CDNS_I2C_TIMEOUT		msecs_to_jiffies(1000) | ||||
| /* timeout for pm runtime autosuspend */ | ||||
| #define CNDS_I2C_PM_TIMEOUT		1000	/* ms */ | ||||
| @ -114,6 +131,32 @@ | ||||
| #define cdns_i2c_readreg(offset)       readl_relaxed(id->membase + offset) | ||||
| #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| /**
 | ||||
|  * enum cdns_i2c_mode - I2C Controller current operating mode | ||||
|  * | ||||
|  * @CDNS_I2C_MODE_SLAVE:       I2C controller operating in slave mode | ||||
|  * @CDNS_I2C_MODE_MASTER:      I2C Controller operating in master mode | ||||
|  */ | ||||
| enum cdns_i2c_mode { | ||||
| 	CDNS_I2C_MODE_SLAVE, | ||||
| 	CDNS_I2C_MODE_MASTER, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * enum cdns_i2c_slave_mode - Slave state when I2C is operating in slave mode | ||||
|  * | ||||
|  * @CDNS_I2C_SLAVE_STATE_IDLE: I2C slave idle | ||||
|  * @CDNS_I2C_SLAVE_STATE_SEND: I2C slave sending data to master | ||||
|  * @CDNS_I2C_SLAVE_STATE_RECV: I2C slave receiving data from master | ||||
|  */ | ||||
| enum cdns_i2c_slave_state { | ||||
| 	CDNS_I2C_SLAVE_STATE_IDLE, | ||||
| 	CDNS_I2C_SLAVE_STATE_SEND, | ||||
| 	CDNS_I2C_SLAVE_STATE_RECV, | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * struct cdns_i2c - I2C device private data structure | ||||
|  * | ||||
| @ -135,6 +178,10 @@ | ||||
|  * @clk:		Pointer to struct clk | ||||
|  * @clk_rate_change_nb:	Notifier block for clock rate changes | ||||
|  * @quirks:		flag for broken hold bit usage in r1p10 | ||||
|  * @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register | ||||
|  * @slave:		Registered slave instance. | ||||
|  * @dev_mode:		I2C operating role(master/slave). | ||||
|  * @slave_state:	I2C Slave state(idle/read/write). | ||||
|  */ | ||||
| struct cdns_i2c { | ||||
| 	struct device		*dev; | ||||
| @ -155,6 +202,12 @@ struct cdns_i2c { | ||||
| 	struct clk *clk; | ||||
| 	struct notifier_block clk_rate_change_nb; | ||||
| 	u32 quirks; | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	u16 ctrl_reg_diva_divb; | ||||
| 	struct i2c_client *slave; | ||||
| 	enum cdns_i2c_mode dev_mode; | ||||
| 	enum cdns_i2c_slave_state slave_state; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| struct cdns_platform_data { | ||||
| @ -183,17 +236,155 @@ static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround) | ||||
| 		(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)); | ||||
| } | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| static void cdns_i2c_set_mode(enum cdns_i2c_mode mode, struct cdns_i2c *id) | ||||
| { | ||||
| 	/* Disable all interrupts */ | ||||
| 	cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET); | ||||
| 
 | ||||
| 	/* Clear FIFO and transfer size */ | ||||
| 	cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET); | ||||
| 
 | ||||
| 	/* Update device mode and state */ | ||||
| 	id->dev_mode = mode; | ||||
| 	id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; | ||||
| 
 | ||||
| 	switch (mode) { | ||||
| 	case CDNS_I2C_MODE_MASTER: | ||||
| 		/* Enable i2c master */ | ||||
| 		cdns_i2c_writereg(id->ctrl_reg_diva_divb | | ||||
| 				  CDNS_I2C_CR_MASTER_EN_MASK, | ||||
| 				  CDNS_I2C_CR_OFFSET); | ||||
| 		/*
 | ||||
| 		 * This delay is needed to give the IP some time to switch to | ||||
| 		 * the master mode. With lower values(like 110 us) i2cdetect | ||||
| 		 * will not detect any slave and without this delay, the IP will | ||||
| 		 * trigger a timeout interrupt. | ||||
| 		 */ | ||||
| 		usleep_range(115, 125); | ||||
| 		break; | ||||
| 	case CDNS_I2C_MODE_SLAVE: | ||||
| 		/* Enable i2c slave */ | ||||
| 		cdns_i2c_writereg(id->ctrl_reg_diva_divb & | ||||
| 				  CDNS_I2C_CR_SLAVE_EN_MASK, | ||||
| 				  CDNS_I2C_CR_OFFSET); | ||||
| 
 | ||||
| 		/* Setting slave address */ | ||||
| 		cdns_i2c_writereg(id->slave->addr & CDNS_I2C_ADDR_MASK, | ||||
| 				  CDNS_I2C_ADDR_OFFSET); | ||||
| 
 | ||||
| 		/* Enable slave send/receive interrupts */ | ||||
| 		cdns_i2c_writereg(CDNS_I2C_IXR_SLAVE_INTR_MASK, | ||||
| 				  CDNS_I2C_IER_OFFSET); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void cdns_i2c_slave_rcv_data(struct cdns_i2c *id) | ||||
| { | ||||
| 	u8 bytes; | ||||
| 	unsigned char data; | ||||
| 
 | ||||
| 	/* Prepare backend for data reception */ | ||||
| 	if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) { | ||||
| 		id->slave_state = CDNS_I2C_SLAVE_STATE_RECV; | ||||
| 		i2c_slave_event(id->slave, I2C_SLAVE_WRITE_REQUESTED, NULL); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fetch number of bytes to receive */ | ||||
| 	bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); | ||||
| 
 | ||||
| 	/* Read data and send to backend */ | ||||
| 	while (bytes--) { | ||||
| 		data = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); | ||||
| 		i2c_slave_event(id->slave, I2C_SLAVE_WRITE_RECEIVED, &data); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void cdns_i2c_slave_send_data(struct cdns_i2c *id) | ||||
| { | ||||
| 	u8 data; | ||||
| 
 | ||||
| 	/* Prepare backend for data transmission */ | ||||
| 	if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) { | ||||
| 		id->slave_state = CDNS_I2C_SLAVE_STATE_SEND; | ||||
| 		i2c_slave_event(id->slave, I2C_SLAVE_READ_REQUESTED, &data); | ||||
| 	} else { | ||||
| 		i2c_slave_event(id->slave, I2C_SLAVE_READ_PROCESSED, &data); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Send data over bus */ | ||||
| 	cdns_i2c_writereg(data, CDNS_I2C_DATA_OFFSET); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * cdns_i2c_isr - Interrupt handler for the I2C device | ||||
|  * @irq:	irq number for the I2C device | ||||
|  * @ptr:	void pointer to cdns_i2c structure | ||||
|  * cdns_i2c_slave_isr - Interrupt handler for the I2C device in slave role | ||||
|  * @ptr:       Pointer to I2C device private data | ||||
|  * | ||||
|  * This function handles the data interrupt, transfer complete interrupt and | ||||
|  * the error interrupts of the I2C device. | ||||
|  * This function handles the data interrupt and transfer complete interrupt of | ||||
|  * the I2C device in slave role. | ||||
|  * | ||||
|  * Return: IRQ_HANDLED always | ||||
|  */ | ||||
| static irqreturn_t cdns_i2c_isr(int irq, void *ptr) | ||||
| static irqreturn_t cdns_i2c_slave_isr(void *ptr) | ||||
| { | ||||
| 	struct cdns_i2c *id = ptr; | ||||
| 	unsigned int isr_status, i2c_status; | ||||
| 
 | ||||
| 	/* Fetch the interrupt status */ | ||||
| 	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); | ||||
| 	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); | ||||
| 
 | ||||
| 	/* Ignore masked interrupts */ | ||||
| 	isr_status &= ~cdns_i2c_readreg(CDNS_I2C_IMR_OFFSET); | ||||
| 
 | ||||
| 	/* Fetch transfer mode (send/receive) */ | ||||
| 	i2c_status = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET); | ||||
| 
 | ||||
| 	/* Handle data send/receive */ | ||||
| 	if (i2c_status & CDNS_I2C_SR_RXRW) { | ||||
| 		/* Send data to master */ | ||||
| 		if (isr_status & CDNS_I2C_IXR_DATA) | ||||
| 			cdns_i2c_slave_send_data(id); | ||||
| 
 | ||||
| 		if (isr_status & CDNS_I2C_IXR_COMP) { | ||||
| 			id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; | ||||
| 			i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL); | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* Receive data from master */ | ||||
| 		if (isr_status & CDNS_I2C_IXR_DATA) | ||||
| 			cdns_i2c_slave_rcv_data(id); | ||||
| 
 | ||||
| 		if (isr_status & CDNS_I2C_IXR_COMP) { | ||||
| 			cdns_i2c_slave_rcv_data(id); | ||||
| 			id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; | ||||
| 			i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Master indicated xfer stop or fifo underflow/overflow */ | ||||
| 	if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_RX_OVF | | ||||
| 			  CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF)) { | ||||
| 		id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; | ||||
| 		i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL); | ||||
| 		cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET); | ||||
| 	} | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * cdns_i2c_master_isr - Interrupt handler for the I2C device in master role | ||||
|  * @ptr:       Pointer to I2C device private data | ||||
|  * | ||||
|  * This function handles the data interrupt, transfer complete interrupt and | ||||
|  * the error interrupts of the I2C device in master role. | ||||
|  * | ||||
|  * Return: IRQ_HANDLED always | ||||
|  */ | ||||
| static irqreturn_t cdns_i2c_master_isr(void *ptr) | ||||
| { | ||||
| 	unsigned int isr_status, avail_bytes, updatetx; | ||||
| 	unsigned int bytes_to_send; | ||||
| @ -357,6 +548,27 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * cdns_i2c_isr - Interrupt handler for the I2C device | ||||
|  * @irq:	irq number for the I2C device | ||||
|  * @ptr:	void pointer to cdns_i2c structure | ||||
|  * | ||||
|  * This function passes the control to slave/master based on current role of | ||||
|  * i2c controller. | ||||
|  * | ||||
|  * Return: IRQ_HANDLED always | ||||
|  */ | ||||
| static irqreturn_t cdns_i2c_isr(int irq, void *ptr) | ||||
| { | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	struct cdns_i2c *id = ptr; | ||||
| 
 | ||||
| 	if (id->dev_mode == CDNS_I2C_MODE_SLAVE) | ||||
| 		return cdns_i2c_slave_isr(ptr); | ||||
| #endif | ||||
| 	return cdns_i2c_master_isr(ptr); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * cdns_i2c_mrecv - Prepare and start a master receive operation | ||||
|  * @id:		pointer to the i2c device structure | ||||
| @ -577,10 +789,28 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||||
| 	u32 reg; | ||||
| 	struct cdns_i2c *id = adap->algo_data; | ||||
| 	bool hold_quirk; | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	bool change_role = false; | ||||
| #endif | ||||
| 
 | ||||
| 	ret = pm_runtime_get_sync(id->dev); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	/* Check i2c operating mode and switch if possible */ | ||||
| 	if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { | ||||
| 		if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) | ||||
| 			return -EAGAIN; | ||||
| 
 | ||||
| 		/* Set mode to master */ | ||||
| 		cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); | ||||
| 
 | ||||
| 		/* Mark flag to change role once xfer is completed */ | ||||
| 		change_role = true; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	/* Check if the bus is free */ | ||||
| 	if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) { | ||||
| 		ret = -EAGAIN; | ||||
| @ -639,7 +869,15 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||||
| 	} | ||||
| 
 | ||||
| 	ret = num; | ||||
| 
 | ||||
| out: | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	/* Switch i2c mode to slave */ | ||||
| 	if (change_role) | ||||
| 		cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); | ||||
| #endif | ||||
| 
 | ||||
| 	pm_runtime_mark_last_busy(id->dev); | ||||
| 	pm_runtime_put_autosuspend(id->dev); | ||||
| 	return ret; | ||||
| @ -653,14 +891,67 @@ out: | ||||
|  */ | ||||
| static u32 cdns_i2c_func(struct i2c_adapter *adap) | ||||
| { | ||||
| 	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | | ||||
| 		(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | | ||||
| 		I2C_FUNC_SMBUS_BLOCK_DATA; | ||||
| 	u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | | ||||
| 			(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | | ||||
| 			I2C_FUNC_SMBUS_BLOCK_DATA; | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	func |= I2C_FUNC_SLAVE; | ||||
| #endif | ||||
| 
 | ||||
| 	return func; | ||||
| } | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| static int cdns_reg_slave(struct i2c_client *slave) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c, | ||||
| 									adap); | ||||
| 
 | ||||
| 	if (id->slave) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	if (slave->flags & I2C_CLIENT_TEN) | ||||
| 		return -EAFNOSUPPORT; | ||||
| 
 | ||||
| 	ret = pm_runtime_get_sync(id->dev); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* Store slave information */ | ||||
| 	id->slave = slave; | ||||
| 
 | ||||
| 	/* Enable I2C slave */ | ||||
| 	cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cdns_unreg_slave(struct i2c_client *slave) | ||||
| { | ||||
| 	struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c, | ||||
| 									adap); | ||||
| 
 | ||||
| 	pm_runtime_put(id->dev); | ||||
| 
 | ||||
| 	/* Remove slave information */ | ||||
| 	id->slave = NULL; | ||||
| 
 | ||||
| 	/* Enable I2C master */ | ||||
| 	cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static const struct i2c_algorithm cdns_i2c_algo = { | ||||
| 	.master_xfer	= cdns_i2c_master_xfer, | ||||
| 	.functionality	= cdns_i2c_func, | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	.reg_slave	= cdns_reg_slave, | ||||
| 	.unreg_slave	= cdns_unreg_slave, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -755,7 +1046,10 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id) | ||||
| 	ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) | | ||||
| 			(div_b << CDNS_I2C_CR_DIVB_SHIFT)); | ||||
| 	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK | | ||||
| 				 CDNS_I2C_CR_DIVB_MASK); | ||||
| #endif | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -948,8 +1242,12 @@ static int cdns_i2c_probe(struct platform_device *pdev) | ||||
| 	if (ret || (id->i2c_clk > I2C_MAX_FAST_MODE_FREQ)) | ||||
| 		id->i2c_clk = I2C_MAX_STANDARD_MODE_FREQ; | ||||
| 
 | ||||
| 	cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS, | ||||
| 			  CDNS_I2C_CR_OFFSET); | ||||
| #if IS_ENABLED(CONFIG_I2C_SLAVE) | ||||
| 	/* Set initial mode to master */ | ||||
| 	id->dev_mode = CDNS_I2C_MODE_MASTER; | ||||
| 	id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; | ||||
| #endif | ||||
| 	cdns_i2c_writereg(CDNS_I2C_CR_MASTER_EN_MASK, CDNS_I2C_CR_OFFSET); | ||||
| 
 | ||||
| 	ret = cdns_i2c_setclk(id->input_clk, id); | ||||
| 	if (ret) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user