forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi2c_nrfx_twi_common.c
163 lines (142 loc) · 3.84 KB
/
i2c_nrfx_twi_common.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* Copyright (c) 2024, Croxel Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/pinctrl.h>
#include <nrfx_twi.h>
#include "i2c_nrfx_twi_common.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(i2c_nrfx_twi);
int i2c_nrfx_twi_init(const struct device *dev)
{
const struct i2c_nrfx_twi_config *config = dev->config;
nrfx_err_t result = nrfx_twi_init(&config->twi, &config->config,
config->event_handler, (void *)dev);
if (result != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize device: %s",
dev->name);
return -EBUSY;
}
return 0;
}
int i2c_nrfx_twi_configure(const struct device *dev, uint32_t dev_config)
{
const struct i2c_nrfx_twi_config *config = dev->config;
struct i2c_nrfx_twi_common_data *data = dev->data;
nrfx_twi_t const *inst = &config->twi;
if (I2C_ADDR_10_BITS & dev_config) {
return -EINVAL;
}
switch (I2C_SPEED_GET(dev_config)) {
case I2C_SPEED_STANDARD:
nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_100K);
break;
case I2C_SPEED_FAST:
nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_400K);
break;
default:
LOG_ERR("unsupported speed");
return -EINVAL;
}
data->dev_config = dev_config;
return 0;
}
int i2c_nrfx_twi_recover_bus(const struct device *dev)
{
const struct i2c_nrfx_twi_config *config = dev->config;
uint32_t scl_pin;
uint32_t sda_pin;
nrfx_err_t err;
scl_pin = nrf_twi_scl_pin_get(config->twi.p_twi);
sda_pin = nrf_twi_sda_pin_get(config->twi.p_twi);
err = nrfx_twi_bus_recover(scl_pin, sda_pin);
return (err == NRFX_SUCCESS ? 0 : -EBUSY);
}
int i2c_nrfx_twi_msg_transfer(const struct device *dev, uint8_t flags,
uint8_t *buf, size_t buf_len,
uint16_t i2c_addr, bool more_msgs)
{
const struct i2c_nrfx_twi_config *config = dev->config;
int ret = 0;
uint32_t xfer_flags = 0;
nrfx_err_t res;
nrfx_twi_xfer_desc_t cur_xfer = {
.p_primary_buf = buf,
.primary_length = buf_len,
.address = i2c_addr,
.type = (flags & I2C_MSG_READ) ?
NRFX_TWI_XFER_RX : NRFX_TWI_XFER_TX,
};
if (flags & I2C_MSG_ADDR_10_BITS) {
LOG_ERR("10-bit I2C Addr devices not supported");
ret = -ENOTSUP;
} else if (!(flags & I2C_MSG_STOP)) {
/* - if the transfer consists of more messages
* and the I2C repeated START is not requested
* to appear before the next message, suspend
* the transfer after the current message,
* so that it can be resumed with the next one,
* resulting in the two messages merged into
* a continuous transfer on the bus
*/
if (more_msgs) {
xfer_flags |= NRFX_TWI_FLAG_SUSPEND;
/* - otherwise, just finish the transfer without
* generating the STOP condition, unless the current
* message is an RX request, for which such feature
* is not supported
*/
} else if (flags & I2C_MSG_READ) {
ret = -ENOTSUP;
} else {
xfer_flags |= NRFX_TWI_FLAG_TX_NO_STOP;
}
}
if (!ret) {
res = nrfx_twi_xfer(&config->twi, &cur_xfer, xfer_flags);
switch (res) {
case NRFX_SUCCESS:
break;
case NRFX_ERROR_BUSY:
ret = -EBUSY;
break;
default:
ret = -EIO;
break;
}
}
return ret;
}
#ifdef CONFIG_PM_DEVICE
int twi_nrfx_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct i2c_nrfx_twi_config *config = dev->config;
struct i2c_nrfx_twi_common_data *data = dev->data;
int ret = 0;
switch (action) {
case PM_DEVICE_ACTION_RESUME:
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
i2c_nrfx_twi_init(dev);
if (data->dev_config) {
i2c_nrfx_twi_configure(dev, data->dev_config);
}
break;
case PM_DEVICE_ACTION_SUSPEND:
nrfx_twi_uninit(&config->twi);
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
if (ret < 0) {
return ret;
}
break;
default:
ret = -ENOTSUP;
}
return ret;
}
#endif /* CONFIG_PM_DEVICE */