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