1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Email: opensource_embedded@phytium.com.cn
7 *
8 * Change Logs:
9 * Date Author Notes
10 * 2023-10-23 zhangyan first version
11 *
12 */
13 #include "rtconfig.h"
14 #include <rtdevice.h>
15 #include <string.h>
16 #define LOG_TAG "i2c_drv_msg"
17 #include "drv_log.h"
18 #include "drv_i2c_msg.h"
19 #include "fi2c_msg.h"
20 #include "fi2c_msg_hw.h"
21 #include "fi2c_msg_master.h"
22 #include "fio_mux.h"
23 #include "drivers/dev_i2c.h"
24 #include "fparameters.h"
25 #ifdef RT_USING_SMART
26 #include <ioremap.h>
27 #endif
28
29 /*Please define the length of the mem_addr of the device*/
30 #ifndef FI2C_DEVICE_MEMADDR_LEN
31 #define FI2C_DEVICE_MEMADDR_LEN 2
32 #endif
33 #define I2C_TIMEOUT_MS 1000
34
35 struct phytium_i2c_msg_bus
36 {
37 struct rt_i2c_bus_device device;
38 FI2cMsgCtrl i2c_handle;
39 struct rt_i2c_msg *msg;
40 const char *name;
41 };
42
i2c_msg_config(struct phytium_i2c_msg_bus * i2c_bus)43 static rt_err_t i2c_msg_config(struct phytium_i2c_msg_bus *i2c_bus)
44 {
45 RT_ASSERT(i2c_bus);
46 FI2cMsgConfig input_cfg;
47 const FI2cMsgConfig *config_p = NULL;
48 FI2cMsgCtrl *instance_p = &i2c_bus->i2c_handle;
49 rt_uint32_t cpu_id = rt_hw_cpu_id();
50 FError ret = FI2C_MSG_SUCCESS;
51 FIOPadSetI2CMux(instance_p->config.instance_id);
52 /* Lookup default configs by instance id */
53 config_p = FI2cMsgLookupConfig(instance_p->config.instance_id);
54 input_cfg = *config_p;
55 #ifdef RT_USING_SMART
56 input_cfg.msg.shmem = (uintptr)rt_ioremap((void *)input_cfg.msg.shmem, 0x1000);
57 input_cfg.msg.regfile= (uintptr)rt_ioremap((void *)input_cfg.msg.regfile, 0x1000);
58 #endif
59 /* Initialization */
60 ret = FI2cMsgCfgInitialize(instance_p, &input_cfg);
61 if (ret != FI2C_MSG_SUCCESS)
62 {
63 LOG_E("FI2cMsgCfgInitialize failed, ret = %d", ret);
64 return -RT_ERROR;
65 }
66 instance_p->speed_mode = FI2C_STANDARD_SPEED;
67 instance_p->timeout_ms = I2C_TIMEOUT_MS;
68 instance_p->clk_clock_frequency = FI2C_CLK_FREQ_HZ;
69
70 rt_hw_interrupt_set_target_cpus(instance_p->config.irq_num, cpu_id);
71 rt_hw_interrupt_set_priority(instance_p->config.irq_num, instance_p->config.irq_prority);
72 rt_hw_interrupt_install(instance_p->config.irq_num, FI2cMsgMasterRegfileIsr, instance_p, i2c_bus->name);
73 rt_hw_interrupt_umask(instance_p->config.irq_num);
74
75 ret = FI2cMsgMasterVirtProbe(instance_p);
76 if (ret != FI2C_MSG_SUCCESS)
77 {
78 LOG_E("FI2cMsgMasterVirtProbe failed, ret = %d", ret);
79 return ret;
80 }
81 return RT_EOK;
82 }
83
phytium_i2c_set_speed(struct phytium_i2c_msg_bus * i2c_bus,rt_uint32_t speed)84 static rt_err_t phytium_i2c_set_speed(struct phytium_i2c_msg_bus *i2c_bus, rt_uint32_t speed)
85 {
86 RT_ASSERT(i2c_bus);
87 FI2cMsgCtrl *instance_p = &i2c_bus->i2c_handle;
88
89 switch (speed)
90 {
91 case FI2C_SPEED_STANDARD_RATE:
92 instance_p->speed_mode = FI2C_STANDARD_SPEED;
93 break;
94 case FI2C_SPEED_FAST_RATE:
95 instance_p->speed_mode = FI2C_FAST_SPEED;
96 break;
97 case FI2C_SPEED_HIGH_RATE:
98 instance_p->speed_mode = FI2C_HIGH_SPEED;
99 break;
100
101 default:
102 return -RT_EIO;
103 }
104
105 FI2cMsgSetBusSpeed(instance_p, instance_p->speed_mode, TRUE);
106
107 return RT_EOK;
108 }
109
i2c_msg_bus_control(struct rt_i2c_bus_device * device,int cmd,void * args)110 static rt_err_t i2c_msg_bus_control(struct rt_i2c_bus_device *device, int cmd, void *args)
111 {
112 RT_ASSERT(device);
113 struct phytium_i2c_msg_bus *i2c_bus;
114 i2c_bus = (struct phytium_i2c_msg_bus *)(device);
115 FI2cMsgConfig *config_p;
116
117 switch (cmd)
118 {
119 case RT_I2C_DEV_CTRL_CLK:
120 phytium_i2c_set_speed(i2c_bus, *(rt_uint32_t *)args);
121 break;
122 case RT_I2C_DEV_CTRL_10BIT:
123
124 break;
125 default:
126 return -RT_EIO;
127 }
128
129 return RT_EOK;
130 }
131
i2c_msg_master_xfer(struct rt_i2c_bus_device * device,struct rt_i2c_msg msgs[],rt_uint32_t num)132 static rt_ssize_t i2c_msg_master_xfer(struct rt_i2c_bus_device *device, struct rt_i2c_msg msgs[], rt_uint32_t num)
133 {
134 RT_ASSERT(device);
135 u32 ret;
136 struct rt_i2c_msg *pmsg;
137 rt_ssize_t i;
138 struct phytium_i2c_msg_bus *i2c_bus;
139 i2c_bus = (struct phytium_i2c_msg_bus *)(device);
140 FI2cMsgCtrl *instance_p = &i2c_bus->i2c_handle;
141
142 for (i = 0; i < num; i++)
143 {
144 pmsg = &msgs[i];
145 if (pmsg->flags & RT_I2C_RD)
146 {
147 /*When performing a read operation, first write to the input memaddr, and then read*/
148 struct FI2cMsg msg[2];
149 msg[0].addr = pmsg->addr;
150 msg[0].flags = FI2C_MSG_WD;
151 msg[0].len = FI2C_DEVICE_MEMADDR_LEN;
152 msg[0].buf = pmsg->buf;
153
154 msg[1].addr = pmsg->addr;
155 msg[1].flags = FI2C_MSG_RD;
156 msg[1].len = pmsg->len;
157 msg[1].buf = pmsg->buf;
158 ret = FI2cMsgMasterVirtXfer(instance_p, msg, 2);
159 if (ret != FI2C_MSG_SUCCESS)
160 {
161 LOG_E("FI2cMsgMasterVirtProbe read failed, ret = %d", ret);
162 }
163 }
164 else
165 {
166 struct FI2cMsg msg;
167 msg.addr = pmsg->addr;
168 msg.buf = pmsg->buf;
169 msg.len = pmsg->len;
170 msg.flags = FI2C_MSG_WD;
171 ret = FI2cMsgMasterVirtXfer(instance_p, &msg, 1); /*num = 1 ,只需发送一次写命令*/
172 if (ret != FI2C_MSG_SUCCESS)
173 {
174 LOG_E("FI2cMsgMasterVirtProbe write failed, ret = %d", ret);
175 }
176 }
177 }
178
179 return i;
180 }
181
182 static const struct rt_i2c_bus_device_ops _i2c_ops =
183 {
184 .master_xfer = i2c_msg_master_xfer,
185 .slave_xfer = NULL,
186 .i2c_bus_control = i2c_msg_bus_control
187 };
188
i2c_msg_controller_init(struct phytium_i2c_msg_bus * i2c_controller_bus)189 static int i2c_msg_controller_init(struct phytium_i2c_msg_bus *i2c_controller_bus)
190 {
191 rt_err_t ret = RT_EOK;
192 ret = i2c_msg_config(i2c_controller_bus);
193 if (ret != RT_EOK)
194 {
195 LOG_E("I2C config failed.\n");
196
197 return -RT_ERROR;
198 }
199 i2c_controller_bus->device.ops = &_i2c_ops;
200 ret = rt_i2c_bus_device_register(&i2c_controller_bus->device, i2c_controller_bus->name);
201 RT_ASSERT(RT_EOK == ret);
202 LOG_D("I2C bus reg success.\n");
203
204 return ret;
205 }
206
207 #if defined(RT_USING_I2C0_MSG)
208 static struct phytium_i2c_msg_bus i2c_msg_controller0_bus;
209 #endif
210 #if defined(RT_USING_I2C1_MSG)
211 static struct phytium_i2c_msg_bus i2c_msg_controller1_bus;
212 #endif
213 #if defined(RT_USING_I2C2_MSG)
214 static struct phytium_i2c_msg_bus i2c_msg_controller2_bus;
215 #endif
216 #if defined(RT_USING_I2C3_MSG)
217 static struct phytium_i2c_msg_bus i2c_msg_controller3_bus;
218 #endif
219
rt_hw_i2c_msg_init(void)220 int rt_hw_i2c_msg_init(void)
221 {
222 #if defined(RT_USING_I2C0_MSG)
223 i2c_msg_controller0_bus.name = "I2C0_MSG";
224 i2c_msg_controller0_bus.i2c_handle.config.instance_id = FI2C0_MSG_ID;
225 i2c_msg_controller_init(&i2c_msg_controller0_bus);
226 #endif
227 #if defined(RT_USING_I2C1_MSG)
228 i2c_msg_controller1_bus.name = "I2C1_MSG";
229 i2c_msg_controller1_bus.i2c_handle.config.instance_id = FI2C1_MSG_ID;
230 i2c_msg_controller_init(&i2c_msg_controller1_bus);
231 #endif
232 #if defined(RT_USING_I2C2_MSG)
233 i2c_msg_controller2_bus.name = "I2C2_MSG";
234 i2c_msg_controller2_bus.i2c_handle.config.instance_id = FI2C2_MSG_ID;
235 i2c_msg_controller_init(&i2c_msg_controller2_bus);
236 #endif
237
238 #if defined(RT_USING_I2C3_MSG)
239 i2c_msg_controller3_bus.name = "I2C3_MSG";
240 i2c_msg_controller3_bus.i2c_handle.config.instance_id = FI2C3_MSG_ID;
241 i2c_msg_controller_init(&i2c_msg_controller3_bus);
242 #endif
243
244 return 0;
245 }
246 INIT_DEVICE_EXPORT(rt_hw_i2c_msg_init);
247