1 /*
2  * Copyright (c) 2018, Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <zephyr/drivers/i2c.h>
9 #include <zephyr/dt-bindings/i2c/i2c.h>
10 #include <zephyr/pm/device.h>
11 #include <zephyr/drivers/pinctrl.h>
12 #include <soc.h>
13 #include <nrfx_twi.h>
14 
15 #include <zephyr/logging/log.h>
16 #include <zephyr/irq.h>
17 LOG_MODULE_REGISTER(i2c_nrfx_twi, CONFIG_I2C_LOG_LEVEL);
18 
19 #if CONFIG_I2C_NRFX_TRANSFER_TIMEOUT
20 #define I2C_TRANSFER_TIMEOUT_MSEC K_MSEC(CONFIG_I2C_NRFX_TRANSFER_TIMEOUT)
21 #else
22 #define I2C_TRANSFER_TIMEOUT_MSEC K_FOREVER
23 #endif
24 
25 struct i2c_nrfx_twi_data {
26 	struct k_sem transfer_sync;
27 	struct k_sem completion_sync;
28 	volatile nrfx_err_t res;
29 	uint32_t dev_config;
30 };
31 
32 struct i2c_nrfx_twi_config {
33 	nrfx_twi_t twi;
34 	nrfx_twi_config_t config;
35 	const struct pinctrl_dev_config *pcfg;
36 };
37 
38 static int i2c_nrfx_twi_recover_bus(const struct device *dev);
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 	const struct i2c_nrfx_twi_config *config = dev->config;
45 	struct i2c_nrfx_twi_data *data = dev->data;
46 	int ret = 0;
47 
48 	k_sem_take(&data->transfer_sync, K_FOREVER);
49 
50 	/* Dummy take on completion_sync sem to be sure that it is empty */
51 	k_sem_take(&data->completion_sync, K_NO_WAIT);
52 
53 	nrfx_twi_enable(&config->twi);
54 
55 	for (size_t i = 0; i < num_msgs; i++) {
56 		if (I2C_MSG_ADDR_10_BITS & msgs[i].flags) {
57 			ret = -ENOTSUP;
58 			break;
59 		}
60 
61 		nrfx_twi_xfer_desc_t cur_xfer = {
62 			.p_primary_buf  = msgs[i].buf,
63 			.primary_length = msgs[i].len,
64 			.address	= addr,
65 			.type		= (msgs[i].flags & I2C_MSG_READ) ?
66 					  NRFX_TWI_XFER_RX : NRFX_TWI_XFER_TX
67 		};
68 		uint32_t xfer_flags = 0;
69 		nrfx_err_t res;
70 
71 		/* In case the STOP condition is not supposed to appear after
72 		 * the current message, check what is requested further:
73 		 */
74 		if (!(msgs[i].flags & I2C_MSG_STOP)) {
75 			/* - if the transfer consists of more messages
76 			 *   and the I2C repeated START is not requested
77 			 *   to appear before the next message, suspend
78 			 *   the transfer after the current message,
79 			 *   so that it can be resumed with the next one,
80 			 *   resulting in the two messages merged into
81 			 *   a continuous transfer on the bus
82 			 */
83 			if ((i < (num_msgs - 1)) &&
84 			    !(msgs[i + 1].flags & I2C_MSG_RESTART)) {
85 				xfer_flags |= NRFX_TWI_FLAG_SUSPEND;
86 			/* - otherwise, just finish the transfer without
87 			 *   generating the STOP condition, unless the current
88 			 *   message is an RX request, for which such feature
89 			 *   is not supported
90 			 */
91 			} else if (msgs[i].flags & I2C_MSG_READ) {
92 				ret = -ENOTSUP;
93 				break;
94 			} else {
95 				xfer_flags |= NRFX_TWI_FLAG_TX_NO_STOP;
96 			}
97 		}
98 
99 		res = nrfx_twi_xfer(&config->twi, &cur_xfer, 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(&data->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 i2c_nrfx_twi_recover_bus()
126 			 * to 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(&config->twi);
131 			(void)i2c_nrfx_twi_recover_bus(dev);
132 			ret = -EIO;
133 			break;
134 		}
135 
136 		res = data->res;
137 		if (res != NRFX_SUCCESS) {
138 			LOG_ERR("Error 0x%08X occurred for message %d", res, i);
139 			ret = -EIO;
140 			break;
141 		}
142 	}
143 
144 	nrfx_twi_disable(&config->twi);
145 	k_sem_give(&data->transfer_sync);
146 
147 	return ret;
148 }
149 
event_handler(nrfx_twi_evt_t const * p_event,void * p_context)150 static void event_handler(nrfx_twi_evt_t const *p_event, void *p_context)
151 {
152 	struct i2c_nrfx_twi_data *dev_data = p_context;
153 
154 	switch (p_event->type) {
155 	case NRFX_TWI_EVT_DONE:
156 		dev_data->res = NRFX_SUCCESS;
157 		break;
158 	case NRFX_TWI_EVT_ADDRESS_NACK:
159 		dev_data->res = NRFX_ERROR_DRV_TWI_ERR_ANACK;
160 		break;
161 	case NRFX_TWI_EVT_DATA_NACK:
162 		dev_data->res = NRFX_ERROR_DRV_TWI_ERR_DNACK;
163 		break;
164 	default:
165 		dev_data->res = NRFX_ERROR_INTERNAL;
166 		break;
167 	}
168 
169 	k_sem_give(&dev_data->completion_sync);
170 }
171 
i2c_nrfx_twi_configure(const struct device * dev,uint32_t dev_config)172 static int i2c_nrfx_twi_configure(const struct device *dev,
173 				  uint32_t dev_config)
174 {
175 	const struct i2c_nrfx_twi_config *config = dev->config;
176 	struct i2c_nrfx_twi_data *data = dev->data;
177 	nrfx_twi_t const *inst = &config->twi;
178 
179 	if (I2C_ADDR_10_BITS & dev_config) {
180 		return -EINVAL;
181 	}
182 
183 	switch (I2C_SPEED_GET(dev_config)) {
184 	case I2C_SPEED_STANDARD:
185 		nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_100K);
186 		break;
187 	case I2C_SPEED_FAST:
188 		nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_400K);
189 		break;
190 	default:
191 		LOG_ERR("unsupported speed");
192 		return -EINVAL;
193 	}
194 	data->dev_config = dev_config;
195 
196 	return 0;
197 }
198 
i2c_nrfx_twi_recover_bus(const struct device * dev)199 static int i2c_nrfx_twi_recover_bus(const struct device *dev)
200 {
201 	const struct i2c_nrfx_twi_config *config = dev->config;
202 	uint32_t scl_pin;
203 	uint32_t sda_pin;
204 	nrfx_err_t err;
205 
206 	scl_pin = nrf_twi_scl_pin_get(config->twi.p_twi);
207 	sda_pin = nrf_twi_sda_pin_get(config->twi.p_twi);
208 
209 	err = nrfx_twi_bus_recover(scl_pin, sda_pin);
210 	return (err == NRFX_SUCCESS ? 0 : -EBUSY);
211 }
212 
213 static const struct i2c_driver_api i2c_nrfx_twi_driver_api = {
214 	.configure   = i2c_nrfx_twi_configure,
215 	.transfer    = i2c_nrfx_twi_transfer,
216 	.recover_bus = i2c_nrfx_twi_recover_bus,
217 };
218 
init_twi(const struct device * dev)219 static int init_twi(const struct device *dev)
220 {
221 	const struct i2c_nrfx_twi_config *config = dev->config;
222 	struct i2c_nrfx_twi_data *dev_data = dev->data;
223 	nrfx_err_t result = nrfx_twi_init(&config->twi, &config->config,
224 					  event_handler, dev_data);
225 	if (result != NRFX_SUCCESS) {
226 		LOG_ERR("Failed to initialize device: %s",
227 			    dev->name);
228 		return -EBUSY;
229 	}
230 
231 	return 0;
232 }
233 
234 #ifdef CONFIG_PM_DEVICE
twi_nrfx_pm_action(const struct device * dev,enum pm_device_action action)235 static int twi_nrfx_pm_action(const struct device *dev,
236 			      enum pm_device_action action)
237 {
238 	const struct i2c_nrfx_twi_config *config = dev->config;
239 	struct i2c_nrfx_twi_data *data = dev->data;
240 	int ret = 0;
241 
242 	switch (action) {
243 	case PM_DEVICE_ACTION_RESUME:
244 		ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
245 		if (ret < 0) {
246 			return ret;
247 		}
248 		init_twi(dev);
249 		if (data->dev_config) {
250 			i2c_nrfx_twi_configure(dev, data->dev_config);
251 		}
252 		break;
253 
254 	case PM_DEVICE_ACTION_SUSPEND:
255 		nrfx_twi_uninit(&config->twi);
256 
257 		ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
258 		if (ret < 0) {
259 			return ret;
260 		}
261 		break;
262 
263 	default:
264 		ret = -ENOTSUP;
265 	}
266 
267 	return ret;
268 }
269 #endif /* CONFIG_PM_DEVICE */
270 
271 #define I2C_NRFX_TWI_INVALID_FREQUENCY  ((nrf_twi_frequency_t)-1)
272 #define I2C_NRFX_TWI_FREQUENCY(bitrate)					       \
273 	 (bitrate == I2C_BITRATE_STANDARD ? NRF_TWI_FREQ_100K		       \
274 	: bitrate == 250000               ? NRF_TWI_FREQ_250K		       \
275 	: bitrate == I2C_BITRATE_FAST     ? NRF_TWI_FREQ_400K		       \
276 					  : I2C_NRFX_TWI_INVALID_FREQUENCY)
277 #define I2C(idx) DT_NODELABEL(i2c##idx)
278 #define I2C_FREQUENCY(idx)						       \
279 	I2C_NRFX_TWI_FREQUENCY(DT_PROP(I2C(idx), clock_frequency))
280 
281 #define I2C_NRFX_TWI_DEVICE(idx)					       \
282 	NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(I2C(idx));			       \
283 	BUILD_ASSERT(I2C_FREQUENCY(idx)	!=				       \
284 		     I2C_NRFX_TWI_INVALID_FREQUENCY,			       \
285 		     "Wrong I2C " #idx " frequency setting in dts");	       \
286 	static int twi_##idx##_init(const struct device *dev)		       \
287 	{								       \
288 		IRQ_CONNECT(DT_IRQN(I2C(idx)), DT_IRQ(I2C(idx), priority),     \
289 			    nrfx_isr, nrfx_twi_##idx##_irq_handler, 0);	       \
290 		const struct i2c_nrfx_twi_config *config = dev->config;	       \
291 		int err = pinctrl_apply_state(config->pcfg,		       \
292 					      PINCTRL_STATE_DEFAULT);	       \
293 		if (err < 0) {						       \
294 			return err;					       \
295 		}							       \
296 		return init_twi(dev);					       \
297 	}								       \
298 	static struct i2c_nrfx_twi_data twi_##idx##_data = {		       \
299 		.transfer_sync = Z_SEM_INITIALIZER(                            \
300 			twi_##idx##_data.transfer_sync, 1, 1),                 \
301 		.completion_sync = Z_SEM_INITIALIZER(                          \
302 			twi_##idx##_data.completion_sync, 0, 1)		       \
303 	};								       \
304 	PINCTRL_DT_DEFINE(I2C(idx));					       \
305 	static const struct i2c_nrfx_twi_config twi_##idx##z_config = {	       \
306 		.twi = NRFX_TWI_INSTANCE(idx),				       \
307 		.config = {						       \
308 			.skip_gpio_cfg = true,				       \
309 			.skip_psel_cfg = true,				       \
310 			.frequency = I2C_FREQUENCY(idx),		       \
311 		},							       \
312 		.pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)),		       \
313 	};								       \
314 	PM_DEVICE_DT_DEFINE(I2C(idx), twi_nrfx_pm_action);		       \
315 	I2C_DEVICE_DT_DEFINE(I2C(idx),					       \
316 		      twi_##idx##_init,					       \
317 		      PM_DEVICE_DT_GET(I2C(idx)),			       \
318 		      &twi_##idx##_data,				       \
319 		      &twi_##idx##z_config,				       \
320 		      POST_KERNEL,					       \
321 		      CONFIG_I2C_INIT_PRIORITY,				       \
322 		      &i2c_nrfx_twi_driver_api)
323 
324 #ifdef CONFIG_HAS_HW_NRF_TWI0
325 I2C_NRFX_TWI_DEVICE(0);
326 #endif
327 
328 #ifdef CONFIG_HAS_HW_NRF_TWI1
329 I2C_NRFX_TWI_DEVICE(1);
330 #endif
331