Skip to content

Commit 3eb62bc

Browse files
Ramakrishna PallalaAnas Nashif
authored andcommitted
drivers: i2c: Add i2c master driver for Nios-II i2c core
Add I2C Master driver for Nios-II I2C soft IP core. This driver relies upon the Altera HAL I2C driver for all the bus level transactions, interrupt handling and register programming. Signed-off-by: Ramakrishna Pallala <[email protected]>
1 parent b574a9b commit 3eb62bc

File tree

4 files changed

+207
-0
lines changed

4 files changed

+207
-0
lines changed

arch/nios2/soc/nios2f-zephyr/Kconfig.defconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ config ALTERA_AVALON_QSPI
2525

2626
endif #SOC_FLASH_NIOS2_QSPI
2727

28+
if I2C_NIOS2
29+
30+
config ALTERA_AVALON_I2C
31+
def_bool y
32+
33+
endif # I2C_NIOS2
34+
2835
if UART_NS16550
2936

3037
config UART_NS16550_PCI

drivers/i2c/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ zephyr_sources_ifdef(CONFIG_I2C_QMSI_SS i2c_qmsi_ss.c)
1111
zephyr_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c)
1212
zephyr_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs.c)
1313
zephyr_sources_ifdef(CONFIG_I2C_SBCON i2c_sbcon.c)
14+
zephyr_sources_ifdef(CONFIG_I2C_NIOS2 i2c_nios2.c)
1415

1516
zephyr_sources_ifdef(CONFIG_I2C_STM32_V1
1617
i2c_ll_stm32_v1.c

drivers/i2c/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ config I2C_BITBANG
129129
help
130130
Enable library used for software driven (bit banging) I2C support
131131

132+
config I2C_NIOS2
133+
bool "Nios-II I2C driver"
134+
depends on HAS_ALTERA_HAL
135+
default n
136+
help
137+
Enable the Nios-II I2C driver.
138+
132139
source "drivers/i2c/Kconfig.sbcon"
133140

134141
source "drivers/i2c/Kconfig.gpio"

drivers/i2c/i2c_nios2.c

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

0 commit comments

Comments
 (0)