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