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  */
9 
10 #include <rtthread.h>
11 #include "drivers/dev_spi.h"
12 
13 #define DBG_TAG     "spi.dev"
14 #define DBG_LVL     DBG_INFO
15 #include <rtdbg.h>
16 
17 #ifdef RT_USING_DM
18 #include "dev_spi_dm.h"
19 #endif
20 
21 /* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */
_spi_bus_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)22 static rt_ssize_t _spi_bus_device_read(rt_device_t dev,
23                                       rt_off_t    pos,
24                                       void       *buffer,
25                                       rt_size_t   size)
26 {
27     struct rt_spi_bus *bus;
28 
29     bus = (struct rt_spi_bus *)dev;
30     RT_ASSERT(bus != RT_NULL);
31     RT_ASSERT(bus->owner != RT_NULL);
32 
33     return rt_spi_transfer(bus->owner, RT_NULL, buffer, size);
34 }
35 
_spi_bus_device_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)36 static rt_ssize_t _spi_bus_device_write(rt_device_t dev,
37                                        rt_off_t    pos,
38                                        const void *buffer,
39                                        rt_size_t   size)
40 {
41     struct rt_spi_bus *bus;
42 
43     bus = (struct rt_spi_bus *)dev;
44     RT_ASSERT(bus != RT_NULL);
45     RT_ASSERT(bus->owner != RT_NULL);
46 
47     return rt_spi_transfer(bus->owner, buffer, RT_NULL, size);
48 }
49 
50 #ifdef RT_USING_DEVICE_OPS
51 const static struct rt_device_ops spi_bus_ops =
52 {
53     RT_NULL,
54     RT_NULL,
55     RT_NULL,
56     _spi_bus_device_read,
57     _spi_bus_device_write,
58     RT_NULL
59 };
60 #endif
61 
rt_spi_bus_device_init(struct rt_spi_bus * bus,const char * name)62 rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
63 {
64     struct rt_device *device;
65     RT_ASSERT(bus != RT_NULL);
66 
67     device = &bus->parent;
68 
69     /* set device type */
70     device->type    = RT_Device_Class_SPIBUS;
71     /* initialize device interface */
72 #ifdef RT_USING_DEVICE_OPS
73     device->ops     = &spi_bus_ops;
74 #else
75     device->init    = RT_NULL;
76     device->open    = RT_NULL;
77     device->close   = RT_NULL;
78     device->read    = _spi_bus_device_read;
79     device->write   = _spi_bus_device_write;
80     device->control = RT_NULL;
81 #endif
82 
83     /* register to device manager */
84     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
85 }
86 
87 /* SPI Dev device interface, compatible with RT-Thread 0.3.x/1.0.x */
_spidev_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)88 static rt_ssize_t _spidev_device_read(rt_device_t dev,
89                                      rt_off_t    pos,
90                                      void       *buffer,
91                                      rt_size_t   size)
92 {
93     struct rt_spi_device *device;
94 
95     device = (struct rt_spi_device *)dev;
96     RT_ASSERT(device != RT_NULL);
97     RT_ASSERT(device->bus != RT_NULL);
98 
99     return rt_spi_transfer(device, RT_NULL, buffer, size);
100 }
101 
_spidev_device_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)102 static rt_ssize_t _spidev_device_write(rt_device_t dev,
103                                       rt_off_t    pos,
104                                       const void *buffer,
105                                       rt_size_t   size)
106 {
107     struct rt_spi_device *device;
108 
109     device = (struct rt_spi_device *)dev;
110     RT_ASSERT(device != RT_NULL);
111     RT_ASSERT(device->bus != RT_NULL);
112 
113     return rt_spi_transfer(device, buffer, RT_NULL, size);
114 }
115 
_spidev_device_control(rt_device_t dev,int cmd,void * args)116 static rt_err_t _spidev_device_control(rt_device_t dev,
117                                        int         cmd,
118                                        void       *args)
119 {
120     switch (cmd)
121     {
122     case 0: /* set device */
123         break;
124     case 1:
125         break;
126     }
127 
128     return RT_EOK;
129 }
130 
131 #ifdef RT_USING_DEVICE_OPS
132 const static struct rt_device_ops spi_device_ops =
133 {
134     RT_NULL,
135     RT_NULL,
136     RT_NULL,
137     _spidev_device_read,
138     _spidev_device_write,
139     _spidev_device_control
140 };
141 #endif
142 
rt_spidev_device_init(struct rt_spi_device * dev,const char * name)143 rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name)
144 {
145     struct rt_device *device;
146     RT_ASSERT(dev != RT_NULL);
147 
148     device = &(dev->parent);
149 
150     /* set device type */
151     device->type    = RT_Device_Class_SPIDevice;
152 #ifdef RT_USING_DEVICE_OPS
153     device->ops     = &spi_device_ops;
154 #else
155     device->init    = RT_NULL;
156     device->open    = RT_NULL;
157     device->close   = RT_NULL;
158     device->read    = _spidev_device_read;
159     device->write   = _spidev_device_write;
160     device->control = _spidev_device_control;
161 #endif
162 
163     /* register to device manager */
164     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
165 }
166 
167 #ifdef RT_USING_DM
spidev_probe(struct rt_spi_device * spi_dev)168 static rt_err_t spidev_probe(struct rt_spi_device *spi_dev)
169 {
170     const char *bus_name;
171     struct rt_device *dev = &spi_dev->parent;
172 
173     if (spi_dev->parent.ofw_node)
174     {
175         if (rt_dm_dev_prop_index_of_string(dev, "compatible", "spidev") >= 0)
176         {
177             LOG_E("spidev is not supported in OFW");
178 
179             return -RT_EINVAL;
180         }
181     }
182 
183     bus_name = rt_dm_dev_get_name(&spi_dev->bus->parent);
184     rt_dm_dev_set_name(dev, "%s_%d", bus_name, spi_dev->chip_select[0]);
185 
186     return RT_EOK;
187 }
188 
189 static const struct rt_spi_device_id spidev_ids[] =
190 {
191     { .name = "dh2228fv" },
192     { .name = "ltc2488" },
193     { .name = "sx1301" },
194     { .name = "bk4" },
195     { .name = "dhcom-board" },
196     { .name = "m53cpld" },
197     { .name = "spi-petra" },
198     { .name = "spi-authenta" },
199     { .name = "em3581" },
200     { .name = "si3210" },
201     { /* sentinel */ },
202 };
203 
204 static const struct rt_ofw_node_id spidev_ofw_ids[] =
205 {
206     { .compatible = "cisco,spi-petra" },
207     { .compatible = "dh,dhcom-board" },
208     { .compatible = "lineartechnology,ltc2488" },
209     { .compatible = "lwn,bk4" },
210     { .compatible = "menlo,m53cpld" },
211     { .compatible = "micron,spi-authenta" },
212     { .compatible = "rohm,dh2228fv" },
213     { .compatible = "semtech,sx1301" },
214     { .compatible = "silabs,em3581" },
215     { .compatible = "silabs,si3210" },
216     { .compatible = "rockchip,spidev" },
217     { /* sentinel */ },
218 };
219 
220 static struct rt_spi_driver spidev_driver =
221 {
222     .ids = spidev_ids,
223     .ofw_ids = spidev_ofw_ids,
224 
225     .probe = spidev_probe,
226 };
227 RT_SPI_DRIVER_EXPORT(spidev_driver);
228 #endif /* RT_USING_DM */
229