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