1 /*
2 * Copyright (c) 2017 Piotr Mienkowski
3 * Copyright (c) 2023 Gerson Fernando Budke
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT atmel_sam_i2c_twi
9
10 /** @file
11 * @brief I2C bus (TWI) driver for Atmel SAM MCU family.
12 *
13 * Limitations:
14 * - Only I2C Master Mode with 7 bit addressing is currently supported.
15 * - No reentrancy support.
16 */
17
18 #include <errno.h>
19 #include <zephyr/sys/__assert.h>
20 #include <stdbool.h>
21 #include <zephyr/kernel.h>
22 #include <zephyr/device.h>
23 #include <zephyr/init.h>
24 #include <soc.h>
25 #include <zephyr/drivers/i2c.h>
26 #include <zephyr/drivers/pinctrl.h>
27 #include <zephyr/drivers/clock_control/atmel_sam_pmc.h>
28
29 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
30 #include <zephyr/logging/log.h>
31 #include <zephyr/irq.h>
32 LOG_MODULE_REGISTER(i2c_sam_twi);
33
34 #include "i2c-priv.h"
35
36 /** I2C bus speed [Hz] in Standard Mode */
37 #define BUS_SPEED_STANDARD_HZ 100000U
38 /** I2C bus speed [Hz] in Fast Mode */
39 #define BUS_SPEED_FAST_HZ 400000U
40 /* Maximum value of Clock Divider (CKDIV) */
41 #define CKDIV_MAX 7
42
43 /* Device constant configuration parameters */
44 struct i2c_sam_twi_dev_cfg {
45 Twi *regs;
46 void (*irq_config)(void);
47 uint32_t bitrate;
48 const struct atmel_sam_pmc_config clock_cfg;
49 const struct pinctrl_dev_config *pcfg;
50 uint8_t irq_id;
51 };
52
53 struct twi_msg {
54 /* Buffer containing data to read or write */
55 uint8_t *buf;
56 /* Length of the buffer */
57 uint32_t len;
58 /* Index of the next byte to be read/written from/to the buffer */
59 uint32_t idx;
60 /* Value of TWI_SR at the end of the message */
61 uint32_t twi_sr;
62 /* Transfer flags as defined in the i2c.h file */
63 uint8_t flags;
64 };
65
66 /* Device run time data */
67 struct i2c_sam_twi_dev_data {
68 struct k_sem lock;
69 struct k_sem sem;
70 struct twi_msg msg;
71 };
72
i2c_clk_set(Twi * const twi,uint32_t speed)73 static int i2c_clk_set(Twi *const twi, uint32_t speed)
74 {
75 uint32_t ck_div = 0U;
76 uint32_t cl_div;
77 bool div_completed = false;
78
79 /* From the datasheet "TWI Clock Waveform Generator Register"
80 * T_low = ( ( CLDIV × 2^CKDIV ) + 4 ) × T_MCK
81 */
82 while (!div_completed) {
83 cl_div = ((SOC_ATMEL_SAM_MCK_FREQ_HZ / (speed * 2U)) - 4)
84 / (1 << ck_div);
85
86 if (cl_div <= 255U) {
87 div_completed = true;
88 } else {
89 ck_div++;
90 }
91 }
92
93 if (ck_div > CKDIV_MAX) {
94 LOG_ERR("Failed to configure I2C clock");
95 return -EIO;
96 }
97
98 /* Set TWI clock duty cycle to 50% */
99 twi->TWI_CWGR = TWI_CWGR_CLDIV(cl_div) | TWI_CWGR_CHDIV(cl_div)
100 | TWI_CWGR_CKDIV(ck_div);
101
102 return 0;
103 }
104
i2c_sam_twi_configure(const struct device * dev,uint32_t config)105 static int i2c_sam_twi_configure(const struct device *dev, uint32_t config)
106 {
107 const struct i2c_sam_twi_dev_cfg *const dev_cfg = dev->config;
108 struct i2c_sam_twi_dev_data *const dev_data = dev->data;
109 Twi *const twi = dev_cfg->regs;
110 uint32_t bitrate;
111 int ret;
112
113 if (!(config & I2C_MODE_CONTROLLER)) {
114 LOG_ERR("Master Mode is not enabled");
115 return -EIO;
116 }
117
118 if (config & I2C_ADDR_10_BITS) {
119 LOG_ERR("I2C 10-bit addressing is currently not supported");
120 LOG_ERR("Please submit a patch");
121 return -EIO;
122 }
123
124 /* Configure clock */
125 switch (I2C_SPEED_GET(config)) {
126 case I2C_SPEED_STANDARD:
127 bitrate = BUS_SPEED_STANDARD_HZ;
128 break;
129 case I2C_SPEED_FAST:
130 bitrate = BUS_SPEED_FAST_HZ;
131 break;
132 default:
133 LOG_ERR("Unsupported I2C speed value");
134 return -EIO;
135 }
136
137 k_sem_take(&dev_data->lock, K_FOREVER);
138
139 /* Setup clock waveform */
140 ret = i2c_clk_set(twi, bitrate);
141 if (ret < 0) {
142 goto unlock;
143 }
144
145 /* Disable Slave Mode */
146 twi->TWI_CR = TWI_CR_SVDIS;
147
148 /* Enable Master Mode */
149 twi->TWI_CR = TWI_CR_MSEN;
150
151 ret = 0;
152 unlock:
153 k_sem_give(&dev_data->lock);
154
155 return ret;
156 }
157
write_msg_start(Twi * const twi,struct twi_msg * msg,uint8_t daddr)158 static void write_msg_start(Twi *const twi, struct twi_msg *msg, uint8_t daddr)
159 {
160 /* Set slave address and number of internal address bytes. */
161 twi->TWI_MMR = TWI_MMR_DADR(daddr);
162
163 /* Write first data byte on I2C bus */
164 twi->TWI_THR = msg->buf[msg->idx++];
165
166 /* Enable Transmit Ready and Transmission Completed interrupts */
167 twi->TWI_IER = TWI_IER_TXRDY | TWI_IER_TXCOMP | TWI_IER_NACK;
168 }
169
read_msg_start(Twi * const twi,struct twi_msg * msg,uint8_t daddr)170 static void read_msg_start(Twi *const twi, struct twi_msg *msg, uint8_t daddr)
171 {
172 uint32_t twi_cr_stop;
173
174 /* Set slave address and number of internal address bytes */
175 twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(daddr);
176
177 /* In single data byte read the START and STOP must both be set */
178 twi_cr_stop = (msg->len == 1U) ? TWI_CR_STOP : 0;
179 /* Start the transfer by sending START condition */
180 twi->TWI_CR = TWI_CR_START | twi_cr_stop;
181
182 /* Enable Receive Ready and Transmission Completed interrupts */
183 twi->TWI_IER = TWI_IER_RXRDY | TWI_IER_TXCOMP | TWI_IER_NACK;
184 }
185
i2c_sam_twi_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)186 static int i2c_sam_twi_transfer(const struct device *dev,
187 struct i2c_msg *msgs,
188 uint8_t num_msgs, uint16_t addr)
189 {
190 const struct i2c_sam_twi_dev_cfg *const dev_cfg = dev->config;
191 struct i2c_sam_twi_dev_data *const dev_data = dev->data;
192 Twi *const twi = dev_cfg->regs;
193 int ret;
194
195 __ASSERT_NO_MSG(msgs);
196 if (!num_msgs) {
197 return 0;
198 }
199 k_sem_take(&dev_data->lock, K_FOREVER);
200
201 /* Clear pending interrupts, such as NACK. */
202 (void)twi->TWI_SR;
203
204 /* Set number of internal address bytes to 0, not used. */
205 twi->TWI_IADR = 0;
206
207 for (; num_msgs > 0; num_msgs--, msgs++) {
208 dev_data->msg.buf = msgs->buf;
209 dev_data->msg.len = msgs->len;
210 dev_data->msg.idx = 0U;
211 dev_data->msg.twi_sr = 0U;
212 dev_data->msg.flags = msgs->flags;
213
214 /*
215 * REMARK: Dirty workaround:
216 *
217 * The controller does not have a documented, generic way to
218 * issue RESTART when changing transfer direction as master.
219 * Send a stop condition in such a case.
220 */
221 if (num_msgs > 1) {
222 if ((msgs[0].flags & I2C_MSG_RW_MASK) !=
223 (msgs[1].flags & I2C_MSG_RW_MASK)) {
224 dev_data->msg.flags |= I2C_MSG_STOP;
225 }
226 }
227
228 if ((msgs->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) {
229 read_msg_start(twi, &dev_data->msg, addr);
230 } else {
231 write_msg_start(twi, &dev_data->msg, addr);
232 }
233 /* Wait for the transfer to complete */
234 k_sem_take(&dev_data->sem, K_FOREVER);
235
236 if (dev_data->msg.twi_sr > 0) {
237 /* Something went wrong */
238 ret = -EIO;
239 goto unlock;
240 }
241 }
242
243 ret = 0;
244 unlock:
245 k_sem_give(&dev_data->lock);
246
247 return ret;
248 }
249
i2c_sam_twi_isr(const struct device * dev)250 static void i2c_sam_twi_isr(const struct device *dev)
251 {
252 const struct i2c_sam_twi_dev_cfg *const dev_cfg = dev->config;
253 struct i2c_sam_twi_dev_data *const dev_data = dev->data;
254 Twi *const twi = dev_cfg->regs;
255 struct twi_msg *msg = &dev_data->msg;
256 uint32_t isr_status;
257
258 /* Retrieve interrupt status */
259 isr_status = twi->TWI_SR & twi->TWI_IMR;
260
261 /* Not Acknowledged */
262 if (isr_status & TWI_SR_NACK) {
263 msg->twi_sr = isr_status;
264 goto tx_comp;
265 }
266
267 /* Byte received */
268 if (isr_status & TWI_SR_RXRDY) {
269
270 msg->buf[msg->idx++] = twi->TWI_RHR;
271
272 if (msg->idx == msg->len - 1U) {
273 /* Send a STOP condition on the TWI */
274 twi->TWI_CR = TWI_CR_STOP;
275 }
276 }
277
278 /* Byte sent */
279 if (isr_status & TWI_SR_TXRDY) {
280 if (msg->idx == msg->len) {
281 if (msg->flags & I2C_MSG_STOP) {
282 /* Send a STOP condition on the TWI */
283 twi->TWI_CR = TWI_CR_STOP;
284 /* Disable Transmit Ready interrupt */
285 twi->TWI_IDR = TWI_IDR_TXRDY;
286 } else {
287 /* Transmission completed */
288 goto tx_comp;
289 }
290 } else {
291 twi->TWI_THR = msg->buf[msg->idx++];
292 }
293 }
294
295 /* Transmission completed */
296 if (isr_status & TWI_SR_TXCOMP) {
297 goto tx_comp;
298 }
299
300 return;
301
302 tx_comp:
303 /* Disable all enabled interrupts */
304 twi->TWI_IDR = twi->TWI_IMR;
305 /* We are done */
306 k_sem_give(&dev_data->sem);
307 }
308
i2c_sam_twi_initialize(const struct device * dev)309 static int i2c_sam_twi_initialize(const struct device *dev)
310 {
311 const struct i2c_sam_twi_dev_cfg *const dev_cfg = dev->config;
312 struct i2c_sam_twi_dev_data *const dev_data = dev->data;
313 Twi *const twi = dev_cfg->regs;
314 uint32_t bitrate_cfg;
315 int ret;
316
317 /* Configure interrupts */
318 dev_cfg->irq_config();
319
320 /* Initialize semaphores */
321 k_sem_init(&dev_data->lock, 1, 1);
322 k_sem_init(&dev_data->sem, 0, 1);
323
324 /* Connect pins to the peripheral */
325 ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
326 if (ret < 0) {
327 return ret;
328 }
329
330 /* Enable TWI clock in PMC */
331 (void)clock_control_on(SAM_DT_PMC_CONTROLLER,
332 (clock_control_subsys_t)&dev_cfg->clock_cfg);
333
334 /* Reset TWI module */
335 twi->TWI_CR = TWI_CR_SWRST;
336
337 bitrate_cfg = i2c_map_dt_bitrate(dev_cfg->bitrate);
338
339 ret = i2c_sam_twi_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
340 if (ret < 0) {
341 LOG_ERR("Failed to initialize %s device", dev->name);
342 return ret;
343 }
344
345 /* Enable module's IRQ */
346 irq_enable(dev_cfg->irq_id);
347
348 LOG_INF("Device %s initialized", dev->name);
349
350 return 0;
351 }
352
353 static const struct i2c_driver_api i2c_sam_twi_driver_api = {
354 .configure = i2c_sam_twi_configure,
355 .transfer = i2c_sam_twi_transfer,
356 };
357
358 #define I2C_TWI_SAM_INIT(n) \
359 PINCTRL_DT_INST_DEFINE(n); \
360 static void i2c##n##_sam_irq_config(void) \
361 { \
362 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
363 i2c_sam_twi_isr, \
364 DEVICE_DT_INST_GET(n), 0); \
365 } \
366 \
367 static const struct i2c_sam_twi_dev_cfg i2c##n##_sam_config = { \
368 .regs = (Twi *)DT_INST_REG_ADDR(n), \
369 .irq_config = i2c##n##_sam_irq_config, \
370 .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n), \
371 .irq_id = DT_INST_IRQN(n), \
372 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
373 .bitrate = DT_INST_PROP(n, clock_frequency), \
374 }; \
375 \
376 static struct i2c_sam_twi_dev_data i2c##n##_sam_data; \
377 \
378 I2C_DEVICE_DT_INST_DEFINE(n, i2c_sam_twi_initialize, \
379 NULL, \
380 &i2c##n##_sam_data, &i2c##n##_sam_config, \
381 POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \
382 &i2c_sam_twi_driver_api);
383
384 DT_INST_FOREACH_STATUS_OKAY(I2C_TWI_SAM_INIT)
385