@@ -20,13 +20,14 @@ struct i2c_nrfx_twim_data {
2020 struct k_sem completion_sync ;
2121 volatile nrfx_err_t res ;
2222 uint32_t dev_config ;
23- uint16_t concat_buf_size ;
24- uint8_t * concat_buf ;
23+ uint8_t * msg_buf ;
2524};
2625
2726struct i2c_nrfx_twim_config {
2827 nrfx_twim_t twim ;
2928 nrfx_twim_config_t config ;
29+ uint16_t concat_buf_size ;
30+ uint16_t flash_buf_max_size ;
3031};
3132
3233static inline struct i2c_nrfx_twim_data * get_dev_data (const struct device * dev )
@@ -44,20 +45,22 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
4445 struct i2c_msg * msgs ,
4546 uint8_t num_msgs , uint16_t addr )
4647{
48+ struct i2c_nrfx_twim_data * dev_data = get_dev_data (dev );
49+ const struct i2c_nrfx_twim_config * dev_config = get_dev_config (dev );
4750 int ret = 0 ;
48- uint32_t concat_len = 0 ;
49- uint8_t * concat_buf = get_dev_data ( dev ) -> concat_buf ;
50- uint16_t concat_buf_size = get_dev_data ( dev ) -> concat_buf_size ;
51+ uint8_t * msg_buf = dev_data -> msg_buf ;
52+ uint16_t msg_buf_used = 0 ;
53+ uint16_t concat_buf_size = dev_config -> concat_buf_size ;
5154 nrfx_twim_xfer_desc_t cur_xfer = {
5255 .address = addr
5356 };
5457
55- k_sem_take (& ( get_dev_data ( dev ) -> transfer_sync ) , K_FOREVER );
58+ k_sem_take (& dev_data -> transfer_sync , K_FOREVER );
5659
5760 /* Dummy take on completion_sync sem to be sure that it is empty */
58- k_sem_take (& ( get_dev_data ( dev ) -> completion_sync ) , K_NO_WAIT );
61+ k_sem_take (& dev_data -> completion_sync , K_NO_WAIT );
5962
60- nrfx_twim_enable (& get_dev_config ( dev ) -> twim );
63+ nrfx_twim_enable (& dev_config -> twim );
6164
6265 for (size_t i = 0 ; i < num_msgs ; i ++ ) {
6366 if (I2C_MSG_ADDR_10_BITS & msgs [i ].flags ) {
@@ -81,41 +84,60 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
8184 * already committed to concatenate this message, add it to
8285 * the buffer after verifying there's room.
8386 */
84- if (concat_next || (concat_len != 0 )) {
85- if ((concat_len + msgs [i ].len ) > concat_buf_size ) {
87+ if (concat_next || (msg_buf_used != 0 )) {
88+ if ((msg_buf_used + msgs [i ].len ) > concat_buf_size ) {
8689 LOG_ERR ("Need to use concatenation buffer and "
8790 "provided size is insufficient "
8891 "(%u + %u > %u). "
8992 "Adjust the zephyr,concat-buf-size "
9093 "property in the \"%s\" node." ,
91- concat_len , msgs [i ].len ,
94+ msg_buf_used , msgs [i ].len ,
9295 concat_buf_size , dev -> name );
9396 ret = - ENOSPC ;
9497 break ;
9598 }
9699 if (!(msgs [i ].flags & I2C_MSG_READ )) {
97- memcpy (concat_buf + concat_len ,
100+ memcpy (msg_buf + msg_buf_used ,
98101 msgs [i ].buf ,
99102 msgs [i ].len );
100103 }
101- concat_len += msgs [i ].len ;
104+ msg_buf_used += msgs [i ].len ;
105+
106+ /* TWIM peripherals cannot transfer data directly from
107+ * flash. If a buffer located in flash is provided for
108+ * a write transaction, its content must be copied to
109+ * RAM before the transfer can be requested.
110+ */
111+ } else if (!(msgs [i ].flags & I2C_MSG_READ ) &&
112+ !nrfx_is_in_ram (msgs [i ].buf )) {
113+ if (msgs [i ].len > dev_config -> flash_buf_max_size ) {
114+ LOG_ERR ("Cannot copy flash buffer of size: %u. "
115+ "Adjust the zephyr,flash-buf-max-size "
116+ "property in the \"%s\" node." ,
117+ msgs [i ].len , dev -> name );
118+ ret = - EINVAL ;
119+ break ;
120+ }
121+
122+ memcpy (msg_buf , msgs [i ].buf , msgs [i ].len );
123+ msg_buf_used = msgs [i ].len ;
102124 }
103125
104126 if (concat_next ) {
105127 continue ;
106128 }
107129
108- if (concat_len == 0 ) {
130+ if (msg_buf_used == 0 ) {
109131 cur_xfer .p_primary_buf = msgs [i ].buf ;
110132 cur_xfer .primary_length = msgs [i ].len ;
111133 } else {
112- cur_xfer .p_primary_buf = concat_buf ;
113- cur_xfer .primary_length = concat_len ;
134+ cur_xfer .p_primary_buf = msg_buf ;
135+ cur_xfer .primary_length = msg_buf_used ;
114136 }
115137 cur_xfer .type = (msgs [i ].flags & I2C_MSG_READ ) ?
116138 NRFX_TWIM_XFER_RX : NRFX_TWIM_XFER_TX ;
117139
118- nrfx_err_t res = nrfx_twim_xfer (& get_dev_config ( dev ) -> twim ,
140+ nrfx_err_t res = nrfx_twim_xfer (& dev_config -> twim ,
119141 & cur_xfer ,
120142 (msgs [i ].flags & I2C_MSG_STOP ) ?
121143 0 : NRFX_TWIM_FLAG_TX_NO_STOP );
@@ -129,7 +151,7 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
129151 }
130152 }
131153
132- ret = k_sem_take (& ( get_dev_data ( dev ) -> completion_sync ) ,
154+ ret = k_sem_take (& dev_data -> completion_sync ,
133155 I2C_TRANSFER_TIMEOUT_MSEC );
134156 if (ret != 0 ) {
135157 /* Whatever the frequency, completion_sync should have
@@ -149,14 +171,14 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
149171 * bus from this error.
150172 */
151173 LOG_ERR ("Error on I2C line occurred for message %d" , i );
152- nrfx_twim_disable (& get_dev_config ( dev ) -> twim );
153- nrfx_twim_bus_recover (get_dev_config ( dev ) -> config .scl ,
154- get_dev_config ( dev ) -> config .sda );
174+ nrfx_twim_disable (& dev_config -> twim );
175+ nrfx_twim_bus_recover (dev_config -> config .scl ,
176+ dev_config -> config .sda );
155177 ret = - EIO ;
156178 break ;
157179 }
158180
159- res = get_dev_data ( dev ) -> res ;
181+ res = dev_data -> res ;
160182
161183 if (res != NRFX_SUCCESS ) {
162184 LOG_ERR ("Error 0x%08X occurred for message %d" , res , i );
@@ -168,24 +190,24 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
168190 * content of concatenation buffer has to be copied back into
169191 * buffers provided by user. */
170192 if ((msgs [i ].flags & I2C_MSG_READ )
171- && cur_xfer .p_primary_buf == concat_buf ) {
193+ && cur_xfer .p_primary_buf == msg_buf ) {
172194 int j = i ;
173195
174- while (concat_len >= msgs [j ].len ) {
175- concat_len -= msgs [j ].len ;
196+ while (msg_buf_used >= msgs [j ].len ) {
197+ msg_buf_used -= msgs [j ].len ;
176198 memcpy (msgs [j ].buf ,
177- concat_buf + concat_len ,
199+ msg_buf + msg_buf_used ,
178200 msgs [j ].len );
179201 j -- ;
180202 }
181203
182204 }
183205
184- concat_len = 0 ;
206+ msg_buf_used = 0 ;
185207 }
186208
187- nrfx_twim_disable (& get_dev_config ( dev ) -> twim );
188- k_sem_give (& ( get_dev_data ( dev ) -> transfer_sync ) );
209+ nrfx_twim_disable (& dev_config -> twim );
210+ k_sem_give (& dev_data -> transfer_sync );
189211
190212 return ret ;
191213}
@@ -296,12 +318,18 @@ static int twim_nrfx_pm_control(const struct device *dev,
296318#define I2C_FREQUENCY (idx ) \
297319 I2C_NRFX_TWIM_FREQUENCY(DT_PROP(I2C(idx), clock_frequency))
298320
299- #define CONCAT_BUF_SIZE (idx ) DT_PROP(I2C(idx), zephyr_concat_buf_size)
300-
301- #define I2C_CONCAT_BUF (idx ) \
321+ #define CONCAT_BUF_SIZE (idx ) \
302322 COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_concat_buf_size), \
303- (.concat_buf = twim_##idx##_concat_buf, \
304- .concat_buf_size = CONCAT_BUF_SIZE(idx),), ())
323+ (DT_PROP(I2C(idx), zephyr_concat_buf_size)), (0))
324+ #define FLASH_BUF_MAX_SIZE (idx ) \
325+ COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_flash_buf_max_size), \
326+ (DT_PROP(I2C(idx), zephyr_flash_buf_max_size)), (0))
327+
328+ #define USES_MSG_BUF (idx ) \
329+ COND_CODE_0(CONCAT_BUF_SIZE(idx), \
330+ (COND_CODE_0(FLASH_BUF_MAX_SIZE(idx), (0), (1))), \
331+ (1))
332+ #define MSG_BUF_SIZE (idx ) MAX(CONCAT_BUF_SIZE(idx), FLASH_BUF_MAX_SIZE(idx))
305333
306334#define I2C_NRFX_TWIM_DEVICE (idx ) \
307335 BUILD_ASSERT(I2C_FREQUENCY(idx) != \
@@ -313,24 +341,25 @@ static int twim_nrfx_pm_control(const struct device *dev,
313341 nrfx_isr, nrfx_twim_##idx##_irq_handler, 0); \
314342 return init_twim(dev); \
315343 } \
316- COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_concat_buf_size), \
317- (static uint8_t twim_##idx##_concat_buf[CONCAT_BUF_SIZE(idx)];), \
318- ()) \
319- \
344+ IF_ENABLED(USES_MSG_BUF(idx), \
345+ (static uint8_t twim_##idx##_msg_buf[MSG_BUF_SIZE(idx)];)) \
320346 static struct i2c_nrfx_twim_data twim_##idx##_data = { \
321- .transfer_sync = Z_SEM_INITIALIZER( \
322- twim_##idx##_data.transfer_sync, 1, 1), \
323- .completion_sync = Z_SEM_INITIALIZER( \
324- twim_##idx##_data.completion_sync, 0, 1), \
325- I2C_CONCAT_BUF(idx) \
347+ .transfer_sync = Z_SEM_INITIALIZER( \
348+ twim_##idx##_data.transfer_sync, 1, 1), \
349+ .completion_sync = Z_SEM_INITIALIZER( \
350+ twim_##idx##_data.completion_sync, 0, 1), \
351+ IF_ENABLED(USES_MSG_BUF(idx), \
352+ (.msg_buf = twim_##idx##_msg_buf,)) \
326353 }; \
327354 static const struct i2c_nrfx_twim_config twim_##idx##z_config = { \
328355 .twim = NRFX_TWIM_INSTANCE(idx), \
329356 .config = { \
330357 .scl = DT_PROP(I2C(idx), scl_pin), \
331358 .sda = DT_PROP(I2C(idx), sda_pin), \
332359 .frequency = I2C_FREQUENCY(idx), \
333- } \
360+ }, \
361+ .concat_buf_size = CONCAT_BUF_SIZE(idx), \
362+ .flash_buf_max_size = FLASH_BUF_MAX_SIZE(idx), \
334363 }; \
335364 DEVICE_DT_DEFINE(I2C(idx), \
336365 twim_##idx##_init, \
0 commit comments