1 /*
2 * Copyright (c) 2018, Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <drivers/i2c.h>
9 #include <dt-bindings/i2c/i2c.h>
10 #include <nrfx_twi.h>
11
12 #include <logging/log.h>
13 LOG_MODULE_REGISTER(i2c_nrfx_twi, CONFIG_I2C_LOG_LEVEL);
14
15 #define I2C_TRANSFER_TIMEOUT_MSEC K_MSEC(500)
16
17 struct i2c_nrfx_twi_data {
18 struct k_sem transfer_sync;
19 struct k_sem completion_sync;
20 volatile nrfx_err_t res;
21 uint32_t dev_config;
22 };
23
24 struct i2c_nrfx_twi_config {
25 nrfx_twi_t twi;
26 nrfx_twi_config_t config;
27 };
28
get_dev_data(const struct device * dev)29 static inline struct i2c_nrfx_twi_data *get_dev_data(const struct device *dev)
30 {
31 return dev->data;
32 }
33
34 static inline
get_dev_config(const struct device * dev)35 const struct i2c_nrfx_twi_config *get_dev_config(const struct device *dev)
36 {
37 return dev->config;
38 }
39
i2c_nrfx_twi_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)40 static int i2c_nrfx_twi_transfer(const struct device *dev,
41 struct i2c_msg *msgs,
42 uint8_t num_msgs, uint16_t addr)
43 {
44 int ret = 0;
45
46 k_sem_take(&(get_dev_data(dev)->transfer_sync), K_FOREVER);
47
48 /* Dummy take on completion_sync sem to be sure that it is empty */
49 k_sem_take(&(get_dev_data(dev)->completion_sync), K_NO_WAIT);
50
51 nrfx_twi_enable(&get_dev_config(dev)->twi);
52
53 for (size_t i = 0; i < num_msgs; i++) {
54 if (I2C_MSG_ADDR_10_BITS & msgs[i].flags) {
55 ret = -ENOTSUP;
56 break;
57 }
58
59 nrfx_twi_xfer_desc_t cur_xfer = {
60 .p_primary_buf = msgs[i].buf,
61 .primary_length = msgs[i].len,
62 .address = addr,
63 .type = (msgs[i].flags & I2C_MSG_READ) ?
64 NRFX_TWI_XFER_RX : NRFX_TWI_XFER_TX
65 };
66 uint32_t xfer_flags = 0;
67 nrfx_err_t res;
68
69 /* In case the STOP condition is not supposed to appear after
70 * the current message, check what is requested further:
71 */
72 if (!(msgs[i].flags & I2C_MSG_STOP)) {
73 /* - if the transfer consists of more messages
74 * and the I2C repeated START is not requested
75 * to appear before the next message, suspend
76 * the transfer after the current message,
77 * so that it can be resumed with the next one,
78 * resulting in the two messages merged into
79 * a continuous transfer on the bus
80 */
81 if ((i < (num_msgs - 1)) &&
82 !(msgs[i + 1].flags & I2C_MSG_RESTART)) {
83 xfer_flags |= NRFX_TWI_FLAG_SUSPEND;
84 /* - otherwise, just finish the transfer without
85 * generating the STOP condition, unless the current
86 * message is an RX request, for which such feature
87 * is not supported
88 */
89 } else if (msgs[i].flags & I2C_MSG_READ) {
90 ret = -ENOTSUP;
91 break;
92 } else {
93 xfer_flags |= NRFX_TWI_FLAG_TX_NO_STOP;
94 }
95 }
96
97 res = nrfx_twi_xfer(&get_dev_config(dev)->twi,
98 &cur_xfer,
99 xfer_flags);
100 if (res != NRFX_SUCCESS) {
101 if (res == NRFX_ERROR_BUSY) {
102 ret = -EBUSY;
103 break;
104 } else {
105 ret = -EIO;
106 break;
107 }
108 }
109
110 ret = k_sem_take(&(get_dev_data(dev)->completion_sync),
111 I2C_TRANSFER_TIMEOUT_MSEC);
112 if (ret != 0) {
113 /* Whatever the frequency, completion_sync should have
114 * been given by the event handler.
115 *
116 * If it hasn't, it's probably due to an hardware issue
117 * on the I2C line, for example a short between SDA and
118 * GND.
119 * This is issue has also been when trying to use the
120 * I2C bus during MCU internal flash erase.
121 *
122 * In many situation, a retry is sufficient.
123 * However, some time the I2C device get stuck and need
124 * help to recover.
125 * Therefore we always call nrfx_twi_bus_recover() to
126 * make sure everything has been done to restore the
127 * bus from this error.
128 */
129 LOG_ERR("Error on I2C line occurred for message %d", i);
130 nrfx_twi_disable(&get_dev_config(dev)->twi);
131 nrfx_twi_bus_recover(get_dev_config(dev)->config.scl,
132 get_dev_config(dev)->config.sda);
133 ret = -EIO;
134 break;
135 }
136
137 res = get_dev_data(dev)->res;
138 if (res != NRFX_SUCCESS) {
139 LOG_ERR("Error 0x%08X occurred for message %d", res, i);
140 ret = -EIO;
141 break;
142 }
143 }
144
145 nrfx_twi_disable(&get_dev_config(dev)->twi);
146 k_sem_give(&(get_dev_data(dev)->transfer_sync));
147
148 return ret;
149 }
150
event_handler(nrfx_twi_evt_t const * p_event,void * p_context)151 static void event_handler(nrfx_twi_evt_t const *p_event, void *p_context)
152 {
153 struct i2c_nrfx_twi_data *dev_data = p_context;
154
155 switch (p_event->type) {
156 case NRFX_TWI_EVT_DONE:
157 dev_data->res = NRFX_SUCCESS;
158 break;
159 case NRFX_TWI_EVT_ADDRESS_NACK:
160 dev_data->res = NRFX_ERROR_DRV_TWI_ERR_ANACK;
161 break;
162 case NRFX_TWI_EVT_DATA_NACK:
163 dev_data->res = NRFX_ERROR_DRV_TWI_ERR_DNACK;
164 break;
165 default:
166 dev_data->res = NRFX_ERROR_INTERNAL;
167 break;
168 }
169
170 k_sem_give(&dev_data->completion_sync);
171 }
172
i2c_nrfx_twi_configure(const struct device * dev,uint32_t dev_config)173 static int i2c_nrfx_twi_configure(const struct device *dev,
174 uint32_t dev_config)
175 {
176 nrfx_twi_t const *inst = &(get_dev_config(dev)->twi);
177
178 if (I2C_ADDR_10_BITS & dev_config) {
179 return -EINVAL;
180 }
181
182 switch (I2C_SPEED_GET(dev_config)) {
183 case I2C_SPEED_STANDARD:
184 nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_100K);
185 break;
186 case I2C_SPEED_FAST:
187 nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_400K);
188 break;
189 default:
190 LOG_ERR("unsupported speed");
191 return -EINVAL;
192 }
193 get_dev_data(dev)->dev_config = dev_config;
194
195 return 0;
196 }
197
198 static const struct i2c_driver_api i2c_nrfx_twi_driver_api = {
199 .configure = i2c_nrfx_twi_configure,
200 .transfer = i2c_nrfx_twi_transfer,
201 };
202
init_twi(const struct device * dev)203 static int init_twi(const struct device *dev)
204 {
205 struct i2c_nrfx_twi_data *dev_data = get_dev_data(dev);
206 nrfx_err_t result = nrfx_twi_init(&get_dev_config(dev)->twi,
207 &get_dev_config(dev)->config,
208 event_handler, dev_data);
209 if (result != NRFX_SUCCESS) {
210 LOG_ERR("Failed to initialize device: %s",
211 dev->name);
212 return -EBUSY;
213 }
214
215 return 0;
216 }
217
218 #ifdef CONFIG_PM_DEVICE
twi_nrfx_pm_control(const struct device * dev,enum pm_device_action action)219 static int twi_nrfx_pm_control(const struct device *dev,
220 enum pm_device_action action)
221 {
222 int ret = 0;
223
224 switch (action) {
225 case PM_DEVICE_ACTION_RESUME:
226 init_twi(dev);
227 if (get_dev_data(dev)->dev_config) {
228 i2c_nrfx_twi_configure(dev,
229 get_dev_data(dev)->dev_config);
230 }
231 break;
232
233 case PM_DEVICE_ACTION_SUSPEND:
234 nrfx_twi_uninit(&get_dev_config(dev)->twi);
235 break;
236
237 default:
238 ret = -ENOTSUP;
239 }
240
241 return ret;
242 }
243 #endif /* CONFIG_PM_DEVICE */
244
245 #define I2C_NRFX_TWI_INVALID_FREQUENCY ((nrf_twi_frequency_t)-1)
246 #define I2C_NRFX_TWI_FREQUENCY(bitrate) \
247 (bitrate == I2C_BITRATE_STANDARD ? NRF_TWI_FREQ_100K \
248 : bitrate == 250000 ? NRF_TWI_FREQ_250K \
249 : bitrate == I2C_BITRATE_FAST ? NRF_TWI_FREQ_400K \
250 : I2C_NRFX_TWI_INVALID_FREQUENCY)
251 #define I2C(idx) DT_NODELABEL(i2c##idx)
252 #define I2C_FREQUENCY(idx) \
253 I2C_NRFX_TWI_FREQUENCY(DT_PROP(I2C(idx), clock_frequency))
254
255 #define I2C_NRFX_TWI_DEVICE(idx) \
256 BUILD_ASSERT(I2C_FREQUENCY(idx) != \
257 I2C_NRFX_TWI_INVALID_FREQUENCY, \
258 "Wrong I2C " #idx " frequency setting in dts"); \
259 static int twi_##idx##_init(const struct device *dev) \
260 { \
261 IRQ_CONNECT(DT_IRQN(I2C(idx)), DT_IRQ(I2C(idx), priority), \
262 nrfx_isr, nrfx_twi_##idx##_irq_handler, 0); \
263 return init_twi(dev); \
264 } \
265 static struct i2c_nrfx_twi_data twi_##idx##_data = { \
266 .transfer_sync = Z_SEM_INITIALIZER( \
267 twi_##idx##_data.transfer_sync, 1, 1), \
268 .completion_sync = Z_SEM_INITIALIZER( \
269 twi_##idx##_data.completion_sync, 0, 1) \
270 }; \
271 static const struct i2c_nrfx_twi_config twi_##idx##z_config = { \
272 .twi = NRFX_TWI_INSTANCE(idx), \
273 .config = { \
274 .scl = DT_PROP(I2C(idx), scl_pin), \
275 .sda = DT_PROP(I2C(idx), sda_pin), \
276 .frequency = I2C_FREQUENCY(idx), \
277 } \
278 }; \
279 DEVICE_DT_DEFINE(I2C(idx), \
280 twi_##idx##_init, \
281 twi_nrfx_pm_control, \
282 &twi_##idx##_data, \
283 &twi_##idx##z_config, \
284 POST_KERNEL, \
285 CONFIG_I2C_INIT_PRIORITY, \
286 &i2c_nrfx_twi_driver_api)
287
288 #ifdef CONFIG_I2C_0_NRF_TWI
289 I2C_NRFX_TWI_DEVICE(0);
290 #endif
291
292 #ifdef CONFIG_I2C_1_NRF_TWI
293 I2C_NRFX_TWI_DEVICE(1);
294 #endif
295