1 /*
2 * Copyright (c) 2021 Telink Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT telink_b91_i2c
8
9 #include "i2c.h"
10 #include "clock.h"
11
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(i2c_telink);
14
15 #include <zephyr/drivers/i2c.h>
16 #include "i2c-priv.h"
17 #include <zephyr/drivers/pinctrl.h>
18
19 /* I2C configuration structure */
20 struct i2c_b91_cfg {
21 uint32_t bitrate;
22 const struct pinctrl_dev_config *pcfg;
23 };
24
25 /* I2C data structure */
26 struct i2c_b91_data {
27 struct k_sem mutex;
28 };
29
30 /* API implementation: configure */
i2c_b91_configure(const struct device * dev,uint32_t dev_config)31 static int i2c_b91_configure(const struct device *dev, uint32_t dev_config)
32 {
33 ARG_UNUSED(dev);
34
35 uint32_t i2c_speed = 0u;
36
37 /* check address size */
38 if (dev_config & I2C_ADDR_10_BITS) {
39 LOG_ERR("10-bits address is not supported");
40 return -ENOTSUP;
41 }
42
43 /* check I2C Master/Slave configuration */
44 if (!(dev_config & I2C_MODE_CONTROLLER)) {
45 LOG_ERR("I2C slave is not implemented");
46 return -ENOTSUP;
47 }
48
49 /* check i2c speed */
50 switch (I2C_SPEED_GET(dev_config)) {
51 case I2C_SPEED_STANDARD:
52 i2c_speed = 100000u;
53 break;
54
55 case I2C_SPEED_FAST:
56 i2c_speed = 400000U;
57 break;
58
59 case I2C_SPEED_FAST_PLUS:
60 case I2C_SPEED_HIGH:
61 case I2C_SPEED_ULTRA:
62 default:
63 LOG_ERR("Unsupported I2C speed requested");
64 return -ENOTSUP;
65 }
66
67 /* init i2c */
68 i2c_master_init();
69 i2c_set_master_clk((unsigned char)(sys_clk.pclk * 1000 * 1000 / (4 * i2c_speed)));
70
71 return 0;
72 }
73
74 /* API implementation: transfer */
i2c_b91_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)75 static int i2c_b91_transfer(const struct device *dev,
76 struct i2c_msg *msgs,
77 uint8_t num_msgs,
78 uint16_t addr)
79 {
80 int status = 0;
81 uint8_t send_stop = 0;
82 struct i2c_b91_data *data = dev->data;
83
84 /* get the mutex */
85 k_sem_take(&data->mutex, K_FOREVER);
86
87 /* loop through all messages */
88 for (int i = 0; i < num_msgs; i++) {
89 /* check addr size */
90 if (msgs[i].flags & I2C_MSG_ADDR_10_BITS) {
91 LOG_ERR("10-bits address is not supported");
92 k_sem_give(&data->mutex);
93 return -ENOTSUP;
94 }
95
96 /* config stop bit */
97 send_stop = msgs[i].flags & I2C_MSG_STOP ? 1 : 0;
98 i2c_master_send_stop(send_stop);
99
100 /* transfer data */
101 if (msgs[i].flags & I2C_MSG_READ) {
102 status = i2c_master_read(addr, msgs[i].buf, msgs[i].len);
103 } else {
104 status = i2c_master_write(addr, msgs[i].buf, msgs[i].len);
105 }
106
107 /* check status */
108 if (!status) {
109 LOG_ERR("Failed to transfer I2C messages\n");
110 k_sem_give(&data->mutex);
111 return -EIO;
112 }
113 }
114
115 /* release the mutex */
116 k_sem_give(&data->mutex);
117
118 return 0;
119 };
120
121 /* API implementation: init */
i2c_b91_init(const struct device * dev)122 static int i2c_b91_init(const struct device *dev)
123 {
124 int status = 0;
125 const struct i2c_b91_cfg *cfg = dev->config;
126 struct i2c_b91_data *data = dev->data;
127 uint32_t dev_config = (I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(cfg->bitrate));
128
129 /* init mutex */
130 k_sem_init(&data->mutex, 1, 1);
131
132 /* config i2c on startup */
133 status = i2c_b91_configure(dev, dev_config);
134 if (status != 0) {
135 LOG_ERR("Failed to configure I2C on init");
136 return status;
137 }
138
139 /* configure pins */
140 status = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
141 if (status < 0) {
142 LOG_ERR("Failed to configure I2C pins");
143 return status;
144 }
145
146 return 0;
147 }
148
149 /* I2C driver APIs structure */
150 static const struct i2c_driver_api i2c_b91_api = {
151 .configure = i2c_b91_configure,
152 .transfer = i2c_b91_transfer,
153 };
154
155 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) <= 1,
156 "unsupported I2C instance");
157
158 /* I2C driver registration */
159 #define I2C_B91_INIT(inst) \
160 \
161 PINCTRL_DT_INST_DEFINE(inst); \
162 \
163 static struct i2c_b91_data i2c_b91_data_##inst; \
164 \
165 static struct i2c_b91_cfg i2c_b91_cfg_##inst = { \
166 .bitrate = DT_INST_PROP(inst, clock_frequency), \
167 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
168 }; \
169 \
170 I2C_DEVICE_DT_INST_DEFINE(inst, i2c_b91_init, \
171 NULL, \
172 &i2c_b91_data_##inst, \
173 &i2c_b91_cfg_##inst, \
174 POST_KERNEL, \
175 CONFIG_I2C_INIT_PRIORITY, \
176 &i2c_b91_api);
177
178 DT_INST_FOREACH_STATUS_OKAY(I2C_B91_INIT)
179