Skip to content

Commit bb8822c

Browse files
stmordretWolfram Sang
authored andcommitted
i2c: i2c-stm32: Add generic DMA API
This patch adds a generic DMA API to implement DMA support for i2c-stm32fx drivers Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com> Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
1 parent 9e48155 commit bb8822c

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

drivers/i2c/busses/i2c-stm32.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* i2c-stm32.c
3+
*
4+
* Copyright (C) M'boumba Cedric Madianga 2017
5+
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
6+
*
7+
* License terms: GNU General Public License (GPL), version 2
8+
*/
9+
10+
#include "i2c-stm32.h"
11+
12+
/* Functions for DMA support */
13+
struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
14+
dma_addr_t phy_addr,
15+
u32 txdr_offset,
16+
u32 rxdr_offset)
17+
{
18+
struct stm32_i2c_dma *dma;
19+
struct dma_slave_config dma_sconfig;
20+
int ret;
21+
22+
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
23+
if (!dma)
24+
return NULL;
25+
26+
/* Request and configure I2C TX dma channel */
27+
dma->chan_tx = dma_request_slave_channel(dev, "tx");
28+
if (!dma->chan_tx) {
29+
dev_dbg(dev, "can't request DMA tx channel\n");
30+
ret = -EINVAL;
31+
goto fail_al;
32+
}
33+
34+
memset(&dma_sconfig, 0, sizeof(dma_sconfig));
35+
dma_sconfig.dst_addr = phy_addr + txdr_offset;
36+
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
37+
dma_sconfig.dst_maxburst = 1;
38+
dma_sconfig.direction = DMA_MEM_TO_DEV;
39+
ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
40+
if (ret < 0) {
41+
dev_err(dev, "can't configure tx channel\n");
42+
goto fail_tx;
43+
}
44+
45+
/* Request and configure I2C RX dma channel */
46+
dma->chan_rx = dma_request_slave_channel(dev, "rx");
47+
if (!dma->chan_rx) {
48+
dev_err(dev, "can't request DMA rx channel\n");
49+
ret = -EINVAL;
50+
goto fail_tx;
51+
}
52+
53+
memset(&dma_sconfig, 0, sizeof(dma_sconfig));
54+
dma_sconfig.src_addr = phy_addr + rxdr_offset;
55+
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
56+
dma_sconfig.src_maxburst = 1;
57+
dma_sconfig.direction = DMA_DEV_TO_MEM;
58+
ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
59+
if (ret < 0) {
60+
dev_err(dev, "can't configure rx channel\n");
61+
goto fail_rx;
62+
}
63+
64+
init_completion(&dma->dma_complete);
65+
66+
dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
67+
dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
68+
69+
return dma;
70+
71+
fail_rx:
72+
dma_release_channel(dma->chan_rx);
73+
fail_tx:
74+
dma_release_channel(dma->chan_tx);
75+
fail_al:
76+
devm_kfree(dev, dma);
77+
dev_info(dev, "can't use DMA\n");
78+
79+
return NULL;
80+
}
81+
82+
void stm32_i2c_dma_free(struct stm32_i2c_dma *dma)
83+
{
84+
dma->dma_buf = 0;
85+
dma->dma_len = 0;
86+
87+
dma_release_channel(dma->chan_tx);
88+
dma->chan_tx = NULL;
89+
90+
dma_release_channel(dma->chan_rx);
91+
dma->chan_rx = NULL;
92+
93+
dma->chan_using = NULL;
94+
}
95+
96+
int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
97+
bool rd_wr, u32 len, u8 *buf,
98+
dma_async_tx_callback callback,
99+
void *dma_async_param)
100+
{
101+
struct dma_async_tx_descriptor *txdesc;
102+
struct device *chan_dev;
103+
int ret;
104+
105+
if (rd_wr) {
106+
dma->chan_using = dma->chan_rx;
107+
dma->dma_transfer_dir = DMA_DEV_TO_MEM;
108+
dma->dma_data_dir = DMA_FROM_DEVICE;
109+
} else {
110+
dma->chan_using = dma->chan_tx;
111+
dma->dma_transfer_dir = DMA_MEM_TO_DEV;
112+
dma->dma_data_dir = DMA_TO_DEVICE;
113+
}
114+
115+
dma->dma_len = len;
116+
chan_dev = dma->chan_using->device->dev;
117+
118+
dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len,
119+
dma->dma_data_dir);
120+
if (dma_mapping_error(chan_dev, dma->dma_buf)) {
121+
dev_err(dev, "DMA mapping failed\n");
122+
return -EINVAL;
123+
}
124+
125+
txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
126+
dma->dma_len,
127+
dma->dma_transfer_dir,
128+
DMA_PREP_INTERRUPT);
129+
if (!txdesc) {
130+
dev_err(dev, "Not able to get desc for DMA xfer\n");
131+
ret = -EINVAL;
132+
goto err;
133+
}
134+
135+
reinit_completion(&dma->dma_complete);
136+
137+
txdesc->callback = callback;
138+
txdesc->callback_param = dma_async_param;
139+
ret = dma_submit_error(dmaengine_submit(txdesc));
140+
if (ret < 0) {
141+
dev_err(dev, "DMA submit failed\n");
142+
goto err;
143+
}
144+
145+
dma_async_issue_pending(dma->chan_using);
146+
147+
return 0;
148+
149+
err:
150+
dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len,
151+
dma->dma_data_dir);
152+
return ret;
153+
}

drivers/i2c/busses/i2c-stm32.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,48 @@
1111
#ifndef _I2C_STM32_H
1212
#define _I2C_STM32_H
1313

14+
#include <linux/dma-direction.h>
15+
#include <linux/dmaengine.h>
16+
#include <linux/dma-mapping.h>
17+
1418
enum stm32_i2c_speed {
1519
STM32_I2C_SPEED_STANDARD, /* 100 kHz */
1620
STM32_I2C_SPEED_FAST, /* 400 kHz */
1721
STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */
1822
STM32_I2C_SPEED_END,
1923
};
2024

25+
/**
26+
* struct stm32_i2c_dma - DMA specific data
27+
* @chan_tx: dma channel for TX transfer
28+
* @chan_rx: dma channel for RX transfer
29+
* @chan_using: dma channel used for the current transfer (TX or RX)
30+
* @dma_buf: dma buffer
31+
* @dma_len: dma buffer len
32+
* @dma_transfer_dir: dma transfer direction indicator
33+
* @dma_data_dir: dma transfer mode indicator
34+
* @dma_complete: dma transfer completion
35+
*/
36+
struct stm32_i2c_dma {
37+
struct dma_chan *chan_tx;
38+
struct dma_chan *chan_rx;
39+
struct dma_chan *chan_using;
40+
dma_addr_t dma_buf;
41+
unsigned int dma_len;
42+
enum dma_transfer_direction dma_transfer_dir;
43+
enum dma_data_direction dma_data_dir;
44+
struct completion dma_complete;
45+
};
46+
47+
struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
48+
dma_addr_t phy_addr,
49+
u32 txdr_offset, u32 rxdr_offset);
50+
51+
void stm32_i2c_dma_free(struct stm32_i2c_dma *dma);
52+
53+
int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
54+
bool rd_wr, u32 len, u8 *buf,
55+
dma_async_tx_callback callback,
56+
void *dma_async_param);
57+
2158
#endif /* _I2C_STM32_H */

0 commit comments

Comments
 (0)