Home | History | Annotate | Line # | Download | only in usb
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, &current_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, &current_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, &current_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, &current_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