1c178a7e7SAndriy Gapon /*- 2c178a7e7SAndriy Gapon * SPDX-License-Identifier: BSD-2-Clause 3c178a7e7SAndriy Gapon * 4c178a7e7SAndriy Gapon * Copyright (c) Andriy Gapon 5c178a7e7SAndriy Gapon * 6c178a7e7SAndriy Gapon * Redistribution and use in source and binary forms, with or without 7c178a7e7SAndriy Gapon * modification, are permitted provided that the following conditions 8c178a7e7SAndriy Gapon * are met: 9c178a7e7SAndriy Gapon * 1. Redistributions of source code must retain the above copyright 10c178a7e7SAndriy Gapon * notice, this list of conditions, and the following disclaimer. 11c178a7e7SAndriy Gapon * 2. Redistributions in binary form must reproduce the above copyright 12c178a7e7SAndriy Gapon * notice, this list of conditions and the following disclaimer in the 13c178a7e7SAndriy Gapon * documentation and/or other materials provided with the distribution. 14c178a7e7SAndriy Gapon * 15c178a7e7SAndriy Gapon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16c178a7e7SAndriy Gapon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17c178a7e7SAndriy Gapon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18c178a7e7SAndriy Gapon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19c178a7e7SAndriy Gapon * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20c178a7e7SAndriy Gapon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21c178a7e7SAndriy Gapon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22c178a7e7SAndriy Gapon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23c178a7e7SAndriy Gapon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24c178a7e7SAndriy Gapon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25c178a7e7SAndriy Gapon * SUCH DAMAGE. 26c178a7e7SAndriy Gapon * 27c178a7e7SAndriy Gapon */ 28c178a7e7SAndriy Gapon 29c178a7e7SAndriy Gapon /* 30c178a7e7SAndriy Gapon * Hardware information links: 31c178a7e7SAndriy Gapon * - CP2112 Datasheet 32c178a7e7SAndriy Gapon * https://www.silabs.com/documents/public/data-sheets/cp2112-datasheet.pdf 33c178a7e7SAndriy Gapon * - AN495: CP2112 Interface Specification 34c178a7e7SAndriy Gapon * https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf 35c178a7e7SAndriy Gapon * - CP2112 Errata 36c178a7e7SAndriy Gapon * https://www.silabs.com/documents/public/errata/cp2112-errata.pdf 37c178a7e7SAndriy Gapon */ 38c178a7e7SAndriy Gapon 39c178a7e7SAndriy Gapon #include <sys/cdefs.h> 40c178a7e7SAndriy Gapon __FBSDID("$FreeBSD$"); 41c178a7e7SAndriy Gapon 42c178a7e7SAndriy Gapon #include <sys/param.h> 43c178a7e7SAndriy Gapon #include <sys/systm.h> 44c178a7e7SAndriy Gapon #include <sys/condvar.h> 45c178a7e7SAndriy Gapon #include <sys/bus.h> 46c178a7e7SAndriy Gapon #include <sys/gpio.h> 47c178a7e7SAndriy Gapon #include <sys/kernel.h> 48c178a7e7SAndriy Gapon #include <sys/lock.h> 49c178a7e7SAndriy Gapon #include <sys/module.h> 50c178a7e7SAndriy Gapon #include <sys/mutex.h> 51c178a7e7SAndriy Gapon #include <sys/sdt.h> 52c178a7e7SAndriy Gapon #include <sys/sx.h> 53c178a7e7SAndriy Gapon 54c178a7e7SAndriy Gapon #include <dev/gpio/gpiobusvar.h> 55c178a7e7SAndriy Gapon 56c178a7e7SAndriy Gapon #include <dev/iicbus/iiconf.h> 57c178a7e7SAndriy Gapon #include <dev/iicbus/iicbus.h> 58c178a7e7SAndriy Gapon #include "iicbus_if.h" 59c178a7e7SAndriy Gapon 60c178a7e7SAndriy Gapon #include <dev/usb/usb.h> 61c178a7e7SAndriy Gapon #include <dev/usb/usbdi.h> 62c178a7e7SAndriy Gapon #include <dev/usb/usbdi_util.h> 63c178a7e7SAndriy Gapon #include <dev/usb/usbhid.h> 64c178a7e7SAndriy Gapon #include "usbdevs.h" 65c178a7e7SAndriy Gapon 66c178a7e7SAndriy Gapon #define USB_DEBUG_VAR usb_debug 67c178a7e7SAndriy Gapon #include <dev/usb/usb_debug.h> 68c178a7e7SAndriy Gapon 69ef32901bSAndriy Gapon #define SIZEOF_FIELD(_s, _f) sizeof(((struct _s *)NULL)->_f) 70ef32901bSAndriy Gapon 71c178a7e7SAndriy Gapon #define CP2112GPIO_LOCK(sc) sx_xlock(&sc->gpio_lock) 72c178a7e7SAndriy Gapon #define CP2112GPIO_UNLOCK(sc) sx_xunlock(&sc->gpio_lock) 73c178a7e7SAndriy Gapon #define CP2112GPIO_LOCKED(sc) sx_assert(&sc->gpio_lock, SX_XLOCKED) 74c178a7e7SAndriy Gapon 75c178a7e7SAndriy Gapon #define CP2112_PART_NUM 0x0c 76c178a7e7SAndriy Gapon #define CP2112_GPIO_COUNT 8 77c178a7e7SAndriy Gapon #define CP2112_REPORT_SIZE 64 78c178a7e7SAndriy Gapon 79c178a7e7SAndriy Gapon #define CP2112_REQ_RESET 0x1 80c178a7e7SAndriy Gapon #define CP2112_REQ_GPIO_CFG 0x2 81c178a7e7SAndriy Gapon #define CP2112_REQ_GPIO_GET 0x3 82c178a7e7SAndriy Gapon #define CP2112_REQ_GPIO_SET 0x4 83c178a7e7SAndriy Gapon #define CP2112_REQ_VERSION 0x5 84c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_CFG 0x6 85c178a7e7SAndriy Gapon 86c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_READ 0x10 87c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_WRITE_READ 0x11 88c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_READ_FORCE_SEND 0x12 89c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_READ_RESPONSE 0x13 90c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_WRITE 0x14 91c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_XFER_STATUS_REQ 0x15 92c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_XFER_STATUS_RESP 0x16 93c178a7e7SAndriy Gapon #define CP2112_REQ_SMB_CANCEL 0x17 94c178a7e7SAndriy Gapon 95c178a7e7SAndriy Gapon #define CP2112_REQ_LOCK 0x20 96c178a7e7SAndriy Gapon #define CP2112_REQ_USB_CFG 0x21 97c178a7e7SAndriy Gapon 98ef32901bSAndriy Gapon #define CP2112_IIC_MAX_READ_LEN 512 99c178a7e7SAndriy Gapon #define CP2112_IIC_REPSTART_VER 2 /* Erratum CP2112_E10. */ 100c178a7e7SAndriy Gapon 101ef32901bSAndriy Gapon #define CP2112_GPIO_SPEC_CLK7 1 /* Pin 7 is clock output. */ 102ef32901bSAndriy Gapon #define CP2112_GPIO_SPEC_TX0 2 /* Pin 0 pulses on USB TX. */ 103ef32901bSAndriy Gapon #define CP2112_GPIO_SPEC_RX1 4 /* Pin 1 pulses on USB RX. */ 104ef32901bSAndriy Gapon 105c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS0_IDLE 0 106c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS0_BUSY 1 107c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS0_CMP 2 108c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS0_ERROR 3 109c178a7e7SAndriy Gapon 110c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS1_TIMEOUT_NACK 0 111c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS1_TIMEOUT_BUS 1 112c178a7e7SAndriy Gapon #define CP2112_IIC_STATUS1_ARB_LOST 2 113c178a7e7SAndriy Gapon 114ef32901bSAndriy Gapon /* CP2112_REQ_VERSION */ 115ef32901bSAndriy Gapon struct version_request { 116ef32901bSAndriy Gapon uint8_t id; 117ef32901bSAndriy Gapon uint8_t part_num; 118ef32901bSAndriy Gapon uint8_t version; 119ef32901bSAndriy Gapon } __packed; 120ef32901bSAndriy Gapon 121ef32901bSAndriy Gapon /* CP2112_REQ_GPIO_GET */ 122ef32901bSAndriy Gapon struct gpio_get_req { 123ef32901bSAndriy Gapon uint8_t id; 124ef32901bSAndriy Gapon uint8_t state; 125ef32901bSAndriy Gapon } __packed; 126ef32901bSAndriy Gapon 127ef32901bSAndriy Gapon /* CP2112_REQ_GPIO_SET */ 128ef32901bSAndriy Gapon struct gpio_set_req { 129ef32901bSAndriy Gapon uint8_t id; 130ef32901bSAndriy Gapon uint8_t state; 131ef32901bSAndriy Gapon uint8_t mask; 132ef32901bSAndriy Gapon } __packed; 133ef32901bSAndriy Gapon 134ef32901bSAndriy Gapon /* CP2112_REQ_GPIO_CFG */ 135ef32901bSAndriy Gapon struct gpio_config_req { 136ef32901bSAndriy Gapon uint8_t id; 137ef32901bSAndriy Gapon uint8_t output; 138ef32901bSAndriy Gapon uint8_t pushpull; 139ef32901bSAndriy Gapon uint8_t special; 140ef32901bSAndriy Gapon uint8_t divider; 141ef32901bSAndriy Gapon } __packed; 142ef32901bSAndriy Gapon 143ef32901bSAndriy Gapon /* CP2112_REQ_SMB_XFER_STATUS_REQ */ 144ef32901bSAndriy Gapon struct i2c_xfer_status_req { 145ef32901bSAndriy Gapon uint8_t id; 146ef32901bSAndriy Gapon uint8_t request; 147ef32901bSAndriy Gapon } __packed; 148ef32901bSAndriy Gapon 149ef32901bSAndriy Gapon /* CP2112_REQ_SMB_XFER_STATUS_RESP */ 150ef32901bSAndriy Gapon struct i2c_xfer_status_resp { 151ef32901bSAndriy Gapon uint8_t id; 152ef32901bSAndriy Gapon uint8_t status0; 153ef32901bSAndriy Gapon uint8_t status1; 154ef32901bSAndriy Gapon uint16_t status2; 155ef32901bSAndriy Gapon uint16_t status3; 156ef32901bSAndriy Gapon } __packed; 157ef32901bSAndriy Gapon 158ef32901bSAndriy Gapon /* CP2112_REQ_SMB_READ_FORCE_SEND */ 159ef32901bSAndriy Gapon struct i2c_data_read_force_send_req { 160ef32901bSAndriy Gapon uint8_t id; 161ef32901bSAndriy Gapon uint16_t len; 162ef32901bSAndriy Gapon } __packed; 163ef32901bSAndriy Gapon 164ef32901bSAndriy Gapon /* CP2112_REQ_SMB_READ_RESPONSE */ 165ef32901bSAndriy Gapon struct i2c_data_read_resp { 166ef32901bSAndriy Gapon uint8_t id; 167ef32901bSAndriy Gapon uint8_t status; 168ef32901bSAndriy Gapon uint8_t len; 169ef32901bSAndriy Gapon uint8_t data[61]; 170ef32901bSAndriy Gapon } __packed; 171ef32901bSAndriy Gapon 172ef32901bSAndriy Gapon /* CP2112_REQ_SMB_READ */ 173ef32901bSAndriy Gapon struct i2c_write_read_req { 174ef32901bSAndriy Gapon uint8_t id; 175ef32901bSAndriy Gapon uint8_t slave; 176ef32901bSAndriy Gapon uint16_t rlen; 177ef32901bSAndriy Gapon uint8_t wlen; 178ef32901bSAndriy Gapon uint8_t wdata[16]; 179ef32901bSAndriy Gapon } __packed; 180ef32901bSAndriy Gapon 181ef32901bSAndriy Gapon /* CP2112_REQ_SMB_WRITE */ 182ef32901bSAndriy Gapon struct i2c_read_req { 183ef32901bSAndriy Gapon uint8_t id; 184ef32901bSAndriy Gapon uint8_t slave; 185ef32901bSAndriy Gapon uint16_t len; 186ef32901bSAndriy Gapon } __packed; 187ef32901bSAndriy Gapon 188ef32901bSAndriy Gapon /* CP2112_REQ_SMB_WRITE_READ */ 189ef32901bSAndriy Gapon struct i2c_write_req { 190ef32901bSAndriy Gapon uint8_t id; 191ef32901bSAndriy Gapon uint8_t slave; 192ef32901bSAndriy Gapon uint8_t len; 193ef32901bSAndriy Gapon uint8_t data[61]; 194ef32901bSAndriy Gapon } __packed; 195ef32901bSAndriy Gapon 196ef32901bSAndriy Gapon /* CP2112_REQ_SMB_CFG */ 197ef32901bSAndriy Gapon struct i2c_cfg_req { 198ef32901bSAndriy Gapon uint8_t id; 199ef32901bSAndriy Gapon uint32_t speed; /* Hz */ 200ef32901bSAndriy Gapon uint8_t slave_addr; /* ACK only */ 201ef32901bSAndriy Gapon uint8_t auto_send_read; /* boolean */ 202ef32901bSAndriy Gapon uint16_t write_timeout; /* 0-1000 ms, 0 ~ no timeout */ 203ef32901bSAndriy Gapon uint16_t read_timeout; /* 0-1000 ms, 0 ~ no timeout */ 204ef32901bSAndriy Gapon uint8_t scl_low_timeout;/* boolean */ 205ef32901bSAndriy Gapon uint16_t retry_count; /* 1-1000, 0 ~ forever */ 206ef32901bSAndriy Gapon } __packed; 207ef32901bSAndriy Gapon 208ef32901bSAndriy Gapon enum cp2112_out_mode { 209ef32901bSAndriy Gapon OUT_OD, 210ef32901bSAndriy Gapon OUT_PP, 211ef32901bSAndriy Gapon OUT_KEEP 212ef32901bSAndriy Gapon }; 213ef32901bSAndriy Gapon 214ef32901bSAndriy Gapon enum { 215ef32901bSAndriy Gapon CP2112_INTR_OUT = 0, 216ef32901bSAndriy Gapon CP2112_INTR_IN, 217ef32901bSAndriy Gapon CP2112_N_TRANSFER, 218ef32901bSAndriy Gapon }; 219c178a7e7SAndriy Gapon 220c178a7e7SAndriy Gapon struct cp2112_softc { 221c178a7e7SAndriy Gapon device_t sc_gpio_dev; 222c178a7e7SAndriy Gapon device_t sc_iic_dev; 223c178a7e7SAndriy Gapon struct usb_device *sc_udev; 224c178a7e7SAndriy Gapon uint8_t sc_iface_index; 225c178a7e7SAndriy Gapon uint8_t sc_version; 226c178a7e7SAndriy Gapon }; 227c178a7e7SAndriy Gapon 228c178a7e7SAndriy Gapon struct cp2112gpio_softc { 229c178a7e7SAndriy Gapon struct sx gpio_lock; 230c178a7e7SAndriy Gapon device_t busdev; 231c178a7e7SAndriy Gapon int gpio_caps; 232c178a7e7SAndriy Gapon struct gpio_pin pins[CP2112_GPIO_COUNT]; 233c178a7e7SAndriy Gapon }; 234c178a7e7SAndriy Gapon 235ef32901bSAndriy Gapon struct cp2112iic_softc { 236ef32901bSAndriy Gapon device_t dev; 237ef32901bSAndriy Gapon device_t iicbus_dev; 238ef32901bSAndriy Gapon struct usb_xfer *xfers[CP2112_N_TRANSFER]; 239ef32901bSAndriy Gapon u_char own_addr; 240ef32901bSAndriy Gapon struct { 241ef32901bSAndriy Gapon struct mtx lock; 242ef32901bSAndriy Gapon struct cv cv; 243ef32901bSAndriy Gapon struct { 244ef32901bSAndriy Gapon uint8_t *data; 245ef32901bSAndriy Gapon int len; 246ef32901bSAndriy Gapon int done; 247ef32901bSAndriy Gapon int error; 248ef32901bSAndriy Gapon } in; 249ef32901bSAndriy Gapon struct { 250ef32901bSAndriy Gapon const uint8_t *data; 251ef32901bSAndriy Gapon int len; 252ef32901bSAndriy Gapon int done; 253ef32901bSAndriy Gapon int error; 254ef32901bSAndriy Gapon } out; 255ef32901bSAndriy Gapon } io; 256ef32901bSAndriy Gapon }; 257ef32901bSAndriy Gapon 258c178a7e7SAndriy Gapon static int cp2112_detach(device_t dev); 259c178a7e7SAndriy Gapon static int cp2112gpio_detach(device_t dev); 260c178a7e7SAndriy Gapon static int cp2112iic_detach(device_t dev); 261c178a7e7SAndriy Gapon 262ef32901bSAndriy Gapon static const STRUCT_USB_HOST_ID cp2112_devs[] = { 263ef32901bSAndriy Gapon { USB_VP(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP2112) }, 264ef32901bSAndriy Gapon { USB_VP(0x1009, USB_PRODUCT_SILABS_CP2112) }, /* XXX */ 265ef32901bSAndriy Gapon }; 266ef32901bSAndriy Gapon 267c178a7e7SAndriy Gapon static int 268c178a7e7SAndriy Gapon cp2112_get_report(device_t dev, uint8_t id, void *data, uint16_t len) 269c178a7e7SAndriy Gapon { 270c178a7e7SAndriy Gapon struct cp2112_softc *sc; 271c178a7e7SAndriy Gapon int err; 272c178a7e7SAndriy Gapon 273c178a7e7SAndriy Gapon sc = device_get_softc(dev); 274c178a7e7SAndriy Gapon err = usbd_req_get_report(sc->sc_udev, NULL, data, 275c178a7e7SAndriy Gapon len, sc->sc_iface_index, UHID_FEATURE_REPORT, id); 276c178a7e7SAndriy Gapon return (err); 277c178a7e7SAndriy Gapon } 278c178a7e7SAndriy Gapon 279c178a7e7SAndriy Gapon static int 280c178a7e7SAndriy Gapon cp2112_set_report(device_t dev, uint8_t id, void *data, uint16_t len) 281c178a7e7SAndriy Gapon { 282c178a7e7SAndriy Gapon struct cp2112_softc *sc; 283c178a7e7SAndriy Gapon int err; 284c178a7e7SAndriy Gapon 285c178a7e7SAndriy Gapon sc = device_get_softc(dev); 286ef32901bSAndriy Gapon *(uint8_t *)data = id; 287c178a7e7SAndriy Gapon err = usbd_req_set_report(sc->sc_udev, NULL, data, 288c178a7e7SAndriy Gapon len, sc->sc_iface_index, UHID_FEATURE_REPORT, id); 289c178a7e7SAndriy Gapon return (err); 290c178a7e7SAndriy Gapon } 291c178a7e7SAndriy Gapon 292c178a7e7SAndriy Gapon static int 293ef32901bSAndriy Gapon cp2112_probe(device_t dev) 294ef32901bSAndriy Gapon { 295ef32901bSAndriy Gapon struct usb_attach_arg *uaa; 296ef32901bSAndriy Gapon 297ef32901bSAndriy Gapon uaa = device_get_ivars(dev); 298ef32901bSAndriy Gapon if (uaa->usb_mode != USB_MODE_HOST) 299ef32901bSAndriy Gapon return (ENXIO); 300ef32901bSAndriy Gapon if (uaa->info.bInterfaceClass != UICLASS_HID) 301ef32901bSAndriy Gapon return (ENXIO); 302ef32901bSAndriy Gapon 303ef32901bSAndriy Gapon if (usbd_lookup_id_by_uaa(cp2112_devs, sizeof(cp2112_devs), uaa) == 0) 304ef32901bSAndriy Gapon return (BUS_PROBE_DEFAULT); 305ef32901bSAndriy Gapon return (ENXIO); 306ef32901bSAndriy Gapon } 307ef32901bSAndriy Gapon 308ef32901bSAndriy Gapon static int 309ef32901bSAndriy Gapon cp2112_attach(device_t dev) 310ef32901bSAndriy Gapon { 311ef32901bSAndriy Gapon struct version_request vdata; 312ef32901bSAndriy Gapon struct usb_attach_arg *uaa; 313ef32901bSAndriy Gapon struct cp2112_softc *sc; 314ef32901bSAndriy Gapon int err; 315ef32901bSAndriy Gapon 316ef32901bSAndriy Gapon uaa = device_get_ivars(dev); 317ef32901bSAndriy Gapon sc = device_get_softc(dev); 318ef32901bSAndriy Gapon 319ef32901bSAndriy Gapon device_set_usb_desc(dev); 320ef32901bSAndriy Gapon 321ef32901bSAndriy Gapon sc->sc_udev = uaa->device; 322ef32901bSAndriy Gapon sc->sc_iface_index = uaa->info.bIfaceIndex; 323ef32901bSAndriy Gapon 324ef32901bSAndriy Gapon err = cp2112_get_report(dev, CP2112_REQ_VERSION, &vdata, sizeof(vdata)); 325ef32901bSAndriy Gapon if (err != 0) 326ef32901bSAndriy Gapon goto detach; 327ef32901bSAndriy Gapon device_printf(dev, "part number 0x%02x, version 0x%02x\n", 328ef32901bSAndriy Gapon vdata.part_num, vdata.version); 329ef32901bSAndriy Gapon if (vdata.part_num != CP2112_PART_NUM) { 330ef32901bSAndriy Gapon device_printf(dev, "unsupported part number\n"); 331ef32901bSAndriy Gapon goto detach; 332ef32901bSAndriy Gapon } 333ef32901bSAndriy Gapon sc->sc_version = vdata.version; 334ef32901bSAndriy Gapon sc->sc_gpio_dev = device_add_child(dev, "gpio", -1); 335ef32901bSAndriy Gapon if (sc->sc_gpio_dev != NULL) { 336ef32901bSAndriy Gapon err = device_probe_and_attach(sc->sc_gpio_dev); 337ef32901bSAndriy Gapon if (err != 0) { 338ef32901bSAndriy Gapon device_printf(dev, "failed to attach gpio child\n"); 339ef32901bSAndriy Gapon } 340ef32901bSAndriy Gapon } else { 341ef32901bSAndriy Gapon device_printf(dev, "failed to create gpio child\n"); 342ef32901bSAndriy Gapon } 343ef32901bSAndriy Gapon 344ef32901bSAndriy Gapon sc->sc_iic_dev = device_add_child(dev, "iichb", -1); 345ef32901bSAndriy Gapon if (sc->sc_iic_dev != NULL) { 346ef32901bSAndriy Gapon err = device_probe_and_attach(sc->sc_iic_dev); 347ef32901bSAndriy Gapon if (err != 0) { 348ef32901bSAndriy Gapon device_printf(dev, "failed to attach iic child\n"); 349ef32901bSAndriy Gapon } 350ef32901bSAndriy Gapon } else { 351ef32901bSAndriy Gapon device_printf(dev, "failed to create iic child\n"); 352ef32901bSAndriy Gapon } 353ef32901bSAndriy Gapon 354ef32901bSAndriy Gapon return (0); 355ef32901bSAndriy Gapon 356ef32901bSAndriy Gapon detach: 357ef32901bSAndriy Gapon cp2112_detach(dev); 358ef32901bSAndriy Gapon return (ENXIO); 359ef32901bSAndriy Gapon } 360ef32901bSAndriy Gapon 361ef32901bSAndriy Gapon static int 362ef32901bSAndriy Gapon cp2112_detach(device_t dev) 363ef32901bSAndriy Gapon { 364ef32901bSAndriy Gapon int err; 365ef32901bSAndriy Gapon 366ef32901bSAndriy Gapon err = bus_generic_detach(dev); 367ef32901bSAndriy Gapon if (err != 0) 368ef32901bSAndriy Gapon return (err); 369ef32901bSAndriy Gapon device_delete_children(dev); 370ef32901bSAndriy Gapon return (0); 371ef32901bSAndriy Gapon } 372ef32901bSAndriy Gapon 373ef32901bSAndriy Gapon static int 374c178a7e7SAndriy Gapon cp2112_gpio_read_pin(device_t dev, uint32_t pin_num, bool *on) 375c178a7e7SAndriy Gapon { 376ef32901bSAndriy Gapon struct gpio_get_req data; 3771c5f1882SJohn Baldwin struct cp2112gpio_softc *sc __diagused; 378c178a7e7SAndriy Gapon int err; 379c178a7e7SAndriy Gapon 380c178a7e7SAndriy Gapon sc = device_get_softc(dev); 381c178a7e7SAndriy Gapon CP2112GPIO_LOCKED(sc); 382c178a7e7SAndriy Gapon 383c178a7e7SAndriy Gapon err = cp2112_get_report(device_get_parent(dev), 384c178a7e7SAndriy Gapon CP2112_REQ_GPIO_GET, &data, sizeof(data)); 385c178a7e7SAndriy Gapon if (err != 0) 386c178a7e7SAndriy Gapon return (err); 387c178a7e7SAndriy Gapon *on = (data.state & ((uint8_t)1 << pin_num)) != 0; 388c178a7e7SAndriy Gapon return (0); 389c178a7e7SAndriy Gapon 390c178a7e7SAndriy Gapon } 391c178a7e7SAndriy Gapon 392c178a7e7SAndriy Gapon static int 393c178a7e7SAndriy Gapon cp2112_gpio_write_pin(device_t dev, uint32_t pin_num, bool on) 394c178a7e7SAndriy Gapon { 395ef32901bSAndriy Gapon struct gpio_set_req data; 3961c5f1882SJohn Baldwin struct cp2112gpio_softc *sc __diagused; 397c178a7e7SAndriy Gapon int err; 398c178a7e7SAndriy Gapon bool actual; 399c178a7e7SAndriy Gapon 400c178a7e7SAndriy Gapon sc = device_get_softc(dev); 401c178a7e7SAndriy Gapon CP2112GPIO_LOCKED(sc); 402c178a7e7SAndriy Gapon 403c178a7e7SAndriy Gapon data.state = (uint8_t)on << pin_num; 404c178a7e7SAndriy Gapon data.mask = (uint8_t)1 << pin_num; 405c178a7e7SAndriy Gapon err = cp2112_set_report(device_get_parent(dev), 406c178a7e7SAndriy Gapon CP2112_REQ_GPIO_SET, &data, sizeof(data)); 407c178a7e7SAndriy Gapon if (err != 0) 408c178a7e7SAndriy Gapon return (err); 409c178a7e7SAndriy Gapon err = cp2112_gpio_read_pin(dev, pin_num, &actual); 410c178a7e7SAndriy Gapon if (err != 0) 411c178a7e7SAndriy Gapon return (err); 412c178a7e7SAndriy Gapon if (actual != on) 413c178a7e7SAndriy Gapon return (EIO); 414c178a7e7SAndriy Gapon return (0); 415c178a7e7SAndriy Gapon } 416c178a7e7SAndriy Gapon 417c178a7e7SAndriy Gapon static int 418c178a7e7SAndriy Gapon cp2112_gpio_configure_write_pin(device_t dev, uint32_t pin_num, 419ef32901bSAndriy Gapon bool output, enum cp2112_out_mode *mode) 420c178a7e7SAndriy Gapon { 421ef32901bSAndriy Gapon struct gpio_config_req data; 4221c5f1882SJohn Baldwin struct cp2112gpio_softc *sc __diagused; 423c178a7e7SAndriy Gapon int err; 424c178a7e7SAndriy Gapon uint8_t mask; 425c178a7e7SAndriy Gapon 426c178a7e7SAndriy Gapon sc = device_get_softc(dev); 427c178a7e7SAndriy Gapon CP2112GPIO_LOCKED(sc); 428c178a7e7SAndriy Gapon 429c178a7e7SAndriy Gapon err = cp2112_get_report(device_get_parent(dev), 430c178a7e7SAndriy Gapon CP2112_REQ_GPIO_CFG, &data, sizeof(data)); 431c178a7e7SAndriy Gapon if (err != 0) 432c178a7e7SAndriy Gapon return (err); 433ef32901bSAndriy Gapon 434ef32901bSAndriy Gapon mask = (uint8_t)1 << pin_num; 435c178a7e7SAndriy Gapon if (output) { 436c178a7e7SAndriy Gapon data.output |= mask; 437ef32901bSAndriy Gapon switch (*mode) { 438ef32901bSAndriy Gapon case OUT_PP: 439c178a7e7SAndriy Gapon data.pushpull |= mask; 440ef32901bSAndriy Gapon break; 441ef32901bSAndriy Gapon case OUT_OD: 442c178a7e7SAndriy Gapon data.pushpull &= ~mask; 443ef32901bSAndriy Gapon break; 444ef32901bSAndriy Gapon default: 445ef32901bSAndriy Gapon break; 446ef32901bSAndriy Gapon } 447c178a7e7SAndriy Gapon } else { 448c178a7e7SAndriy Gapon data.output &= ~mask; 449c178a7e7SAndriy Gapon } 450c178a7e7SAndriy Gapon 451c178a7e7SAndriy Gapon err = cp2112_set_report(device_get_parent(dev), 452c178a7e7SAndriy Gapon CP2112_REQ_GPIO_CFG, &data, sizeof(data)); 453c178a7e7SAndriy Gapon if (err != 0) 454c178a7e7SAndriy Gapon return (err); 455c178a7e7SAndriy Gapon 456c178a7e7SAndriy Gapon /* Read back and verify. */ 457c178a7e7SAndriy Gapon err = cp2112_get_report(device_get_parent(dev), 458c178a7e7SAndriy Gapon CP2112_REQ_GPIO_CFG, &data, sizeof(data)); 459c178a7e7SAndriy Gapon if (err != 0) 460c178a7e7SAndriy Gapon return (err); 461ef32901bSAndriy Gapon 462c178a7e7SAndriy Gapon if (((data.output & mask) != 0) != output) 463c178a7e7SAndriy Gapon return (EIO); 464ef32901bSAndriy Gapon if (output) { 465ef32901bSAndriy Gapon switch (*mode) { 466ef32901bSAndriy Gapon case OUT_PP: 467ef32901bSAndriy Gapon if ((data.pushpull & mask) == 0) 468c178a7e7SAndriy Gapon return (EIO); 469ef32901bSAndriy Gapon break; 470ef32901bSAndriy Gapon case OUT_OD: 471ef32901bSAndriy Gapon if ((data.pushpull & mask) != 0) 472ef32901bSAndriy Gapon return (EIO); 473ef32901bSAndriy Gapon break; 474ef32901bSAndriy Gapon default: 475ef32901bSAndriy Gapon *mode = (data.pushpull & mask) != 0 ? 476ef32901bSAndriy Gapon OUT_PP : OUT_OD; 477ef32901bSAndriy Gapon break; 478ef32901bSAndriy Gapon } 479ef32901bSAndriy Gapon } 480c178a7e7SAndriy Gapon return (0); 481c178a7e7SAndriy Gapon } 482c178a7e7SAndriy Gapon 483c178a7e7SAndriy Gapon static device_t 484c178a7e7SAndriy Gapon cp2112_gpio_get_bus(device_t dev) 485c178a7e7SAndriy Gapon { 486c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 487c178a7e7SAndriy Gapon 488c178a7e7SAndriy Gapon sc = device_get_softc(dev); 489c178a7e7SAndriy Gapon return (sc->busdev); 490c178a7e7SAndriy Gapon } 491c178a7e7SAndriy Gapon 492c178a7e7SAndriy Gapon static int 493c178a7e7SAndriy Gapon cp2112_gpio_pin_max(device_t dev, int *maxpin) 494c178a7e7SAndriy Gapon { 495c178a7e7SAndriy Gapon 496c178a7e7SAndriy Gapon *maxpin = CP2112_GPIO_COUNT - 1; 497c178a7e7SAndriy Gapon return (0); 498c178a7e7SAndriy Gapon } 499c178a7e7SAndriy Gapon 500c178a7e7SAndriy Gapon static int 501c178a7e7SAndriy Gapon cp2112_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value) 502c178a7e7SAndriy Gapon { 503c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 504c178a7e7SAndriy Gapon int err; 505c178a7e7SAndriy Gapon 506c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 507c178a7e7SAndriy Gapon return (EINVAL); 508c178a7e7SAndriy Gapon 509c178a7e7SAndriy Gapon sc = device_get_softc(dev); 510c178a7e7SAndriy Gapon CP2112GPIO_LOCK(sc); 511c178a7e7SAndriy Gapon err = cp2112_gpio_write_pin(dev, pin_num, pin_value != 0); 512c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 513c178a7e7SAndriy Gapon 514c178a7e7SAndriy Gapon return (err); 515c178a7e7SAndriy Gapon } 516c178a7e7SAndriy Gapon 517c178a7e7SAndriy Gapon static int 518c178a7e7SAndriy Gapon cp2112_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value) 519c178a7e7SAndriy Gapon { 520c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 521c178a7e7SAndriy Gapon int err; 522c178a7e7SAndriy Gapon bool on; 523c178a7e7SAndriy Gapon 524c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 525c178a7e7SAndriy Gapon return (EINVAL); 526c178a7e7SAndriy Gapon 527c178a7e7SAndriy Gapon sc = device_get_softc(dev); 528c178a7e7SAndriy Gapon CP2112GPIO_LOCK(sc); 529c178a7e7SAndriy Gapon err = cp2112_gpio_read_pin(dev, pin_num, &on); 530c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 531c178a7e7SAndriy Gapon 532c178a7e7SAndriy Gapon if (err == 0) 533c178a7e7SAndriy Gapon *pin_value = on; 534c178a7e7SAndriy Gapon return (err); 535c178a7e7SAndriy Gapon } 536c178a7e7SAndriy Gapon 537c178a7e7SAndriy Gapon static int 538c178a7e7SAndriy Gapon cp2112_gpio_pin_toggle(device_t dev, uint32_t pin_num) 539c178a7e7SAndriy Gapon { 540c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 541c178a7e7SAndriy Gapon int err; 542c178a7e7SAndriy Gapon bool on; 543c178a7e7SAndriy Gapon 544c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 545c178a7e7SAndriy Gapon return (EINVAL); 546c178a7e7SAndriy Gapon 547c178a7e7SAndriy Gapon sc = device_get_softc(dev); 548c178a7e7SAndriy Gapon CP2112GPIO_LOCK(sc); 549c178a7e7SAndriy Gapon err = cp2112_gpio_read_pin(dev, pin_num, &on); 550c178a7e7SAndriy Gapon if (err == 0) 551c178a7e7SAndriy Gapon err = cp2112_gpio_write_pin(dev, pin_num, !on); 552c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 553c178a7e7SAndriy Gapon 554c178a7e7SAndriy Gapon return (err); 555c178a7e7SAndriy Gapon } 556c178a7e7SAndriy Gapon 557c178a7e7SAndriy Gapon static int 558c178a7e7SAndriy Gapon cp2112_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps) 559c178a7e7SAndriy Gapon { 560c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 561c178a7e7SAndriy Gapon 562c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 563c178a7e7SAndriy Gapon return (EINVAL); 564c178a7e7SAndriy Gapon 565c178a7e7SAndriy Gapon sc = device_get_softc(dev); 566c178a7e7SAndriy Gapon CP2112GPIO_LOCK(sc); 567c178a7e7SAndriy Gapon *caps = sc->gpio_caps; 568c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 569c178a7e7SAndriy Gapon 570c178a7e7SAndriy Gapon return (0); 571c178a7e7SAndriy Gapon } 572c178a7e7SAndriy Gapon 573c178a7e7SAndriy Gapon static int 574c178a7e7SAndriy Gapon cp2112_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags) 575c178a7e7SAndriy Gapon { 576c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 577c178a7e7SAndriy Gapon 578c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 579c178a7e7SAndriy Gapon return (EINVAL); 580c178a7e7SAndriy Gapon 581c178a7e7SAndriy Gapon sc = device_get_softc(dev); 582c178a7e7SAndriy Gapon CP2112GPIO_LOCK(sc); 583c178a7e7SAndriy Gapon *flags = sc->pins[pin_num].gp_flags; 584c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 585c178a7e7SAndriy Gapon 586c178a7e7SAndriy Gapon return (0); 587c178a7e7SAndriy Gapon } 588c178a7e7SAndriy Gapon 589c178a7e7SAndriy Gapon static int 590c178a7e7SAndriy Gapon cp2112_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name) 591c178a7e7SAndriy Gapon { 592c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 593c178a7e7SAndriy Gapon 594c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 595c178a7e7SAndriy Gapon return (EINVAL); 596c178a7e7SAndriy Gapon 597c178a7e7SAndriy Gapon sc = device_get_softc(dev); 598c178a7e7SAndriy Gapon CP2112GPIO_LOCK(sc); 599c178a7e7SAndriy Gapon memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME); 600c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 601c178a7e7SAndriy Gapon 602c178a7e7SAndriy Gapon return (0); 603c178a7e7SAndriy Gapon } 604c178a7e7SAndriy Gapon 605c178a7e7SAndriy Gapon static int 606c178a7e7SAndriy Gapon cp2112_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) 607c178a7e7SAndriy Gapon { 608c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 609c178a7e7SAndriy Gapon struct gpio_pin *pin; 610ef32901bSAndriy Gapon enum cp2112_out_mode out_mode; 611c178a7e7SAndriy Gapon int err; 612c178a7e7SAndriy Gapon 613c178a7e7SAndriy Gapon if (pin_num >= CP2112_GPIO_COUNT) 614c178a7e7SAndriy Gapon return (EINVAL); 615c178a7e7SAndriy Gapon 616c178a7e7SAndriy Gapon sc = device_get_softc(dev); 617c178a7e7SAndriy Gapon if ((flags & sc->gpio_caps) != flags) 618c178a7e7SAndriy Gapon return (EINVAL); 619c178a7e7SAndriy Gapon 620c178a7e7SAndriy Gapon if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0) 621c178a7e7SAndriy Gapon return (EINVAL); 622c178a7e7SAndriy Gapon if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 623c178a7e7SAndriy Gapon (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 624c178a7e7SAndriy Gapon return (EINVAL); 625c178a7e7SAndriy Gapon } 626c178a7e7SAndriy Gapon if ((flags & GPIO_PIN_INPUT) != 0) { 627c178a7e7SAndriy Gapon if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) != 0) 628c178a7e7SAndriy Gapon return (EINVAL); 629c178a7e7SAndriy Gapon } else { 630c178a7e7SAndriy Gapon if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) == 631c178a7e7SAndriy Gapon (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) 632c178a7e7SAndriy Gapon return (EINVAL); 633c178a7e7SAndriy Gapon } 634c178a7e7SAndriy Gapon 635c178a7e7SAndriy Gapon /* 636ef32901bSAndriy Gapon * If neither push-pull or open-drain is explicitly requested, then 637c178a7e7SAndriy Gapon * preserve the current state. 638c178a7e7SAndriy Gapon */ 639ef32901bSAndriy Gapon out_mode = OUT_KEEP; 640ef32901bSAndriy Gapon if ((flags & GPIO_PIN_OUTPUT) != 0) { 641ef32901bSAndriy Gapon if ((flags & GPIO_PIN_OPENDRAIN) != 0) 642ef32901bSAndriy Gapon out_mode = OUT_OD; 643ef32901bSAndriy Gapon if ((flags & GPIO_PIN_PUSHPULL) != 0) 644ef32901bSAndriy Gapon out_mode = OUT_PP; 645ef32901bSAndriy Gapon } 646ef32901bSAndriy Gapon 647ef32901bSAndriy Gapon CP2112GPIO_LOCK(sc); 648ef32901bSAndriy Gapon pin = &sc->pins[pin_num]; 649c178a7e7SAndriy Gapon err = cp2112_gpio_configure_write_pin(dev, pin_num, 650ef32901bSAndriy Gapon (flags & GPIO_PIN_OUTPUT) != 0, &out_mode); 651ef32901bSAndriy Gapon if (err == 0) { 652ef32901bSAndriy Gapon /* 653ef32901bSAndriy Gapon * If neither open-drain or push-pull was requested, then see 654ef32901bSAndriy Gapon * what hardware actually had. Otherwise, it has been 655ef32901bSAndriy Gapon * reconfigured as requested. 656ef32901bSAndriy Gapon */ 657ef32901bSAndriy Gapon if ((flags & GPIO_PIN_OUTPUT) != 0 && 658ef32901bSAndriy Gapon (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) == 0) { 659ef32901bSAndriy Gapon KASSERT(out_mode != OUT_KEEP, 660ef32901bSAndriy Gapon ("impossible current output mode")); 661ef32901bSAndriy Gapon if (out_mode == OUT_OD) 662ef32901bSAndriy Gapon flags |= GPIO_PIN_OPENDRAIN; 663ef32901bSAndriy Gapon else 664ef32901bSAndriy Gapon flags |= GPIO_PIN_PUSHPULL; 665ef32901bSAndriy Gapon } 666c178a7e7SAndriy Gapon pin->gp_flags = flags; 667ef32901bSAndriy Gapon } 668c178a7e7SAndriy Gapon CP2112GPIO_UNLOCK(sc); 669c178a7e7SAndriy Gapon 670c178a7e7SAndriy Gapon return (err); 671c178a7e7SAndriy Gapon } 672c178a7e7SAndriy Gapon 673c178a7e7SAndriy Gapon static int 674c178a7e7SAndriy Gapon cp2112gpio_probe(device_t dev) 675c178a7e7SAndriy Gapon { 676c178a7e7SAndriy Gapon device_set_desc(dev, "CP2112 GPIO interface"); 677c178a7e7SAndriy Gapon return (BUS_PROBE_SPECIFIC); 678c178a7e7SAndriy Gapon } 679c178a7e7SAndriy Gapon 680c178a7e7SAndriy Gapon static int 681c178a7e7SAndriy Gapon cp2112gpio_attach(device_t dev) 682c178a7e7SAndriy Gapon { 683ef32901bSAndriy Gapon struct gpio_config_req data; 684c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 685c178a7e7SAndriy Gapon device_t cp2112; 686c178a7e7SAndriy Gapon int err; 687c178a7e7SAndriy Gapon int i; 688c178a7e7SAndriy Gapon uint8_t mask; 689c178a7e7SAndriy Gapon 690c178a7e7SAndriy Gapon cp2112 = device_get_parent(dev); 691c178a7e7SAndriy Gapon sc = device_get_softc(dev); 692c178a7e7SAndriy Gapon sx_init(&sc->gpio_lock, "cp2112 lock"); 693c178a7e7SAndriy Gapon 694c178a7e7SAndriy Gapon sc->gpio_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 695c178a7e7SAndriy Gapon GPIO_PIN_PUSHPULL; 696c178a7e7SAndriy Gapon 697c178a7e7SAndriy Gapon err = cp2112_get_report(cp2112, CP2112_REQ_GPIO_CFG, 698c178a7e7SAndriy Gapon &data, sizeof(data)); 699c178a7e7SAndriy Gapon if (err != 0) 700c178a7e7SAndriy Gapon goto detach; 701c178a7e7SAndriy Gapon 702c178a7e7SAndriy Gapon for (i = 0; i < CP2112_GPIO_COUNT; i++) { 703c178a7e7SAndriy Gapon struct gpio_pin *pin; 704c178a7e7SAndriy Gapon 705c178a7e7SAndriy Gapon mask = (uint8_t)1 << i; 706c178a7e7SAndriy Gapon pin = &sc->pins[i]; 707c178a7e7SAndriy Gapon pin->gp_flags = 0; 708c178a7e7SAndriy Gapon 709c178a7e7SAndriy Gapon snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u", i); 710c178a7e7SAndriy Gapon pin->gp_name[GPIOMAXNAME - 1] = '\0'; 711c178a7e7SAndriy Gapon 712ef32901bSAndriy Gapon if ((i == 0 && (data.special & CP2112_GPIO_SPEC_TX0) != 0) || 713ef32901bSAndriy Gapon (i == 1 && (data.special & CP2112_GPIO_SPEC_RX1) != 0) || 714ef32901bSAndriy Gapon (i == 7 && (data.special & CP2112_GPIO_SPEC_CLK7) != 0)) { 715ef32901bSAndriy Gapon /* Special mode means that a pin is not for GPIO. */ 716ef32901bSAndriy Gapon } else if ((data.output & mask) != 0) { 717c178a7e7SAndriy Gapon pin->gp_flags |= GPIO_PIN_OUTPUT; 718c178a7e7SAndriy Gapon if ((data.pushpull & mask) != 0) 719c178a7e7SAndriy Gapon pin->gp_flags |= GPIO_PIN_PUSHPULL; 720c178a7e7SAndriy Gapon else 721c178a7e7SAndriy Gapon pin->gp_flags |= GPIO_PIN_OPENDRAIN; 722c178a7e7SAndriy Gapon } else { 723c178a7e7SAndriy Gapon pin->gp_flags |= GPIO_PIN_INPUT; 724c178a7e7SAndriy Gapon } 725c178a7e7SAndriy Gapon } 726c178a7e7SAndriy Gapon 727c178a7e7SAndriy Gapon sc->busdev = gpiobus_attach_bus(dev); 728c178a7e7SAndriy Gapon if (sc->busdev == NULL) { 729c178a7e7SAndriy Gapon device_printf(dev, "gpiobus_attach_bus failed\n"); 730c178a7e7SAndriy Gapon goto detach; 731c178a7e7SAndriy Gapon } 732c178a7e7SAndriy Gapon return (0); 733c178a7e7SAndriy Gapon 734c178a7e7SAndriy Gapon detach: 735c178a7e7SAndriy Gapon cp2112gpio_detach(dev); 736c178a7e7SAndriy Gapon return (ENXIO); 737c178a7e7SAndriy Gapon } 738c178a7e7SAndriy Gapon 739c178a7e7SAndriy Gapon static int 740c178a7e7SAndriy Gapon cp2112gpio_detach(device_t dev) 741c178a7e7SAndriy Gapon { 742c178a7e7SAndriy Gapon struct cp2112gpio_softc *sc; 743c178a7e7SAndriy Gapon 744c178a7e7SAndriy Gapon sc = device_get_softc(dev); 745c178a7e7SAndriy Gapon if (sc->busdev != NULL) 746c178a7e7SAndriy Gapon gpiobus_detach_bus(dev); 747c178a7e7SAndriy Gapon sx_destroy(&sc->gpio_lock); 748c178a7e7SAndriy Gapon return (0); 749c178a7e7SAndriy Gapon } 750c178a7e7SAndriy Gapon 751c178a7e7SAndriy Gapon static void 752c178a7e7SAndriy Gapon cp2112iic_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) 753c178a7e7SAndriy Gapon { 754c178a7e7SAndriy Gapon struct cp2112iic_softc *sc; 755c178a7e7SAndriy Gapon struct usb_page_cache *pc; 756c178a7e7SAndriy Gapon 757c178a7e7SAndriy Gapon sc = usbd_xfer_softc(xfer); 758c178a7e7SAndriy Gapon 759c178a7e7SAndriy Gapon mtx_assert(&sc->io.lock, MA_OWNED); 760c178a7e7SAndriy Gapon 761c178a7e7SAndriy Gapon switch (USB_GET_STATE(xfer)) { 762c178a7e7SAndriy Gapon case USB_ST_SETUP: 763c178a7e7SAndriy Gapon pc = usbd_xfer_get_frame(xfer, 0); 764c178a7e7SAndriy Gapon usbd_copy_in(pc, 0, sc->io.out.data, sc->io.out.len); 765c178a7e7SAndriy Gapon usbd_xfer_set_frame_len(xfer, 0, sc->io.out.len); 766c178a7e7SAndriy Gapon usbd_xfer_set_frames(xfer, 1); 767c178a7e7SAndriy Gapon usbd_transfer_submit(xfer); 768c178a7e7SAndriy Gapon break; 769c178a7e7SAndriy Gapon case USB_ST_TRANSFERRED: 770c178a7e7SAndriy Gapon sc->io.out.error = 0; 771c178a7e7SAndriy Gapon sc->io.out.done = 1; 772c178a7e7SAndriy Gapon cv_signal(&sc->io.cv); 773c178a7e7SAndriy Gapon break; 774c178a7e7SAndriy Gapon default: /* Error */ 775c178a7e7SAndriy Gapon device_printf(sc->dev, "write intr state %d error %d\n", 776c178a7e7SAndriy Gapon USB_GET_STATE(xfer), error); 777c178a7e7SAndriy Gapon sc->io.out.error = IIC_EBUSERR; 778c178a7e7SAndriy Gapon cv_signal(&sc->io.cv); 779c178a7e7SAndriy Gapon if (error != USB_ERR_CANCELLED) { 780c178a7e7SAndriy Gapon /* try to clear stall first */ 781c178a7e7SAndriy Gapon usbd_xfer_set_stall(xfer); 782c178a7e7SAndriy Gapon } 783c178a7e7SAndriy Gapon break; 784c178a7e7SAndriy Gapon } 785c178a7e7SAndriy Gapon } 786c178a7e7SAndriy Gapon 787c178a7e7SAndriy Gapon static void 788c178a7e7SAndriy Gapon cp2112iic_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) 789c178a7e7SAndriy Gapon { 790c178a7e7SAndriy Gapon struct cp2112iic_softc *sc = usbd_xfer_softc(xfer); 791c178a7e7SAndriy Gapon struct usb_page_cache *pc; 792c178a7e7SAndriy Gapon int act_len, len; 793c178a7e7SAndriy Gapon 794c178a7e7SAndriy Gapon mtx_assert(&sc->io.lock, MA_OWNED); 795c178a7e7SAndriy Gapon usbd_xfer_status(xfer, &act_len, NULL, NULL, NULL); 796c178a7e7SAndriy Gapon 797c178a7e7SAndriy Gapon switch (USB_GET_STATE(xfer)) { 798c178a7e7SAndriy Gapon case USB_ST_TRANSFERRED: 799c178a7e7SAndriy Gapon if (sc->io.in.done) { 800c178a7e7SAndriy Gapon device_printf(sc->dev, 801c178a7e7SAndriy Gapon "interrupt while previous is pending, ignored\n"); 802c178a7e7SAndriy Gapon } else if (sc->io.in.len == 0) { 803c178a7e7SAndriy Gapon uint8_t buf[8]; 804c178a7e7SAndriy Gapon 805c178a7e7SAndriy Gapon /* 806c178a7e7SAndriy Gapon * There is a spurious Transfer Status Response and 807c178a7e7SAndriy Gapon * zero-length Read Response during hardware 808c178a7e7SAndriy Gapon * configuration. Possibly they carry some information 809c178a7e7SAndriy Gapon * about the initial bus state. 810c178a7e7SAndriy Gapon */ 811c178a7e7SAndriy Gapon if (device_is_attached(sc->dev)) { 812c178a7e7SAndriy Gapon device_printf(sc->dev, 813c178a7e7SAndriy Gapon "unsolicited interrupt, ignored\n"); 814c178a7e7SAndriy Gapon if (bootverbose) { 815c178a7e7SAndriy Gapon pc = usbd_xfer_get_frame(xfer, 0); 816c178a7e7SAndriy Gapon len = MIN(sizeof(buf), act_len); 817c178a7e7SAndriy Gapon usbd_copy_out(pc, 0, buf, len); 818c178a7e7SAndriy Gapon device_printf(sc->dev, "data: %*D\n", 819c178a7e7SAndriy Gapon len, buf, " "); 820c178a7e7SAndriy Gapon } 821c178a7e7SAndriy Gapon } else { 822c178a7e7SAndriy Gapon pc = usbd_xfer_get_frame(xfer, 0); 823c178a7e7SAndriy Gapon len = MIN(sizeof(buf), act_len); 824c178a7e7SAndriy Gapon usbd_copy_out(pc, 0, buf, len); 825c178a7e7SAndriy Gapon if (buf[0] == CP2112_REQ_SMB_XFER_STATUS_RESP) { 826c178a7e7SAndriy Gapon device_printf(sc->dev, 827c178a7e7SAndriy Gapon "initial bus status0 = 0x%02x, " 828c178a7e7SAndriy Gapon "status1 = 0x%02x\n", 829c178a7e7SAndriy Gapon buf[1], buf[2]); 830c178a7e7SAndriy Gapon } 831c178a7e7SAndriy Gapon } 832c178a7e7SAndriy Gapon } else if (act_len == CP2112_REPORT_SIZE) { 833c178a7e7SAndriy Gapon pc = usbd_xfer_get_frame(xfer, 0); 834c178a7e7SAndriy Gapon usbd_copy_out(pc, 0, sc->io.in.data, sc->io.in.len); 835c178a7e7SAndriy Gapon sc->io.in.error = 0; 836c178a7e7SAndriy Gapon sc->io.in.done = 1; 837c178a7e7SAndriy Gapon } else { 838c178a7e7SAndriy Gapon device_printf(sc->dev, 839c178a7e7SAndriy Gapon "unexpected input report length %u\n", act_len); 840c178a7e7SAndriy Gapon sc->io.in.error = IIC_EBUSERR; 841c178a7e7SAndriy Gapon sc->io.in.done = 1; 842c178a7e7SAndriy Gapon } 843c178a7e7SAndriy Gapon cv_signal(&sc->io.cv); 844c178a7e7SAndriy Gapon case USB_ST_SETUP: 845c178a7e7SAndriy Gapon tr_setup: 846c178a7e7SAndriy Gapon usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 847c178a7e7SAndriy Gapon usbd_transfer_submit(xfer); 848c178a7e7SAndriy Gapon break; 849c178a7e7SAndriy Gapon 850c178a7e7SAndriy Gapon default: /* Error */ 851c178a7e7SAndriy Gapon device_printf(sc->dev, "read intr state %d error %d\n", 852c178a7e7SAndriy Gapon USB_GET_STATE(xfer), error); 853c178a7e7SAndriy Gapon 854c178a7e7SAndriy Gapon sc->io.in.error = IIC_EBUSERR; 855c178a7e7SAndriy Gapon sc->io.in.done = 1; 856c178a7e7SAndriy Gapon cv_signal(&sc->io.cv); 857c178a7e7SAndriy Gapon if (error != USB_ERR_CANCELLED) { 858c178a7e7SAndriy Gapon /* try to clear stall first */ 859c178a7e7SAndriy Gapon usbd_xfer_set_stall(xfer); 860c178a7e7SAndriy Gapon goto tr_setup; 861c178a7e7SAndriy Gapon } 862c178a7e7SAndriy Gapon break; 863c178a7e7SAndriy Gapon } 864c178a7e7SAndriy Gapon } 865c178a7e7SAndriy Gapon 866c178a7e7SAndriy Gapon static const struct usb_config cp2112iic_config[CP2112_N_TRANSFER] = { 867c178a7e7SAndriy Gapon [CP2112_INTR_OUT] = { 868c178a7e7SAndriy Gapon .type = UE_INTERRUPT, 869c178a7e7SAndriy Gapon .endpoint = UE_ADDR_ANY, 870c178a7e7SAndriy Gapon .direction = UE_DIR_OUT, 871c178a7e7SAndriy Gapon .flags = { .pipe_bof = 1, .no_pipe_ok = 1, }, 872c178a7e7SAndriy Gapon .bufsize = 0, /* use wMaxPacketSize */ 873c178a7e7SAndriy Gapon .callback = &cp2112iic_intr_write_callback, 874c178a7e7SAndriy Gapon }, 875c178a7e7SAndriy Gapon [CP2112_INTR_IN] = { 876c178a7e7SAndriy Gapon .type = UE_INTERRUPT, 877c178a7e7SAndriy Gapon .endpoint = UE_ADDR_ANY, 878c178a7e7SAndriy Gapon .direction = UE_DIR_IN, 879c178a7e7SAndriy Gapon .flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, 880c178a7e7SAndriy Gapon .bufsize = 0, /* use wMaxPacketSize */ 881c178a7e7SAndriy Gapon .callback = &cp2112iic_intr_read_callback, 882c178a7e7SAndriy Gapon }, 883c178a7e7SAndriy Gapon }; 884c178a7e7SAndriy Gapon 885c178a7e7SAndriy Gapon static int 886c178a7e7SAndriy Gapon cp2112iic_send_req(struct cp2112iic_softc *sc, const void *data, 887c178a7e7SAndriy Gapon uint16_t len) 888c178a7e7SAndriy Gapon { 889c178a7e7SAndriy Gapon int err; 890c178a7e7SAndriy Gapon 891c178a7e7SAndriy Gapon mtx_assert(&sc->io.lock, MA_OWNED); 892c178a7e7SAndriy Gapon KASSERT(sc->io.out.done == 0, ("%s: conflicting request", __func__)); 893c178a7e7SAndriy Gapon 894c178a7e7SAndriy Gapon sc->io.out.data = data; 895c178a7e7SAndriy Gapon sc->io.out.len = len; 896c178a7e7SAndriy Gapon 897c178a7e7SAndriy Gapon DTRACE_PROBE1(send__req, uint8_t, *(const uint8_t *)data); 898c178a7e7SAndriy Gapon 899c178a7e7SAndriy Gapon usbd_transfer_start(sc->xfers[CP2112_INTR_OUT]); 900c178a7e7SAndriy Gapon 901c178a7e7SAndriy Gapon while (!sc->io.out.done) 902c178a7e7SAndriy Gapon cv_wait(&sc->io.cv, &sc->io.lock); 903c178a7e7SAndriy Gapon 904c178a7e7SAndriy Gapon usbd_transfer_stop(sc->xfers[CP2112_INTR_OUT]); 905c178a7e7SAndriy Gapon 906c178a7e7SAndriy Gapon sc->io.out.done = 0; 907c178a7e7SAndriy Gapon sc->io.out.data = NULL; 908c178a7e7SAndriy Gapon sc->io.out.len = 0; 909c178a7e7SAndriy Gapon err = sc->io.out.error; 910c178a7e7SAndriy Gapon if (err != 0) { 911c178a7e7SAndriy Gapon device_printf(sc->dev, "output report 0x%02x failed: %d\n", 912c178a7e7SAndriy Gapon *(const uint8_t*)data, err); 913c178a7e7SAndriy Gapon } 914c178a7e7SAndriy Gapon return (err); 915c178a7e7SAndriy Gapon } 916c178a7e7SAndriy Gapon 917c178a7e7SAndriy Gapon static int 918c178a7e7SAndriy Gapon cp2112iic_req_resp(struct cp2112iic_softc *sc, const void *req_data, 919c178a7e7SAndriy Gapon uint16_t req_len, void *resp_data, uint16_t resp_len) 920c178a7e7SAndriy Gapon { 921c178a7e7SAndriy Gapon int err; 922c178a7e7SAndriy Gapon 923c178a7e7SAndriy Gapon mtx_assert(&sc->io.lock, MA_OWNED); 924c178a7e7SAndriy Gapon 925c178a7e7SAndriy Gapon /* 926c178a7e7SAndriy Gapon * Prepare to receive a response interrupt even before the 927c178a7e7SAndriy Gapon * request transfer is confirmed (USB_ST_TRANSFERED). 928c178a7e7SAndriy Gapon */ 929c178a7e7SAndriy Gapon KASSERT(sc->io.in.done == 0, ("%s: conflicting request", __func__)); 930c178a7e7SAndriy Gapon sc->io.in.len = resp_len; 931c178a7e7SAndriy Gapon sc->io.in.data = resp_data; 932c178a7e7SAndriy Gapon 933c178a7e7SAndriy Gapon err = cp2112iic_send_req(sc, req_data, req_len); 934c178a7e7SAndriy Gapon if (err != 0) { 935c178a7e7SAndriy Gapon sc->io.in.len = 0; 936c178a7e7SAndriy Gapon sc->io.in.data = NULL; 937c178a7e7SAndriy Gapon return (err); 938c178a7e7SAndriy Gapon } 939c178a7e7SAndriy Gapon 940c178a7e7SAndriy Gapon while (!sc->io.in.done) 941c178a7e7SAndriy Gapon cv_wait(&sc->io.cv, &sc->io.lock); 942c178a7e7SAndriy Gapon 943c178a7e7SAndriy Gapon err = sc->io.in.error; 944c178a7e7SAndriy Gapon sc->io.in.done = 0; 945c178a7e7SAndriy Gapon sc->io.in.error = 0; 946c178a7e7SAndriy Gapon sc->io.in.len = 0; 947c178a7e7SAndriy Gapon sc->io.in.data = NULL; 948c178a7e7SAndriy Gapon return (err); 949c178a7e7SAndriy Gapon } 950c178a7e7SAndriy Gapon 951c178a7e7SAndriy Gapon static int 952c178a7e7SAndriy Gapon cp2112iic_check_req_status(struct cp2112iic_softc *sc) 953c178a7e7SAndriy Gapon { 954ef32901bSAndriy Gapon struct i2c_xfer_status_req xfer_status_req; 955ef32901bSAndriy Gapon struct i2c_xfer_status_resp xfer_status_resp; 956c178a7e7SAndriy Gapon int err; 957c178a7e7SAndriy Gapon 958c178a7e7SAndriy Gapon mtx_assert(&sc->io.lock, MA_OWNED); 959c178a7e7SAndriy Gapon 960c178a7e7SAndriy Gapon do { 961c178a7e7SAndriy Gapon xfer_status_req.id = CP2112_REQ_SMB_XFER_STATUS_REQ; 962c178a7e7SAndriy Gapon xfer_status_req.request = 1; 963c178a7e7SAndriy Gapon err = cp2112iic_req_resp(sc, 964c178a7e7SAndriy Gapon &xfer_status_req, sizeof(xfer_status_req), 965c178a7e7SAndriy Gapon &xfer_status_resp, sizeof(xfer_status_resp)); 966c178a7e7SAndriy Gapon 967c178a7e7SAndriy Gapon if (xfer_status_resp.id != CP2112_REQ_SMB_XFER_STATUS_RESP) { 968c178a7e7SAndriy Gapon device_printf(sc->dev, 969c178a7e7SAndriy Gapon "unexpected response 0x%02x to status request\n", 970c178a7e7SAndriy Gapon xfer_status_resp.id); 971c178a7e7SAndriy Gapon err = IIC_EBUSERR; 972c178a7e7SAndriy Gapon goto out; 973c178a7e7SAndriy Gapon } 974c178a7e7SAndriy Gapon 975c178a7e7SAndriy Gapon DTRACE_PROBE4(xfer__status, uint8_t, xfer_status_resp.status0, 976c178a7e7SAndriy Gapon uint8_t, xfer_status_resp.status1, 977c178a7e7SAndriy Gapon uint16_t, be16toh(xfer_status_resp.status2), 978c178a7e7SAndriy Gapon uint16_t, be16toh(xfer_status_resp.status3)); 979c178a7e7SAndriy Gapon 980c178a7e7SAndriy Gapon switch (xfer_status_resp.status0) { 981c178a7e7SAndriy Gapon case CP2112_IIC_STATUS0_IDLE: 982c178a7e7SAndriy Gapon err = IIC_ESTATUS; 983c178a7e7SAndriy Gapon break; 984c178a7e7SAndriy Gapon case CP2112_IIC_STATUS0_BUSY: 985c178a7e7SAndriy Gapon err = ERESTART; /* non-I2C, special handling */ 986c178a7e7SAndriy Gapon break; 987c178a7e7SAndriy Gapon case CP2112_IIC_STATUS0_CMP: 988c178a7e7SAndriy Gapon err = IIC_NOERR; 989c178a7e7SAndriy Gapon break; 990c178a7e7SAndriy Gapon case CP2112_IIC_STATUS0_ERROR: 991c178a7e7SAndriy Gapon switch (xfer_status_resp.status1) { 992c178a7e7SAndriy Gapon case CP2112_IIC_STATUS1_TIMEOUT_NACK: 993c178a7e7SAndriy Gapon err = IIC_ENOACK; 994c178a7e7SAndriy Gapon break; 995c178a7e7SAndriy Gapon case CP2112_IIC_STATUS1_TIMEOUT_BUS: 996c178a7e7SAndriy Gapon err = IIC_ETIMEOUT; 997c178a7e7SAndriy Gapon break; 998c178a7e7SAndriy Gapon case CP2112_IIC_STATUS1_ARB_LOST: 999c178a7e7SAndriy Gapon err = IIC_EBUSBSY; 1000c178a7e7SAndriy Gapon break; 1001c178a7e7SAndriy Gapon default: 1002c178a7e7SAndriy Gapon device_printf(sc->dev, 1003c178a7e7SAndriy Gapon "i2c error, status = 0x%02x\n", 1004c178a7e7SAndriy Gapon xfer_status_resp.status1); 1005c178a7e7SAndriy Gapon err = IIC_ESTATUS; 1006c178a7e7SAndriy Gapon break; 1007c178a7e7SAndriy Gapon } 1008c178a7e7SAndriy Gapon break; 1009c178a7e7SAndriy Gapon default: 1010c178a7e7SAndriy Gapon device_printf(sc->dev, 1011c178a7e7SAndriy Gapon "unknown i2c xfer status0 0x%02x\n", 1012c178a7e7SAndriy Gapon xfer_status_resp.status0); 1013c178a7e7SAndriy Gapon err = IIC_EBUSERR; 1014c178a7e7SAndriy Gapon break; 1015c178a7e7SAndriy Gapon } 1016c178a7e7SAndriy Gapon 1017c178a7e7SAndriy Gapon } while (err == ERESTART); 1018c178a7e7SAndriy Gapon out: 1019c178a7e7SAndriy Gapon return (err); 1020c178a7e7SAndriy Gapon } 1021c178a7e7SAndriy Gapon 1022c178a7e7SAndriy Gapon static int 1023c178a7e7SAndriy Gapon cp2112iic_read_data(struct cp2112iic_softc *sc, void *data, uint16_t in_len, 1024c178a7e7SAndriy Gapon uint16_t *out_len) 1025c178a7e7SAndriy Gapon { 1026ef32901bSAndriy Gapon struct i2c_data_read_force_send_req data_read_force_send; 1027ef32901bSAndriy Gapon struct i2c_data_read_resp data_read_resp; 1028c178a7e7SAndriy Gapon int err; 1029c178a7e7SAndriy Gapon 1030c178a7e7SAndriy Gapon mtx_assert(&sc->io.lock, MA_OWNED); 1031c178a7e7SAndriy Gapon 1032c178a7e7SAndriy Gapon /* 1033c178a7e7SAndriy Gapon * Prepare to receive a response interrupt even before the request 1034c178a7e7SAndriy Gapon * transfer is confirmed (USB_ST_TRANSFERED). 1035c178a7e7SAndriy Gapon */ 1036c178a7e7SAndriy Gapon 1037c178a7e7SAndriy Gapon if (in_len > sizeof(data_read_resp.data)) 1038c178a7e7SAndriy Gapon in_len = sizeof(data_read_resp.data); 1039c178a7e7SAndriy Gapon data_read_force_send.id = CP2112_REQ_SMB_READ_FORCE_SEND; 1040ef32901bSAndriy Gapon data_read_force_send.len = htobe16(in_len); 1041c178a7e7SAndriy Gapon err = cp2112iic_req_resp(sc, 1042c178a7e7SAndriy Gapon &data_read_force_send, sizeof(data_read_force_send), 1043c178a7e7SAndriy Gapon &data_read_resp, sizeof(data_read_resp)); 1044c178a7e7SAndriy Gapon if (err != 0) 1045c178a7e7SAndriy Gapon goto out; 1046c178a7e7SAndriy Gapon 1047c178a7e7SAndriy Gapon if (data_read_resp.id != CP2112_REQ_SMB_READ_RESPONSE) { 1048c178a7e7SAndriy Gapon device_printf(sc->dev, 1049c178a7e7SAndriy Gapon "unexpected response 0x%02x to data read request\n", 1050c178a7e7SAndriy Gapon data_read_resp.id); 1051c178a7e7SAndriy Gapon err = IIC_EBUSERR; 1052c178a7e7SAndriy Gapon goto out; 1053c178a7e7SAndriy Gapon } 1054c178a7e7SAndriy Gapon 1055c178a7e7SAndriy Gapon DTRACE_PROBE2(read__response, uint8_t, data_read_resp.status, 1056ef32901bSAndriy Gapon uint8_t, data_read_resp.len); 1057c178a7e7SAndriy Gapon 1058c178a7e7SAndriy Gapon /* 1059c178a7e7SAndriy Gapon * We expect either the request completed status or, more typical for 1060c178a7e7SAndriy Gapon * this driver, the bus idle status because of the preceding 1061c178a7e7SAndriy Gapon * Force Read Status command (which is not an I2C request). 1062c178a7e7SAndriy Gapon */ 1063c178a7e7SAndriy Gapon if (data_read_resp.status != CP2112_IIC_STATUS0_CMP && 1064c178a7e7SAndriy Gapon data_read_resp.status != CP2112_IIC_STATUS0_IDLE) { 1065c178a7e7SAndriy Gapon err = IIC_EBUSERR; 1066c178a7e7SAndriy Gapon goto out; 1067c178a7e7SAndriy Gapon } 1068ef32901bSAndriy Gapon if (data_read_resp.len > in_len) { 1069c178a7e7SAndriy Gapon device_printf(sc->dev, "device returns more data than asked\n"); 1070c178a7e7SAndriy Gapon err = IIC_EOVERFLOW; 1071c178a7e7SAndriy Gapon goto out; 1072c178a7e7SAndriy Gapon } 1073c178a7e7SAndriy Gapon 1074ef32901bSAndriy Gapon *out_len = data_read_resp.len; 1075c178a7e7SAndriy Gapon if (*out_len > 0) 1076c178a7e7SAndriy Gapon memcpy(data, data_read_resp.data, *out_len); 1077c178a7e7SAndriy Gapon out: 1078c178a7e7SAndriy Gapon return (err); 1079c178a7e7SAndriy Gapon } 1080c178a7e7SAndriy Gapon 1081c178a7e7SAndriy Gapon static int 1082c178a7e7SAndriy Gapon cp2112iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 1083c178a7e7SAndriy Gapon { 1084c178a7e7SAndriy Gapon struct cp2112iic_softc *sc = device_get_softc(dev); 1085c178a7e7SAndriy Gapon struct cp2112_softc *psc = device_get_softc(device_get_parent(dev)); 1086c178a7e7SAndriy Gapon const char *reason = NULL; 1087c178a7e7SAndriy Gapon uint32_t i; 1088c178a7e7SAndriy Gapon uint16_t read_off, to_read; 1089c178a7e7SAndriy Gapon int err; 1090c178a7e7SAndriy Gapon 1091c178a7e7SAndriy Gapon /* 1092c178a7e7SAndriy Gapon * The hardware interface imposes limits on allowed I2C messages. 1093c178a7e7SAndriy Gapon * It is not possible to explicitly send a start or stop. 1094c178a7e7SAndriy Gapon * It is not possible to do a zero length transfer. 1095c178a7e7SAndriy Gapon * For this reason it's impossible to send a message with no data 1096c178a7e7SAndriy Gapon * at all (like an SMBus quick message). 1097c178a7e7SAndriy Gapon * Each read or write transfer beginning with the start condition 1098c178a7e7SAndriy Gapon * and ends with the stop condition. The only exception is that 1099c178a7e7SAndriy Gapon * it is possible to have a write transfer followed by a read 1100c178a7e7SAndriy Gapon * transfer to the same slave with the repeated start condition 1101c178a7e7SAndriy Gapon * between them. 1102c178a7e7SAndriy Gapon */ 1103c178a7e7SAndriy Gapon for (i = 0; i < nmsgs; i++) { 1104c178a7e7SAndriy Gapon if (i == 0 && (msgs[i].flags & IIC_M_NOSTART) != 0) { 1105c178a7e7SAndriy Gapon reason = "first message without start"; 1106c178a7e7SAndriy Gapon break; 1107c178a7e7SAndriy Gapon } 1108c178a7e7SAndriy Gapon if (i == nmsgs - 1 && (msgs[i].flags & IIC_M_NOSTOP) != 0) { 1109c178a7e7SAndriy Gapon reason = "last message without stop"; 1110c178a7e7SAndriy Gapon break; 1111c178a7e7SAndriy Gapon } 1112c178a7e7SAndriy Gapon if (msgs[i].len == 0) { 1113c178a7e7SAndriy Gapon reason = "message with no data"; 1114c178a7e7SAndriy Gapon break; 1115c178a7e7SAndriy Gapon } 1116ef32901bSAndriy Gapon if ((msgs[i].flags & IIC_M_RD) != 0 && 1117ef32901bSAndriy Gapon msgs[i].len > CP2112_IIC_MAX_READ_LEN) { 1118c178a7e7SAndriy Gapon reason = "too long read"; 1119c178a7e7SAndriy Gapon break; 1120c178a7e7SAndriy Gapon } 1121ef32901bSAndriy Gapon if ((msgs[i].flags & IIC_M_RD) == 0 && 1122ef32901bSAndriy Gapon msgs[i].len > SIZEOF_FIELD(i2c_write_req, data)) { 1123c178a7e7SAndriy Gapon reason = "too long write"; 1124c178a7e7SAndriy Gapon break; 1125c178a7e7SAndriy Gapon } 1126c178a7e7SAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTART) != 0) { 1127c178a7e7SAndriy Gapon reason = "message without start or repeated start"; 1128c178a7e7SAndriy Gapon break; 1129c178a7e7SAndriy Gapon } 1130c178a7e7SAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTOP) != 0 && 1131c178a7e7SAndriy Gapon (msgs[i].flags & IIC_M_RD) != 0) { 1132c178a7e7SAndriy Gapon reason = "read without stop"; 1133c178a7e7SAndriy Gapon break; 1134c178a7e7SAndriy Gapon } 1135c178a7e7SAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTOP) != 0 && 1136c178a7e7SAndriy Gapon psc->sc_version < CP2112_IIC_REPSTART_VER) { 1137c178a7e7SAndriy Gapon reason = "write without stop"; 1138c178a7e7SAndriy Gapon break; 1139c178a7e7SAndriy Gapon } 1140ef32901bSAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTOP) != 0 && 1141ef32901bSAndriy Gapon msgs[i].len > SIZEOF_FIELD(i2c_write_read_req, wdata)) { 1142c178a7e7SAndriy Gapon reason = "too long write without stop"; 1143c178a7e7SAndriy Gapon break; 1144c178a7e7SAndriy Gapon } 1145c178a7e7SAndriy Gapon if (i > 0) { 1146c178a7e7SAndriy Gapon if ((msgs[i - 1].flags & IIC_M_NOSTOP) != 0 && 1147c178a7e7SAndriy Gapon msgs[i].slave != msgs[i - 1].slave) { 1148c178a7e7SAndriy Gapon reason = "change of slave without stop"; 1149c178a7e7SAndriy Gapon break; 1150c178a7e7SAndriy Gapon } 1151c178a7e7SAndriy Gapon if ((msgs[i - 1].flags & IIC_M_NOSTOP) != 0 && 1152c178a7e7SAndriy Gapon (msgs[i].flags & IIC_M_RD) == 0) { 1153c178a7e7SAndriy Gapon reason = "write after repeated start"; 1154c178a7e7SAndriy Gapon break; 1155c178a7e7SAndriy Gapon } 1156c178a7e7SAndriy Gapon } 1157c178a7e7SAndriy Gapon } 1158c178a7e7SAndriy Gapon if (reason != NULL) { 1159c178a7e7SAndriy Gapon if (bootverbose) 1160c178a7e7SAndriy Gapon device_printf(dev, "unsupported i2c message: %s\n", 1161c178a7e7SAndriy Gapon reason); 1162c178a7e7SAndriy Gapon return (IIC_ENOTSUPP); 1163c178a7e7SAndriy Gapon } 1164c178a7e7SAndriy Gapon 1165c178a7e7SAndriy Gapon mtx_lock(&sc->io.lock); 1166c178a7e7SAndriy Gapon 1167c178a7e7SAndriy Gapon for (i = 0; i < nmsgs; i++) { 1168c178a7e7SAndriy Gapon if (i + 1 < nmsgs && (msgs[i].flags & IIC_M_NOSTOP) != 0) { 1169c178a7e7SAndriy Gapon /* 1170c178a7e7SAndriy Gapon * Combine <write><repeated start><read> into a single 1171c178a7e7SAndriy Gapon * CP2112 operation. 1172c178a7e7SAndriy Gapon */ 1173ef32901bSAndriy Gapon struct i2c_write_read_req req; 1174c178a7e7SAndriy Gapon 1175ef32901bSAndriy Gapon KASSERT((msgs[i].flags & IIC_M_RD) == 0, 1176ef32901bSAndriy Gapon ("read without stop")); 1177ef32901bSAndriy Gapon KASSERT((msgs[i + 1].flags & IIC_M_RD) != 0, 1178ef32901bSAndriy Gapon ("write after write without stop")); 1179c178a7e7SAndriy Gapon req.id = CP2112_REQ_SMB_WRITE_READ; 1180c178a7e7SAndriy Gapon req.slave = msgs[i].slave & ~LSB; 1181c178a7e7SAndriy Gapon to_read = msgs[i + 1].len; 1182c178a7e7SAndriy Gapon req.rlen = htobe16(to_read); 1183c178a7e7SAndriy Gapon req.wlen = msgs[i].len; 1184c178a7e7SAndriy Gapon memcpy(req.wdata, msgs[i].buf, msgs[i].len); 1185c178a7e7SAndriy Gapon err = cp2112iic_send_req(sc, &req, msgs[i].len + 5); 1186c178a7e7SAndriy Gapon 1187c178a7e7SAndriy Gapon /* 1188c178a7e7SAndriy Gapon * The next message is already handled. 1189c178a7e7SAndriy Gapon * Also needed for read data to go into the right msg. 1190c178a7e7SAndriy Gapon */ 1191c178a7e7SAndriy Gapon i++; 1192c178a7e7SAndriy Gapon } else if ((msgs[i].flags & IIC_M_RD) != 0) { 1193ef32901bSAndriy Gapon struct i2c_read_req req; 1194c178a7e7SAndriy Gapon 1195c178a7e7SAndriy Gapon req.id = CP2112_REQ_SMB_READ; 1196c178a7e7SAndriy Gapon req.slave = msgs[i].slave & ~LSB; 1197c178a7e7SAndriy Gapon to_read = msgs[i].len; 1198c178a7e7SAndriy Gapon req.len = htobe16(to_read); 1199c178a7e7SAndriy Gapon err = cp2112iic_send_req(sc, &req, sizeof(req)); 1200c178a7e7SAndriy Gapon } else { 1201ef32901bSAndriy Gapon struct i2c_write_req req; 1202c178a7e7SAndriy Gapon 1203c178a7e7SAndriy Gapon req.id = CP2112_REQ_SMB_WRITE; 1204c178a7e7SAndriy Gapon req.slave = msgs[i].slave & ~LSB; 1205c178a7e7SAndriy Gapon req.len = msgs[i].len; 1206c178a7e7SAndriy Gapon memcpy(req.data, msgs[i].buf, msgs[i].len); 1207c178a7e7SAndriy Gapon to_read = 0; 1208c178a7e7SAndriy Gapon err = cp2112iic_send_req(sc, &req, msgs[i].len + 3); 1209c178a7e7SAndriy Gapon } 1210c178a7e7SAndriy Gapon if (err != 0) 1211c178a7e7SAndriy Gapon break; 1212c178a7e7SAndriy Gapon 1213c178a7e7SAndriy Gapon err = cp2112iic_check_req_status(sc); 1214c178a7e7SAndriy Gapon if (err != 0) 1215c178a7e7SAndriy Gapon break; 1216c178a7e7SAndriy Gapon 1217c178a7e7SAndriy Gapon read_off = 0; 1218c178a7e7SAndriy Gapon while (to_read > 0) { 1219c178a7e7SAndriy Gapon uint16_t act_read; 1220c178a7e7SAndriy Gapon 1221c178a7e7SAndriy Gapon err = cp2112iic_read_data(sc, msgs[i].buf + read_off, 1222c178a7e7SAndriy Gapon to_read, &act_read); 1223c178a7e7SAndriy Gapon if (err != 0) 1224c178a7e7SAndriy Gapon break; 1225c178a7e7SAndriy Gapon KASSERT(act_read <= to_read, ("cp2112iic_read_data " 1226c178a7e7SAndriy Gapon "returned more data than asked")); 1227c178a7e7SAndriy Gapon read_off += act_read; 1228c178a7e7SAndriy Gapon to_read -= act_read; 1229c178a7e7SAndriy Gapon } 1230c178a7e7SAndriy Gapon if (err != 0) 1231c178a7e7SAndriy Gapon break; 1232c178a7e7SAndriy Gapon } 1233c178a7e7SAndriy Gapon 1234c178a7e7SAndriy Gapon mtx_unlock(&sc->io.lock); 1235c178a7e7SAndriy Gapon return (err); 1236c178a7e7SAndriy Gapon } 1237c178a7e7SAndriy Gapon 1238c178a7e7SAndriy Gapon static int 1239c178a7e7SAndriy Gapon cp2112iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 1240c178a7e7SAndriy Gapon { 1241ef32901bSAndriy Gapon struct i2c_cfg_req i2c_cfg; 1242c178a7e7SAndriy Gapon struct cp2112iic_softc *sc; 1243c178a7e7SAndriy Gapon device_t cp2112; 1244c178a7e7SAndriy Gapon u_int busfreq; 1245c178a7e7SAndriy Gapon int err; 1246c178a7e7SAndriy Gapon 1247c178a7e7SAndriy Gapon sc = device_get_softc(dev); 1248c178a7e7SAndriy Gapon cp2112 = device_get_parent(dev); 1249c178a7e7SAndriy Gapon if (sc->iicbus_dev == NULL) 1250c178a7e7SAndriy Gapon busfreq = 100000; 1251c178a7e7SAndriy Gapon else 1252c178a7e7SAndriy Gapon busfreq = IICBUS_GET_FREQUENCY(sc->iicbus_dev, speed); 1253c178a7e7SAndriy Gapon 1254c178a7e7SAndriy Gapon err = cp2112_get_report(cp2112, CP2112_REQ_SMB_CFG, 1255ef32901bSAndriy Gapon &i2c_cfg, sizeof(i2c_cfg)); 1256c178a7e7SAndriy Gapon if (err != 0) { 1257c178a7e7SAndriy Gapon device_printf(dev, "failed to get CP2112_REQ_SMB_CFG report\n"); 1258c178a7e7SAndriy Gapon return (err); 1259c178a7e7SAndriy Gapon } 1260c178a7e7SAndriy Gapon 1261c178a7e7SAndriy Gapon if (oldaddr != NULL) 1262ef32901bSAndriy Gapon *oldaddr = i2c_cfg.slave_addr; 1263c178a7e7SAndriy Gapon /* 1264c178a7e7SAndriy Gapon * For simplicity we do not enable Auto Send Read 1265c178a7e7SAndriy Gapon * because of erratum CP2112_E101 (fixed in version 3). 1266c178a7e7SAndriy Gapon * 1267c178a7e7SAndriy Gapon * TODO: set I2C parameters based on configuration preferences: 1268c178a7e7SAndriy Gapon * - read and write timeouts (no timeout by default), 1269c178a7e7SAndriy Gapon * - SCL low timeout (disabled by default), 1270c178a7e7SAndriy Gapon * etc. 1271c178a7e7SAndriy Gapon * 1272c178a7e7SAndriy Gapon * TODO: should the device reset request (0x01) be sent? 1273c178a7e7SAndriy Gapon * If the device disconnects as a result, then no. 1274c178a7e7SAndriy Gapon */ 1275ef32901bSAndriy Gapon i2c_cfg.speed = htobe32(busfreq); 1276c178a7e7SAndriy Gapon if (addr != 0) 1277ef32901bSAndriy Gapon i2c_cfg.slave_addr = addr; 1278ef32901bSAndriy Gapon i2c_cfg.auto_send_read = 0; 1279ef32901bSAndriy Gapon i2c_cfg.retry_count = htobe16(1); 1280ef32901bSAndriy Gapon i2c_cfg.scl_low_timeout = 0; 1281c178a7e7SAndriy Gapon if (bootverbose) { 1282ef32901bSAndriy Gapon device_printf(dev, "speed %d Hz\n", be32toh(i2c_cfg.speed)); 1283ef32901bSAndriy Gapon device_printf(dev, "slave addr 0x%02x\n", i2c_cfg.slave_addr); 1284c178a7e7SAndriy Gapon device_printf(dev, "auto send read %s\n", 1285ef32901bSAndriy Gapon i2c_cfg.auto_send_read ? "on" : "off"); 1286c178a7e7SAndriy Gapon device_printf(dev, "write timeout %d ms (0 - disabled)\n", 1287ef32901bSAndriy Gapon be16toh(i2c_cfg.write_timeout)); 1288c178a7e7SAndriy Gapon device_printf(dev, "read timeout %d ms (0 - disabled)\n", 1289ef32901bSAndriy Gapon be16toh(i2c_cfg.read_timeout)); 1290c178a7e7SAndriy Gapon device_printf(dev, "scl low timeout %s\n", 1291ef32901bSAndriy Gapon i2c_cfg.scl_low_timeout ? "on" : "off"); 1292c178a7e7SAndriy Gapon device_printf(dev, "retry count %d (0 - no limit)\n", 1293ef32901bSAndriy Gapon be16toh(i2c_cfg.retry_count)); 1294c178a7e7SAndriy Gapon } 1295c178a7e7SAndriy Gapon err = cp2112_set_report(cp2112, CP2112_REQ_SMB_CFG, 1296ef32901bSAndriy Gapon &i2c_cfg, sizeof(i2c_cfg)); 1297c178a7e7SAndriy Gapon if (err != 0) { 1298c178a7e7SAndriy Gapon device_printf(dev, "failed to set CP2112_REQ_SMB_CFG report\n"); 1299c178a7e7SAndriy Gapon return (err); 1300c178a7e7SAndriy Gapon } 1301c178a7e7SAndriy Gapon return (0); 1302c178a7e7SAndriy Gapon } 1303c178a7e7SAndriy Gapon 1304c178a7e7SAndriy Gapon static int 1305c178a7e7SAndriy Gapon cp2112iic_probe(device_t dev) 1306c178a7e7SAndriy Gapon { 1307c178a7e7SAndriy Gapon device_set_desc(dev, "CP2112 I2C interface"); 1308c178a7e7SAndriy Gapon return (BUS_PROBE_SPECIFIC); 1309c178a7e7SAndriy Gapon } 1310c178a7e7SAndriy Gapon 1311c178a7e7SAndriy Gapon static int 1312c178a7e7SAndriy Gapon cp2112iic_attach(device_t dev) 1313c178a7e7SAndriy Gapon { 1314c178a7e7SAndriy Gapon struct cp2112iic_softc *sc; 1315c178a7e7SAndriy Gapon struct cp2112_softc *psc; 1316c178a7e7SAndriy Gapon device_t cp2112; 1317c178a7e7SAndriy Gapon int err; 1318c178a7e7SAndriy Gapon 1319c178a7e7SAndriy Gapon sc = device_get_softc(dev); 1320c178a7e7SAndriy Gapon sc->dev = dev; 1321c178a7e7SAndriy Gapon cp2112 = device_get_parent(dev); 1322c178a7e7SAndriy Gapon psc = device_get_softc(cp2112); 1323c178a7e7SAndriy Gapon 1324c178a7e7SAndriy Gapon mtx_init(&sc->io.lock, "cp2112iic lock", NULL, MTX_DEF | MTX_RECURSE); 1325c178a7e7SAndriy Gapon cv_init(&sc->io.cv, "cp2112iic cv"); 1326c178a7e7SAndriy Gapon 1327c178a7e7SAndriy Gapon err = usbd_transfer_setup(psc->sc_udev, 1328c178a7e7SAndriy Gapon &psc->sc_iface_index, sc->xfers, cp2112iic_config, 1329c178a7e7SAndriy Gapon nitems(cp2112iic_config), sc, &sc->io.lock); 1330c178a7e7SAndriy Gapon if (err != 0) { 1331c178a7e7SAndriy Gapon device_printf(dev, "usbd_transfer_setup failed %d\n", err); 1332c178a7e7SAndriy Gapon goto detach; 1333c178a7e7SAndriy Gapon } 1334c178a7e7SAndriy Gapon 1335c178a7e7SAndriy Gapon /* Prepare to receive interrupts. */ 1336c178a7e7SAndriy Gapon mtx_lock(&sc->io.lock); 1337c178a7e7SAndriy Gapon usbd_transfer_start(sc->xfers[CP2112_INTR_IN]); 1338c178a7e7SAndriy Gapon mtx_unlock(&sc->io.lock); 1339c178a7e7SAndriy Gapon 1340c178a7e7SAndriy Gapon sc->iicbus_dev = device_add_child(dev, "iicbus", -1); 1341c178a7e7SAndriy Gapon if (sc->iicbus_dev == NULL) { 1342c178a7e7SAndriy Gapon device_printf(dev, "iicbus creation failed\n"); 1343c178a7e7SAndriy Gapon err = ENXIO; 1344c178a7e7SAndriy Gapon goto detach; 1345c178a7e7SAndriy Gapon } 1346c178a7e7SAndriy Gapon bus_generic_attach(dev); 1347c178a7e7SAndriy Gapon return (0); 1348c178a7e7SAndriy Gapon 1349c178a7e7SAndriy Gapon detach: 1350c178a7e7SAndriy Gapon cp2112iic_detach(dev); 1351c178a7e7SAndriy Gapon return (err); 1352c178a7e7SAndriy Gapon } 1353c178a7e7SAndriy Gapon 1354c178a7e7SAndriy Gapon static int 1355c178a7e7SAndriy Gapon cp2112iic_detach(device_t dev) 1356c178a7e7SAndriy Gapon { 1357c178a7e7SAndriy Gapon struct cp2112iic_softc *sc; 1358c178a7e7SAndriy Gapon int err; 1359c178a7e7SAndriy Gapon 1360c178a7e7SAndriy Gapon sc = device_get_softc(dev); 1361c178a7e7SAndriy Gapon err = bus_generic_detach(dev); 1362c178a7e7SAndriy Gapon if (err != 0) 1363c178a7e7SAndriy Gapon return (err); 1364c178a7e7SAndriy Gapon device_delete_children(dev); 1365c178a7e7SAndriy Gapon 1366c178a7e7SAndriy Gapon mtx_lock(&sc->io.lock); 1367c178a7e7SAndriy Gapon usbd_transfer_stop(sc->xfers[CP2112_INTR_IN]); 1368c178a7e7SAndriy Gapon mtx_unlock(&sc->io.lock); 1369c178a7e7SAndriy Gapon usbd_transfer_unsetup(sc->xfers, nitems(cp2112iic_config)); 1370c178a7e7SAndriy Gapon 1371c178a7e7SAndriy Gapon cv_destroy(&sc->io.cv); 1372c178a7e7SAndriy Gapon mtx_destroy(&sc->io.lock); 1373c178a7e7SAndriy Gapon 1374c178a7e7SAndriy Gapon return (0); 1375c178a7e7SAndriy Gapon } 1376c178a7e7SAndriy Gapon 1377ef32901bSAndriy Gapon static device_method_t cp2112hid_methods[] = { 1378ef32901bSAndriy Gapon DEVMETHOD(device_probe, cp2112_probe), 1379ef32901bSAndriy Gapon DEVMETHOD(device_attach, cp2112_attach), 1380ef32901bSAndriy Gapon DEVMETHOD(device_detach, cp2112_detach), 1381ef32901bSAndriy Gapon 1382ef32901bSAndriy Gapon DEVMETHOD_END 1383ef32901bSAndriy Gapon }; 1384ef32901bSAndriy Gapon 1385ef32901bSAndriy Gapon static driver_t cp2112hid_driver = { 1386ef32901bSAndriy Gapon .name = "cp2112hid", 1387ef32901bSAndriy Gapon .methods = cp2112hid_methods, 1388ef32901bSAndriy Gapon .size = sizeof(struct cp2112_softc), 1389ef32901bSAndriy Gapon }; 1390ef32901bSAndriy Gapon 1391*bc9372d7SJohn Baldwin DRIVER_MODULE(cp2112hid, uhub, cp2112hid_driver, NULL, NULL); 1392ef32901bSAndriy Gapon MODULE_DEPEND(cp2112hid, usb, 1, 1, 1); 1393ef32901bSAndriy Gapon MODULE_VERSION(cp2112hid, 1); 1394ef32901bSAndriy Gapon USB_PNP_HOST_INFO(cp2112_devs); 1395ef32901bSAndriy Gapon 1396ef32901bSAndriy Gapon static device_method_t cp2112gpio_methods[] = { 1397ef32901bSAndriy Gapon /* Device */ 1398ef32901bSAndriy Gapon DEVMETHOD(device_probe, cp2112gpio_probe), 1399ef32901bSAndriy Gapon DEVMETHOD(device_attach, cp2112gpio_attach), 1400ef32901bSAndriy Gapon DEVMETHOD(device_detach, cp2112gpio_detach), 1401ef32901bSAndriy Gapon 1402ef32901bSAndriy Gapon /* GPIO */ 1403ef32901bSAndriy Gapon DEVMETHOD(gpio_get_bus, cp2112_gpio_get_bus), 1404ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_max, cp2112_gpio_pin_max), 1405ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_get, cp2112_gpio_pin_get), 1406ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_set, cp2112_gpio_pin_set), 1407ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_toggle, cp2112_gpio_pin_toggle), 1408ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_getname, cp2112_gpio_pin_getname), 1409ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_getcaps, cp2112_gpio_pin_getcaps), 1410ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_getflags, cp2112_gpio_pin_getflags), 1411ef32901bSAndriy Gapon DEVMETHOD(gpio_pin_setflags, cp2112_gpio_pin_setflags), 1412ef32901bSAndriy Gapon 1413ef32901bSAndriy Gapon DEVMETHOD_END 1414ef32901bSAndriy Gapon }; 1415ef32901bSAndriy Gapon 1416ef32901bSAndriy Gapon static driver_t cp2112gpio_driver = { 1417ef32901bSAndriy Gapon .name = "gpio", 1418ef32901bSAndriy Gapon .methods = cp2112gpio_methods, 1419ef32901bSAndriy Gapon .size = sizeof(struct cp2112gpio_softc), 1420ef32901bSAndriy Gapon }; 1421ef32901bSAndriy Gapon 1422*bc9372d7SJohn Baldwin DRIVER_MODULE(cp2112gpio, cp2112hid, cp2112gpio_driver, NULL, NULL); 1423ef32901bSAndriy Gapon MODULE_DEPEND(cp2112gpio, cp2112hid, 1, 1, 1); 1424ef32901bSAndriy Gapon MODULE_DEPEND(cp2112gpio, gpiobus, 1, 1, 1); 1425ef32901bSAndriy Gapon MODULE_VERSION(cp2112gpio, 1); 1426ef32901bSAndriy Gapon 1427c178a7e7SAndriy Gapon static device_method_t cp2112iic_methods[] = { 1428c178a7e7SAndriy Gapon /* Device interface */ 1429c178a7e7SAndriy Gapon DEVMETHOD(device_probe, cp2112iic_probe), 1430c178a7e7SAndriy Gapon DEVMETHOD(device_attach, cp2112iic_attach), 1431c178a7e7SAndriy Gapon DEVMETHOD(device_detach, cp2112iic_detach), 1432c178a7e7SAndriy Gapon 1433c178a7e7SAndriy Gapon /* I2C methods */ 1434c178a7e7SAndriy Gapon DEVMETHOD(iicbus_transfer, cp2112iic_transfer), 1435c178a7e7SAndriy Gapon DEVMETHOD(iicbus_reset, cp2112iic_reset), 1436c178a7e7SAndriy Gapon DEVMETHOD(iicbus_callback, iicbus_null_callback), 1437c178a7e7SAndriy Gapon 1438c178a7e7SAndriy Gapon DEVMETHOD_END 1439c178a7e7SAndriy Gapon }; 1440c178a7e7SAndriy Gapon 1441c178a7e7SAndriy Gapon static driver_t cp2112iic_driver = { 1442c178a7e7SAndriy Gapon "iichb", 1443c178a7e7SAndriy Gapon cp2112iic_methods, 1444c178a7e7SAndriy Gapon sizeof(struct cp2112iic_softc) 1445c178a7e7SAndriy Gapon }; 1446c178a7e7SAndriy Gapon 1447*bc9372d7SJohn Baldwin DRIVER_MODULE(cp2112iic, cp2112hid, cp2112iic_driver, NULL, NULL); 1448c178a7e7SAndriy Gapon MODULE_DEPEND(cp2112iic, cp2112hid, 1, 1, 1); 1449c178a7e7SAndriy Gapon MODULE_DEPEND(cp2112iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 1450c178a7e7SAndriy Gapon MODULE_VERSION(cp2112iic, 1); 1451