1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author        Notes
8  * 2012-04-25     weety         first version
9  * 2014-08-03     bernard       fix some compiling warning
10  * 2021-04-20     RiceChen      added support for bus clock control
11  */
12 
13 #include <rtdevice.h>
14 
15 #define DBG_TAG               "I2C"
16 #ifdef RT_I2C_DEBUG
17 #define DBG_LVL               DBG_LOG
18 #else
19 #define DBG_LVL               DBG_INFO
20 #endif
21 #include <rtdbg.h>
22 
i2c_bus_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t count)23 static rt_ssize_t i2c_bus_device_read(rt_device_t dev,
24                                      rt_off_t    pos,
25                                      void       *buffer,
26                                      rt_size_t   count)
27 {
28     rt_uint16_t addr;
29     rt_uint16_t flags;
30     struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
31 
32     RT_ASSERT(bus != RT_NULL);
33     RT_ASSERT(buffer != RT_NULL);
34 
35     LOG_D("I2C bus dev [%s] reading %u bytes.", dev->parent.name, count);
36 
37     addr = pos & 0xffff;
38     flags = (pos >> 16) & 0xffff;
39 
40     return rt_i2c_master_recv(bus, addr, flags, (rt_uint8_t *)buffer, count);
41 }
42 
i2c_bus_device_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t count)43 static rt_ssize_t i2c_bus_device_write(rt_device_t dev,
44                                       rt_off_t    pos,
45                                       const void *buffer,
46                                       rt_size_t   count)
47 {
48     rt_uint16_t addr;
49     rt_uint16_t flags;
50     struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
51 
52     RT_ASSERT(bus != RT_NULL);
53     RT_ASSERT(buffer != RT_NULL);
54 
55     LOG_D("I2C bus dev [%s] writing %u bytes.", dev->parent.name, count);
56 
57     addr = pos & 0xffff;
58     flags = (pos >> 16) & 0xffff;
59 
60     return rt_i2c_master_send(bus, addr, flags, (const rt_uint8_t *)buffer, count);
61 }
62 
i2c_bus_device_control(rt_device_t dev,int cmd,void * args)63 static rt_err_t i2c_bus_device_control(rt_device_t dev,
64                                        int         cmd,
65                                        void       *args)
66 {
67     rt_err_t ret;
68     struct rt_i2c_priv_data *priv_data;
69     struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
70 
71     RT_ASSERT(bus != RT_NULL);
72 
73     switch (cmd)
74     {
75     /* set 10-bit addr mode */
76     case RT_I2C_DEV_CTRL_10BIT:
77         bus->flags |= RT_I2C_ADDR_10BIT;
78         break;
79     case RT_I2C_DEV_CTRL_TIMEOUT:
80         bus->timeout = *(rt_uint32_t *)args;
81         break;
82     case RT_I2C_DEV_CTRL_RW:
83         priv_data = (struct rt_i2c_priv_data *)args;
84         ret = rt_i2c_transfer(bus, priv_data->msgs, priv_data->number);
85         if (ret < 0)
86         {
87             return -RT_EIO;
88         }
89         break;
90     default:
91         return rt_i2c_control(bus, cmd, args);
92     }
93 
94     return RT_EOK;
95 }
96 
97 #ifdef RT_USING_DEVICE_OPS
98 const static struct rt_device_ops i2c_ops =
99 {
100     RT_NULL,
101     RT_NULL,
102     RT_NULL,
103     i2c_bus_device_read,
104     i2c_bus_device_write,
105     i2c_bus_device_control
106 };
107 #endif
108 
rt_i2c_bus_device_device_init(struct rt_i2c_bus_device * bus,const char * name)109 rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
110                                        const char               *name)
111 {
112     struct rt_device *device;
113     RT_ASSERT(bus != RT_NULL);
114 
115     device = &bus->parent;
116 
117     device->user_data = bus;
118 
119     /* set device type */
120     device->type    = RT_Device_Class_I2CBUS;
121     /* initialize device interface */
122 #ifdef RT_USING_DEVICE_OPS
123     device->ops     = &i2c_ops;
124 #else
125     device->init    = RT_NULL;
126     device->open    = RT_NULL;
127     device->close   = RT_NULL;
128     device->read    = i2c_bus_device_read;
129     device->write   = i2c_bus_device_write;
130     device->control = i2c_bus_device_control;
131 #endif
132 
133     /* register to device manager */
134     rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
135 
136     return RT_EOK;
137 }
138