1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT altr_nios2_i2c
8 
9 #include <errno.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/kernel.h>
13 #include <soc.h>
14 #include <zephyr/sys/util.h>
15 #include <altera_common.h>
16 #include "altera_avalon_i2c.h"
17 
18 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(i2c_nios2);
21 
22 #define NIOS2_I2C_TIMEOUT_USEC		1000
23 
24 struct i2c_nios2_data {
25 	ALT_AVALON_I2C_DEV_t i2c_dev;
26 	IRQ_DATA_t irq_data;
27 	struct k_sem sem_lock;
28 };
29 
30 static int
i2c_nios2_configure(const struct device * dev,uint32_t dev_config)31 i2c_nios2_configure(const struct device *dev, uint32_t dev_config)
32 {
33 	struct i2c_nios2_data *data = (struct i2c_nios2_data *)dev->data;
34 
35 	int32_t rc = 0;
36 
37 	k_sem_take(&data->sem_lock, K_FOREVER);
38 	if (!(I2C_MODE_CONTROLLER & dev_config)) {
39 		LOG_ERR("i2c config mode error\n");
40 		rc = -EINVAL;
41 		goto i2c_cfg_err;
42 	}
43 
44 	if (I2C_ADDR_10_BITS & dev_config) {
45 		LOG_ERR("i2c config addressing error\n");
46 		rc = -EINVAL;
47 		goto i2c_cfg_err;
48 	}
49 
50 	if (I2C_SPEED_GET(dev_config) != I2C_SPEED_STANDARD) {
51 		LOG_ERR("i2c config speed error\n");
52 		rc = -EINVAL;
53 		goto i2c_cfg_err;
54 	}
55 
56 	alt_avalon_i2c_init(&data->i2c_dev);
57 
58 i2c_cfg_err:
59 	k_sem_give(&data->sem_lock);
60 	return rc;
61 }
62 
i2c_nios2_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)63 static int i2c_nios2_transfer(const struct device *dev, struct i2c_msg *msgs,
64 			      uint8_t num_msgs, uint16_t addr)
65 {
66 	struct i2c_nios2_data *data = (struct i2c_nios2_data *)dev->data;
67 	ALT_AVALON_I2C_STATUS_CODE status;
68 	uint32_t restart, stop;
69 	int32_t i, timeout, rc = 0;
70 
71 	k_sem_take(&data->sem_lock, K_FOREVER);
72 	/* register the optional interrupt callback */
73 	alt_avalon_i2c_register_optional_irq_handler(
74 			&data->i2c_dev, &data->irq_data);
75 
76 	/* Iterate over all the messages */
77 	for (i = 0; i < num_msgs; i++) {
78 
79 		/* convert restart flag */
80 		if (msgs->flags & I2C_MSG_RESTART) {
81 			restart = ALT_AVALON_I2C_RESTART;
82 		} else {
83 			restart = ALT_AVALON_I2C_NO_RESTART;
84 		}
85 
86 		/* convert stop flag */
87 		if (msgs->flags & I2C_MSG_STOP) {
88 			stop = ALT_AVALON_I2C_STOP;
89 		} else {
90 			stop = ALT_AVALON_I2C_NO_STOP;
91 		}
92 
93 		/* Set the slave device address */
94 		alt_avalon_i2c_master_target_set(&data->i2c_dev, addr);
95 
96 		/* Start the transfer */
97 		if (msgs->flags & I2C_MSG_READ) {
98 			status = alt_avalon_i2c_master_receive_using_interrupts(
99 							&data->i2c_dev,
100 							msgs->buf, msgs->len,
101 							restart, stop);
102 		} else {
103 			status = alt_avalon_i2c_master_transmit_using_interrupts
104 							(&data->i2c_dev,
105 							msgs->buf, msgs->len,
106 							restart, stop);
107 		}
108 
109 		/* Return an error if the transfer didn't
110 		 * start successfully e.g., if the bus was busy
111 		 */
112 		if (status != ALT_AVALON_I2C_SUCCESS) {
113 			LOG_ERR("i2c transfer error %lu\n", status);
114 			rc = -EIO;
115 			goto i2c_transfer_err;
116 		}
117 
118 		timeout = NIOS2_I2C_TIMEOUT_USEC;
119 		while (timeout) {
120 			k_busy_wait(1);
121 			status = alt_avalon_i2c_interrupt_transaction_status(
122 							&data->i2c_dev);
123 			if (status == ALT_AVALON_I2C_SUCCESS) {
124 				break;
125 			}
126 			timeout--;
127 		}
128 
129 		if (timeout <= 0) {
130 			LOG_ERR("i2c busy or timeout error %lu\n", status);
131 			rc = -EIO;
132 			goto i2c_transfer_err;
133 		}
134 
135 		/* move to the next message */
136 		msgs++;
137 	}
138 
139 i2c_transfer_err:
140 	alt_avalon_i2c_disable(&data->i2c_dev);
141 	k_sem_give(&data->sem_lock);
142 	return rc;
143 }
144 
i2c_nios2_isr(const struct device * dev)145 static void i2c_nios2_isr(const struct device *dev)
146 {
147 	struct i2c_nios2_data *data = (struct i2c_nios2_data *)dev->data;
148 
149 	/* Call Altera HAL driver ISR */
150 	alt_handle_irq(&data->i2c_dev, DT_INST_IRQN(0));
151 }
152 
153 static int i2c_nios2_init(const struct device *dev);
154 
155 static DEVICE_API(i2c, i2c_nios2_driver_api) = {
156 	.configure = i2c_nios2_configure,
157 	.transfer = i2c_nios2_transfer,
158 #ifdef CONFIG_I2C_RTIO
159 	.iodev_submit = i2c_iodev_submit_fallback,
160 #endif
161 };
162 
163 static struct i2c_nios2_data i2c_nios2_dev_data = {
164 	.i2c_dev = {
165 		.i2c_base = (alt_u32 *)DT_INST_REG_ADDR(0),
166 		.irq_controller_ID = I2C_0_IRQ_INTERRUPT_CONTROLLER_ID,
167 		.irq_ID = DT_INST_IRQN(0),
168 		.ip_freq_in_hz = DT_INST_PROP(0, clock_frequency),
169 	},
170 };
171 
i2c_nios2_init(const struct device * dev)172 static int i2c_nios2_init(const struct device *dev)
173 {
174 	struct i2c_nios2_data *data = (struct i2c_nios2_data *)dev->data;
175 	int rc;
176 
177 	/* initialize semaphore */
178 	k_sem_init(&data->sem_lock, 1, 1);
179 
180 	rc = i2c_nios2_configure(dev,
181 			I2C_MODE_CONTROLLER |
182 			I2C_SPEED_SET(I2C_SPEED_STANDARD));
183 	if (rc) {
184 		LOG_ERR("i2c configure failed %d\n", rc);
185 		return rc;
186 	}
187 
188 	/* clear ISR register content */
189 	alt_avalon_i2c_int_clear(&data->i2c_dev,
190 			ALT_AVALON_I2C_ISR_ALL_CLEARABLE_INTS_MSK);
191 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
192 			i2c_nios2_isr, DEVICE_DT_INST_GET(0), 0);
193 	irq_enable(DT_INST_IRQN(0));
194 	return 0;
195 }
196 
197 I2C_DEVICE_DT_INST_DEFINE(0, i2c_nios2_init, NULL,
198 		    &i2c_nios2_dev_data, NULL,
199 		    POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,
200 		    &i2c_nios2_driver_api);
201