1 /*
2  * Copyright (c) 2017 Piotr Mienkowski
3  * Copyright (c) 2023 Gerson Fernando Budke
4  * Copyright (c) 2023 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #define DT_DRV_COMPAT atmel_sam_i2c_twihs
10 
11 /** @file
12  * @brief I2C bus (TWIHS) driver for Atmel SAM MCU family.
13  *
14  * Only I2C Controller Mode with 7 bit addressing is currently supported.
15  */
16 
17 #include <errno.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/device.h>
21 #include <zephyr/init.h>
22 #include <soc.h>
23 #include <zephyr/drivers/i2c.h>
24 #include <zephyr/drivers/i2c/rtio.h>
25 #include <zephyr/drivers/pinctrl.h>
26 #include <zephyr/drivers/clock_control/atmel_sam_pmc.h>
27 
28 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
29 #include <zephyr/logging/log.h>
30 #include <zephyr/irq.h>
31 LOG_MODULE_REGISTER(i2c_sam_twihs_rtio);
32 
33 #include "i2c-priv.h"
34 
35 /** I2C bus speed [Hz] in Standard Mode */
36 #define BUS_SPEED_STANDARD_HZ         100000U
37 /** I2C bus speed [Hz] in Fast Mode */
38 #define BUS_SPEED_FAST_HZ             400000U
39 /** I2C bus speed [Hz] in High Speed Mode */
40 #define BUS_SPEED_HIGH_HZ            3400000U
41 /* Maximum value of Clock Divider (CKDIV) */
42 #define CKDIV_MAX                          7
43 
44 /* Device constant configuration parameters */
45 struct i2c_sam_twihs_dev_cfg {
46 	Twihs *regs;
47 	void (*irq_config)(void);
48 	uint32_t bitrate;
49 	const struct atmel_sam_pmc_config clock_cfg;
50 	const struct pinctrl_dev_config *pcfg;
51 	uint8_t irq_id;
52 };
53 
54 /* Device run time data */
55 struct i2c_sam_twihs_dev_data {
56 	struct i2c_rtio *ctx;
57 	uint32_t buf_idx;
58 };
59 
i2c_clk_set(Twihs * const twihs,uint32_t speed)60 static int i2c_clk_set(Twihs *const twihs, uint32_t speed)
61 {
62 	uint32_t ck_div = 0U;
63 	uint32_t cl_div;
64 	bool div_completed = false;
65 
66 	/*  From the datasheet "TWIHS Clock Waveform Generator Register"
67 	 *  T_low = ( ( CLDIV × 2^CKDIV ) + 3 ) × T_MCK
68 	 */
69 	while (!div_completed) {
70 		cl_div =   ((SOC_ATMEL_SAM_MCK_FREQ_HZ / (speed * 2U)) - 3)
71 			 / (1 << ck_div);
72 
73 		if (cl_div <= 255U) {
74 			div_completed = true;
75 		} else {
76 			ck_div++;
77 		}
78 	}
79 
80 	if (ck_div > CKDIV_MAX) {
81 		LOG_ERR("Failed to configure I2C clock");
82 		return -EIO;
83 	}
84 
85 	/* Set I2C bus clock duty cycle to 50% */
86 	twihs->TWIHS_CWGR = TWIHS_CWGR_CLDIV(cl_div) | TWIHS_CWGR_CHDIV(cl_div)
87 			    | TWIHS_CWGR_CKDIV(ck_div);
88 
89 	return 0;
90 }
91 
i2c_sam_twihs_configure(const struct device * dev,uint32_t config)92 static int i2c_sam_twihs_configure(const struct device *dev, uint32_t config)
93 {
94 	const struct i2c_sam_twihs_dev_cfg *const dev_cfg = dev->config;
95 	Twihs *const twihs = dev_cfg->regs;
96 	uint32_t bitrate;
97 	int ret;
98 
99 	if (!(config & I2C_MODE_CONTROLLER)) {
100 		LOG_ERR("Master Mode is not enabled");
101 		return -EIO;
102 	}
103 
104 	if (config & I2C_ADDR_10_BITS) {
105 		LOG_ERR("I2C 10-bit addressing is currently not supported");
106 		LOG_ERR("Please submit a patch");
107 		return -EIO;
108 	}
109 
110 	/* Configure clock */
111 	switch (I2C_SPEED_GET(config)) {
112 	case I2C_SPEED_STANDARD:
113 		bitrate = BUS_SPEED_STANDARD_HZ;
114 		break;
115 	case I2C_SPEED_FAST:
116 		bitrate = BUS_SPEED_FAST_HZ;
117 		break;
118 	default:
119 		LOG_ERR("Unsupported I2C speed value");
120 		return -EIO;
121 	}
122 
123 	/* Setup clock waveform */
124 	ret = i2c_clk_set(twihs, bitrate);
125 	if (ret < 0) {
126 		return ret;
127 	}
128 
129 	/* Disable Target Mode */
130 	twihs->TWIHS_CR = TWIHS_CR_SVDIS;
131 
132 	/* Enable Controller Mode */
133 	twihs->TWIHS_CR = TWIHS_CR_MSEN;
134 
135 	return 0;
136 }
137 
write_msg_start(Twihs * const twihs,const uint8_t * buf,const uint32_t idx,const uint8_t daddr)138 static void write_msg_start(Twihs *const twihs, const uint8_t *buf, const uint32_t idx,
139 			    const uint8_t daddr)
140 {
141 	/* Set target address. */
142 	twihs->TWIHS_MMR = TWIHS_MMR_DADR(daddr);
143 
144 	/* Write first data byte on I2C bus */
145 	twihs->TWIHS_THR = buf[idx];
146 
147 	/* Enable Transmit Ready and Transmission Completed interrupts */
148 	twihs->TWIHS_IER = TWIHS_IER_TXRDY | TWIHS_IER_TXCOMP | TWIHS_IER_NACK;
149 
150 }
151 
read_msg_start(Twihs * const twihs,const uint32_t len,const uint8_t daddr)152 static void read_msg_start(Twihs *const twihs, const uint32_t len, const uint8_t daddr)
153 {
154 	uint32_t twihs_cr_stop;
155 
156 	/* Set target address and number of internal address bytes */
157 	twihs->TWIHS_MMR = TWIHS_MMR_MREAD | TWIHS_MMR_DADR(daddr);
158 
159 	/* In single data byte read the START and STOP must both be set */
160 	twihs_cr_stop = (len == 1U) ? TWIHS_CR_STOP : 0;
161 
162 	/* Enable Receive Ready and Transmission Completed interrupts */
163 	twihs->TWIHS_IER = TWIHS_IER_RXRDY | TWIHS_IER_TXCOMP | TWIHS_IER_NACK;
164 
165 	/* Start the transfer by sending START condition */
166 	twihs->TWIHS_CR = TWIHS_CR_START | twihs_cr_stop;
167 }
168 
169 static void i2c_sam_twihs_complete(const struct device *dev, int status);
170 
i2c_sam_twihs_start(const struct device * dev)171 static void i2c_sam_twihs_start(const struct device *dev)
172 {
173 	struct i2c_sam_twihs_dev_data *const dev_data = dev->data;
174 	const struct i2c_sam_twihs_dev_cfg *const dev_cfg = dev->config;
175 	Twihs *const twihs = dev_cfg->regs;
176 	struct rtio_sqe *sqe = &dev_data->ctx->txn_curr->sqe;
177 	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
178 
179 	/* Clear pending interrupts, such as NACK. */
180 	(void)twihs->TWIHS_SR;
181 
182 	/* Set number of internal address bytes to 0, not used. */
183 	twihs->TWIHS_IADR = 0;
184 
185 	/* Set the current index to 0 */
186 	dev_data->buf_idx = 0;
187 
188 	switch (sqe->op) {
189 	case RTIO_OP_RX:
190 		read_msg_start(twihs, sqe->rx.buf_len, dt_spec->addr);
191 		break;
192 	case RTIO_OP_TX:
193 		dev_data->buf_idx = 1;
194 		write_msg_start(twihs, sqe->tx.buf, 0, dt_spec->addr);
195 		break;
196 	default:
197 		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
198 		i2c_sam_twihs_complete(dev, -EINVAL);
199 	}
200 }
201 
i2c_sam_twihs_complete(const struct device * dev,int status)202 static void i2c_sam_twihs_complete(const struct device *dev, int status)
203 {
204 	const struct i2c_sam_twihs_dev_cfg *const dev_cfg = dev->config;
205 	Twihs *const twihs = dev_cfg->regs;
206 	struct i2c_rtio *const ctx = ((struct i2c_sam_twihs_dev_data *)
207 		dev->data)->ctx;
208 
209 	/* Disable all enabled interrupts */
210 	twihs->TWIHS_IDR = twihs->TWIHS_IMR;
211 
212 	if (i2c_rtio_complete(ctx, status)) {
213 		i2c_sam_twihs_start(dev);
214 	}
215 }
216 
i2c_sam_twihs_submit(const struct device * dev,struct rtio_iodev_sqe * iodev_sqe)217 static void i2c_sam_twihs_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
218 {
219 	struct i2c_rtio *const ctx = ((struct i2c_sam_twihs_dev_data *)
220 		dev->data)->ctx;
221 
222 	if (i2c_rtio_submit(ctx, iodev_sqe)) {
223 		i2c_sam_twihs_start(dev);
224 	}
225 }
226 
i2c_sam_twihs_isr(const struct device * dev)227 static void i2c_sam_twihs_isr(const struct device *dev)
228 {
229 	const struct i2c_sam_twihs_dev_cfg *const dev_cfg = dev->config;
230 	struct i2c_sam_twihs_dev_data *const dev_data = dev->data;
231 	Twihs *const twihs = dev_cfg->regs;
232 	struct rtio_sqe *sqe = &dev_data->ctx->txn_curr->sqe;
233 	uint32_t isr_status;
234 
235 	/* Retrieve interrupt status */
236 	isr_status = twihs->TWIHS_SR & twihs->TWIHS_IMR;
237 
238 	/* Not Acknowledged */
239 	if (isr_status & TWIHS_SR_NACK) {
240 		i2c_sam_twihs_complete(dev, -EIO);
241 		return;
242 	}
243 
244 	/* Byte received */
245 	if (isr_status & TWIHS_SR_RXRDY) {
246 		sqe->rx.buf[dev_data->buf_idx] = twihs->TWIHS_RHR;
247 		dev_data->buf_idx += 1;
248 
249 		if (dev_data->buf_idx == sqe->rx.buf_len - 1U) {
250 			/* Send STOP condition */
251 			twihs->TWIHS_CR = TWIHS_CR_STOP;
252 		}
253 	}
254 
255 	/* Byte sent */
256 	if (isr_status & TWIHS_SR_TXRDY) {
257 		if (dev_data->buf_idx == sqe->tx.buf_len) {
258 			if (sqe->iodev_flags & RTIO_IODEV_I2C_STOP) {
259 				/* Send STOP condition */
260 				twihs->TWIHS_CR = TWIHS_CR_STOP;
261 				/* Disable Transmit Ready interrupt */
262 				twihs->TWIHS_IDR = TWIHS_IDR_TXRDY;
263 			} else {
264 				/* Transmission completed */
265 				i2c_sam_twihs_complete(dev, 0);
266 				return;
267 			}
268 		} else {
269 			twihs->TWIHS_THR = sqe->tx.buf[dev_data->buf_idx++];
270 		}
271 	}
272 
273 	/* Transmission completed */
274 	if (isr_status & TWIHS_SR_TXCOMP) {
275 		i2c_sam_twihs_complete(dev, 0);
276 	}
277 }
278 
i2c_sam_twihs_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)279 static int i2c_sam_twihs_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
280 				  uint16_t addr)
281 {
282 	struct i2c_rtio *const ctx = ((struct i2c_sam_twihs_dev_data *)
283 		dev->data)->ctx;
284 
285 	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
286 }
287 
i2c_sam_twihs_initialize(const struct device * dev)288 static int i2c_sam_twihs_initialize(const struct device *dev)
289 {
290 	const struct i2c_sam_twihs_dev_cfg *const dev_cfg = dev->config;
291 	struct i2c_sam_twihs_dev_data *const dev_data = dev->data;
292 	Twihs *const twihs = dev_cfg->regs;
293 	uint32_t bitrate_cfg;
294 	int ret;
295 
296 	/* Configure interrupts */
297 	dev_cfg->irq_config();
298 
299 	/* Connect pins to the peripheral */
300 	ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
301 	if (ret < 0) {
302 		return ret;
303 	}
304 
305 	/* Enable TWIHS clock in PMC */
306 	(void)clock_control_on(SAM_DT_PMC_CONTROLLER,
307 			       (clock_control_subsys_t *)&dev_cfg->clock_cfg);
308 
309 	/* Reset the module */
310 	twihs->TWIHS_CR = TWIHS_CR_SWRST;
311 
312 	bitrate_cfg = i2c_map_dt_bitrate(dev_cfg->bitrate);
313 
314 	ret = i2c_sam_twihs_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
315 	if (ret < 0) {
316 		LOG_ERR("Failed to initialize %s device", dev->name);
317 		return ret;
318 	}
319 
320 	i2c_rtio_init(dev_data->ctx, dev);
321 
322 	/* Enable module's IRQ */
323 	irq_enable(dev_cfg->irq_id);
324 
325 	LOG_INF("Device %s initialized", dev->name);
326 
327 	return 0;
328 }
329 
330 static DEVICE_API(i2c, i2c_sam_twihs_driver_api) = {
331 	.configure = i2c_sam_twihs_configure,
332 	.transfer = i2c_sam_twihs_transfer,
333 	.iodev_submit = i2c_sam_twihs_submit,
334 };
335 
336 #define I2C_TWIHS_SAM_INIT(n)									\
337 	PINCTRL_DT_INST_DEFINE(n);								\
338 	static void i2c##n##_sam_irq_config(void)						\
339 	{											\
340 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),				\
341 			    i2c_sam_twihs_isr,							\
342 			    DEVICE_DT_INST_GET(n), 0);						\
343 	}											\
344 												\
345 	I2C_RTIO_DEFINE(_i2c##n##_sam_rtio,							\
346 		    DT_INST_PROP_OR(n, sq_size, CONFIG_I2C_RTIO_SQ_SIZE),			\
347 		    DT_INST_PROP_OR(n, cq_size, CONFIG_I2C_RTIO_CQ_SIZE));			\
348 												\
349 	static const struct i2c_sam_twihs_dev_cfg i2c##n##_sam_config = {			\
350 		.regs = (Twihs *)DT_INST_REG_ADDR(n),						\
351 		.irq_config = i2c##n##_sam_irq_config,						\
352 		.clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n),					\
353 		.irq_id = DT_INST_IRQN(n),							\
354 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),					\
355 		.bitrate = DT_INST_PROP(n, clock_frequency),					\
356 	};											\
357 												\
358 	static struct i2c_sam_twihs_dev_data i2c##n##_sam_data = {				\
359 		.ctx = &_i2c##n##_sam_rtio,							\
360 	};											\
361 												\
362 	I2C_DEVICE_DT_INST_DEFINE(n, i2c_sam_twihs_initialize,					\
363 			    NULL,								\
364 			    &i2c##n##_sam_data, &i2c##n##_sam_config,				\
365 			    POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,				\
366 			    &i2c_sam_twihs_driver_api);
367 
368 DT_INST_FOREACH_STATUS_OKAY(I2C_TWIHS_SAM_INIT)
369