1 /* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5  * 1. Redistributions of source code must retain the above copyright
6  * notice, this list of conditions and the following disclaimer.
7  * 2. Redistributions in binary form must reproduce the above copyright
8  * notice, this list of conditions and the following disclaimer in the
9  * documentation and/or other materials provided with the distribution.
10  *
11  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
12  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
16  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 /*
27  * Copyright (c) 2006-2025 RT-Thread Development Team
28  *
29  * SPDX-License-Identifier: Apache-2.0
30  */
31 
32 #include "drv_ts.h"
33 #include <rtthread.h>
34 #include <rthw.h>
35 #include <rtdevice.h>
36 
37 #ifdef RT_USING_POSIX
38 #include <dfs_posix.h>
39 #include <dfs_poll.h>
40 #include <posix_termios.h>
41 #endif
42 
43 #include "math.h"
44 #include "rtdbg.h"
45 #include "board.h"
46 #include <riscv_io.h>
47 #include "ioremap.h"
48 
49 // Register offsets
50 #define REG_TSENW_OFFSET          0x000
51 #define REG_TSENR_OFFSET          0x004
52 
53 // Bit positions for REG_TSENW
54 #define TSENW_TS_TEST_EN_POS      6
55 #define TSENW_TS_TRIM_POS         2
56 #define TSENW_TS_CONV_MODE_POS    1
57 #define TSENW_TS_EN_POS           0
58 
59 // Bit positions for REG_TSENR
60 #define TSENR_TS_DOUT_VALID_POS   12
61 #define TSENR_TS_DOUT_MASK        0xFFF
62 
63 static struct rt_mutex ts_mutex;
64 static uint8_t ts_trim = 8;
65 static uint8_t ts_mode = RT_DEVICE_TS_CTRL_MODE_CONTINUUOS;
66 static void *ts_base_addr = RT_NULL;
67 
tsensor_start(void)68 static rt_err_t tsensor_start(void)
69 {
70     uint32_t reg_val;
71 
72     if (ts_base_addr == RT_NULL)
73         return -RT_ERROR;
74 
75     reg_val = readl(ts_base_addr + REG_TSENW_OFFSET);
76 
77     if (RT_DEVICE_TS_CTRL_MODE_CONTINUUOS == ts_mode)
78         reg_val |= (1 << TSENW_TS_CONV_MODE_POS);
79     else
80         reg_val &= ~(1 << TSENW_TS_CONV_MODE_POS);
81 
82     reg_val |= (1 << TSENW_TS_EN_POS);
83 
84     writel(reg_val, ts_base_addr + REG_TSENW_OFFSET);
85 
86     return RT_EOK;
87 }
88 
tsensor_stop(void)89 static rt_err_t tsensor_stop(void)
90 {
91     if (ts_base_addr == RT_NULL)
92         return -RT_ERROR;
93 
94     uint32_t reg_val = readl(ts_base_addr + REG_TSENW_OFFSET);
95     reg_val &= ~(1 << TSENW_TS_EN_POS);
96     writel(reg_val, ts_base_addr + REG_TSENW_OFFSET);
97 
98     return RT_EOK;
99 }
100 
tsensor_read_data(uint16_t * data,uint32_t timeout_ms)101 static int tsensor_read_data(uint16_t *data, uint32_t timeout_ms)
102 {
103     if (ts_base_addr == RT_NULL || data == RT_NULL) // Ensure base address is set
104         return -RT_ERROR;
105 
106     uint32_t max_attempts = timeout_ms; // Max attempts for the given timeout in ms
107 
108     for (uint32_t attempt = 0; attempt < max_attempts; attempt++)
109     {
110         // Check if the data is valid
111         if ((readl(ts_base_addr + REG_TSENR_OFFSET) >> TSENR_TS_DOUT_VALID_POS) & 0x1)
112         {
113             // Read the 12-bit temperature data
114             *data = readl(ts_base_addr + REG_TSENR_OFFSET) & TSENR_TS_DOUT_MASK;
115             return RT_EOK; // Success
116         }
117 
118         // Delay before next polling attempt
119         rt_thread_mdelay(1); // Delay in microseconds
120     }
121 
122     return -RT_ETIMEOUT; // Timeout error
123 }
124 
tsensor_calculate_temperature(uint16_t data)125 static double tsensor_calculate_temperature(uint16_t data)
126 {
127     return (1e-10 * pow(data, 4) * 1.01472
128             - 1e-6 * pow(data, 3) * 1.10063
129             + 4.36150 * 1e-3 * pow(data, 2)
130             - 7.10128 * data
131             + 3565.87);
132 }
133 
tsensor_init(void)134 static rt_err_t tsensor_init(void)
135 {
136     if (ts_base_addr == RT_NULL)
137     {
138         return -RT_ERROR;
139     }
140 
141     if (RT_EOK != rt_mutex_take(&ts_mutex, rt_tick_from_millisecond(500)))
142     {
143         LOG_E("%s mutex take timeout.\n", __func__);
144         return -RT_ETIMEOUT;
145     }
146 
147     uint32_t reg_val = readl(ts_base_addr + REG_TSENW_OFFSET);
148     reg_val &= ~(0xF << TSENW_TS_TRIM_POS);
149     reg_val |= (ts_trim << TSENW_TS_TRIM_POS);
150     writel(reg_val, ts_base_addr + REG_TSENW_OFFSET);
151 
152     rt_mutex_release(&ts_mutex);
153 
154     return RT_EOK;
155 }
156 
157 
k230_tsensor_set_trim(uint8_t trim)158 static rt_err_t k230_tsensor_set_trim(uint8_t trim)
159 {
160     if(RT_EOK != rt_mutex_take(&ts_mutex, rt_tick_from_millisecond(500)))
161     {
162         LOG_E("%s mutex take timeout.\n");
163         return -RT_ETIMEOUT;
164     }
165 
166     // Ensure the trim_value is within range (4 bits)
167     ts_trim = trim & 0xF;
168     rt_mutex_release(&ts_mutex);
169     tsensor_init();
170     return RT_EOK;
171 }
172 
k230_tsensor_get_trim(void)173 static uint8_t k230_tsensor_get_trim(void)
174 {
175     uint8_t temp;
176 
177     if(RT_EOK != rt_mutex_take(&ts_mutex, rt_tick_from_millisecond(500)))
178     {
179         LOG_E("%s mutex take timeout.\n");
180         return -RT_ETIMEOUT;
181     }
182 
183     temp = ts_trim;
184 
185     rt_mutex_release(&ts_mutex);
186 
187     return temp;
188 }
189 
k230_tsensor_set_mode(uint8_t mode)190 static rt_err_t k230_tsensor_set_mode(uint8_t mode)
191 {
192     if(RT_EOK != rt_mutex_take(&ts_mutex, rt_tick_from_millisecond(500)))
193     {
194         LOG_E("%s mutex take timeout.\n");
195         return -RT_ETIMEOUT;
196     }
197     ts_mode = mode;
198     rt_mutex_release(&ts_mutex);
199     return RT_EOK;
200 }
201 
k230_tsensor_get_mode(void)202 static uint8_t k230_tsensor_get_mode(void)
203 {
204     uint8_t temp;
205 
206     if(RT_EOK != rt_mutex_take(&ts_mutex, rt_tick_from_millisecond(500)))
207     {
208         LOG_E("%s mutex take timeout.\n");
209         return -RT_ETIMEOUT;
210     }
211 
212     temp = ts_mode;
213     rt_mutex_release(&ts_mutex);
214     return temp;
215 }
216 
k230_tsensor_read_temp(double * temp)217 static rt_err_t k230_tsensor_read_temp(double *temp)
218 {
219     uint16_t data;
220     rt_err_t ret = RT_EOK;
221     if (RT_EOK != rt_mutex_take(&ts_mutex, rt_tick_from_millisecond(500)))
222     {
223         LOG_E("%s mutex take timeout.\n");
224         return -RT_ETIMEOUT;
225     }
226 
227     ret = tsensor_start();
228     if (ret != RT_EOK)
229     {
230         return ret;
231     }
232 
233     rt_thread_mdelay(10);
234 
235     if (0x00 == tsensor_read_data(&data, 100))
236     {
237         *((double *)temp) = tsensor_calculate_temperature(data);
238         tsensor_stop();
239         rt_mutex_release(&ts_mutex);
240         return RT_EOK;
241     }
242     else
243     {
244         tsensor_stop();
245         rt_mutex_release(&ts_mutex);
246         return -RT_ERROR;
247     }
248 }
249 
ts_device_open(rt_device_t dev,rt_uint16_t oflag)250 static rt_err_t ts_device_open(rt_device_t dev, rt_uint16_t oflag)
251 {
252     rt_err_t ret;
253 
254     ret = tsensor_init();
255     return ret;
256 }
257 
ts_device_close(rt_device_t dev)258 static rt_err_t ts_device_close(rt_device_t dev)
259 {
260     rt_err_t ret;
261     ret = tsensor_stop();
262     return ret;
263 }
264 
ts_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)265 static rt_ssize_t ts_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
266 {
267     rt_err_t ret;
268 
269     if (sizeof(double) != size)
270     {
271         LOG_E("%s invalid buffer size %u\n", __func__, size);
272         return -RT_ERROR;
273     }
274 
275     ret = k230_tsensor_read_temp((double *)buffer);
276     if (ret != 0x00)
277     {
278         return -RT_ERROR;
279     }
280     return sizeof(double);
281 }
282 
ts_device_control(rt_device_t dev,int cmd,void * args)283 static rt_err_t ts_device_control(rt_device_t dev, int cmd, void *args)
284 {
285     uint8_t trim_val = k230_tsensor_get_trim();
286     uint8_t work_mode = k230_tsensor_get_mode();
287     rt_err_t ret = RT_EOK;
288 
289     switch(cmd)
290     {
291         case RT_DEVICE_TS_CTRL_SET_MODE:
292             work_mode = *(uint8_t *)args;
293             ret = k230_tsensor_set_mode(work_mode);
294             break;
295         case RT_DEVICE_TS_CTRL_GET_MODE:
296             *(uint8_t *)args = work_mode;
297             break;
298         case RT_DEVICE_TS_CTRL_SET_TRIM:
299             trim_val = *(uint8_t *)args;
300             ret = k230_tsensor_set_trim(trim_val);
301             break;
302         case RT_DEVICE_TS_CTRL_GET_TRIM:
303             *(uint8_t *)args = trim_val;
304             break;
305         default:
306             LOG_E("%s unsupported cmd 0x%x\n", __func__, cmd);
307             ret = -RT_ERROR;
308             break;
309     }
310 
311     return ret;
312 }
313 
314 static struct rt_device ts_device;
315 
316 static const struct rt_device_ops ts_ops =
317 {
318     .open    = ts_device_open,
319     .close   = ts_device_close,
320     .read    = ts_device_read,
321     .control = ts_device_control
322 };
323 
register_ts_device(void)324 static rt_err_t register_ts_device(void)
325 {
326     rt_device_t device;
327     rt_err_t ret = RT_EOK;
328 
329     device = &ts_device;
330 
331 #ifdef RT_USING_DEVICE_OPS
332     device->ops = &ts_ops;
333 #else
334     device->init       =     RT_NULL;
335     device->open       =     ts_device_open;
336     device->close      =     ts_device_close;
337     device->read       =     ts_device_read;
338     device->write      =     RT_NULL;
339     device->control    =     ts_device_control;
340 #endif
341 
342     ret = rt_device_register(device, "ts", RT_DEVICE_FLAG_RDWR);
343     if(ret != RT_EOK)
344     {
345         LOG_E("ts device register fail\n");
346         return -RT_ERROR;
347     }
348     return ret;
349 }
350 
rt_hw_ts_init(void)351 static int rt_hw_ts_init(void)
352 {
353     ts_base_addr = rt_ioremap((void *)TS_BASE_ADDR, TS_IO_SIZE);
354     if (ts_base_addr == RT_NULL)
355     {
356         LOG_E("ts ioremap error\n");
357         return -RT_ERROR;
358     }
359     if (RT_EOK != register_ts_device())
360     {
361         LOG_E("ts device register error\n");
362         return -RT_ERROR;
363     }
364     if (RT_EOK != rt_mutex_init(&ts_mutex, "dev_ts", RT_IPC_FLAG_PRIO))
365     {
366         LOG_E("ts mutex init error\n");
367         return -RT_ERROR;
368     }
369     return RT_EOK;
370 }
371 INIT_DEVICE_EXPORT(rt_hw_ts_init);