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);