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+
68+ static void tsensor_start (void ) {
69+ if (ts_base_addr == RT_NULL ) return ; // Ensure base address is set
70+
71+ // Ensure single output mode is selected and enable the TSensor
72+ uint32_t reg_val = readl (ts_base_addr + REG_TSENW_OFFSET );
73+ if (RT_DEVICE_TS_CTRL_MODE_CONTINUUOS == ts_mode ) {
74+ reg_val |= (1 << TSENW_TS_CONV_MODE_POS ); // Set continuous mode bit
75+ } else {
76+ reg_val &= ~(1 << TSENW_TS_CONV_MODE_POS ); // Clear continuous mode bit
77+ }
78+ reg_val |= (1 << TSENW_TS_EN_POS ); // Set enable bit
79+ writel (reg_val , ts_base_addr + REG_TSENW_OFFSET );
80+ }
81+
82+ static void tsensor_stop (void ) {
83+ if (ts_base_addr == RT_NULL ) return ; // Ensure base address is set
84+
85+ // Disable the TSensor
86+ uint32_t reg_val = readl (ts_base_addr + REG_TSENW_OFFSET );
87+ reg_val &= ~((1 << TSENW_TS_EN_POS ));
88+ writel (reg_val , ts_base_addr + REG_TSENW_OFFSET );
89+ }
90+
91+ static int tsensor_read_data (uint16_t * data , uint32_t timeout_ms ) {
92+ if (ts_base_addr == RT_NULL || data == RT_NULL ) return -1 ; // Ensure base address is set
93+
94+ uint32_t max_attempts = timeout_ms ; // Max attempts for the given timeout in ms
95+
96+ for (uint32_t attempt = 0 ; attempt < max_attempts ; attempt ++ ) {
97+ // Check if the data is valid
98+ if ((readl (ts_base_addr + REG_TSENR_OFFSET ) >> TSENR_TS_DOUT_VALID_POS ) & 0x1 ) {
99+ // Read the 12-bit temperature data
100+ * data = readl (ts_base_addr + REG_TSENR_OFFSET ) & TSENR_TS_DOUT_MASK ;
101+ return 0 ; // Success
102+ }
103+
104+ // Delay before next polling attempt
105+ rt_thread_mdelay (1 ); // Delay in microseconds
106+ }
107+
108+ return -2 ; // Timeout error
109+ }
110+
111+ static double tsensor_calculate_temperature (uint16_t data ) {
112+ return (1e-10 * pow (data , 4 ) * 1.01472
113+ - 1e-6 * pow (data , 3 ) * 1.10063
114+ + 4.36150 * 1e-3 * pow (data , 2 )
115+ - 7.10128 * data
116+ + 3565.87 );
117+ }
118+
119+ void tsensor_init (void ) {
120+ if (ts_base_addr == RT_NULL ) return ; // Ensure base address is set
121+
122+ if (RT_EOK != rt_mutex_take (& ts_mutex , rt_tick_from_millisecond (500 ))) {
123+ LOG_E ("%s mutex take timeout.\n" );
124+
125+ return ;
126+ }
127+
128+ // Configure the TSensor with the default settings
129+ uint32_t reg_val = readl (ts_base_addr + REG_TSENW_OFFSET );
130+ reg_val &= ~(0xF << TSENW_TS_TRIM_POS ); // Clear previous trim value
131+ reg_val |= (ts_trim << TSENW_TS_TRIM_POS ); // Set new trim value
132+ writel (reg_val , ts_base_addr + REG_TSENW_OFFSET );
133+
134+ rt_mutex_release (& ts_mutex );
135+ }
136+
137+ void tsensor_set_trim (uint8_t trim ) {
138+ if (RT_EOK != rt_mutex_take (& ts_mutex , rt_tick_from_millisecond (500 ))) {
139+ LOG_E ("%s mutex take timeout.\n" );
140+ return ;
141+ }
142+
143+ // Ensure the trim_value is within range (4 bits)
144+ ts_trim = trim & 0xF ;
145+ rt_mutex_release (& ts_mutex );
146+ tsensor_init ();
147+ }
148+
149+ uint8_t tsensor_get_trim (void ) {
150+ uint8_t temp ;
151+
152+ if (RT_EOK != rt_mutex_take (& ts_mutex , rt_tick_from_millisecond (500 ))) {
153+ LOG_E ("%s mutex take timeout.\n" );
154+ return -1 ;
155+ }
156+
157+ temp = ts_trim ;
158+
159+ rt_mutex_release (& ts_mutex );
160+
161+ return temp ;
162+ }
163+
164+ void tsensor_set_mode (uint8_t mode ) {
165+ if (RT_EOK != rt_mutex_take (& ts_mutex , rt_tick_from_millisecond (500 ))) {
166+ LOG_E ("%s mutex take timeout.\n" );
167+
168+ return ;
169+ }
170+
171+ ts_mode = mode ;
172+
173+ rt_mutex_release (& ts_mutex );
174+ }
175+
176+ uint8_t tsensor_get_mode (void ) {
177+ uint8_t temp ;
178+
179+ if (RT_EOK != rt_mutex_take (& ts_mutex , rt_tick_from_millisecond (500 ))) {
180+ LOG_E ("%s mutex take timeout.\n" );
181+ return -1 ;
182+ }
183+
184+ temp = ts_mode ;
185+ rt_mutex_release (& ts_mutex );
186+ return temp ;
187+ }
188+
189+ int tsensor_read_temp (double * temp ) {
190+ uint16_t data ;
191+
192+ if (RT_EOK != rt_mutex_take (& ts_mutex , rt_tick_from_millisecond (500 ))) {
193+ LOG_E ("%s mutex take timeout.\n" );
194+ return -1 ;
195+ }
196+
197+ tsensor_start ();
198+ rt_thread_mdelay (10 );
199+
200+ if (0x00 == tsensor_read_data (& data , 100 )) {
201+ * ((double * )temp ) = tsensor_calculate_temperature (data );
202+ tsensor_stop ();
203+ rt_mutex_release (& ts_mutex );
204+ return 0 ;
205+ } else {
206+ tsensor_stop ();
207+ rt_mutex_release (& ts_mutex );
208+ return -1 ;
209+ }
210+ }
211+
212+ static rt_err_t ts_deivce_open (rt_device_t dev , rt_uint16_t oflag )
213+ {
214+ tsensor_init ();
215+
216+ return RT_EOK ;
217+ }
218+
219+ static rt_err_t ts_device_close (rt_device_t dev )
220+ {
221+ tsensor_stop ();
222+
223+ return RT_EOK ;
224+ }
225+
226+ static rt_ssize_t ts_device_read (rt_device_t dev , rt_off_t pos , void * buffer , rt_size_t size )
227+ {
228+ if (sizeof (double ) != size ) {
229+ LOG_E ("%s invalid buffer size %u\n" , __func__ , size );
230+ return 0 ;
231+ }
232+
233+ if (0x00 != tsensor_read_temp (buffer )) {
234+ return 0 ; // read failed
235+ }
236+
237+ return sizeof (double );
238+ }
239+
240+ static rt_err_t ts_device_control (rt_device_t dev , int cmd , void * args )
241+ {
242+ uint8_t trim_val = tsensor_get_trim ();
243+ uint8_t work_mode = tsensor_get_mode ();
244+
245+ switch (cmd ) {
246+ case RT_DEVICE_TS_CTRL_SET_MODE :
247+ work_mode = (rt_uint8_t )(* (rt_uint8_t * )args );
248+ tsensor_set_mode (work_mode );
249+ break ;
250+ case RT_DEVICE_TS_CTRL_GET_MODE :
251+ * ((rt_uint8_t * )args ) = (rt_uint8_t )work_mode ;
252+ break ;
253+ case RT_DEVICE_TS_CTRL_SET_TRIM :
254+ trim_val = (rt_uint8_t )(* (rt_uint8_t * )args );
255+ tsensor_set_trim (trim_val );
256+ break ;
257+ case RT_DEVICE_TS_CTRL_GET_TRIM :
258+ * ((rt_uint8_t * )args ) = (rt_uint8_t )trim_val ;
259+ break ;
260+ default :
261+ LOG_E ("%s unsupport cmd 0x%x\n" , __func__ , cmd );
262+ break ;
263+ }
264+
265+ return RT_EOK ;
266+ }
267+
268+ static struct rt_device ts_device ;
269+
270+ static const struct rt_device_ops ts_ops =
271+ {
272+ RT_NULL ,
273+ ts_deivce_open ,
274+ ts_device_close ,
275+ ts_device_read ,
276+ RT_NULL ,
277+ ts_device_control
278+ };
279+
280+ static int register_ts_device (void )
281+ {
282+ rt_device_t device ;
283+ rt_err_t ret = RT_EOK ;
284+
285+ device = & ts_device ;
286+
287+ #ifdef RT_USING_DEVICE_OPS
288+ device -> ops = & ts_ops ;
289+ #else
290+ device -> init = RT_NULL ;
291+ device -> open = ts_deivce_open ;
292+ device -> close = ts_device_close ;
293+ device -> read = ts_device_read ;
294+ device -> write = RT_NULL ;
295+ device -> control = ts_device_control ;
296+ #endif
297+
298+ if (RT_EOK != (ret = rt_device_register (device , "ts" , RT_DEVICE_FLAG_RDWR ))) {
299+ LOG_E ("ts device register fail\n" );
300+ return -1 ;
301+ }
302+
303+ return 0 ;
304+ }
305+
306+ static int rt_hw_ts_init (void )
307+ {
308+ if (RT_NULL == (ts_base_addr = rt_ioremap ((void * )TS_BASE_ADDR , TS_IO_SIZE ))) {
309+ LOG_E ("ts ioremap error\n" );
310+ return -1 ;
311+ }
312+ if (0x00 != register_ts_device ()) {
313+ return -2 ;
314+ }
315+ if (RT_EOK != rt_mutex_init (& ts_mutex , "dev_ts" , RT_IPC_FLAG_PRIO )) {
316+ LOG_E ("ts init mutex error\n" );
317+ return -3 ;
318+ }
319+
320+ return RT_EOK ;
321+ }
322+ INIT_DEVICE_EXPORT (rt_hw_ts_init );
0 commit comments