umcpmio.c revision 1.1 1 1.1 brad /* $NetBSD: umcpmio.c,v 1.1 2024/12/16 16:37:38 brad Exp $ */
2 1.1 brad
3 1.1 brad /*
4 1.1 brad * Copyright (c) 2024 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 #include <sys/cdefs.h>
20 1.1 brad __KERNEL_RCSID(0, "$NetBSD: umcpmio.c,v 1.1 2024/12/16 16:37:38 brad Exp $");
21 1.1 brad
22 1.1 brad /*
23 1.1 brad Driver for the Microchip MCP2221 / MCP2221A USB multi-io chip
24 1.1 brad */
25 1.1 brad
26 1.1 brad #ifdef _KERNEL_OPT
27 1.1 brad #include "opt_usb.h"
28 1.1 brad #endif
29 1.1 brad
30 1.1 brad #include <sys/param.h>
31 1.1 brad #include <sys/systm.h>
32 1.1 brad #include <sys/conf.h>
33 1.1 brad #include <sys/kernel.h>
34 1.1 brad #include <sys/kmem.h>
35 1.1 brad #include <sys/device.h>
36 1.1 brad #include <sys/sysctl.h>
37 1.1 brad #include <sys/tty.h>
38 1.1 brad #include <sys/file.h>
39 1.1 brad #include <sys/vnode.h>
40 1.1 brad #include <sys/kauth.h>
41 1.1 brad #include <sys/lwp.h>
42 1.1 brad
43 1.1 brad #include <sys/gpio.h>
44 1.1 brad #include <dev/gpio/gpiovar.h>
45 1.1 brad
46 1.1 brad #include <dev/i2c/i2cvar.h>
47 1.1 brad
48 1.1 brad #include <dev/usb/usb.h>
49 1.1 brad #include <dev/usb/usbhid.h>
50 1.1 brad
51 1.1 brad #include <dev/usb/usbdi.h>
52 1.1 brad #include <dev/usb/usbdi_util.h>
53 1.1 brad #include <dev/usb/usbdevs.h>
54 1.1 brad #include <dev/usb/uhidev.h>
55 1.1 brad #include <dev/hid/hid.h>
56 1.1 brad
57 1.1 brad #include <dev/usb/umcpmio.h>
58 1.1 brad #include <dev/usb/umcpmio_subr.h>
59 1.1 brad #include <dev/usb/umcpmio_hid_reports.h>
60 1.1 brad #include <dev/usb/umcpmio_io.h>
61 1.1 brad
62 1.1 brad int umcpmio_send_report(struct umcpmio_softc *, uint8_t *, size_t, uint8_t *, int);
63 1.1 brad
64 1.1 brad static const struct usb_devno umcpmio_devs[] = {
65 1.1 brad { USB_VENDOR_MICROCHIP, USB_PRODUCT_MICROCHIP_MCP2221 },
66 1.1 brad };
67 1.1 brad #define umcpmio_lookup(v, p) usb_lookup(umcpmio_devs, v, p)
68 1.1 brad
69 1.1 brad static int umcpmio_match(device_t, cfdata_t, void *);
70 1.1 brad static void umcpmio_attach(device_t, device_t, void *);
71 1.1 brad static int umcpmio_detach(device_t, int);
72 1.1 brad static int umcpmio_activate(device_t, enum devact);
73 1.1 brad static int umcpmio_verify_sysctl(SYSCTLFN_ARGS);
74 1.1 brad static int umcpmio_verify_dac_sysctl(SYSCTLFN_ARGS);
75 1.1 brad static int umcpmio_verify_adc_sysctl(SYSCTLFN_ARGS);
76 1.1 brad static int umcpmio_verify_gpioclock_dc_sysctl(SYSCTLFN_ARGS);
77 1.1 brad static int umcpmio_verify_gpioclock_cd_sysctl(SYSCTLFN_ARGS);
78 1.1 brad
79 1.1 brad #define UMCPMIO_DEBUG 1
80 1.1 brad #ifdef UMCPMIO_DEBUG
81 1.1 brad #define DPRINTF(x) if (umcpmiodebug) printf x
82 1.1 brad #define DPRINTFN(n, x) if (umcpmiodebug > (n)) printf x
83 1.1 brad int umcpmiodebug = 0;
84 1.1 brad #else
85 1.1 brad #define DPRINTF(x) __nothing
86 1.1 brad #define DPRINTFN(n,x) __nothing
87 1.1 brad #endif
88 1.1 brad
89 1.1 brad
90 1.1 brad CFATTACH_DECL_NEW(umcpmio, sizeof(struct umcpmio_softc), umcpmio_match,
91 1.1 brad umcpmio_attach, umcpmio_detach, umcpmio_activate);
92 1.1 brad
93 1.1 brad
94 1.1 brad #define WAITMS(ms) if (ms > 0) delay(ms * 1000)
95 1.1 brad
96 1.1 brad extern struct cfdriver umcpmio_cd;
97 1.1 brad
98 1.1 brad static dev_type_open(umcpmio_dev_open);
99 1.1 brad static dev_type_read(umcpmio_dev_read);
100 1.1 brad static dev_type_write(umcpmio_dev_write);
101 1.1 brad static dev_type_close(umcpmio_dev_close);
102 1.1 brad static dev_type_ioctl(umcpmio_dev_ioctl);
103 1.1 brad const struct cdevsw umcpmio_cdevsw = {
104 1.1 brad .d_open = umcpmio_dev_open,
105 1.1 brad .d_close = umcpmio_dev_close,
106 1.1 brad .d_read = umcpmio_dev_read,
107 1.1 brad .d_write = umcpmio_dev_write,
108 1.1 brad .d_ioctl = umcpmio_dev_ioctl,
109 1.1 brad .d_stop = nostop,
110 1.1 brad .d_tty = notty,
111 1.1 brad .d_poll = nopoll,
112 1.1 brad .d_mmap = nommap,
113 1.1 brad .d_kqfilter = nokqfilter,
114 1.1 brad .d_discard = nodiscard,
115 1.1 brad .d_flag = D_OTHER
116 1.1 brad };
117 1.1 brad
118 1.1 brad
119 1.1 brad static const char umcpmio_valid_vrefs[] =
120 1.1 brad "4.096V, 2.048V, 1.024V, OFF, VDD";
121 1.1 brad
122 1.1 brad static const char umcpmio_valid_dcs[] =
123 1.1 brad "75%, 50%, 25%, 0%";
124 1.1 brad
125 1.1 brad static const char umcpmio_valid_cds[] =
126 1.1 brad "375kHz, 750kHz, 1.5MHz, 3MHz, 6MHz, 12MHz, 24MHz";
127 1.1 brad
128 1.1 brad static void
129 1.1 brad umcpmio_dump_buffer(bool enabled, uint8_t *buf, u_int len, const char *name)
130 1.1 brad {
131 1.1 brad if (enabled) {
132 1.1 brad DPRINTF(("%s:",name));
133 1.1 brad for(int i=0; i < len; i++) {
134 1.1 brad DPRINTF((" %02x",buf[i]));
135 1.1 brad }
136 1.1 brad DPRINTF(("\n"));
137 1.1 brad }
138 1.1 brad }
139 1.1 brad
140 1.1 brad /* Communication with the HID function requires sending a HID report request and
141 1.1 brad * then waiting for a response.
142 1.1 brad *
143 1.1 brad * The panic that occurs when trying to use the interrupt... i.e.
144 1.1 brad * attaching though this driver seems to be related to the fact that
145 1.1 brad * a spin lock is held and the USB stack wants to wait.
146 1.1 brad *
147 1.1 brad * The USB stack *IS* going to have to wait for the response from
148 1.1 brad * the device, somehow...
149 1.1 brad *
150 1.1 brad * It didn't seem possible to defer the uhidev_write to a thread.
151 1.1 brad * Attempts to yield() while spinning hard also did not work and
152 1.1 brad * not yield()ing didn't allow anything else to run.
153 1.1 brad *
154 1.1 brad */
155 1.1 brad
156 1.1 brad /*
157 1.1 brad * This is the panic you will get:
158 1.1 brad *
159 1.1 brad panic: kernel diagnostic assertion "ci->ci_mtx_count == -1" failed: file "../../../../kern/kern_synch.c", line 762 mi_switch: cpu0: ci_mtx_count (-2) != -1 (block with spin-mutex held)
160 1.1 brad
161 1.1 brad */
162 1.1 brad
163 1.1 brad static void
164 1.1 brad umcpmio_uhidev_intr(void *cookie, void *ibuf, u_int len)
165 1.1 brad {
166 1.1 brad struct umcpmio_softc *sc = cookie;
167 1.1 brad
168 1.1 brad if (sc->sc_dying)
169 1.1 brad return;
170 1.1 brad
171 1.1 brad DPRINTFN(30,("umcpmio_uhidev_intr: len=%d\n",len));
172 1.1 brad
173 1.1 brad mutex_enter(&sc->sc_res_mutex);
174 1.1 brad switch(len) {
175 1.1 brad case MCP2221_RES_BUFFER_SIZE:
176 1.1 brad if (sc->sc_res_buffer != NULL) {
177 1.1 brad memcpy(sc->sc_res_buffer, ibuf, MCP2221_RES_BUFFER_SIZE);
178 1.1 brad sc->sc_res_ready = true;
179 1.1 brad cv_signal(&sc->sc_res_cv);
180 1.1 brad } else {
181 1.1 brad int d=umcpmiodebug;
182 1.1 brad device_printf(sc->sc_dev,"umcpmio_uhidev_intr: NULL sc_res_buffer: len=%d\n",len);
183 1.1 brad umcpmiodebug=20;
184 1.1 brad umcpmio_dump_buffer(true, (uint8_t *)ibuf, len, "umcpmio_uhidev_intr: ibuf");
185 1.1 brad umcpmiodebug=d;
186 1.1 brad }
187 1.1 brad
188 1.1 brad break;
189 1.1 brad default:
190 1.1 brad device_printf(sc->sc_dev,"umcpmio_uhidev_intr: Unknown interrupt length: %d",len);
191 1.1 brad break;
192 1.1 brad }
193 1.1 brad mutex_exit(&sc->sc_res_mutex);
194 1.1 brad }
195 1.1 brad
196 1.1 brad /* Send a HID report. This needs to be called with the action mutex held */
197 1.1 brad
198 1.1 brad int
199 1.1 brad umcpmio_send_report(struct umcpmio_softc *sc, uint8_t *sendbuf,
200 1.1 brad size_t sendlen, uint8_t *resbuf, int timeout)
201 1.1 brad {
202 1.1 brad int err = 0;
203 1.1 brad int err_count=0;
204 1.1 brad
205 1.1 brad if (sc->sc_dying)
206 1.1 brad return EIO;
207 1.1 brad
208 1.1 brad KASSERT(mutex_owned(&sc->sc_action_mutex));
209 1.1 brad
210 1.1 brad if (sc->sc_res_buffer != NULL) {
211 1.1 brad device_printf(sc->sc_dev,"umcpmio_send_report: sc->sc_res_buffer is not NULL\n");
212 1.1 brad }
213 1.1 brad sc->sc_res_buffer = resbuf;
214 1.1 brad sc->sc_res_ready = false;
215 1.1 brad
216 1.1 brad err = uhidev_write(sc->sc_hdev, sendbuf, sendlen);
217 1.1 brad
218 1.1 brad if (err) {
219 1.1 brad DPRINTF(("umcpmio_send_report: uhidev_write errored with: err=%d\n", err));
220 1.1 brad goto out;
221 1.1 brad }
222 1.1 brad
223 1.1 brad DPRINTFN(30,("umcpmio_send_report: about to wait on cv. err=%d\n", err));
224 1.1 brad
225 1.1 brad mutex_enter(&sc->sc_res_mutex);
226 1.1 brad while (!sc->sc_res_ready) {
227 1.1 brad DPRINTFN(20,("umcpmio_send_report: LOOP for response. sc_res_ready=%d, err_count=%d, timeout=%d\n",sc->sc_res_ready, err_count, mstohz(timeout)));
228 1.1 brad
229 1.1 brad err = cv_timedwait_sig(&sc->sc_res_cv, &sc->sc_res_mutex, mstohz(timeout));
230 1.1 brad
231 1.1 brad /* We are only going to allow this to loop on an error,
232 1.1 brad * any error at all, so many times.
233 1.1 brad */
234 1.1 brad if (err) {
235 1.1 brad DPRINTF(("umcpmio_send_report: cv_timedwait_sig reported an error: err=%d, sc->sc_res_ready=%d\n",err,sc->sc_res_ready));
236 1.1 brad err_count++;
237 1.1 brad }
238 1.1 brad
239 1.1 brad /* The CV was interrupted, but the buffer is ready so, clear the error
240 1.1 brad * and break out.
241 1.1 brad */
242 1.1 brad if ((err == ERESTART) && (sc->sc_res_ready)) {
243 1.1 brad DPRINTF(("umcpmio_send_report: ERESTART and buffer is ready\n"));
244 1.1 brad err = 0;
245 1.1 brad break;
246 1.1 brad }
247 1.1 brad
248 1.1 brad /* Too many times though the loop, just break out. Turn
249 1.1 brad * a ERESTART (interruption) into a I/O error at this point.
250 1.1 brad */
251 1.1 brad if (err_count > sc->sc_response_errcnt) {
252 1.1 brad DPRINTF(("umcpmio_send_report: err_count exceeded: err=%d\n",err));
253 1.1 brad if (err == ERESTART)
254 1.1 brad err = EIO;
255 1.1 brad break;
256 1.1 brad }
257 1.1 brad
258 1.1 brad /* This is a normal timeout, without interruption, try again */
259 1.1 brad if (err == EWOULDBLOCK) {
260 1.1 brad DPRINTF(("umcpmio_send_report: EWOULDBLOCK: err_count=%d\n",err_count));
261 1.1 brad continue;
262 1.1 brad }
263 1.1 brad
264 1.1 brad /* The CV was interrupted and the buffer wasn't filled in, so try again */
265 1.1 brad if ((err == ERESTART) && (!sc->sc_res_ready)) {
266 1.1 brad DPRINTF(("umcpmio_send_report: ERESTART and buffer is NOT ready. err_count=%d\n",err_count));
267 1.1 brad continue;
268 1.1 brad }
269 1.1 brad }
270 1.1 brad
271 1.1 brad sc->sc_res_buffer = NULL;
272 1.1 brad sc->sc_res_ready = false;
273 1.1 brad mutex_exit(&sc->sc_res_mutex);
274 1.1 brad
275 1.1 brad /* Turn most errors into an I/O error */
276 1.1 brad if (err &&
277 1.1 brad err != ERESTART)
278 1.1 brad err = EIO;
279 1.1 brad
280 1.1 brad out:
281 1.1 brad return err;
282 1.1 brad }
283 1.1 brad
284 1.1 brad /* These are standard gpio reads and set calls */
285 1.1 brad
286 1.1 brad static int
287 1.1 brad umcpmio_gpio_pin_read(void *arg, int pin)
288 1.1 brad {
289 1.1 brad struct umcpmio_softc *sc = arg;
290 1.1 brad int r = GPIO_PIN_LOW;
291 1.1 brad
292 1.1 brad r = umcpmio_get_gpio_value(sc, pin, true);
293 1.1 brad
294 1.1 brad return(r);
295 1.1 brad }
296 1.1 brad
297 1.1 brad static void
298 1.1 brad umcpmio_gpio_pin_write(void *arg, int pin, int value)
299 1.1 brad {
300 1.1 brad struct umcpmio_softc *sc = arg;
301 1.1 brad
302 1.1 brad umcpmio_set_gpio_value_one(sc, pin, value, true);
303 1.1 brad }
304 1.1 brad
305 1.1 brad /* Internal function that does the dirty work of setting a gpio
306 1.1 brad * pin to its "type".
307 1.1 brad *
308 1.1 brad * There are really two ways to do some of this, one is to set the pin to input
309 1.1 brad * and output, or whatever, using SRAM calls, the other is to use the GPIO
310 1.1 brad * config calls to set input and output and SRAM for everything else. This just
311 1.1 brad * uses SRAM for everything.
312 1.1 brad */
313 1.1 brad
314 1.1 brad static int
315 1.1 brad umcpmio_gpio_pin_ctlctl(void *arg, int pin, int flags, bool takemutex)
316 1.1 brad {
317 1.1 brad struct umcpmio_softc *sc = arg;
318 1.1 brad struct mcp2221_set_sram_req set_sram_req;
319 1.1 brad struct mcp2221_set_sram_res set_sram_res;
320 1.1 brad struct mcp2221_get_sram_res current_sram_res;
321 1.1 brad struct mcp2221_get_gpio_cfg_res current_gpio_cfg_res;
322 1.1 brad int err = 0;
323 1.1 brad
324 1.1 brad if (sc->sc_dying)
325 1.1 brad return 0;
326 1.1 brad
327 1.1 brad if (takemutex)
328 1.1 brad mutex_enter(&sc->sc_action_mutex);
329 1.1 brad
330 1.1 brad err = umcpmio_get_sram(sc, ¤t_sram_res, false);
331 1.1 brad if (err)
332 1.1 brad goto out;
333 1.1 brad
334 1.1 brad err = umcpmio_get_gpio_cfg(sc, ¤t_gpio_cfg_res, false);
335 1.1 brad if (err)
336 1.1 brad goto out;
337 1.1 brad
338 1.1 brad /* You can't just set one pin, you must set all of them, so copy the
339 1.1 brad * current settings for the pin we are not messing with.
340 1.1 brad *
341 1.1 brad * And, yes, of course, if the MCP-2210 is ever supported with this
342 1.1 brad * driver, this sort of unrolling will need to be turned into
343 1.1 brad * something different, but for now, just unroll as there are only
344 1.1 brad * 4 pins to care about.
345 1.1 brad *
346 1.1 brad */
347 1.1 brad
348 1.1 brad memset(&set_sram_req, 0, MCP2221_REQ_BUFFER_SIZE);
349 1.1 brad switch (pin) {
350 1.1 brad case 0:
351 1.1 brad set_sram_req.gp1_settings = current_sram_res.gp1_settings;
352 1.1 brad set_sram_req.gp2_settings = current_sram_res.gp2_settings;
353 1.1 brad set_sram_req.gp3_settings = current_sram_res.gp3_settings;
354 1.1 brad break;
355 1.1 brad case 1:
356 1.1 brad set_sram_req.gp0_settings = current_sram_res.gp0_settings;
357 1.1 brad set_sram_req.gp2_settings = current_sram_res.gp2_settings;
358 1.1 brad set_sram_req.gp3_settings = current_sram_res.gp3_settings;
359 1.1 brad break;
360 1.1 brad case 2:
361 1.1 brad set_sram_req.gp0_settings = current_sram_res.gp0_settings;
362 1.1 brad set_sram_req.gp1_settings = current_sram_res.gp1_settings;
363 1.1 brad set_sram_req.gp3_settings = current_sram_res.gp3_settings;
364 1.1 brad break;
365 1.1 brad case 3:
366 1.1 brad set_sram_req.gp0_settings = current_sram_res.gp0_settings;
367 1.1 brad set_sram_req.gp1_settings = current_sram_res.gp1_settings;
368 1.1 brad set_sram_req.gp2_settings = current_sram_res.gp2_settings;
369 1.1 brad break;
370 1.1 brad }
371 1.1 brad umcpmio_set_gpio_designation_sram(&set_sram_req, pin, flags);
372 1.1 brad umcpmio_set_gpio_dir_sram(&set_sram_req, pin, flags);
373 1.1 brad
374 1.1 brad /*
375 1.1 brad * This part is unfortunate... if a pin is set to output, the value set
376 1.1 brad * on the pin is not mirrored by the chip into SRAM, but the chip will
377 1.1 brad * use the value from SRAM to set the value of the pin. What this means is
378 1.1 brad * that we have to learn the value from the GPIO config and make sure it is
379 1.1 brad * set properly when updating SRAM.
380 1.1 brad */
381 1.1 brad
382 1.1 brad if (current_gpio_cfg_res.gp0_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) {
383 1.1 brad if (current_gpio_cfg_res.gp0_pin_value == 1)
384 1.1 brad set_sram_req.gp0_settings |= MCP2221_SRAM_GPIO_OUTPUT_HIGH;
385 1.1 brad else
386 1.1 brad set_sram_req.gp0_settings &= ~MCP2221_SRAM_GPIO_OUTPUT_HIGH;
387 1.1 brad }
388 1.1 brad if (current_gpio_cfg_res.gp1_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) {
389 1.1 brad if (current_gpio_cfg_res.gp1_pin_value == 1)
390 1.1 brad set_sram_req.gp1_settings |= MCP2221_SRAM_GPIO_OUTPUT_HIGH;
391 1.1 brad else
392 1.1 brad set_sram_req.gp1_settings &= ~MCP2221_SRAM_GPIO_OUTPUT_HIGH;
393 1.1 brad }
394 1.1 brad if (current_gpio_cfg_res.gp2_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) {
395 1.1 brad if (current_gpio_cfg_res.gp2_pin_value == 1)
396 1.1 brad set_sram_req.gp2_settings |= MCP2221_SRAM_GPIO_OUTPUT_HIGH;
397 1.1 brad else
398 1.1 brad set_sram_req.gp2_settings &= ~MCP2221_SRAM_GPIO_OUTPUT_HIGH;
399 1.1 brad }
400 1.1 brad if (current_gpio_cfg_res.gp3_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) {
401 1.1 brad if (current_gpio_cfg_res.gp3_pin_value == 1)
402 1.1 brad set_sram_req.gp3_settings |= MCP2221_SRAM_GPIO_OUTPUT_HIGH;
403 1.1 brad else
404 1.1 brad set_sram_req.gp3_settings &= ~MCP2221_SRAM_GPIO_OUTPUT_HIGH;
405 1.1 brad }
406 1.1 brad
407 1.1 brad err = umcpmio_put_sram(sc, &set_sram_req, &set_sram_res, false);
408 1.1 brad if (! err) {
409 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&set_sram_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_gpio_pin_ctlctl set sram buffer copy");
410 1.1 brad if (set_sram_res.cmd == MCP2221_CMD_SET_SRAM &&
411 1.1 brad set_sram_res.completion == MCP2221_CMD_COMPLETE_OK) {
412 1.1 brad sc->sc_gpio_pins[pin].pin_flags = flags;
413 1.1 brad } else {
414 1.1 brad device_printf(sc->sc_dev, "umcpmio_gpio_pin_ctlctl: not the command desired, or error: %02x %02x\n",
415 1.1 brad set_sram_res.cmd,
416 1.1 brad set_sram_res.completion);
417 1.1 brad err = EIO;
418 1.1 brad }
419 1.1 brad }
420 1.1 brad
421 1.1 brad out:
422 1.1 brad if (takemutex)
423 1.1 brad mutex_exit(&sc->sc_action_mutex);
424 1.1 brad
425 1.1 brad return err;
426 1.1 brad }
427 1.1 brad
428 1.1 brad static void
429 1.1 brad umcpmio_gpio_pin_ctl(void *arg, int pin, int flags)
430 1.1 brad {
431 1.1 brad struct umcpmio_softc *sc = arg;
432 1.1 brad
433 1.1 brad if (sc->sc_dying)
434 1.1 brad return;
435 1.1 brad
436 1.1 brad umcpmio_gpio_pin_ctlctl(sc, pin, flags, true);
437 1.1 brad }
438 1.1 brad
439 1.1 brad /*
440 1.1 brad XXX -
441 1.1 brad
442 1.1 brad Since testing of gpio interrupts wasn't possible, this part probably is not
443 1.1 brad complete. At the very least, there is a scheduled callout that needs to exist
444 1.1 brad to read the interrupt status. The chip does not send anything on its own when
445 1.1 brad the interrupt happens.
446 1.1 brad */
447 1.1 brad
448 1.1 brad
449 1.1 brad static void *
450 1.1 brad umcpmio_gpio_intr_establish(void *vsc, int pin, int ipl, int irqmode,
451 1.1 brad int (*func)(void *), void *arg)
452 1.1 brad {
453 1.1 brad struct umcpmio_softc *sc = vsc;
454 1.1 brad struct umcpmio_irq *irq = &sc->sc_gpio_irqs[0];
455 1.1 brad struct mcp2221_set_sram_req set_sram_req;
456 1.1 brad struct mcp2221_set_sram_res set_sram_res;
457 1.1 brad struct mcp2221_get_sram_res current_sram_res;
458 1.1 brad int err = 0;
459 1.1 brad
460 1.1 brad if (sc->sc_dying)
461 1.1 brad return(NULL);
462 1.1 brad
463 1.1 brad irq->sc_gpio_irqfunc = func;
464 1.1 brad irq->sc_gpio_irqarg = arg;
465 1.1 brad
466 1.1 brad DPRINTF(("umcpmio_intr_establish: pin=%d, irqmode=%04x\n",pin,irqmode));
467 1.1 brad
468 1.1 brad mutex_enter(&sc->sc_action_mutex);
469 1.1 brad
470 1.1 brad err = umcpmio_get_sram(sc, ¤t_sram_res, false);
471 1.1 brad if (err)
472 1.1 brad goto out;
473 1.1 brad
474 1.1 brad memset(&set_sram_req, 0, MCP2221_REQ_BUFFER_SIZE);
475 1.1 brad set_sram_req.gp0_settings = current_sram_res.gp0_settings;
476 1.1 brad set_sram_req.gp2_settings = current_sram_res.gp2_settings;
477 1.1 brad set_sram_req.gp3_settings = current_sram_res.gp3_settings;
478 1.1 brad umcpmio_set_gpio_irq_sram(&set_sram_req, irqmode);
479 1.1 brad err = umcpmio_put_sram(sc, &set_sram_req, &set_sram_res, false);
480 1.1 brad if (! err) {
481 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&set_sram_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_intr_establish set sram buffer copy");
482 1.1 brad if (set_sram_res.cmd == MCP2221_CMD_SET_SRAM &&
483 1.1 brad set_sram_res.completion == MCP2221_CMD_COMPLETE_OK) {
484 1.1 brad sc->sc_gpio_pins[1].pin_flags = GPIO_PIN_ALT2;
485 1.1 brad } else {
486 1.1 brad device_printf(sc->sc_dev, "umcpmio_intr_establish: not the command desired, or error: %02x %02x\n",
487 1.1 brad set_sram_res.cmd,
488 1.1 brad set_sram_res.completion);
489 1.1 brad }
490 1.1 brad } else {
491 1.1 brad device_printf(sc->sc_dev, "umcpmio_intr_establish: set sram error: err=%d\n",
492 1.1 brad err);
493 1.1 brad }
494 1.1 brad
495 1.1 brad out:
496 1.1 brad mutex_exit(&sc->sc_action_mutex);
497 1.1 brad
498 1.1 brad return(irq);
499 1.1 brad }
500 1.1 brad
501 1.1 brad static void
502 1.1 brad umcpmio_gpio_intr_disestablish(void *vsc, void *ih)
503 1.1 brad {
504 1.1 brad struct umcpmio_softc *sc = vsc;
505 1.1 brad struct mcp2221_set_sram_req set_sram_req;
506 1.1 brad struct mcp2221_set_sram_res set_sram_res;
507 1.1 brad struct mcp2221_get_sram_res current_sram_res;
508 1.1 brad int err = 0;
509 1.1 brad
510 1.1 brad if (sc->sc_dying)
511 1.1 brad return;
512 1.1 brad
513 1.1 brad DPRINTF(("umcpmio_intr_disestablish:\n"));
514 1.1 brad
515 1.1 brad mutex_enter(&sc->sc_action_mutex);
516 1.1 brad
517 1.1 brad err = umcpmio_get_sram(sc, ¤t_sram_res, false);
518 1.1 brad if (err)
519 1.1 brad goto out;
520 1.1 brad
521 1.1 brad memset(&set_sram_req, 0, MCP2221_REQ_BUFFER_SIZE);
522 1.1 brad set_sram_req.gp0_settings = current_sram_res.gp0_settings;
523 1.1 brad set_sram_req.gp2_settings = current_sram_res.gp2_settings;
524 1.1 brad set_sram_req.gp3_settings = current_sram_res.gp3_settings;
525 1.1 brad umcpmio_set_gpio_irq_sram(&set_sram_req, 0);
526 1.1 brad err = umcpmio_put_sram(sc, &set_sram_req, &set_sram_res, true);
527 1.1 brad if (! err) {
528 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&set_sram_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_intr_disestablish set sram buffer copy");
529 1.1 brad if (set_sram_res.cmd == MCP2221_CMD_SET_SRAM &&
530 1.1 brad set_sram_res.completion == MCP2221_CMD_COMPLETE_OK) {
531 1.1 brad sc->sc_gpio_pins[1].pin_flags = GPIO_PIN_INPUT;
532 1.1 brad } else {
533 1.1 brad device_printf(sc->sc_dev, "umcpmio_intr_disestablish: not the command desired, or error: %02x %02x\n",
534 1.1 brad set_sram_res.cmd,
535 1.1 brad set_sram_res.completion);
536 1.1 brad }
537 1.1 brad } else {
538 1.1 brad device_printf(sc->sc_dev, "umcpmio_intr_disestablish: set sram error: err=%d\n",
539 1.1 brad err);
540 1.1 brad }
541 1.1 brad out:
542 1.1 brad mutex_exit(&sc->sc_action_mutex);
543 1.1 brad }
544 1.1 brad
545 1.1 brad static bool
546 1.1 brad umcpmio_gpio_intrstr(void *vsc, int pin, int irqmode, char *buf, size_t buflen)
547 1.1 brad {
548 1.1 brad
549 1.1 brad if (pin < 0 || pin >= MCP2221_NPINS) {
550 1.1 brad DPRINTF(("umcpmio_gpio_intrstr: pin %d less than zero or too big\n",pin));
551 1.1 brad return (false);
552 1.1 brad }
553 1.1 brad
554 1.1 brad if (pin != 1) {
555 1.1 brad DPRINTF(("umcpmio_gpio_intrstr: pin %d was not 1\n",pin));
556 1.1 brad return (false);
557 1.1 brad }
558 1.1 brad
559 1.1 brad snprintf(buf, buflen, "GPIO %d", pin);
560 1.1 brad
561 1.1 brad return (true);
562 1.1 brad }
563 1.1 brad
564 1.1 brad /* Clear status of the I2C engine */
565 1.1 brad
566 1.1 brad static int
567 1.1 brad umcpmio_i2c_clear(struct umcpmio_softc *sc, bool takemutex)
568 1.1 brad {
569 1.1 brad int err = 0;
570 1.1 brad struct mcp2221_status_req status_req;
571 1.1 brad struct mcp2221_status_res status_res;
572 1.1 brad
573 1.1 brad memset(&status_req, 0, MCP2221_REQ_BUFFER_SIZE);
574 1.1 brad status_req.cmd = MCP2221_CMD_STATUS;
575 1.1 brad status_req.cancel_transfer = MCP2221_I2C_DO_CANCEL;
576 1.1 brad
577 1.1 brad if (takemutex)
578 1.1 brad mutex_enter(&sc->sc_action_mutex);
579 1.1 brad err = umcpmio_send_report(sc, (uint8_t *)&status_req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)&status_res, sc->sc_cv_wait);
580 1.1 brad if (takemutex)
581 1.1 brad mutex_exit(&sc->sc_action_mutex);
582 1.1 brad
583 1.1 brad if (! err) {
584 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&status_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_clear buffer copy");
585 1.1 brad if (status_res.cmd == MCP2221_CMD_STATUS &&
586 1.1 brad status_res.completion == MCP2221_CMD_COMPLETE_OK) {
587 1.1 brad umcpmio_dump_buffer(true, (uint8_t *)&status_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_clear res buffer");
588 1.1 brad } else {
589 1.1 brad device_printf(sc->sc_dev, "umcpmio_i2c_clear: cmd exec: not the command desired, or error: %02x %02x\n",
590 1.1 brad status_res.cmd,
591 1.1 brad status_res.completion);
592 1.1 brad err = EIO;
593 1.1 brad }
594 1.1 brad } else {
595 1.1 brad device_printf(sc->sc_dev, "umcpmio_i2c_clear: request error: err=%d\n", err);
596 1.1 brad err = EIO;
597 1.1 brad }
598 1.1 brad
599 1.1 brad return(err);
600 1.1 brad }
601 1.1 brad
602 1.1 brad /* There isn't much required to acquire or release the I2C bus, but the man
603 1.1 brad * pages says these are needed
604 1.1 brad */
605 1.1 brad
606 1.1 brad static int
607 1.1 brad umcpmio_acquire_bus(void *v, int flags)
608 1.1 brad {
609 1.1 brad return(0);
610 1.1 brad }
611 1.1 brad
612 1.1 brad static void
613 1.1 brad umcpmio_release_bus(void *v, int flags)
614 1.1 brad {
615 1.1 brad return;
616 1.1 brad }
617 1.1 brad
618 1.1 brad /* The I2C write and I2C read functions mostly use an algorithm that Adafruit
619 1.1 brad * came up with in their Python based driver. A lot of other people have used
620 1.1 brad * this same algorithm to good effect. If changes are made to the I2C read and
621 1.1 brad * write functions, it is HIGHLY advisable that a MCP2221 or MCP2221A be on
622 1.1 brad * hand to test them.
623 1.1 brad */
624 1.1 brad
625 1.1 brad
626 1.1 brad /* This is what is considered a fatal return from the engine. */
627 1.1 brad
628 1.1 brad static bool
629 1.1 brad umcpmio_i2c_fatal(uint8_t state)
630 1.1 brad {
631 1.1 brad int r = false;
632 1.1 brad
633 1.1 brad if (state == MCP2221_ENGINE_ADDRNACK ||
634 1.1 brad state == MCP2221_ENGINE_STARTTIMEOUT ||
635 1.1 brad state == MCP2221_ENGINE_REPSTARTTIMEOUT ||
636 1.1 brad state == MCP2221_ENGINE_STOPTIMEOUT ||
637 1.1 brad state == MCP2221_ENGINE_READTIMEOUT ||
638 1.1 brad state == MCP2221_ENGINE_WRITETIMEOUT ||
639 1.1 brad state == MCP2221_ENGINE_ADDRTIMEOUT)
640 1.1 brad r = true;
641 1.1 brad return(r);
642 1.1 brad }
643 1.1 brad
644 1.1 brad static int
645 1.1 brad umcpmio_i2c_write(struct umcpmio_softc *sc, i2c_op_t op, i2c_addr_t addr,
646 1.1 brad const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags)
647 1.1 brad {
648 1.1 brad struct mcp2221_i2c_req i2c_req;
649 1.1 brad struct mcp2221_i2c_res i2c_res;
650 1.1 brad struct mcp2221_status_res status_res;
651 1.1 brad int remaining;
652 1.1 brad int err = 0;
653 1.1 brad uint8_t cmd;
654 1.1 brad size_t totallen = 0;
655 1.1 brad int wretry = sc->sc_retry_busy_write;
656 1.1 brad int wsretry = sc->sc_retry_busy_write;
657 1.1 brad
658 1.1 brad err = umcpmio_get_status(sc, &status_res, true);
659 1.1 brad if (err)
660 1.1 brad goto out;
661 1.1 brad if (status_res.internal_i2c_state != 0) {
662 1.1 brad DPRINTF(("umcpmio_i2c_write: internal state not zero, clearing. internal_i2c_state=%02x\n",status_res.internal_i2c_state));
663 1.1 brad err = umcpmio_i2c_clear(sc, true);
664 1.1 brad }
665 1.1 brad if (err)
666 1.1 brad goto out;
667 1.1 brad
668 1.1 brad if (cmdbuf != NULL)
669 1.1 brad totallen += cmdlen;
670 1.1 brad if (databuf != NULL)
671 1.1 brad totallen += datalen;
672 1.1 brad
673 1.1 brad again:
674 1.1 brad memset(&i2c_req, 0, MCP2221_REQ_BUFFER_SIZE);
675 1.1 brad cmd = MCP2221_I2C_WRITE_DATA_NS;
676 1.1 brad if (I2C_OP_STOP_P(op))
677 1.1 brad cmd = MCP2221_I2C_WRITE_DATA;
678 1.1 brad i2c_req.cmd = cmd;
679 1.1 brad i2c_req.lsblen = totallen;
680 1.1 brad i2c_req.msblen = 0;
681 1.1 brad i2c_req.slaveaddr = addr << 1;
682 1.1 brad
683 1.1 brad remaining = 0;
684 1.1 brad if (cmdbuf != NULL) {
685 1.1 brad memcpy(&i2c_req.data[0], cmdbuf, cmdlen);
686 1.1 brad remaining = cmdlen;
687 1.1 brad }
688 1.1 brad if (databuf != NULL)
689 1.1 brad memcpy(&i2c_req.data[remaining], databuf, datalen);
690 1.1 brad
691 1.1 brad DPRINTF(("umcpmio_i2c_write: I2C WRITE: cmd: %02x\n",cmd));
692 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&i2c_req, MCP2221_REQ_BUFFER_SIZE, "umcpmio_i2c_write: write req buffer copy");
693 1.1 brad
694 1.1 brad mutex_enter(&sc->sc_action_mutex);
695 1.1 brad err = umcpmio_send_report(sc, (uint8_t *)&i2c_req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)&i2c_res, sc->sc_cv_wait);
696 1.1 brad mutex_exit(&sc->sc_action_mutex);
697 1.1 brad if (! err) {
698 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&i2c_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_write: write res buffer copy");
699 1.1 brad if (i2c_res.cmd == cmd &&
700 1.1 brad i2c_res.completion == MCP2221_CMD_COMPLETE_OK) {
701 1.1 brad /* Adafruit does a read back of the status at this
702 1.1 brad * point. We choose not to do that. That is done later
703 1.1 brad * anyway, and it seemed to be redundent.
704 1.1 brad */
705 1.1 brad } else {
706 1.1 brad if (i2c_res.cmd == cmd &&
707 1.1 brad i2c_res.completion == MCP2221_I2C_ENGINE_BUSY) {
708 1.1 brad DPRINTF(("umcpmio_i2c_write: I2C engine busy\n"));
709 1.1 brad
710 1.1 brad if (umcpmio_i2c_fatal(i2c_res.internal_i2c_state)) {
711 1.1 brad err = EIO;
712 1.1 brad } else {
713 1.1 brad wretry--;
714 1.1 brad if (wretry > 0) {
715 1.1 brad WAITMS(sc->sc_busy_delay);
716 1.1 brad goto again;
717 1.1 brad } else {
718 1.1 brad err = EBUSY;
719 1.1 brad }
720 1.1 brad }
721 1.1 brad } else {
722 1.1 brad device_printf(sc->sc_dev, "umcpmio_i2c_write: not the command desired, or error: %02x %02x\n",
723 1.1 brad i2c_res.cmd,
724 1.1 brad i2c_res.completion);
725 1.1 brad err = EIO;
726 1.1 brad }
727 1.1 brad }
728 1.1 brad } else {
729 1.1 brad device_printf(sc->sc_dev, "umcpmio_i2c_write request error: err=%d\n", err);
730 1.1 brad err = EIO;
731 1.1 brad }
732 1.1 brad
733 1.1 brad if (! err) {
734 1.1 brad while (wsretry > 0) {
735 1.1 brad wsretry--;
736 1.1 brad
737 1.1 brad DPRINTF(("umcpmio_i2c_write: checking status loop: wcretry=%d\n",wsretry));
738 1.1 brad
739 1.1 brad err = umcpmio_get_status(sc, &status_res, true);
740 1.1 brad if (! err) {
741 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&status_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_write post check status");
742 1.1 brad /* Since there isn't any documentation on what
743 1.1 brad * some of the internal state means, it isn't
744 1.1 brad * clear that this is any different than than
745 1.1 brad * MCP2221_ENGINE_ADDRNACK in the other state
746 1.1 brad * register.
747 1.1 brad */
748 1.1 brad
749 1.1 brad if (status_res.internal_i2c_state20 & MCP2221_ENGINE_T1_MASK_NACK) {
750 1.1 brad DPRINTF(("umcpmio_i2c_write post check: engine internal state T1 says NACK\n"));
751 1.1 brad err = EIO;
752 1.1 brad break;
753 1.1 brad }
754 1.1 brad if (status_res.internal_i2c_state == 0) {
755 1.1 brad DPRINTF(("umcpmio_i2c_write post check: engine internal state is ZERO\n"));
756 1.1 brad err = 0;
757 1.1 brad break;
758 1.1 brad }
759 1.1 brad if (status_res.internal_i2c_state == MCP2221_ENGINE_WRITINGNOSTOP &&
760 1.1 brad cmd == MCP2221_I2C_WRITE_DATA_NS) {
761 1.1 brad DPRINTF(("umcpmio_i2c_write post check: engine internal state is WRITINGNOSTOP\n"));
762 1.1 brad err = 0;
763 1.1 brad break;
764 1.1 brad }
765 1.1 brad if (umcpmio_i2c_fatal(status_res.internal_i2c_state)) {
766 1.1 brad DPRINTF(("umcpmio_i2c_write post check: engine internal state is fatal: %02x\n", status_res.internal_i2c_state));
767 1.1 brad err = EIO;
768 1.1 brad break;
769 1.1 brad }
770 1.1 brad WAITMS(sc->sc_busy_delay);
771 1.1 brad } else {
772 1.1 brad err = EIO;
773 1.1 brad break;
774 1.1 brad }
775 1.1 brad }
776 1.1 brad }
777 1.1 brad
778 1.1 brad out:
779 1.1 brad
780 1.1 brad return(err);
781 1.1 brad }
782 1.1 brad
783 1.1 brad /* This one deviates a bit from Adafruit in that is supports a straight read and
784 1.1 brad * a write + read. That is, write a register to read from and then do the read.
785 1.1 brad */
786 1.1 brad
787 1.1 brad static int
788 1.1 brad umcpmio_i2c_read(struct umcpmio_softc *sc, i2c_op_t op, i2c_addr_t addr,
789 1.1 brad const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags)
790 1.1 brad {
791 1.1 brad struct mcp2221_i2c_req i2c_req;
792 1.1 brad struct mcp2221_i2c_res i2c_res;
793 1.1 brad struct mcp2221_i2c_fetch_req i2c_fetch_req;
794 1.1 brad struct mcp2221_i2c_fetch_res i2c_fetch_res;
795 1.1 brad struct mcp2221_status_res status_res;
796 1.1 brad int err = 0;
797 1.1 brad uint8_t cmd;
798 1.1 brad int rretry = sc->sc_retry_busy_read;
799 1.1 brad
800 1.1 brad if (cmdbuf != NULL) {
801 1.1 brad DPRINTF(("umcpmio_i2c_read: has a cmdbuf, doing write first: addr=%02x\n",addr));
802 1.1 brad err = umcpmio_i2c_write(sc, I2C_OP_WRITE, addr, cmdbuf, cmdlen, NULL, 0, flags);
803 1.1 brad }
804 1.1 brad if (err)
805 1.1 brad goto out;
806 1.1 brad
807 1.1 brad err = umcpmio_get_status(sc, &status_res, true);
808 1.1 brad if (err)
809 1.1 brad goto out;
810 1.1 brad
811 1.1 brad if (status_res.internal_i2c_state !=0 &&
812 1.1 brad status_res.internal_i2c_state != MCP2221_ENGINE_WRITINGNOSTOP) {
813 1.1 brad DPRINTF(("umcpmio_i2c_read: internal state not zero and not WRITINGNOSTOP, clearing. internal_i2c_state=%02x\n",status_res.internal_i2c_state));
814 1.1 brad err = umcpmio_i2c_clear(sc, true);
815 1.1 brad }
816 1.1 brad if (err)
817 1.1 brad goto out;
818 1.1 brad
819 1.1 brad memset(&i2c_req, 0, MCP2221_REQ_BUFFER_SIZE);
820 1.1 brad if (cmdbuf == NULL &&
821 1.1 brad status_res.internal_i2c_state != MCP2221_ENGINE_WRITINGNOSTOP) {
822 1.1 brad cmd = MCP2221_I2C_READ_DATA;
823 1.1 brad } else {
824 1.1 brad cmd = MCP2221_I2C_READ_DATA_RS;
825 1.1 brad }
826 1.1 brad
827 1.1 brad /* The chip apparently can't do a READ without a STOP operation. Report that, and try
828 1.1 brad * treating it like a READ with a STOP. This won't work for a lot of devices.
829 1.1 brad */
830 1.1 brad
831 1.1 brad if (!I2C_OP_STOP_P(op) &&
832 1.1 brad sc->sc_reportreadnostop)
833 1.1 brad device_printf(sc->sc_dev,"umcpmio_i2c_read: ************ called with READ without STOP ***************\n");
834 1.1 brad
835 1.1 brad i2c_req.cmd = cmd;
836 1.1 brad i2c_req.lsblen = datalen;
837 1.1 brad i2c_req.msblen = 0;
838 1.1 brad i2c_req.slaveaddr = (addr << 1) | 0x01;
839 1.1 brad
840 1.1 brad DPRINTF(("umcpmio_i2c_read: I2C READ normal read: cmd=%02x, addr=%02x\n",cmd,addr));
841 1.1 brad
842 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&i2c_req, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_read normal read req buffer copy");
843 1.1 brad
844 1.1 brad mutex_enter(&sc->sc_action_mutex);
845 1.1 brad err = umcpmio_send_report(sc, (uint8_t *)&i2c_req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)&i2c_res, sc->sc_cv_wait);
846 1.1 brad mutex_exit(&sc->sc_action_mutex);
847 1.1 brad
848 1.1 brad if (! err) {
849 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&i2c_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_read read-request response buffer copy");
850 1.1 brad
851 1.1 brad while (rretry > 0) {
852 1.1 brad rretry--;
853 1.1 brad DPRINTF(("umcpmio_i2c_read: fetch loop: rretry=%d\n",rretry));
854 1.1 brad err = 0;
855 1.1 brad memset(&i2c_fetch_req, 0, MCP2221_REQ_BUFFER_SIZE);
856 1.1 brad i2c_fetch_req.cmd = MCP2221_CMD_I2C_FETCH_READ_DATA;
857 1.1 brad mutex_enter(&sc->sc_action_mutex);
858 1.1 brad err = umcpmio_send_report(sc, (uint8_t *)&i2c_fetch_req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)&i2c_fetch_res, sc->sc_cv_wait);
859 1.1 brad mutex_exit(&sc->sc_action_mutex);
860 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&i2c_fetch_req, MCP2221_RES_BUFFER_SIZE, "umcpmio_i2c_read fetch res buffer copy");
861 1.1 brad
862 1.1 brad if (i2c_fetch_res.cmd == MCP2221_CMD_I2C_FETCH_READ_DATA) {
863 1.1 brad if (i2c_fetch_res.completion == MCP2221_FETCH_READ_PARTIALDATA ||
864 1.1 brad i2c_fetch_res.fetchlen == MCP2221_FETCH_READERROR) {
865 1.1 brad DPRINTF(("umcpmio_i2c_read: fetch loop: partial data or read error: completion=%02x,fetchlen=%02x\n",i2c_fetch_res.completion,i2c_fetch_res.fetchlen));
866 1.1 brad WAITMS(sc->sc_busy_delay);
867 1.1 brad err = EAGAIN;
868 1.1 brad continue;
869 1.1 brad }
870 1.1 brad if (i2c_fetch_res.internal_i2c_state == MCP2221_ENGINE_ADDRNACK) {
871 1.1 brad DPRINTF(("umcpmio_i2c_read: fetch loop: engine NACK\n"));
872 1.1 brad err = EIO;
873 1.1 brad break;
874 1.1 brad }
875 1.1 brad if (i2c_fetch_res.internal_i2c_state == 0 &&
876 1.1 brad i2c_fetch_res.fetchlen == 0) {
877 1.1 brad DPRINTF(("umcpmio_i2c_read: fetch loop: internal state and fetch len are ZERO\n"));
878 1.1 brad err = 0;
879 1.1 brad break;
880 1.1 brad }
881 1.1 brad if (i2c_fetch_res.internal_i2c_state == MCP2221_ENGINE_READPARTIAL ||
882 1.1 brad i2c_fetch_res.internal_i2c_state == MCP2221_ENGINE_READCOMPLETE) {
883 1.1 brad DPRINTF(("umcpmio_i2c_read: fetch loop: read partial or read complete: internal_i2c_state=%02x\n", i2c_fetch_res.internal_i2c_state));
884 1.1 brad err = 0;
885 1.1 brad break;
886 1.1 brad }
887 1.1 brad } else {
888 1.1 brad device_printf(sc->sc_dev, "umcpmio_i2c_read: fetch2: not the command desired: %02x\n",
889 1.1 brad i2c_fetch_res.cmd);
890 1.1 brad err = EIO;
891 1.1 brad break;
892 1.1 brad }
893 1.1 brad }
894 1.1 brad if (err == EAGAIN)
895 1.1 brad err = ETIMEDOUT;
896 1.1 brad
897 1.1 brad if (! err) {
898 1.1 brad if (databuf != NULL &&
899 1.1 brad i2c_fetch_res.fetchlen != MCP2221_FETCH_READERROR) {
900 1.1 brad int size = uimin(i2c_fetch_res.fetchlen, datalen);
901 1.1 brad DPRINTF(("umcpmio_i2c_read: copy data: size=%d,fetchlen=%d\n",size, i2c_fetch_res.fetchlen));
902 1.1 brad if (size > 0)
903 1.1 brad memcpy(databuf, &i2c_fetch_res.data[0], size);
904 1.1 brad } else {
905 1.1 brad DPRINTF(("umcpmio_i2c_read: copy data: databuf is NULL\n"));
906 1.1 brad }
907 1.1 brad }
908 1.1 brad } else {
909 1.1 brad device_printf(sc->sc_dev, "umcpmio_i2c_read request error: cmd=%02x,err=%d\n", cmd, err);
910 1.1 brad err = EIO;
911 1.1 brad }
912 1.1 brad out:
913 1.1 brad
914 1.1 brad return(err);
915 1.1 brad }
916 1.1 brad
917 1.1 brad static int
918 1.1 brad umcpmio_i2c_exec(void *v, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
919 1.1 brad size_t cmdlen, void *databuf, size_t datalen, int flags)
920 1.1 brad {
921 1.1 brad struct umcpmio_softc *sc = v;
922 1.1 brad size_t totallen = 0;
923 1.1 brad int err = 0;
924 1.1 brad
925 1.1 brad if (addr > 0x7f)
926 1.1 brad return (ENOTSUP);
927 1.1 brad
928 1.1 brad if (cmdbuf != NULL)
929 1.1 brad totallen += cmdlen;
930 1.1 brad if (databuf != NULL)
931 1.1 brad totallen += datalen;
932 1.1 brad
933 1.1 brad /* There is a way to do a transfer that is larger than 60 bytes,
934 1.1 brad * but it requires that your break the transfer up into pieces and
935 1.1 brad * send them in 60 byte chunks. We just won't support that right now.
936 1.1 brad * It would be somewhat unusual for there to be a transfer that big,
937 1.1 brad * unless you are trying to do block transfers and that isn't natively
938 1.1 brad * supported by the chip anyway... so those have to be broken up and
939 1.1 brad * sent as bytes.
940 1.1 brad */
941 1.1 brad
942 1.1 brad if (totallen > 60)
943 1.1 brad return (ENOTSUP);
944 1.1 brad
945 1.1 brad if (I2C_OP_WRITE_P(op)) {
946 1.1 brad err = umcpmio_i2c_write(sc, op, addr, cmdbuf, cmdlen, databuf, datalen, flags);
947 1.1 brad
948 1.1 brad DPRINTF(("umcpmio_exec: I2C WRITE: err=%d\n", err));
949 1.1 brad } else {
950 1.1 brad err = umcpmio_i2c_read(sc, op, addr, cmdbuf, cmdlen, databuf, datalen, flags);
951 1.1 brad
952 1.1 brad DPRINTF(("umcpmio_exec: I2C READ: err=%d\n", err));
953 1.1 brad }
954 1.1 brad
955 1.1 brad return(err);
956 1.1 brad }
957 1.1 brad
958 1.1 brad /* Accessing the ADC and DAC part of the chip */
959 1.1 brad
960 1.1 brad #define UMCPMIO_DEV_UNIT(m) (m & 0x80 ? (m & 0x7f) / 3 : m)
961 1.1 brad #define UMCPMIO_DEV_WHAT(m) (m & 0x80 ? ((m & 0x7f) % 3) + 1: CONTROL_DEV)
962 1.1 brad
963 1.1 brad static int
964 1.1 brad umcpmio_dev_open(dev_t dev, int flags, int fmt, struct lwp *l)
965 1.1 brad {
966 1.1 brad struct umcpmio_softc *sc;
967 1.1 brad int dunit;
968 1.1 brad int pin = -1;
969 1.1 brad int error = 0;
970 1.1 brad
971 1.1 brad sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
972 1.1 brad if (!sc)
973 1.1 brad return ENXIO;
974 1.1 brad
975 1.1 brad dunit = UMCPMIO_DEV_WHAT(minor(dev));
976 1.1 brad
977 1.1 brad if (sc->sc_dev_open[dunit]) {
978 1.1 brad DPRINTF(("umcpmio_dev_open: dunit=%d BUSY\n",dunit));
979 1.1 brad return EBUSY;
980 1.1 brad }
981 1.1 brad
982 1.1 brad /* The control device only allows for ioctl calls, so pretty much allow
983 1.1 brad * any sort of access. For the ADC, you perform a strict O_RDONLY and
984 1.1 brad * for the DAC a strict O_WRONLY. It is an error to try and do a O_RDWR
985 1.1 brad * It makes little sense to try and support select or poll. The ADC and
986 1.1 brad * DAC are always available for use.
987 1.1 brad */
988 1.1 brad
989 1.1 brad if (dunit != CONTROL_DEV &&
990 1.1 brad ((flags & FREAD) && (flags & FWRITE))) {
991 1.1 brad DPRINTF(("umcpmio_dev_open: Not CONTROL device and trying to do READ and WRITE\n"));
992 1.1 brad return EINVAL;
993 1.1 brad }
994 1.1 brad
995 1.1 brad /* Ya, this unrolling will also have to be changed if the MCP-2210 is
996 1.1 brad * supported. There are currently only 4 pins, so don't worry too much
997 1.1 brad * about it. The MCP-2210 has RAM, so there would be a fifth for it.
998 1.1 brad */
999 1.1 brad
1000 1.1 brad mutex_enter(&sc->sc_action_mutex);
1001 1.1 brad if (dunit != CONTROL_DEV) {
1002 1.1 brad switch (dunit) {
1003 1.1 brad case GP1_DEV:
1004 1.1 brad pin = 1;
1005 1.1 brad break;
1006 1.1 brad case GP2_DEV:
1007 1.1 brad pin = 2;
1008 1.1 brad break;
1009 1.1 brad case GP3_DEV:
1010 1.1 brad pin = 3;
1011 1.1 brad break;
1012 1.1 brad default:
1013 1.1 brad error = EINVAL;
1014 1.1 brad break;
1015 1.1 brad }
1016 1.1 brad if (! error) {
1017 1.1 brad /* XXX - we can probably do better here... it doesn't
1018 1.1 brad * remember what the pin was set to and probably should.
1019 1.1 brad */
1020 1.1 brad if (flags & FREAD) {
1021 1.1 brad error = umcpmio_gpio_pin_ctlctl(sc, pin, GPIO_PIN_ALT0, false);
1022 1.1 brad } else {
1023 1.1 brad if (pin == 1) {
1024 1.1 brad error = EINVAL;
1025 1.1 brad } else {
1026 1.1 brad error = umcpmio_gpio_pin_ctlctl(sc, pin, GPIO_PIN_ALT1, false);
1027 1.1 brad }
1028 1.1 brad }
1029 1.1 brad }
1030 1.1 brad }
1031 1.1 brad if (! error)
1032 1.1 brad sc->sc_dev_open[dunit] = true;
1033 1.1 brad mutex_exit(&sc->sc_action_mutex);
1034 1.1 brad
1035 1.1 brad DPRINTF(("umcpmio_dev_open: Opened dunit=%d,pin=%d,error=%d\n",dunit,pin,error));
1036 1.1 brad
1037 1.1 brad return error;
1038 1.1 brad }
1039 1.1 brad
1040 1.1 brad /* Read an ADC value */
1041 1.1 brad
1042 1.1 brad static int
1043 1.1 brad umcpmio_dev_read(dev_t dev, struct uio *uio, int flags)
1044 1.1 brad {
1045 1.1 brad struct umcpmio_softc *sc;
1046 1.1 brad struct mcp2221_status_res status_res;
1047 1.1 brad int dunit;
1048 1.1 brad int error = 0;
1049 1.1 brad uint8_t adc_lsb;
1050 1.1 brad uint8_t adc_msb;
1051 1.1 brad uint16_t buf;
1052 1.1 brad
1053 1.1 brad if ((sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)))) == NULL)
1054 1.1 brad return ENXIO;
1055 1.1 brad
1056 1.1 brad dunit = UMCPMIO_DEV_WHAT(minor(dev));
1057 1.1 brad
1058 1.1 brad if (dunit != CONTROL_DEV) {
1059 1.1 brad while (uio->uio_resid &&
1060 1.1 brad !sc->sc_dying) {
1061 1.1 brad error = umcpmio_get_status(sc, &status_res, true);
1062 1.1 brad if (! error) {
1063 1.1 brad switch (dunit) {
1064 1.1 brad case GP1_DEV:
1065 1.1 brad adc_lsb = status_res.adc_channel0_lsb;
1066 1.1 brad adc_msb = status_res.adc_channel0_msb;
1067 1.1 brad break;
1068 1.1 brad case GP2_DEV:
1069 1.1 brad adc_lsb = status_res.adc_channel1_lsb;
1070 1.1 brad adc_msb = status_res.adc_channel1_msb;
1071 1.1 brad break;
1072 1.1 brad case GP3_DEV:
1073 1.1 brad adc_lsb = status_res.adc_channel2_lsb;
1074 1.1 brad adc_msb = status_res.adc_channel2_msb;
1075 1.1 brad break;
1076 1.1 brad default:
1077 1.1 brad error = EINVAL;
1078 1.1 brad break;
1079 1.1 brad }
1080 1.1 brad
1081 1.1 brad if (! error) {
1082 1.1 brad if (sc->sc_dying)
1083 1.1 brad break;
1084 1.1 brad
1085 1.1 brad buf = adc_msb << 8;
1086 1.1 brad buf |= adc_lsb;
1087 1.1 brad error = uiomove(&buf, 2, uio);
1088 1.1 brad }
1089 1.1 brad }
1090 1.1 brad }
1091 1.1 brad } else {
1092 1.1 brad error = EINVAL;
1093 1.1 brad }
1094 1.1 brad
1095 1.1 brad
1096 1.1 brad return error;
1097 1.1 brad }
1098 1.1 brad
1099 1.1 brad /* Write to the DAC */
1100 1.1 brad
1101 1.1 brad static int
1102 1.1 brad umcpmio_dev_write(dev_t dev, struct uio *uio, int flags)
1103 1.1 brad {
1104 1.1 brad struct umcpmio_softc *sc;
1105 1.1 brad int dunit;
1106 1.1 brad int error = 0;
1107 1.1 brad
1108 1.1 brad if ((sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)))) == NULL)
1109 1.1 brad return ENXIO;
1110 1.1 brad
1111 1.1 brad dunit = UMCPMIO_DEV_WHAT(minor(dev));
1112 1.1 brad
1113 1.1 brad if (dunit != CONTROL_DEV) {
1114 1.1 brad while (uio->uio_resid &&
1115 1.1 brad !sc->sc_dying) {
1116 1.1 brad uint8_t buf;
1117 1.1 brad
1118 1.1 brad if ((error = uiomove(&buf, 1, uio)) != 0)
1119 1.1 brad break;
1120 1.1 brad
1121 1.1 brad if (sc->sc_dying)
1122 1.1 brad break;
1123 1.1 brad
1124 1.1 brad error = umcpmio_set_dac_value_one(sc, buf, true);
1125 1.1 brad if (error)
1126 1.1 brad break;
1127 1.1 brad }
1128 1.1 brad } else {
1129 1.1 brad error = EINVAL;
1130 1.1 brad }
1131 1.1 brad
1132 1.1 brad return error;
1133 1.1 brad }
1134 1.1 brad
1135 1.1 brad /* Close everything up */
1136 1.1 brad
1137 1.1 brad static int
1138 1.1 brad umcpmio_dev_close(dev_t dev, int flags, int fmt, struct lwp *l)
1139 1.1 brad {
1140 1.1 brad struct umcpmio_softc *sc;
1141 1.1 brad int dunit;
1142 1.1 brad int pin;
1143 1.1 brad int error = 0;
1144 1.1 brad
1145 1.1 brad sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
1146 1.1 brad if (sc->sc_dying)
1147 1.1 brad return EIO;
1148 1.1 brad
1149 1.1 brad dunit = UMCPMIO_DEV_WHAT(minor(dev));
1150 1.1 brad
1151 1.1 brad mutex_enter(&sc->sc_action_mutex);
1152 1.1 brad if (dunit != CONTROL_DEV) {
1153 1.1 brad switch (dunit) {
1154 1.1 brad case GP1_DEV:
1155 1.1 brad pin = 1;
1156 1.1 brad break;
1157 1.1 brad case GP2_DEV:
1158 1.1 brad pin = 2;
1159 1.1 brad break;
1160 1.1 brad case GP3_DEV:
1161 1.1 brad pin = 3;
1162 1.1 brad break;
1163 1.1 brad default:
1164 1.1 brad error = EINVAL;
1165 1.1 brad break;
1166 1.1 brad }
1167 1.1 brad if (! error) {
1168 1.1 brad /* XXX - Ya, this really could be done better. Probably should
1169 1.1 brad * read the sram config and maybe the gpio config and save out
1170 1.1 brad * what the pin was set to.
1171 1.1 brad */
1172 1.1 brad
1173 1.1 brad error = umcpmio_gpio_pin_ctlctl(sc, pin, GPIO_PIN_INPUT, false);
1174 1.1 brad }
1175 1.1 brad }
1176 1.1 brad sc->sc_dev_open[dunit] = false;
1177 1.1 brad mutex_exit(&sc->sc_action_mutex);
1178 1.1 brad
1179 1.1 brad return error;
1180 1.1 brad }
1181 1.1 brad
1182 1.1 brad static int
1183 1.1 brad umcpmio_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1184 1.1 brad {
1185 1.1 brad struct umcpmio_softc *sc;
1186 1.1 brad struct mcp2221_status_res get_status_res;
1187 1.1 brad struct mcp2221_get_sram_res get_sram_res;
1188 1.1 brad struct mcp2221_get_gpio_cfg_res get_gpio_cfg_res;
1189 1.1 brad struct mcp2221_get_flash_res get_flash_res;
1190 1.1 brad struct mcp2221_status_res *ioctl_get_status;
1191 1.1 brad struct mcp2221_get_sram_res *ioctl_get_sram;
1192 1.1 brad struct mcp2221_get_gpio_cfg_res *ioctl_get_gpio_cfg;
1193 1.1 brad struct umcpmio_ioctl_get_flash *ioctl_get_flash;
1194 1.1 brad struct umcpmio_ioctl_put_flash *ioctl_put_flash;
1195 1.1 brad struct mcp2221_put_flash_req put_flash_req;
1196 1.1 brad struct mcp2221_put_flash_res put_flash_res;
1197 1.1 brad int dunit;
1198 1.1 brad int error = 0;
1199 1.1 brad
1200 1.1 brad sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
1201 1.1 brad if (sc->sc_dying)
1202 1.1 brad return EIO;
1203 1.1 brad
1204 1.1 brad dunit = UMCPMIO_DEV_WHAT(minor(dev));
1205 1.1 brad
1206 1.1 brad if (dunit != CONTROL_DEV) {
1207 1.1 brad /* It actually is fine to call ioctl with a unsupported cmd,
1208 1.1 brad * but be a little noisy if debug is enabled.
1209 1.1 brad */
1210 1.1 brad DPRINTF(("umcpmio_dev_ioctl: dunit is not the CONTROL device: dunit=%d,cmd=%ld\n",dunit,cmd));
1211 1.1 brad return EINVAL;
1212 1.1 brad }
1213 1.1 brad
1214 1.1 brad mutex_enter(&sc->sc_action_mutex);
1215 1.1 brad
1216 1.1 brad switch (cmd) {
1217 1.1 brad /* The GET calls use a shadow buffer for each type of call. That
1218 1.1 brad * probably isn't actually needed and the memcpy could be avoided.
1219 1.1 brad * but... it is only ever 64 bytes, so maybe not a big deal.
1220 1.1 brad */
1221 1.1 brad case UMCPMIO_GET_STATUS:
1222 1.1 brad ioctl_get_status = (struct mcp2221_status_res *)data;
1223 1.1 brad error = umcpmio_get_status(sc, &get_status_res, false);
1224 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&get_status_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_GET_STATUS: get_status_res");
1225 1.1 brad DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_GET_STATUS: umcpmio_get_status error=%d\n",error));
1226 1.1 brad if (! error)
1227 1.1 brad memcpy(ioctl_get_status, &get_status_res, MCP2221_RES_BUFFER_SIZE);
1228 1.1 brad break;
1229 1.1 brad
1230 1.1 brad case UMCPMIO_GET_SRAM:
1231 1.1 brad ioctl_get_sram = (struct mcp2221_get_sram_res *)data;
1232 1.1 brad error = umcpmio_get_sram(sc, &get_sram_res, false);
1233 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&get_sram_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_GET_SRAM: get_sram_res");
1234 1.1 brad DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_GET_SRAM: umcpmio_get_sram error=%d\n",error));
1235 1.1 brad if (! error)
1236 1.1 brad memcpy(ioctl_get_sram, &get_sram_res, MCP2221_RES_BUFFER_SIZE);
1237 1.1 brad break;
1238 1.1 brad
1239 1.1 brad case UMCPMIO_GET_GP_CFG:
1240 1.1 brad ioctl_get_gpio_cfg = (struct mcp2221_get_gpio_cfg_res *)data;
1241 1.1 brad error = umcpmio_get_gpio_cfg(sc, &get_gpio_cfg_res, false);
1242 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&get_gpio_cfg_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_GET_GP_CFG: get_gpio_cfg_res");
1243 1.1 brad DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_GET_GP_CFG: umcpmio_get_gpio_cfg error=%d\n",error));
1244 1.1 brad if (! error)
1245 1.1 brad memcpy(ioctl_get_gpio_cfg, &get_gpio_cfg_res, MCP2221_RES_BUFFER_SIZE);
1246 1.1 brad break;
1247 1.1 brad
1248 1.1 brad case UMCPMIO_GET_FLASH:
1249 1.1 brad ioctl_get_flash = (struct umcpmio_ioctl_get_flash *)data;
1250 1.1 brad error = umcpmio_get_flash(sc, ioctl_get_flash->subcode, &get_flash_res, false);
1251 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&get_flash_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_GET_FLASH: get_flash_res");
1252 1.1 brad DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_GET_FLASH: umcpmio_get_flash subcode=%d,error=%d\n",ioctl_get_flash->subcode,error));
1253 1.1 brad if (! error)
1254 1.1 brad memcpy(&ioctl_get_flash->get_flash_res, &get_flash_res, MCP2221_RES_BUFFER_SIZE);
1255 1.1 brad break;
1256 1.1 brad
1257 1.1 brad case UMCPMIO_PUT_FLASH:
1258 1.1 brad /* We only allow the flash parts related to gpio to be changed.
1259 1.1 brad * Bounce any attempt to do something else. Also use a shadow
1260 1.1 brad * buffer for the put, so we get to control just literally
1261 1.1 brad * everything about the write to flash.
1262 1.1 brad */
1263 1.1 brad ioctl_put_flash = (struct umcpmio_ioctl_put_flash *)data;
1264 1.1 brad DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH: umcpmio_put_flash subcode=%d\n",ioctl_put_flash->subcode));
1265 1.1 brad if (ioctl_put_flash->subcode == MCP2221_FLASH_SUBCODE_GP) {
1266 1.1 brad memset(&put_flash_req, 0, MCP2221_REQ_BUFFER_SIZE);
1267 1.1 brad put_flash_req.subcode = ioctl_put_flash->subcode;
1268 1.1 brad put_flash_req.u.gp.gp0_settings = ioctl_put_flash->put_flash_req.u.gp.gp0_settings;
1269 1.1 brad put_flash_req.u.gp.gp1_settings = ioctl_put_flash->put_flash_req.u.gp.gp1_settings;
1270 1.1 brad put_flash_req.u.gp.gp2_settings = ioctl_put_flash->put_flash_req.u.gp.gp2_settings;
1271 1.1 brad put_flash_req.u.gp.gp3_settings = ioctl_put_flash->put_flash_req.u.gp.gp3_settings;
1272 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&ioctl_put_flash->put_flash_req, MCP2221_REQ_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH: ioctl put_flash_req");
1273 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&put_flash_req, MCP2221_REQ_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH: put_flash_req");
1274 1.1 brad memset(&put_flash_res, 0, MCP2221_RES_BUFFER_SIZE);
1275 1.1 brad error = umcpmio_put_flash(sc, &put_flash_req, &put_flash_res, false);
1276 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&put_flash_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH: put_flash_res");
1277 1.1 brad memcpy(&ioctl_put_flash->put_flash_res, &put_flash_res, MCP2221_RES_BUFFER_SIZE);
1278 1.1 brad } else {
1279 1.1 brad error = EINVAL;
1280 1.1 brad }
1281 1.1 brad break;
1282 1.1 brad default:
1283 1.1 brad error = EINVAL;
1284 1.1 brad }
1285 1.1 brad
1286 1.1 brad mutex_exit(&sc->sc_action_mutex);
1287 1.1 brad
1288 1.1 brad return error;
1289 1.1 brad }
1290 1.1 brad
1291 1.1 brad /* This is for sysctl variables that don't actually change the chip. */
1292 1.1 brad
1293 1.1 brad int
1294 1.1 brad umcpmio_verify_sysctl(SYSCTLFN_ARGS)
1295 1.1 brad {
1296 1.1 brad int error, t;
1297 1.1 brad struct sysctlnode node;
1298 1.1 brad
1299 1.1 brad node = *rnode;
1300 1.1 brad t = *(int *)rnode->sysctl_data;
1301 1.1 brad node.sysctl_data = &t;
1302 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
1303 1.1 brad if (error || newp == NULL)
1304 1.1 brad return error;
1305 1.1 brad
1306 1.1 brad if (t < 0)
1307 1.1 brad return EINVAL;
1308 1.1 brad
1309 1.1 brad *(int *)rnode->sysctl_data = t;
1310 1.1 brad
1311 1.1 brad return 0;
1312 1.1 brad }
1313 1.1 brad
1314 1.1 brad /* sysctl validation for stuff that interacts with the chip needs to happen in a
1315 1.1 brad * transaction. The read of the current state and the update to new state can't
1316 1.1 brad * allow for someone to sneak in between the two.
1317 1.1 brad *
1318 1.1 brad * We use text for the values of a lot of these variables so you don't need the
1319 1.1 brad * datasheet in front of you. You get to do that with umcpmioctl(8).
1320 1.1 brad */
1321 1.1 brad
1322 1.1 brad static struct umcpmio_sysctl_name umcpmio_vref_names[] = {
1323 1.1 brad {
1324 1.1 brad .text = "4.096V",
1325 1.1 brad },
1326 1.1 brad {
1327 1.1 brad .text = "2.048V",
1328 1.1 brad },
1329 1.1 brad {
1330 1.1 brad .text = "1.024V",
1331 1.1 brad },
1332 1.1 brad {
1333 1.1 brad .text = "OFF",
1334 1.1 brad },
1335 1.1 brad {
1336 1.1 brad .text = "VDD",
1337 1.1 brad }
1338 1.1 brad };
1339 1.1 brad
1340 1.1 brad int
1341 1.1 brad umcpmio_verify_dac_sysctl(SYSCTLFN_ARGS)
1342 1.1 brad {
1343 1.1 brad char buf[UMCPMIO_VREF_NAME];
1344 1.1 brad char cbuf[UMCPMIO_VREF_NAME];
1345 1.1 brad struct umcpmio_softc *sc;
1346 1.1 brad struct sysctlnode node;
1347 1.1 brad int error = 0;
1348 1.1 brad int vrm;
1349 1.1 brad size_t i;
1350 1.1 brad struct mcp2221_get_sram_res sram_res;
1351 1.1 brad
1352 1.1 brad node = *rnode;
1353 1.1 brad sc = node.sysctl_data;
1354 1.1 brad
1355 1.1 brad mutex_enter(&sc->sc_action_mutex);
1356 1.1 brad
1357 1.1 brad error = umcpmio_get_sram(sc, &sram_res, false);
1358 1.1 brad if (error)
1359 1.1 brad goto out;
1360 1.1 brad
1361 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&sram_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_verify_dac_sysctl SRAM res buffer");
1362 1.1 brad
1363 1.1 brad if (sram_res.dac_reference_voltage & MCP2221_SRAM_DAC_IS_VRM) {
1364 1.1 brad vrm = sram_res.dac_reference_voltage & MCP2221_SRAM_DAC_VRM_MASK;
1365 1.1 brad switch (vrm) {
1366 1.1 brad case MCP2221_SRAM_DAC_VRM_4096V:
1367 1.1 brad strncpy(buf, "4.096V", UMCPMIO_VREF_NAME);
1368 1.1 brad break;
1369 1.1 brad case MCP2221_SRAM_DAC_VRM_2048V:
1370 1.1 brad strncpy(buf, "2.048V", UMCPMIO_VREF_NAME);
1371 1.1 brad break;
1372 1.1 brad case MCP2221_SRAM_DAC_VRM_1024V:
1373 1.1 brad strncpy(buf, "1.024V", UMCPMIO_VREF_NAME);
1374 1.1 brad break;
1375 1.1 brad case MCP2221_SRAM_DAC_VRM_OFF:
1376 1.1 brad default:
1377 1.1 brad strncpy(buf, "OFF", UMCPMIO_VREF_NAME);
1378 1.1 brad break;
1379 1.1 brad }
1380 1.1 brad } else {
1381 1.1 brad strncpy(buf, "VDD", UMCPMIO_VREF_NAME);
1382 1.1 brad }
1383 1.1 brad strncpy(cbuf, buf, UMCPMIO_VREF_NAME);
1384 1.1 brad node.sysctl_data = buf;
1385 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
1386 1.1 brad if (error || newp == NULL)
1387 1.1 brad goto out;
1388 1.1 brad
1389 1.1 brad for (i = 0; i < __arraycount(umcpmio_vref_names); i++) {
1390 1.1 brad if (strncmp(node.sysctl_data, umcpmio_vref_names[i].text,
1391 1.1 brad UMCPMIO_VREF_NAME) == 0) {
1392 1.1 brad break;
1393 1.1 brad }
1394 1.1 brad }
1395 1.1 brad
1396 1.1 brad if (i == __arraycount(umcpmio_vref_names))
1397 1.1 brad error = EINVAL;
1398 1.1 brad
1399 1.1 brad if (! error) {
1400 1.1 brad if (strncmp(cbuf, buf, UMCPMIO_VREF_NAME) != 0) {
1401 1.1 brad DPRINTF(("umcpmio_verify_dac_sysctl: setting DAC vref: %s\n",buf));
1402 1.1 brad error = umcpmio_set_dac_vref_one(sc, buf, false);
1403 1.1 brad }
1404 1.1 brad }
1405 1.1 brad
1406 1.1 brad out:
1407 1.1 brad mutex_exit(&sc->sc_action_mutex);
1408 1.1 brad return error;
1409 1.1 brad }
1410 1.1 brad
1411 1.1 brad int
1412 1.1 brad umcpmio_verify_adc_sysctl(SYSCTLFN_ARGS)
1413 1.1 brad {
1414 1.1 brad char buf[UMCPMIO_VREF_NAME];
1415 1.1 brad char cbuf[UMCPMIO_VREF_NAME];
1416 1.1 brad struct umcpmio_softc *sc;
1417 1.1 brad struct sysctlnode node;
1418 1.1 brad int error = 0;
1419 1.1 brad int vrm;
1420 1.1 brad size_t i;
1421 1.1 brad struct mcp2221_get_sram_res sram_res;
1422 1.1 brad
1423 1.1 brad node = *rnode;
1424 1.1 brad sc = node.sysctl_data;
1425 1.1 brad
1426 1.1 brad mutex_enter(&sc->sc_action_mutex);
1427 1.1 brad
1428 1.1 brad error = umcpmio_get_sram(sc, &sram_res, false);
1429 1.1 brad if (error)
1430 1.1 brad goto out;
1431 1.1 brad
1432 1.1 brad if (sram_res.irq_adc_reference_voltage & MCP2221_SRAM_ADC_IS_VRM) {
1433 1.1 brad vrm = sram_res.irq_adc_reference_voltage & MCP2221_SRAM_ADC_VRM_MASK;
1434 1.1 brad switch (vrm) {
1435 1.1 brad case MCP2221_SRAM_ADC_VRM_4096V:
1436 1.1 brad strncpy(buf, "4.096V", UMCPMIO_VREF_NAME);
1437 1.1 brad break;
1438 1.1 brad case MCP2221_SRAM_ADC_VRM_2048V:
1439 1.1 brad strncpy(buf, "2.048V", UMCPMIO_VREF_NAME);
1440 1.1 brad break;
1441 1.1 brad case MCP2221_SRAM_ADC_VRM_1024V:
1442 1.1 brad strncpy(buf, "1.024V", UMCPMIO_VREF_NAME);
1443 1.1 brad break;
1444 1.1 brad case MCP2221_SRAM_ADC_VRM_OFF:
1445 1.1 brad default:
1446 1.1 brad strncpy(buf, "OFF", UMCPMIO_VREF_NAME);
1447 1.1 brad break;
1448 1.1 brad }
1449 1.1 brad } else {
1450 1.1 brad strncpy(buf, "VDD", UMCPMIO_VREF_NAME);
1451 1.1 brad }
1452 1.1 brad strncpy(cbuf, buf, UMCPMIO_VREF_NAME);
1453 1.1 brad node.sysctl_data = buf;
1454 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
1455 1.1 brad if (error || newp == NULL)
1456 1.1 brad goto out;
1457 1.1 brad
1458 1.1 brad for (i = 0; i < __arraycount(umcpmio_vref_names); i++) {
1459 1.1 brad if (strncmp(node.sysctl_data, umcpmio_vref_names[i].text,
1460 1.1 brad UMCPMIO_VREF_NAME) == 0) {
1461 1.1 brad break;
1462 1.1 brad }
1463 1.1 brad }
1464 1.1 brad
1465 1.1 brad if (i == __arraycount(umcpmio_vref_names))
1466 1.1 brad error = EINVAL;
1467 1.1 brad
1468 1.1 brad if (! error) {
1469 1.1 brad if (strncmp(cbuf, buf, UMCPMIO_VREF_NAME) != 0) {
1470 1.1 brad DPRINTF(("umcpmio_verify_adc_sysctl: setting ADC vref: %s\n",buf));
1471 1.1 brad error = umcpmio_set_adc_vref_one(sc, buf, false);
1472 1.1 brad }
1473 1.1 brad }
1474 1.1 brad
1475 1.1 brad out:
1476 1.1 brad mutex_exit(&sc->sc_action_mutex);
1477 1.1 brad return error;
1478 1.1 brad }
1479 1.1 brad
1480 1.1 brad static struct umcpmio_sysctl_name umcpmio_dc_names[] = {
1481 1.1 brad {
1482 1.1 brad .text = "75%",
1483 1.1 brad },
1484 1.1 brad {
1485 1.1 brad .text = "50%",
1486 1.1 brad },
1487 1.1 brad {
1488 1.1 brad .text = "25%",
1489 1.1 brad },
1490 1.1 brad {
1491 1.1 brad .text = "0%",
1492 1.1 brad }
1493 1.1 brad };
1494 1.1 brad
1495 1.1 brad static int
1496 1.1 brad umcpmio_verify_gpioclock_dc_sysctl(SYSCTLFN_ARGS)
1497 1.1 brad {
1498 1.1 brad char buf[UMCPMIO_VREF_NAME];
1499 1.1 brad char cbuf[UMCPMIO_VREF_NAME];
1500 1.1 brad struct umcpmio_softc *sc;
1501 1.1 brad struct sysctlnode node;
1502 1.1 brad int error = 0;
1503 1.1 brad uint8_t duty_cycle;
1504 1.1 brad size_t i;
1505 1.1 brad struct mcp2221_get_sram_res sram_res;
1506 1.1 brad
1507 1.1 brad node = *rnode;
1508 1.1 brad sc = node.sysctl_data;
1509 1.1 brad
1510 1.1 brad mutex_enter(&sc->sc_action_mutex);
1511 1.1 brad
1512 1.1 brad error = umcpmio_get_sram(sc, &sram_res, false);
1513 1.1 brad if (error)
1514 1.1 brad goto out;
1515 1.1 brad
1516 1.1 brad duty_cycle = sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_DC_MASK;
1517 1.1 brad DPRINTF(("umcpmio_verify_gpioclock_dc_sysctl: current duty cycle: %02x\n",duty_cycle));
1518 1.1 brad switch (duty_cycle) {
1519 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_DC_75:
1520 1.1 brad strncpy(buf, "75%", UMCPMIO_DC_NAME);
1521 1.1 brad break;
1522 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_DC_50:
1523 1.1 brad strncpy(buf, "50%", UMCPMIO_DC_NAME);
1524 1.1 brad break;
1525 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_DC_25:
1526 1.1 brad strncpy(buf, "25%", UMCPMIO_DC_NAME);
1527 1.1 brad break;
1528 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_DC_0:
1529 1.1 brad default:
1530 1.1 brad strncpy(buf, "0%", UMCPMIO_DC_NAME);
1531 1.1 brad break;
1532 1.1 brad }
1533 1.1 brad strncpy(cbuf, buf, UMCPMIO_VREF_NAME);
1534 1.1 brad node.sysctl_data = buf;
1535 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
1536 1.1 brad if (error || newp == NULL)
1537 1.1 brad goto out;
1538 1.1 brad
1539 1.1 brad for (i = 0; i < __arraycount(umcpmio_dc_names); i++) {
1540 1.1 brad if (strncmp(node.sysctl_data, umcpmio_dc_names[i].text,
1541 1.1 brad UMCPMIO_VREF_NAME) == 0) {
1542 1.1 brad break;
1543 1.1 brad }
1544 1.1 brad }
1545 1.1 brad
1546 1.1 brad if (i == __arraycount(umcpmio_dc_names))
1547 1.1 brad error = EINVAL;
1548 1.1 brad
1549 1.1 brad if (! error) {
1550 1.1 brad if (strncmp(cbuf, buf, UMCPMIO_VREF_NAME) != 0) {
1551 1.1 brad DPRINTF(("umcpmio_verify_gpioclock_dc_sysctl: setting GPIO clock duty cycle: %s\n",buf));
1552 1.1 brad error = umcpmio_set_gpioclock_dc_one(sc, buf, false);
1553 1.1 brad }
1554 1.1 brad }
1555 1.1 brad
1556 1.1 brad out:
1557 1.1 brad mutex_exit(&sc->sc_action_mutex);
1558 1.1 brad return error;
1559 1.1 brad }
1560 1.1 brad
1561 1.1 brad
1562 1.1 brad static struct umcpmio_sysctl_name umcpmio_cd_names[] = {
1563 1.1 brad {
1564 1.1 brad .text = "375kHz",
1565 1.1 brad },
1566 1.1 brad {
1567 1.1 brad .text = "750kHz",
1568 1.1 brad },
1569 1.1 brad {
1570 1.1 brad .text = "1.5MHz",
1571 1.1 brad },
1572 1.1 brad {
1573 1.1 brad .text = "3MHz",
1574 1.1 brad },
1575 1.1 brad {
1576 1.1 brad .text = "6MHz",
1577 1.1 brad },
1578 1.1 brad {
1579 1.1 brad .text = "12MHz",
1580 1.1 brad },
1581 1.1 brad {
1582 1.1 brad .text = "24MHz",
1583 1.1 brad }
1584 1.1 brad };
1585 1.1 brad
1586 1.1 brad static int
1587 1.1 brad umcpmio_verify_gpioclock_cd_sysctl(SYSCTLFN_ARGS)
1588 1.1 brad {
1589 1.1 brad char buf[UMCPMIO_CD_NAME];
1590 1.1 brad char cbuf[UMCPMIO_CD_NAME];
1591 1.1 brad struct umcpmio_softc *sc;
1592 1.1 brad struct sysctlnode node;
1593 1.1 brad int error = 0;
1594 1.1 brad uint8_t clock_divider;
1595 1.1 brad size_t i;
1596 1.1 brad struct mcp2221_get_sram_res sram_res;
1597 1.1 brad
1598 1.1 brad node = *rnode;
1599 1.1 brad sc = node.sysctl_data;
1600 1.1 brad
1601 1.1 brad mutex_enter(&sc->sc_action_mutex);
1602 1.1 brad
1603 1.1 brad error = umcpmio_get_sram(sc, &sram_res, false);
1604 1.1 brad if (error)
1605 1.1 brad goto out;
1606 1.1 brad
1607 1.1 brad clock_divider = sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_CD_MASK;
1608 1.1 brad DPRINTF(("umcpmio_verify_gpioclock_cd_sysctl: current clock divider: %02x\n",clock_divider));
1609 1.1 brad switch (clock_divider) {
1610 1.1 brad
1611 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_375KHZ:
1612 1.1 brad strncpy(buf, "375kHz", UMCPMIO_CD_NAME);
1613 1.1 brad break;
1614 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_750KHZ:
1615 1.1 brad strncpy(buf, "750kHz", UMCPMIO_CD_NAME);
1616 1.1 brad break;
1617 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_1P5MHZ:
1618 1.1 brad strncpy(buf, "1.5MHz", UMCPMIO_CD_NAME);
1619 1.1 brad break;
1620 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_3MHZ:
1621 1.1 brad strncpy(buf, "3MHz", UMCPMIO_CD_NAME);
1622 1.1 brad break;
1623 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_6MHZ:
1624 1.1 brad strncpy(buf, "6MHz", UMCPMIO_CD_NAME);
1625 1.1 brad break;
1626 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_12MHZ:
1627 1.1 brad strncpy(buf, "12MHz", UMCPMIO_CD_NAME);
1628 1.1 brad break;
1629 1.1 brad case MCP2221_SRAM_GPIO_CLOCK_CD_24MHZ:
1630 1.1 brad strncpy(buf, "24MHz", UMCPMIO_CD_NAME);
1631 1.1 brad break;
1632 1.1 brad default:
1633 1.1 brad strncpy(buf, "12MHz", UMCPMIO_CD_NAME);
1634 1.1 brad break;
1635 1.1 brad }
1636 1.1 brad strncpy(cbuf, buf, UMCPMIO_CD_NAME);
1637 1.1 brad node.sysctl_data = buf;
1638 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
1639 1.1 brad if (error || newp == NULL)
1640 1.1 brad goto out;
1641 1.1 brad
1642 1.1 brad for (i = 0; i < __arraycount(umcpmio_cd_names); i++) {
1643 1.1 brad if (strncmp(node.sysctl_data, umcpmio_cd_names[i].text,
1644 1.1 brad UMCPMIO_CD_NAME) == 0) {
1645 1.1 brad break;
1646 1.1 brad }
1647 1.1 brad }
1648 1.1 brad
1649 1.1 brad if (i == __arraycount(umcpmio_cd_names))
1650 1.1 brad error = EINVAL;
1651 1.1 brad
1652 1.1 brad if (! error) {
1653 1.1 brad if (strncmp(cbuf, buf, UMCPMIO_CD_NAME) != 0) {
1654 1.1 brad DPRINTF(("umcpmio_verify_gpioclock_cd_sysctl: setting GPIO clock clock divider: %s\n",buf));
1655 1.1 brad error = umcpmio_set_gpioclock_cd_one(sc, buf, false);
1656 1.1 brad }
1657 1.1 brad }
1658 1.1 brad
1659 1.1 brad out:
1660 1.1 brad mutex_exit(&sc->sc_action_mutex);
1661 1.1 brad return error;
1662 1.1 brad }
1663 1.1 brad
1664 1.1 brad static int
1665 1.1 brad umcpmio_sysctl_init(struct umcpmio_softc *sc)
1666 1.1 brad {
1667 1.1 brad int error;
1668 1.1 brad const struct sysctlnode *cnode;
1669 1.1 brad int sysctlroot_num, i2c_num, adc_dac_num, adc_num, dac_num, gpio_num;
1670 1.1 brad
1671 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1672 1.1 brad 0, CTLTYPE_NODE, device_xname(sc->sc_dev),
1673 1.1 brad SYSCTL_DESCR("mcpmio controls"), NULL, 0, NULL, 0, CTL_HW,
1674 1.1 brad CTL_CREATE, CTL_EOL)) != 0)
1675 1.1 brad return error;
1676 1.1 brad
1677 1.1 brad sysctlroot_num = cnode->sysctl_num;
1678 1.1 brad
1679 1.1 brad #ifdef UMCPMIO_DEBUG
1680 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1681 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
1682 1.1 brad SYSCTL_DESCR("Debug level"), umcpmio_verify_sysctl, 0,
1683 1.1 brad &umcpmiodebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
1684 1.1 brad CTL_EOL)) != 0)
1685 1.1 brad return error;
1686 1.1 brad
1687 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1688 1.1 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "dump_buffers",
1689 1.1 brad SYSCTL_DESCR("Dump buffer when debugging"), NULL, 0, &sc->sc_dumpbuffer,
1690 1.1 brad 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1691 1.1 brad return error;
1692 1.1 brad #endif
1693 1.1 brad
1694 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1695 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "response_wait",
1696 1.1 brad SYSCTL_DESCR("How long to wait in ms for a response for a HID report"),
1697 1.1 brad umcpmio_verify_sysctl, 0, &sc->sc_cv_wait, 0, CTL_HW,
1698 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1699 1.1 brad return error;
1700 1.1 brad
1701 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1702 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "response_errcnt",
1703 1.1 brad SYSCTL_DESCR("How many errors to allow on a response"),
1704 1.1 brad umcpmio_verify_sysctl, 0, &sc->sc_response_errcnt, 0, CTL_HW,
1705 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1706 1.1 brad return error;
1707 1.1 brad
1708 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1709 1.1 brad 0, CTLTYPE_NODE, "i2c",
1710 1.1 brad SYSCTL_DESCR("I2C controls"), NULL, 0, NULL, 0, CTL_HW,
1711 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1712 1.1 brad return error;
1713 1.1 brad
1714 1.1 brad i2c_num = cnode->sysctl_num;
1715 1.1 brad
1716 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1717 1.1 brad 0, CTLTYPE_NODE, "adcdac",
1718 1.1 brad SYSCTL_DESCR("ADC and DAC controls"), NULL, 0, NULL, 0, CTL_HW,
1719 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1720 1.1 brad return error;
1721 1.1 brad
1722 1.1 brad adc_dac_num = cnode->sysctl_num;
1723 1.1 brad
1724 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1725 1.1 brad 0, CTLTYPE_NODE, "adc",
1726 1.1 brad SYSCTL_DESCR("ADC controls"), NULL, 0, NULL, 0, CTL_HW,
1727 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1728 1.1 brad return error;
1729 1.1 brad
1730 1.1 brad adc_num = cnode->sysctl_num;
1731 1.1 brad
1732 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1733 1.1 brad 0, CTLTYPE_NODE, "dac",
1734 1.1 brad SYSCTL_DESCR("DAC controls"), NULL, 0, NULL, 0, CTL_HW,
1735 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1736 1.1 brad return error;
1737 1.1 brad
1738 1.1 brad dac_num = cnode->sysctl_num;
1739 1.1 brad
1740 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1741 1.1 brad 0, CTLTYPE_NODE, "gpio",
1742 1.1 brad SYSCTL_DESCR("GPIO controls"), NULL, 0, NULL, 0, CTL_HW,
1743 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1744 1.1 brad return error;
1745 1.1 brad
1746 1.1 brad gpio_num = cnode->sysctl_num;
1747 1.1 brad
1748 1.1 brad /* I2C */
1749 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1750 1.1 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "reportreadnostop",
1751 1.1 brad SYSCTL_DESCR("Report that a READ without STOP was attempted by a device"),
1752 1.1 brad NULL, 0, &sc->sc_reportreadnostop, 0, CTL_HW, sysctlroot_num, i2c_num,
1753 1.1 brad CTL_CREATE, CTL_EOL)) != 0)
1754 1.1 brad return error;
1755 1.1 brad
1756 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1757 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "busy_delay",
1758 1.1 brad SYSCTL_DESCR("How long to wait in ms when the I2C engine is busy"),
1759 1.1 brad umcpmio_verify_sysctl, 0, &sc->sc_busy_delay, 0, CTL_HW,
1760 1.1 brad sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
1761 1.1 brad return error;
1762 1.1 brad
1763 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1764 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "retry_busy_read",
1765 1.1 brad SYSCTL_DESCR("How many times to retry a busy I2C read"),
1766 1.1 brad umcpmio_verify_sysctl, 0, &sc->sc_retry_busy_read, 0, CTL_HW,
1767 1.1 brad sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
1768 1.1 brad return error;
1769 1.1 brad
1770 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1771 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "retry_busy_write",
1772 1.1 brad SYSCTL_DESCR("How many times to retry a busy I2C write"),
1773 1.1 brad umcpmio_verify_sysctl, 0, &sc->sc_retry_busy_write, 0, CTL_HW,
1774 1.1 brad sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
1775 1.1 brad return error;
1776 1.1 brad
1777 1.1 brad /* GPIO */
1778 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1779 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "irq_poll",
1780 1.1 brad SYSCTL_DESCR("How often to poll for a IRQ change"),
1781 1.1 brad umcpmio_verify_sysctl, 0, &sc->sc_irq_poll, 0, CTL_HW,
1782 1.1 brad sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
1783 1.1 brad return error;
1784 1.1 brad
1785 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1786 1.1 brad CTLFLAG_READONLY, CTLTYPE_STRING, "clock_duty_cycles",
1787 1.1 brad SYSCTL_DESCR("Valid duty cycles for GPIO clock on GP1 ALT3 duty cycle"),
1788 1.1 brad 0, 0, __UNCONST(umcpmio_valid_dcs),
1789 1.1 brad sizeof(umcpmio_valid_dcs) + 1, CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
1790 1.1 brad return error;
1791 1.1 brad
1792 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1793 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "clock_duty_cycle",
1794 1.1 brad SYSCTL_DESCR("GPIO clock on GP1 ALT3 duty cycle"),
1795 1.1 brad umcpmio_verify_gpioclock_dc_sysctl, 0, (void *) sc,
1796 1.1 brad UMCPMIO_DC_NAME, CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
1797 1.1 brad return error;
1798 1.1 brad
1799 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1800 1.1 brad CTLFLAG_READONLY, CTLTYPE_STRING, "clock_dividers",
1801 1.1 brad SYSCTL_DESCR("Valid clock dividers for GPIO clock on GP1 with ALT3"),
1802 1.1 brad 0, 0, __UNCONST(umcpmio_valid_cds),
1803 1.1 brad sizeof(umcpmio_valid_cds) + 1, CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
1804 1.1 brad return error;
1805 1.1 brad
1806 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1807 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "clock_divider",
1808 1.1 brad SYSCTL_DESCR("GPIO clock on GP1 ALT3 clock divider"),
1809 1.1 brad umcpmio_verify_gpioclock_cd_sysctl, 0, (void *) sc,
1810 1.1 brad UMCPMIO_CD_NAME, CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
1811 1.1 brad return error;
1812 1.1 brad
1813 1.1 brad /* ADC and DAC */
1814 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1815 1.1 brad CTLFLAG_READONLY, CTLTYPE_STRING, "vrefs",
1816 1.1 brad SYSCTL_DESCR("Valid vref values for ADC and DAC"),
1817 1.1 brad 0, 0, __UNCONST(umcpmio_valid_vrefs),
1818 1.1 brad sizeof(umcpmio_valid_vrefs) + 1, CTL_HW, sysctlroot_num, adc_dac_num, CTL_CREATE, CTL_EOL)) != 0)
1819 1.1 brad return error;
1820 1.1 brad
1821 1.1 brad /* ADC */
1822 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1823 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "vref",
1824 1.1 brad SYSCTL_DESCR("ADC voltage reference"),
1825 1.1 brad umcpmio_verify_adc_sysctl, 0, (void *) sc,
1826 1.1 brad UMCPMIO_VREF_NAME, CTL_HW, sysctlroot_num, adc_num, CTL_CREATE, CTL_EOL)) != 0)
1827 1.1 brad return error;
1828 1.1 brad
1829 1.1 brad /* DAC */
1830 1.1 brad if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
1831 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "vref",
1832 1.1 brad SYSCTL_DESCR("DAC voltage reference"),
1833 1.1 brad umcpmio_verify_dac_sysctl, 0, (void *) sc,
1834 1.1 brad UMCPMIO_VREF_NAME, CTL_HW, sysctlroot_num, dac_num, CTL_CREATE, CTL_EOL)) != 0)
1835 1.1 brad return error;
1836 1.1 brad
1837 1.1 brad return 0;
1838 1.1 brad }
1839 1.1 brad
1840 1.1 brad static int
1841 1.1 brad umcpmio_match(device_t parent, cfdata_t match, void *aux)
1842 1.1 brad {
1843 1.1 brad struct uhidev_attach_arg *uha = aux;
1844 1.1 brad
1845 1.1 brad return umcpmio_lookup(uha->uiaa->uiaa_vendor, uha->uiaa->uiaa_product)
1846 1.1 brad != NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
1847 1.1 brad }
1848 1.1 brad
1849 1.1 brad
1850 1.1 brad /* This driver could be extended to support the MCP-2210 which is MCP's USB to
1851 1.1 brad * SPI / gpio chip. It also appears to be a something like the PIC16F1455 used in
1852 1.1 brad * the MCP2221 / MCP2221A. It is likely that a lot of this could use tables to
1853 1.1 brad * drive behavior.
1854 1.1 brad */
1855 1.1 brad
1856 1.1 brad static void
1857 1.1 brad umcpmio_attach(device_t parent, device_t self, void *aux)
1858 1.1 brad {
1859 1.1 brad struct umcpmio_softc *sc = device_private(self);
1860 1.1 brad struct uhidev_attach_arg *uha = aux;
1861 1.1 brad struct gpiobus_attach_args gba;
1862 1.1 brad struct i2cbus_attach_args iba;
1863 1.1 brad int err;
1864 1.1 brad struct mcp2221_status_res status_res;
1865 1.1 brad
1866 1.1 brad sc->sc_dev = self;
1867 1.1 brad sc->sc_hdev = uha->parent;
1868 1.1 brad sc->sc_udev = uha->uiaa->uiaa_device;
1869 1.1 brad
1870 1.1 brad sc->sc_umcpmiolog = NULL;
1871 1.1 brad sc->sc_dumpbuffer = false;
1872 1.1 brad
1873 1.1 brad sc->sc_reportreadnostop = true;
1874 1.1 brad sc->sc_cv_wait = 2500;
1875 1.1 brad sc->sc_response_errcnt = 5;
1876 1.1 brad sc->sc_busy_delay = 1;
1877 1.1 brad sc->sc_retry_busy_read = 50;
1878 1.1 brad sc->sc_retry_busy_write = 50;
1879 1.1 brad sc->sc_irq_poll = 10;
1880 1.1 brad sc->sc_dev_open[CONTROL_DEV] = sc->sc_dev_open[GP1_DEV] = sc->sc_dev_open[GP2_DEV] = sc->sc_dev_open[GP3_DEV] = false;
1881 1.1 brad
1882 1.1 brad aprint_normal("\n");
1883 1.1 brad
1884 1.1 brad if ((err = umcpmio_sysctl_init(sc)) != 0) {
1885 1.1 brad aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", err);
1886 1.1 brad return;
1887 1.1 brad }
1888 1.1 brad
1889 1.1 brad mutex_init(&sc->sc_action_mutex, MUTEX_DEFAULT, IPL_NONE);
1890 1.1 brad cv_init(&sc->sc_res_cv, "mcpres");
1891 1.1 brad mutex_init(&sc->sc_res_mutex, MUTEX_DEFAULT, IPL_NONE);
1892 1.1 brad sc->sc_res_buffer = NULL;
1893 1.1 brad sc->sc_res_ready = false;
1894 1.1 brad
1895 1.1 brad err = uhidev_open(sc->sc_hdev, &umcpmio_uhidev_intr, sc);
1896 1.1 brad
1897 1.1 brad /* It is not clear that this should be needed, but it was noted
1898 1.1 brad * that the device would sometimes not be ready if this delay
1899 1.1 brad * was not present. In fact, the attempts to set stuff a little
1900 1.1 brad * later would sometimes fail.
1901 1.1 brad */
1902 1.1 brad
1903 1.1 brad delay(1000);
1904 1.1 brad
1905 1.1 brad if (err)
1906 1.1 brad aprint_error_dev(sc->sc_dev, "umcpmio_attach: open uhidev_open: err=%d\n",err);
1907 1.1 brad
1908 1.1 brad if (!err)
1909 1.1 brad err = umcpmio_get_status(sc, &status_res, true);
1910 1.1 brad
1911 1.1 brad if (!err) {
1912 1.1 brad aprint_normal_dev(sc->sc_dev, "Hardware revision: %d.%d, Firmware revision: %d.%d\n",
1913 1.1 brad status_res.mcp2221_hardware_rev_major,
1914 1.1 brad status_res.mcp2221_hardware_rev_minor,
1915 1.1 brad status_res.mcp2221_firmware_rev_major,
1916 1.1 brad status_res.mcp2221_firmware_rev_minor);
1917 1.1 brad
1918 1.1 brad /* The datasheet suggests that it is possble for this to fail if the I2C port
1919 1.1 brad * is currently being used. However... since you just plugged in the chip,
1920 1.1 brad * the I2C port should not really be in use at that moment. In any case, try
1921 1.1 brad * hard to set this and don't make it fatal if it did not get set.
1922 1.1 brad */
1923 1.1 brad int i2cspeed=0;
1924 1.1 brad while (! err && i2cspeed < 3) {
1925 1.1 brad err = umcpmio_set_i2c_speed_one(sc, I2C_SPEED_SM, true);
1926 1.1 brad if (err) {
1927 1.1 brad aprint_error_dev(sc->sc_dev, "umcpmio_attach: set I2C speed: err=%d\n",
1928 1.1 brad err);
1929 1.1 brad delay(300);
1930 1.1 brad }
1931 1.1 brad i2cspeed++;
1932 1.1 brad }
1933 1.1 brad
1934 1.1 brad struct mcp2221_get_sram_res get_sram_res;
1935 1.1 brad err = umcpmio_get_sram(sc, &get_sram_res, true);
1936 1.1 brad
1937 1.1 brad if (! err) {
1938 1.1 brad umcpmio_dump_buffer(sc->sc_dumpbuffer, (uint8_t *)&get_sram_res, MCP2221_RES_BUFFER_SIZE, "umcpmio_attach get sram buffer copy");
1939 1.1 brad
1940 1.1 brad /* There are only 4 pins right now, just unroll any loops */
1941 1.1 brad
1942 1.1 brad sc->sc_gpio_pins[0].pin_num = 0;
1943 1.1 brad sc->sc_gpio_pins[0].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_ALT0 | GPIO_PIN_ALT3;
1944 1.1 brad sc->sc_gpio_pins[0].pin_flags = umcpmio_sram_gpio_to_flags(get_sram_res.gp0_settings);
1945 1.1 brad sc->sc_gpio_pins[0].pin_intrcaps = 0;
1946 1.1 brad snprintf(sc->sc_gpio_pins[0].pin_defname, 4, "GP0");
1947 1.1 brad
1948 1.1 brad sc->sc_gpio_pins[1].pin_num = 1;
1949 1.1 brad sc->sc_gpio_pins[1].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_ALT0 | GPIO_PIN_ALT1 | GPIO_PIN_ALT2 | GPIO_PIN_ALT3;
1950 1.1 brad sc->sc_gpio_pins[1].pin_flags = umcpmio_sram_gpio_to_flags(get_sram_res.gp1_settings);
1951 1.1 brad /* XXX - lets not advertise this right now... */
1952 1.1 brad #if 0
1953 1.1 brad sc->sc_gpio_pins[1].pin_intrcaps = GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE | GPIO_INTR_DOUBLE_EDGE | GPIO_INTR_MPSAFE;
1954 1.1 brad #endif
1955 1.1 brad sc->sc_gpio_pins[1].pin_intrcaps = 0;
1956 1.1 brad snprintf(sc->sc_gpio_pins[1].pin_defname, 4, "GP1");
1957 1.1 brad
1958 1.1 brad sc->sc_gpio_pins[2].pin_num = 2;
1959 1.1 brad sc->sc_gpio_pins[2].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_ALT0 | GPIO_PIN_ALT1 | GPIO_PIN_ALT3;
1960 1.1 brad sc->sc_gpio_pins[2].pin_flags = umcpmio_sram_gpio_to_flags(get_sram_res.gp2_settings);
1961 1.1 brad sc->sc_gpio_pins[2].pin_intrcaps = 0;
1962 1.1 brad snprintf(sc->sc_gpio_pins[2].pin_defname, 4, "GP2");
1963 1.1 brad
1964 1.1 brad sc->sc_gpio_pins[3].pin_num = 3;
1965 1.1 brad sc->sc_gpio_pins[3].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_ALT0 | GPIO_PIN_ALT1 | GPIO_PIN_ALT3;
1966 1.1 brad sc->sc_gpio_pins[3].pin_flags = umcpmio_sram_gpio_to_flags(get_sram_res.gp3_settings);
1967 1.1 brad sc->sc_gpio_pins[3].pin_intrcaps = 0;
1968 1.1 brad snprintf(sc->sc_gpio_pins[3].pin_defname, 4, "GP3");
1969 1.1 brad
1970 1.1 brad sc->sc_gpio_gc.gp_cookie = sc;
1971 1.1 brad sc->sc_gpio_gc.gp_pin_read = umcpmio_gpio_pin_read;
1972 1.1 brad sc->sc_gpio_gc.gp_pin_write = umcpmio_gpio_pin_write;
1973 1.1 brad sc->sc_gpio_gc.gp_pin_ctl = umcpmio_gpio_pin_ctl;
1974 1.1 brad
1975 1.1 brad sc->sc_gpio_gc.gp_intr_establish = umcpmio_gpio_intr_establish;
1976 1.1 brad sc->sc_gpio_gc.gp_intr_disestablish = umcpmio_gpio_intr_disestablish;
1977 1.1 brad sc->sc_gpio_gc.gp_intr_str = umcpmio_gpio_intrstr;
1978 1.1 brad
1979 1.1 brad
1980 1.1 brad gba.gba_gc = &sc->sc_gpio_gc;
1981 1.1 brad gba.gba_pins = sc->sc_gpio_pins;
1982 1.1 brad gba.gba_npins = MCP2221_NPINS;
1983 1.1 brad
1984 1.1 brad sc->sc_gpio_dev = config_found(self, &gba, gpiobus_print, CFARGS(.iattr = "gpiobus"));
1985 1.1 brad
1986 1.1 brad iic_tag_init(&sc->sc_i2c_tag);
1987 1.1 brad sc->sc_i2c_tag.ic_cookie = sc;
1988 1.1 brad sc->sc_i2c_tag.ic_acquire_bus = umcpmio_acquire_bus;
1989 1.1 brad sc->sc_i2c_tag.ic_release_bus = umcpmio_release_bus;
1990 1.1 brad sc->sc_i2c_tag.ic_exec = umcpmio_i2c_exec;
1991 1.1 brad
1992 1.1 brad memset(&iba, 0, sizeof(iba));
1993 1.1 brad iba.iba_tag = &sc->sc_i2c_tag;
1994 1.1 brad sc->sc_i2c_dev = config_found(self, &iba, iicbus_print, CFARGS(.iattr = "i2cbus"));
1995 1.1 brad } else {
1996 1.1 brad aprint_error_dev(sc->sc_dev, "umcpmio_attach: get sram error: err=%d\n",
1997 1.1 brad err);
1998 1.1 brad }
1999 1.1 brad } else {
2000 1.1 brad aprint_error_dev(sc->sc_dev, "umcpmio_attach: open uhidev_open: err=%d\n", err);
2001 1.1 brad }
2002 1.1 brad }
2003 1.1 brad
2004 1.1 brad
2005 1.1 brad static int
2006 1.1 brad umcpmio_detach(device_t self, int flags)
2007 1.1 brad {
2008 1.1 brad struct umcpmio_softc *sc = device_private(self);
2009 1.1 brad int err;
2010 1.1 brad
2011 1.1 brad DPRINTF(("umcpmio_detach: sc=%p flags=%d\n", sc, flags));
2012 1.1 brad
2013 1.1 brad mutex_enter(&sc->sc_action_mutex);
2014 1.1 brad sc->sc_dying = 1;
2015 1.1 brad
2016 1.1 brad err = config_detach_children(self, flags);
2017 1.1 brad if (err)
2018 1.1 brad return err;
2019 1.1 brad
2020 1.1 brad uhidev_close(sc->sc_hdev);
2021 1.1 brad
2022 1.1 brad mutex_destroy(&sc->sc_res_mutex);
2023 1.1 brad cv_destroy(&sc->sc_res_cv);
2024 1.1 brad
2025 1.1 brad sysctl_teardown(&sc->sc_umcpmiolog);
2026 1.1 brad
2027 1.1 brad mutex_exit(&sc->sc_action_mutex);
2028 1.1 brad mutex_destroy(&sc->sc_action_mutex);
2029 1.1 brad
2030 1.1 brad return 0;
2031 1.1 brad }
2032 1.1 brad
2033 1.1 brad static int
2034 1.1 brad umcpmio_activate(device_t self, enum devact act)
2035 1.1 brad {
2036 1.1 brad struct umcpmio_softc *sc = device_private(self);
2037 1.1 brad
2038 1.1 brad DPRINTFN(5,("umcpmio_activate: %d\n", act));
2039 1.1 brad
2040 1.1 brad switch (act) {
2041 1.1 brad case DVACT_DEACTIVATE:
2042 1.1 brad sc->sc_dying = 1;
2043 1.1 brad return 0;
2044 1.1 brad default:
2045 1.1 brad return EOPNOTSUPP;
2046 1.1 brad }
2047 1.1 brad }
2048