common.c revision 1.1 1 1.1 brad /* $NetBSD: common.c,v 1.1 2021/12/07 17:39:55 brad Exp $ */
2 1.1 brad
3 1.1 brad /*
4 1.1 brad * Copyright (c) 2021 Brad Spencer <brad (at) anduin.eldar.org>
5 1.1 brad *
6 1.1 brad * Permission to use, copy, modify, and distribute this software for any
7 1.1 brad * purpose with or without fee is hereby granted, provided that the above
8 1.1 brad * copyright notice and this permission notice appear in all copies.
9 1.1 brad *
10 1.1 brad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 1.1 brad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 1.1 brad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 1.1 brad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 1.1 brad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 1.1 brad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 1.1 brad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 1.1 brad */
18 1.1 brad
19 1.1 brad #ifdef __RCSID
20 1.1 brad __RCSID("$NetBSD: common.c,v 1.1 2021/12/07 17:39:55 brad Exp $");
21 1.1 brad #endif
22 1.1 brad
23 1.1 brad /* Common functions dealing with the SCMD devices. This does not
24 1.1 brad * know how to talk to anything in particular, it calls out to the
25 1.1 brad * functions defined in the function blocks for that.
26 1.1 brad */
27 1.1 brad
28 1.1 brad #include <inttypes.h>
29 1.1 brad #include <stdbool.h>
30 1.1 brad #include <stdio.h>
31 1.1 brad #include <stdlib.h>
32 1.1 brad #include <unistd.h>
33 1.1 brad #include <err.h>
34 1.1 brad #include <fcntl.h>
35 1.1 brad #include <string.h>
36 1.1 brad #include <limits.h>
37 1.1 brad #include <errno.h>
38 1.1 brad
39 1.1 brad #include <dev/ic/scmdreg.h>
40 1.1 brad
41 1.1 brad #define EXTERN
42 1.1 brad #include "common.h"
43 1.1 brad #include "responses.h"
44 1.1 brad #include "scmdctl.h"
45 1.1 brad
46 1.1 brad
47 1.1 brad int
48 1.1 brad decode_motor_level(int raw)
49 1.1 brad {
50 1.1 brad int r;
51 1.1 brad
52 1.1 brad r = abs(128 - raw);
53 1.1 brad if (raw < 128)
54 1.1 brad r = r * -1;
55 1.1 brad
56 1.1 brad return r;
57 1.1 brad }
58 1.1 brad
59 1.1 brad int common_clear(struct function_block *fb, int fd, bool debug)
60 1.1 brad {
61 1.1 brad return (*(fb->func_clear))(fd, debug);
62 1.1 brad }
63 1.1 brad
64 1.1 brad int
65 1.1 brad common_identify(struct function_block *fb, int fd, bool debug, int a_module, struct scmd_identify_response *r)
66 1.1 brad {
67 1.1 brad uint8_t b;
68 1.1 brad int err;
69 1.1 brad
70 1.1 brad err = (*(fb->func_clear))(fd, debug);
71 1.1 brad if (! err) {
72 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_ID, SCMD_REG_ID, &b);
73 1.1 brad if (! err)
74 1.1 brad r->id = b;
75 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_FID, SCMD_REG_FID, &b);
76 1.1 brad if (! err)
77 1.1 brad r->fwversion = b;
78 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_CONFIG_BITS, SCMD_REG_CONFIG_BITS, &b);
79 1.1 brad if (! err)
80 1.1 brad r->config_bits = b;
81 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_SLAVE_ADDR, SCMD_REG_SLAVE_ADDR, &b);
82 1.1 brad if (! err)
83 1.1 brad r->slv_i2c_address = b;
84 1.1 brad }
85 1.1 brad
86 1.1 brad return err;
87 1.1 brad }
88 1.1 brad
89 1.1 brad int common_diag(struct function_block *fb, int fd, bool debug, int a_module, struct scmd_diag_response *r)
90 1.1 brad {
91 1.1 brad uint8_t b;
92 1.1 brad int err, m;
93 1.1 brad
94 1.1 brad err = (*(fb->func_clear))(fd, debug);
95 1.1 brad if (! err) {
96 1.1 brad m = 0;
97 1.1 brad for(uint8_t n = SCMD_REG_U_I2C_RD_ERR; n <= SCMD_REG_GEN_TEST_WORD; n++) {
98 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, n, n, &b);
99 1.1 brad if (! err) {
100 1.1 brad r->diags[m] = b;
101 1.1 brad }
102 1.1 brad m++;
103 1.1 brad }
104 1.1 brad }
105 1.1 brad
106 1.1 brad return err;
107 1.1 brad }
108 1.1 brad
109 1.1 brad /* This tries to avoid reading just every register if only one
110 1.1 brad * motor is asked about.
111 1.1 brad */
112 1.1 brad int
113 1.1 brad common_get_motor(struct function_block *fb, int fd, bool debug, int a_module, struct scmd_motor_response *r)
114 1.1 brad {
115 1.1 brad uint8_t b;
116 1.1 brad int err = 0,m;
117 1.1 brad
118 1.1 brad if (a_module != SCMD_ANY_MODULE &&
119 1.1 brad (a_module < 0 || a_module > 16))
120 1.1 brad return EINVAL;
121 1.1 brad
122 1.1 brad err = (*(fb->func_clear))(fd, debug);
123 1.1 brad if (! err) {
124 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_DRIVER_ENABLE, SCMD_REG_DRIVER_ENABLE, &b);
125 1.1 brad if (! err)
126 1.1 brad r->driver = b;
127 1.1 brad
128 1.1 brad m = 0;
129 1.1 brad for(uint8_t n = SCMD_REG_MA_DRIVE; n <= SCMD_REG_S16B_DRIVE; n++) {
130 1.1 brad r->motorlevels[m] = SCMD_NO_MOTOR;
131 1.1 brad if (a_module != SCMD_ANY_MODULE &&
132 1.1 brad (m / 2) != a_module)
133 1.1 brad goto skip;
134 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, n, n, &b);
135 1.1 brad if (! err)
136 1.1 brad r->motorlevels[m] = b;
137 1.1 brad skip:
138 1.1 brad m++;
139 1.1 brad }
140 1.1 brad
141 1.1 brad if (a_module == SCMD_ANY_MODULE ||
142 1.1 brad a_module == 0) {
143 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_MOTOR_A_INVERT, SCMD_REG_MOTOR_A_INVERT, &b);
144 1.1 brad if (!err)
145 1.1 brad r->invert[0] = (b & 0x01);
146 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_MOTOR_B_INVERT, SCMD_REG_MOTOR_B_INVERT, &b);
147 1.1 brad if (!err)
148 1.1 brad r->invert[1] = (b & 0x01);
149 1.1 brad }
150 1.1 brad
151 1.1 brad if (a_module != 0) {
152 1.1 brad m = 2;
153 1.1 brad for(uint8_t n = SCMD_REG_INV_2_9; n <= SCMD_REG_INV_26_33; n++) {
154 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, n, n, &b);
155 1.1 brad if (!err) {
156 1.1 brad for(uint8_t j = 0; j < 8;j++) {
157 1.1 brad r->invert[m] = (b & (1 << j));
158 1.1 brad m++;
159 1.1 brad }
160 1.1 brad }
161 1.1 brad }
162 1.1 brad }
163 1.1 brad
164 1.1 brad if (a_module == SCMD_ANY_MODULE ||
165 1.1 brad a_module == 0) {
166 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_BRIDGE, SCMD_REG_BRIDGE, &b);
167 1.1 brad if (!err)
168 1.1 brad r->bridge[0] = (b & 0x01);
169 1.1 brad }
170 1.1 brad
171 1.1 brad if (a_module != 0) {
172 1.1 brad m = 1;
173 1.1 brad for(uint8_t n = SCMD_REG_BRIDGE_SLV_L; n <= SCMD_REG_BRIDGE_SLV_H; n++) {
174 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, n, n, &b);
175 1.1 brad if (!err) {
176 1.1 brad for(uint8_t j = 0; j < 8;j++) {
177 1.1 brad r->bridge[m] = (b & (1 << j));
178 1.1 brad m++;
179 1.1 brad }
180 1.1 brad }
181 1.1 brad }
182 1.1 brad }
183 1.1 brad }
184 1.1 brad
185 1.1 brad return err;
186 1.1 brad }
187 1.1 brad
188 1.1 brad int
189 1.1 brad common_set_motor(struct function_block *fb, int fd, bool debug, int a_module, char a_motor, int8_t reg_v)
190 1.1 brad {
191 1.1 brad uint8_t reg;
192 1.1 brad int err;
193 1.1 brad int reg_index;
194 1.1 brad
195 1.1 brad if (a_module < 0 || a_module > 16)
196 1.1 brad return EINVAL;
197 1.1 brad
198 1.1 brad if (!(a_motor == 'A' || a_motor == 'B'))
199 1.1 brad return EINVAL;
200 1.1 brad
201 1.1 brad err = (*(fb->func_clear))(fd, debug);
202 1.1 brad if (! err) {
203 1.1 brad reg_index = a_module * 2;
204 1.1 brad if (a_motor == 'B')
205 1.1 brad reg_index++;
206 1.1 brad reg = SCMD_REG_MA_DRIVE + reg_index;
207 1.1 brad reg_v = reg_v + 128;
208 1.1 brad if (debug)
209 1.1 brad fprintf(stderr,"common_set_motor: reg_index: %d ; reg: %02X ; reg_v: %d\n",reg_index,reg,reg_v);
210 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, reg_v);
211 1.1 brad }
212 1.1 brad
213 1.1 brad return err;
214 1.1 brad }
215 1.1 brad
216 1.1 brad int
217 1.1 brad common_invert_motor(struct function_block *fb, int fd, bool debug, int a_module, char a_motor)
218 1.1 brad {
219 1.1 brad uint8_t b;
220 1.1 brad int err;
221 1.1 brad uint8_t reg, reg_index = 0, reg_offset = 0;
222 1.1 brad int motor_index;
223 1.1 brad
224 1.1 brad err = (*(fb->func_clear))(fd, debug);
225 1.1 brad if (! err) {
226 1.1 brad if (a_module == 0) {
227 1.1 brad if (a_motor == 'A') {
228 1.1 brad reg = SCMD_REG_MOTOR_A_INVERT;
229 1.1 brad } else {
230 1.1 brad reg = SCMD_REG_MOTOR_B_INVERT;
231 1.1 brad }
232 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b);
233 1.1 brad if (!err) {
234 1.1 brad b = b ^ 0x01;
235 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, b);
236 1.1 brad }
237 1.1 brad } else {
238 1.1 brad motor_index = (a_module * 2) - 2;
239 1.1 brad if (a_motor == 'B')
240 1.1 brad motor_index++;
241 1.1 brad reg_offset = motor_index / 8;
242 1.1 brad motor_index = motor_index % 8;
243 1.1 brad reg_index = 1 << motor_index;
244 1.1 brad reg = SCMD_REG_INV_2_9 + reg_offset;
245 1.1 brad if (debug)
246 1.1 brad fprintf(stderr,"common_invert_motor: remote invert: motor_index: %d ; reg_offset: %d ; reg_index: %02X ; reg: %02X\n",motor_index,reg_offset,reg_index,reg);
247 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b);
248 1.1 brad if (!err) {
249 1.1 brad b = b ^ reg_index;
250 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, b);
251 1.1 brad }
252 1.1 brad }
253 1.1 brad }
254 1.1 brad
255 1.1 brad return err;
256 1.1 brad }
257 1.1 brad
258 1.1 brad int
259 1.1 brad common_bridge_motor(struct function_block *fb, int fd, bool debug, int a_module)
260 1.1 brad {
261 1.1 brad uint8_t b;
262 1.1 brad int err = 0;
263 1.1 brad uint8_t reg, reg_index = 0, reg_offset = 0;
264 1.1 brad int module_index;
265 1.1 brad
266 1.1 brad err = (*(fb->func_clear))(fd, debug);
267 1.1 brad if (! err) {
268 1.1 brad if (a_module == 0) {
269 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_BRIDGE, SCMD_REG_BRIDGE, &b);
270 1.1 brad if (!err) {
271 1.1 brad b = b ^ 0x01;
272 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_BRIDGE, b);
273 1.1 brad }
274 1.1 brad } else {
275 1.1 brad module_index = a_module - 1;
276 1.1 brad reg_offset = module_index / 8;
277 1.1 brad module_index = module_index % 8;
278 1.1 brad reg_index = 1 << module_index;
279 1.1 brad reg = SCMD_REG_BRIDGE_SLV_L + reg_offset;
280 1.1 brad if (debug)
281 1.1 brad fprintf(stderr,"common_bridge_motor: remote bridge: module_index: %d ; reg_offset: %d ; reg_index: %02X ; reg: %02X\n",module_index,reg_offset,reg_index,reg);
282 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b);
283 1.1 brad if (!err) {
284 1.1 brad b = b ^ reg_index;
285 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, b);
286 1.1 brad }
287 1.1 brad }
288 1.1 brad }
289 1.1 brad
290 1.1 brad return err;
291 1.1 brad }
292 1.1 brad
293 1.1 brad int
294 1.1 brad common_enable_disable(struct function_block *fb, int fd, bool debug, int subcmd)
295 1.1 brad {
296 1.1 brad int err;
297 1.1 brad uint8_t reg_v;
298 1.1 brad
299 1.1 brad if (!(subcmd == SCMD_ENABLE || subcmd == SCMD_DISABLE))
300 1.1 brad return EINVAL;
301 1.1 brad
302 1.1 brad err = (*(fb->func_clear))(fd, debug);
303 1.1 brad if (! err) {
304 1.1 brad switch (subcmd) {
305 1.1 brad case SCMD_ENABLE:
306 1.1 brad reg_v = SCMD_DRIVER_ENABLE;
307 1.1 brad break;
308 1.1 brad case SCMD_DISABLE:
309 1.1 brad reg_v = SCMD_DRIVER_DISABLE;
310 1.1 brad break;
311 1.1 brad default:
312 1.1 brad return EINVAL;
313 1.1 brad }
314 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_DRIVER_ENABLE, reg_v);
315 1.1 brad }
316 1.1 brad
317 1.1 brad return err;
318 1.1 brad }
319 1.1 brad
320 1.1 brad /* These control commands can take a very long time and the restart
321 1.1 brad * make cause the device to become unresponsive for a bit.
322 1.1 brad */
323 1.1 brad int
324 1.1 brad common_control_1(struct function_block *fb, int fd, bool debug, int subcmd)
325 1.1 brad {
326 1.1 brad int err;
327 1.1 brad uint8_t reg_v;
328 1.1 brad
329 1.1 brad if (!(subcmd == SCMD_RESTART || subcmd == SCMD_ENUMERATE))
330 1.1 brad return EINVAL;
331 1.1 brad
332 1.1 brad err = (*(fb->func_clear))(fd, debug);
333 1.1 brad if (! err) {
334 1.1 brad switch (subcmd) {
335 1.1 brad case SCMD_RESTART:
336 1.1 brad reg_v = SCMD_CONTROL_1_RESTART;
337 1.1 brad break;
338 1.1 brad case SCMD_ENUMERATE:
339 1.1 brad reg_v = SCMD_CONTROL_1_REENUMERATE;
340 1.1 brad break;
341 1.1 brad default:
342 1.1 brad return EINVAL;
343 1.1 brad }
344 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_CONTROL_1, reg_v);
345 1.1 brad }
346 1.1 brad
347 1.1 brad return err;
348 1.1 brad }
349 1.1 brad
350 1.1 brad int
351 1.1 brad common_get_update_rate(struct function_block *fb, int fd, bool debug, uint8_t *rate)
352 1.1 brad {
353 1.1 brad uint8_t b;
354 1.1 brad int err;
355 1.1 brad
356 1.1 brad err = (*(fb->func_clear))(fd, debug);
357 1.1 brad if (! err) {
358 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_UPDATE_RATE, SCMD_REG_UPDATE_RATE, &b);
359 1.1 brad if (!err)
360 1.1 brad *rate = b;
361 1.1 brad }
362 1.1 brad
363 1.1 brad return err;
364 1.1 brad }
365 1.1 brad
366 1.1 brad int
367 1.1 brad common_set_update_rate(struct function_block *fb, int fd, bool debug, uint8_t rate)
368 1.1 brad {
369 1.1 brad int err;
370 1.1 brad
371 1.1 brad err = (*(fb->func_clear))(fd, debug);
372 1.1 brad if (! err) {
373 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_UPDATE_RATE, rate);
374 1.1 brad }
375 1.1 brad
376 1.1 brad return err;
377 1.1 brad }
378 1.1 brad
379 1.1 brad int
380 1.1 brad common_force_update(struct function_block *fb, int fd, bool debug)
381 1.1 brad {
382 1.1 brad int err;
383 1.1 brad
384 1.1 brad err = (*(fb->func_clear))(fd, debug);
385 1.1 brad if (! err) {
386 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_FORCE_UPDATE, 0x01);
387 1.1 brad }
388 1.1 brad
389 1.1 brad return err;
390 1.1 brad }
391 1.1 brad
392 1.1 brad int
393 1.1 brad common_get_ebus_speed(struct function_block *fb, int fd, bool debug, uint8_t *speed)
394 1.1 brad {
395 1.1 brad uint8_t b;
396 1.1 brad int err;
397 1.1 brad
398 1.1 brad err = (*(fb->func_clear))(fd, debug);
399 1.1 brad if (! err) {
400 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_E_BUS_SPEED, SCMD_REG_E_BUS_SPEED, &b);
401 1.1 brad if (!err)
402 1.1 brad *speed = b;
403 1.1 brad }
404 1.1 brad
405 1.1 brad return err;
406 1.1 brad }
407 1.1 brad
408 1.1 brad int
409 1.1 brad common_set_ebus_speed(struct function_block *fb, int fd, bool debug, uint8_t speed)
410 1.1 brad {
411 1.1 brad int err;
412 1.1 brad
413 1.1 brad if (speed > 0x03)
414 1.1 brad return EINVAL;
415 1.1 brad
416 1.1 brad err = (*(fb->func_clear))(fd, debug);
417 1.1 brad if (! err) {
418 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_E_BUS_SPEED, speed);
419 1.1 brad }
420 1.1 brad
421 1.1 brad return err;
422 1.1 brad }
423 1.1 brad
424 1.1 brad int
425 1.1 brad common_get_lock_state(struct function_block *fb, int fd, bool debug, int ltype, uint8_t *lstate)
426 1.1 brad {
427 1.1 brad uint8_t b;
428 1.1 brad uint8_t reg;
429 1.1 brad int err;
430 1.1 brad
431 1.1 brad switch (ltype) {
432 1.1 brad case SCMD_LOCAL_USER_LOCK:
433 1.1 brad reg = SCMD_REG_LOCAL_USER_LOCK;
434 1.1 brad break;
435 1.1 brad case SCMD_LOCAL_MASTER_LOCK:
436 1.1 brad reg = SCMD_REG_LOCAL_MASTER_LOCK;
437 1.1 brad break;
438 1.1 brad case SCMD_GLOBAL_USER_LOCK:
439 1.1 brad reg = SCMD_REG_USER_LOCK;
440 1.1 brad break;
441 1.1 brad case SCMD_GLOBAL_MASTER_LOCK:
442 1.1 brad reg = SCMD_REG_MASTER_LOCK;
443 1.1 brad break;
444 1.1 brad default:
445 1.1 brad return EINVAL;
446 1.1 brad }
447 1.1 brad
448 1.1 brad err = (*(fb->func_clear))(fd, debug);
449 1.1 brad if (! err) {
450 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b);
451 1.1 brad if (!err)
452 1.1 brad *lstate = b;
453 1.1 brad }
454 1.1 brad
455 1.1 brad return err;
456 1.1 brad }
457 1.1 brad
458 1.1 brad int
459 1.1 brad common_set_lock_state(struct function_block *fb, int fd, bool debug, int ltype, uint8_t lstate)
460 1.1 brad {
461 1.1 brad uint8_t reg;
462 1.1 brad uint8_t state;
463 1.1 brad int err;
464 1.1 brad
465 1.1 brad switch (ltype) {
466 1.1 brad case SCMD_LOCAL_USER_LOCK:
467 1.1 brad reg = SCMD_REG_LOCAL_USER_LOCK;
468 1.1 brad break;
469 1.1 brad case SCMD_LOCAL_MASTER_LOCK:
470 1.1 brad reg = SCMD_REG_LOCAL_MASTER_LOCK;
471 1.1 brad break;
472 1.1 brad case SCMD_GLOBAL_USER_LOCK:
473 1.1 brad reg = SCMD_REG_USER_LOCK;
474 1.1 brad break;
475 1.1 brad case SCMD_GLOBAL_MASTER_LOCK:
476 1.1 brad reg = SCMD_REG_MASTER_LOCK;
477 1.1 brad break;
478 1.1 brad default:
479 1.1 brad return EINVAL;
480 1.1 brad }
481 1.1 brad
482 1.1 brad switch (lstate) {
483 1.1 brad case SCMD_LOCK_LOCKED:
484 1.1 brad state = SCMD_ANY_LOCK_LOCKED;
485 1.1 brad break;
486 1.1 brad case SCMD_LOCK_UNLOCK:
487 1.1 brad state = SCMD_MASTER_LOCK_UNLOCKED;
488 1.1 brad if (ltype == SCMD_LOCAL_USER_LOCK ||
489 1.1 brad ltype == SCMD_GLOBAL_USER_LOCK)
490 1.1 brad state = SCMD_USER_LOCK_UNLOCKED;
491 1.1 brad break;
492 1.1 brad default:
493 1.1 brad return EINVAL;
494 1.1 brad }
495 1.1 brad
496 1.1 brad err = (*(fb->func_clear))(fd, debug);
497 1.1 brad if (! err) {
498 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, state);
499 1.1 brad }
500 1.1 brad
501 1.1 brad return err;
502 1.1 brad }
503