forked from mirrors/linux
		
	i2c: mediatek: Use DMA safe buffers for i2c transactions
DMA mode will always be used in i2c transactions, try to allocate a DMA safe buffer if the buf of struct i2c_msg used is not DMA safe. Signed-off-by: Jun Gao <jun.gao@mediatek.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
		
							parent
							
								
									9cbeeca050
								
							
						
					
					
						commit
						fc66b39fe3
					
				
					 1 changed files with 58 additions and 10 deletions
				
			
		|  | @ -441,6 +441,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, | ||||||
| 	u16 control_reg; | 	u16 control_reg; | ||||||
| 	u16 restart_flag = 0; | 	u16 restart_flag = 0; | ||||||
| 	u32 reg_4g_mode; | 	u32 reg_4g_mode; | ||||||
|  | 	u8 *dma_rd_buf = NULL; | ||||||
|  | 	u8 *dma_wr_buf = NULL; | ||||||
| 	dma_addr_t rpaddr = 0; | 	dma_addr_t rpaddr = 0; | ||||||
| 	dma_addr_t wpaddr = 0; | 	dma_addr_t wpaddr = 0; | ||||||
| 	int ret; | 	int ret; | ||||||
|  | @ -500,11 +502,19 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, | ||||||
| 	if (i2c->op == I2C_MASTER_RD) { | 	if (i2c->op == I2C_MASTER_RD) { | ||||||
| 		writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); | 		writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); | ||||||
| 		writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON); | 		writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON); | ||||||
| 		rpaddr = dma_map_single(i2c->dev, msgs->buf, | 
 | ||||||
| 					msgs->len, DMA_FROM_DEVICE); | 		dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 0); | ||||||
| 		if (dma_mapping_error(i2c->dev, rpaddr)) | 		if (!dma_rd_buf) | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | 		rpaddr = dma_map_single(i2c->dev, dma_rd_buf, | ||||||
|  | 					msgs->len, DMA_FROM_DEVICE); | ||||||
|  | 		if (dma_mapping_error(i2c->dev, rpaddr)) { | ||||||
|  | 			i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, false); | ||||||
|  | 
 | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if (i2c->dev_comp->support_33bits) { | 		if (i2c->dev_comp->support_33bits) { | ||||||
| 			reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr); | 			reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr); | ||||||
| 			writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE); | 			writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE); | ||||||
|  | @ -515,11 +525,19 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, | ||||||
| 	} else if (i2c->op == I2C_MASTER_WR) { | 	} else if (i2c->op == I2C_MASTER_WR) { | ||||||
| 		writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); | 		writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); | ||||||
| 		writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON); | 		writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON); | ||||||
| 		wpaddr = dma_map_single(i2c->dev, msgs->buf, | 
 | ||||||
| 					msgs->len, DMA_TO_DEVICE); | 		dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0); | ||||||
| 		if (dma_mapping_error(i2c->dev, wpaddr)) | 		if (!dma_wr_buf) | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | 		wpaddr = dma_map_single(i2c->dev, dma_wr_buf, | ||||||
|  | 					msgs->len, DMA_TO_DEVICE); | ||||||
|  | 		if (dma_mapping_error(i2c->dev, wpaddr)) { | ||||||
|  | 			i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false); | ||||||
|  | 
 | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if (i2c->dev_comp->support_33bits) { | 		if (i2c->dev_comp->support_33bits) { | ||||||
| 			reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr); | 			reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr); | ||||||
| 			writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE); | 			writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE); | ||||||
|  | @ -530,16 +548,39 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, | ||||||
| 	} else { | 	} else { | ||||||
| 		writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG); | 		writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG); | ||||||
| 		writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON); | 		writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON); | ||||||
| 		wpaddr = dma_map_single(i2c->dev, msgs->buf, | 
 | ||||||
| 					msgs->len, DMA_TO_DEVICE); | 		dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0); | ||||||
| 		if (dma_mapping_error(i2c->dev, wpaddr)) | 		if (!dma_wr_buf) | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 		rpaddr = dma_map_single(i2c->dev, (msgs + 1)->buf, | 
 | ||||||
|  | 		wpaddr = dma_map_single(i2c->dev, dma_wr_buf, | ||||||
|  | 					msgs->len, DMA_TO_DEVICE); | ||||||
|  | 		if (dma_mapping_error(i2c->dev, wpaddr)) { | ||||||
|  | 			i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false); | ||||||
|  | 
 | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		dma_rd_buf = i2c_get_dma_safe_msg_buf((msgs + 1), 0); | ||||||
|  | 		if (!dma_rd_buf) { | ||||||
|  | 			dma_unmap_single(i2c->dev, wpaddr, | ||||||
|  | 					 msgs->len, DMA_TO_DEVICE); | ||||||
|  | 
 | ||||||
|  | 			i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false); | ||||||
|  | 
 | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		rpaddr = dma_map_single(i2c->dev, dma_rd_buf, | ||||||
| 					(msgs + 1)->len, | 					(msgs + 1)->len, | ||||||
| 					DMA_FROM_DEVICE); | 					DMA_FROM_DEVICE); | ||||||
| 		if (dma_mapping_error(i2c->dev, rpaddr)) { | 		if (dma_mapping_error(i2c->dev, rpaddr)) { | ||||||
| 			dma_unmap_single(i2c->dev, wpaddr, | 			dma_unmap_single(i2c->dev, wpaddr, | ||||||
| 					 msgs->len, DMA_TO_DEVICE); | 					 msgs->len, DMA_TO_DEVICE); | ||||||
|  | 
 | ||||||
|  | 			i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false); | ||||||
|  | 			i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false); | ||||||
|  | 
 | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -578,14 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, | ||||||
| 	if (i2c->op == I2C_MASTER_WR) { | 	if (i2c->op == I2C_MASTER_WR) { | ||||||
| 		dma_unmap_single(i2c->dev, wpaddr, | 		dma_unmap_single(i2c->dev, wpaddr, | ||||||
| 				 msgs->len, DMA_TO_DEVICE); | 				 msgs->len, DMA_TO_DEVICE); | ||||||
|  | 
 | ||||||
|  | 		i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true); | ||||||
| 	} else if (i2c->op == I2C_MASTER_RD) { | 	} else if (i2c->op == I2C_MASTER_RD) { | ||||||
| 		dma_unmap_single(i2c->dev, rpaddr, | 		dma_unmap_single(i2c->dev, rpaddr, | ||||||
| 				 msgs->len, DMA_FROM_DEVICE); | 				 msgs->len, DMA_FROM_DEVICE); | ||||||
|  | 
 | ||||||
|  | 		i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true); | ||||||
| 	} else { | 	} else { | ||||||
| 		dma_unmap_single(i2c->dev, wpaddr, msgs->len, | 		dma_unmap_single(i2c->dev, wpaddr, msgs->len, | ||||||
| 				 DMA_TO_DEVICE); | 				 DMA_TO_DEVICE); | ||||||
| 		dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len, | 		dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len, | ||||||
| 				 DMA_FROM_DEVICE); | 				 DMA_FROM_DEVICE); | ||||||
|  | 
 | ||||||
|  | 		i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true); | ||||||
|  | 		i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (ret == 0) { | 	if (ret == 0) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jun Gao
						Jun Gao