6
6
* Copyright (C) 2020 by Renesas Electronics Corporation
7
7
*/
8
8
9
+ #include <generated/utsrelease.h>
9
10
#include <linux/bitops.h>
10
11
#include <linux/i2c.h>
11
12
#include <linux/init.h>
15
16
#include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
16
17
17
18
#define TU_CUR_VERSION 0x01
19
+ #define TU_VERSION_MAX_LENGTH 128
18
20
19
21
enum testunit_cmds {
20
22
TU_CMD_READ_BYTES = 1 , /* save 0 for ABORT, RESET or similar */
21
23
TU_CMD_SMBUS_HOST_NOTIFY ,
22
24
TU_CMD_SMBUS_BLOCK_PROC_CALL ,
25
+ TU_CMD_GET_VERSION_WITH_REP_START ,
23
26
TU_NUM_CMDS
24
27
};
25
28
@@ -39,10 +42,13 @@ struct testunit_data {
39
42
unsigned long flags ;
40
43
u8 regs [TU_NUM_REGS ];
41
44
u8 reg_idx ;
45
+ u8 read_idx ;
42
46
struct i2c_client * client ;
43
47
struct delayed_work worker ;
44
48
};
45
49
50
+ static char tu_version_info [] = "v" UTS_RELEASE "\n\0" ;
51
+
46
52
static void i2c_slave_testunit_work (struct work_struct * work )
47
53
{
48
54
struct testunit_data * tu = container_of (work , struct testunit_data , worker .work );
@@ -91,6 +97,8 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
91
97
struct testunit_data * tu = i2c_get_clientdata (client );
92
98
bool is_proc_call = tu -> reg_idx == 3 && tu -> regs [TU_REG_DATAL ] == 1 &&
93
99
tu -> regs [TU_REG_CMD ] == TU_CMD_SMBUS_BLOCK_PROC_CALL ;
100
+ bool is_get_version = tu -> reg_idx == 3 &&
101
+ tu -> regs [TU_REG_CMD ] == TU_CMD_GET_VERSION_WITH_REP_START ;
94
102
int ret = 0 ;
95
103
96
104
switch (event ) {
@@ -100,6 +108,7 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
100
108
101
109
memset (tu -> regs , 0 , TU_NUM_REGS );
102
110
tu -> reg_idx = 0 ;
111
+ tu -> read_idx = 0 ;
103
112
break ;
104
113
105
114
case I2C_SLAVE_WRITE_RECEIVED :
@@ -136,12 +145,21 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
136
145
break ;
137
146
138
147
case I2C_SLAVE_READ_PROCESSED :
139
- if (is_proc_call && tu -> regs [TU_REG_DATAH ])
148
+ /* Advance until we reach the NUL character */
149
+ if (is_get_version && tu_version_info [tu -> read_idx ] != 0 )
150
+ tu -> read_idx ++ ;
151
+ else if (is_proc_call && tu -> regs [TU_REG_DATAH ])
140
152
tu -> regs [TU_REG_DATAH ]-- ;
153
+
141
154
fallthrough ;
142
155
143
156
case I2C_SLAVE_READ_REQUESTED :
144
- * val = is_proc_call ? tu -> regs [TU_REG_DATAH ] : TU_CUR_VERSION ;
157
+ if (is_get_version )
158
+ * val = tu_version_info [tu -> read_idx ];
159
+ else if (is_proc_call )
160
+ * val = tu -> regs [TU_REG_DATAH ];
161
+ else
162
+ * val = TU_CUR_VERSION ;
145
163
break ;
146
164
}
147
165
@@ -160,6 +178,9 @@ static int i2c_slave_testunit_probe(struct i2c_client *client)
160
178
i2c_set_clientdata (client , tu );
161
179
INIT_DELAYED_WORK (& tu -> worker , i2c_slave_testunit_work );
162
180
181
+ if (sizeof (tu_version_info ) > TU_VERSION_MAX_LENGTH )
182
+ tu_version_info [TU_VERSION_MAX_LENGTH - 1 ] = 0 ;
183
+
163
184
return i2c_slave_register (client , i2c_slave_testunit_slave_cb );
164
185
};
165
186
0 commit comments