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