11.1Sbrad/* $NetBSD: umcpmio_spi.c,v 1.1 2025/11/29 18:39:14 brad Exp $ */ 21.1Sbrad 31.1Sbrad/* 41.1Sbrad * Copyright (c) 2025 Brad Spencer <brad@anduin.eldar.org> 51.1Sbrad * 61.1Sbrad * Permission to use, copy, modify, and distribute this software for any 71.1Sbrad * purpose with or without fee is hereby granted, provided that the above 81.1Sbrad * copyright notice and this permission notice appear in all copies. 91.1Sbrad * 101.1Sbrad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 111.1Sbrad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 121.1Sbrad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 131.1Sbrad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 141.1Sbrad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 151.1Sbrad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 161.1Sbrad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 171.1Sbrad */ 181.1Sbrad 191.1Sbrad#include <sys/cdefs.h> 201.1Sbrad__KERNEL_RCSID(0, "$NetBSD: umcpmio_spi.c,v 1.1 2025/11/29 18:39:14 brad Exp $"); 211.1Sbrad 221.1Sbrad#ifdef _KERNEL_OPT 231.1Sbrad#include "opt_usb.h" 241.1Sbrad#endif 251.1Sbrad 261.1Sbrad#include <sys/param.h> 271.1Sbrad#include <sys/types.h> 281.1Sbrad 291.1Sbrad#include <dev/spi/spivar.h> 301.1Sbrad 311.1Sbrad#include <dev/usb/umcpmio.h> 321.1Sbrad#include <dev/usb/umcpmio_hid_reports.h> 331.1Sbrad#include <dev/usb/umcpmio_transport.h> 341.1Sbrad#include <dev/usb/umcpmio_spi.h> 351.1Sbrad#include <dev/usb/umcpmio_gpio.h> 361.1Sbrad#include <dev/usb/umcpmio_subr.h> 371.1Sbrad 381.1Sbrad#define UMCPMIO_DEBUG 1 391.1Sbrad#ifdef UMCPMIO_DEBUG 401.1Sbrad#define DPRINTF(x) do { if (umcpmiodebug) printf x; } while (0) 411.1Sbrad#define DPRINTFN(n, x) do { if (umcpmiodebug > (n)) printf x; } while (0) 421.1Sbradextern int umcpmiodebug; 431.1Sbrad#else 441.1Sbrad#define DPRINTF(x) __nothing 451.1Sbrad#define DPRINTFN(n, x) __nothing 461.1Sbrad#endif 471.1Sbrad 481.1Sbrad/* Stuff required for the SPI part of the MCP2210 */ 491.1Sbrad 501.1Sbradstatic int 511.1Sbradmcp2210_get_spi_sram(struct umcpmio_softc *sc, 521.1Sbrad struct mcp2210_get_spi_sram_res *res) 531.1Sbrad{ 541.1Sbrad struct mcp2210_get_spi_sram_req req; 551.1Sbrad int err = 0; 561.1Sbrad 571.1Sbrad memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 581.1Sbrad req.cmd = MCP2210_CMD_GET_SPI_SRAM; 591.1Sbrad 601.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 611.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 621.1Sbrad "mcp2210_get_spi_sram req"); 631.1Sbrad 641.1Sbrad mutex_enter(&sc->sc_action_mutex); 651.1Sbrad err = umcpmio_send_report(sc, 661.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 671.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 681.1Sbrad mutex_exit(&sc->sc_action_mutex); 691.1Sbrad 701.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 711.1Sbrad (uint8_t *) res, MCP2210_RES_BUFFER_SIZE, 721.1Sbrad "mcp2210_get_spi_sram res"); 731.1Sbrad 741.1Sbrad err = mcp2210_decode_errors(req.cmd, err, res->completion); 751.1Sbrad 761.1Sbrad return err; 771.1Sbrad} 781.1Sbrad 791.1Sbradstatic int 801.1Sbradmcp2210_set_spi_sram(struct umcpmio_softc *sc, 811.1Sbrad struct mcp2210_set_spi_sram_req *req, struct mcp2210_set_spi_sram_res *res) 821.1Sbrad{ 831.1Sbrad int err = 0; 841.1Sbrad 851.1Sbrad req->cmd = MCP2210_CMD_SET_SPI_SRAM; 861.1Sbrad 871.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 881.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 891.1Sbrad "mcp2210_set_spi_sram req"); 901.1Sbrad 911.1Sbrad mutex_enter(&sc->sc_action_mutex); 921.1Sbrad err = umcpmio_send_report(sc, 931.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 941.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 951.1Sbrad mutex_exit(&sc->sc_action_mutex); 961.1Sbrad 971.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 981.1Sbrad (uint8_t *) res, MCP2210_RES_BUFFER_SIZE, 991.1Sbrad "mcp2210_set_spi_sram res"); 1001.1Sbrad 1011.1Sbrad err = mcp2210_decode_errors(req->cmd, err, res->completion); 1021.1Sbrad 1031.1Sbrad return err; 1041.1Sbrad} 1051.1Sbrad 1061.1Sbradstatic int 1071.1Sbradmcp2210_do_spi_transfer(struct umcpmio_softc *sc, 1081.1Sbrad struct mcp2210_spi_transfer_req *req, struct mcp2210_spi_transfer_res *res) 1091.1Sbrad{ 1101.1Sbrad int err = 0; 1111.1Sbrad 1121.1Sbrad req->cmd = MCP2210_CMD_SPI_TRANSFER; 1131.1Sbrad 1141.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 1151.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 1161.1Sbrad "mcp2210_do_spi_transfer req"); 1171.1Sbrad 1181.1Sbrad mutex_enter(&sc->sc_action_mutex); 1191.1Sbrad err = umcpmio_send_report(sc, 1201.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 1211.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 1221.1Sbrad mutex_exit(&sc->sc_action_mutex); 1231.1Sbrad 1241.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 1251.1Sbrad (uint8_t *) res, MCP2210_RES_BUFFER_SIZE, 1261.1Sbrad "mcp2210_do_spi_transfer res"); 1271.1Sbrad 1281.1Sbrad err = mcp2210_decode_errors(req->cmd, err, res->completion); 1291.1Sbrad 1301.1Sbrad return err; 1311.1Sbrad} 1321.1Sbrad 1331.1Sbrad/* Most configuration is defered until a tranfer actually happens. The 1341.1Sbrad * exception is setting the pin that is to be used as a CS to ALT0. 1351.1Sbrad * 1361.1Sbrad * There is no attempt to reset the mode of the pin used for the CS, 1371.1Sbrad * as there is no concept of a session with the SPI framework. That is, 1381.1Sbrad * you would never know when to do it. Further, it will cause pin 1391.1Sbrad * flapping of all of the other pins if the CS is set to INPUT 1401.1Sbrad * or OUTPUT. Of course, that will happen when the CS mode (ALT0) 1411.1Sbrad * is set, but only the first time the pin is used as a CS. 1421.1Sbrad * 1431.1Sbrad * It is adviseable to make use of the NVRAM to set up the pin mode 1441.1Sbrad * upon boot up of the chip. 1451.1Sbrad * 1461.1Sbrad */ 1471.1Sbrad 1481.1Sbradstatic int 1491.1Sbradmcp2210_spi_configure(void *cookie, int slave, int mode, int speed) 1501.1Sbrad{ 1511.1Sbrad struct umcpmio_softc *sc = cookie; 1521.1Sbrad uint8_t desired_mode = 0; 1531.1Sbrad struct umcpmio_spi_received *r; 1541.1Sbrad int err = 0; 1551.1Sbrad 1561.1Sbrad if (slave >= sc->sc_spi.sct_nslaves) 1571.1Sbrad return EINVAL; 1581.1Sbrad 1591.1Sbrad /* The speed is in bps and the MCP2210 uses bps, but is not suppose to 1601.1Sbrad * be able to go below 1500 bps. There is also a upper bound of 12Mbps, 1611.1Sbrad * but the chip will not do anything wrong if you try to go faster as it 1621.1Sbrad * will cap the speed. 1631.1Sbrad */ 1641.1Sbrad 1651.1Sbrad if (speed < 1500) { 1661.1Sbrad aprint_error_dev(sc->sc_dev, 1671.1Sbrad "Speed %d is too low and not supported.", speed); 1681.1Sbrad return EINVAL; 1691.1Sbrad } 1701.1Sbrad mutex_enter(&sc->sc_spi_mutex); 1711.1Sbrad 1721.1Sbrad umcpmio_gpio_pin_ctl(sc, slave, GPIO_PIN_ALT0); 1731.1Sbrad 1741.1Sbrad switch (mode) { 1751.1Sbrad case SPI_MODE_0: 1761.1Sbrad desired_mode = MCP2210_SPI_MODE_0; 1771.1Sbrad break; 1781.1Sbrad case SPI_MODE_1: 1791.1Sbrad desired_mode = MCP2210_SPI_MODE_1; 1801.1Sbrad break; 1811.1Sbrad case SPI_MODE_2: 1821.1Sbrad desired_mode = MCP2210_SPI_MODE_2; 1831.1Sbrad break; 1841.1Sbrad case SPI_MODE_3: 1851.1Sbrad desired_mode = MCP2210_SPI_MODE_3; 1861.1Sbrad break; 1871.1Sbrad default: 1881.1Sbrad err = EINVAL; 1891.1Sbrad } 1901.1Sbrad 1911.1Sbrad 1921.1Sbrad /* Remove any queued up data. This is a choice, but it seems the 1931.1Sbrad * right now. If you call configure() you are probably resetting 1941.1Sbrad * the SPI port. 1951.1Sbrad */ 1961.1Sbrad 1971.1Sbrad if (!err) { 1981.1Sbrad sc->sc_slave_configs[slave].bit_rate = (uint32_t) speed; 1991.1Sbrad sc->sc_slave_configs[slave].mode = desired_mode; 2001.1Sbrad 2011.1Sbrad if (!SIMPLEQ_EMPTY(&sc->sc_received[slave])) { 2021.1Sbrad while ((r = SIMPLEQ_FIRST(&sc->sc_received[slave])) != NULL) { 2031.1Sbrad SIMPLEQ_REMOVE_HEAD(&sc->sc_received[slave], umcpmio_spi_received_q); 2041.1Sbrad kmem_free(r, sizeof(struct umcpmio_spi_received)); 2051.1Sbrad } 2061.1Sbrad } 2071.1Sbrad } 2081.1Sbrad 2091.1Sbrad mutex_exit(&sc->sc_spi_mutex); 2101.1Sbrad 2111.1Sbrad return err; 2121.1Sbrad} 2131.1Sbrad 2141.1Sbrad/* Set all of the stuff about the slave device that is needed 2151.1Sbrad * to do a transfer. 2161.1Sbrad */ 2171.1Sbrad 2181.1Sbradstatic int 2191.1Sbradmcp2210_spi_set_slave_config(struct umcpmio_softc *sc, 2201.1Sbrad uint16_t max_transfer_size, int slave) 2211.1Sbrad{ 2221.1Sbrad struct mcp2210_get_spi_sram_res get_res; 2231.1Sbrad struct mcp2210_set_spi_sram_req set_req; 2241.1Sbrad struct mcp2210_set_spi_sram_res set_res; 2251.1Sbrad uint16_t idle; 2261.1Sbrad uint16_t active; 2271.1Sbrad int err = 0; 2281.1Sbrad 2291.1Sbrad err = mcp2210_get_spi_sram(sc, &get_res); 2301.1Sbrad if (err) 2311.1Sbrad goto out; 2321.1Sbrad 2331.1Sbrad memset(&set_res, 0, MCP2210_RES_BUFFER_SIZE); 2341.1Sbrad memcpy(&set_req, &get_res, MCP2210_REQ_BUFFER_SIZE); 2351.1Sbrad 2361.1Sbrad /* The MCP2210 supports the notion of a high active for 2371.1Sbrad * the CS, but spi(4) doesn't so, just use the normal 2381.1Sbrad * low active behavior all of the time. 2391.1Sbrad * 2401.1Sbrad * The chip also appears to support more than one CS 2411.1Sbrad * being active at the same time, but that is really 2421.1Sbrad * an unusual desire to have. 2431.1Sbrad */ 2441.1Sbrad 2451.1Sbrad idle = 0xffff; 2461.1Sbrad active = ~(1 << slave); 2471.1Sbrad 2481.1Sbrad set_req.idle_cs_value_lsb = (uint8_t)(idle & 0xff); 2491.1Sbrad set_req.idle_cs_value_msb = (uint8_t)(idle >> 8); 2501.1Sbrad set_req.active_cs_value_lsb = (uint8_t)(active & 0xff); 2511.1Sbrad set_req.active_cs_value_msb = (uint8_t)(active >> 8); 2521.1Sbrad 2531.1Sbrad set_req.spi_mode = sc->sc_slave_configs[slave].mode; 2541.1Sbrad 2551.1Sbrad uint32_t s = sc->sc_slave_configs[slave].bit_rate; 2561.1Sbrad set_req.bit_rate_byte_3 = (0x000000ff & s); 2571.1Sbrad set_req.bit_rate_byte_2 |= (0x000000ff & (s >> 8)); 2581.1Sbrad set_req.bit_rate_byte_1 |= (0x000000ff & (s >> 16)); 2591.1Sbrad set_req.bit_rate_byte_0 |= (0x000000ff & (s >> 24)); 2601.1Sbrad 2611.1Sbrad /* The MCP2210 does best when the tranfer size is set to the 2621.1Sbrad * same max amount that a transfer incoming might have. 2631.1Sbrad */ 2641.1Sbrad 2651.1Sbrad set_req.bytes_per_spi_transaction_lsb = (uint8_t)(max_transfer_size & 0xff); 2661.1Sbrad set_req.bytes_per_spi_transaction_msb = (uint8_t)(max_transfer_size >> 8); 2671.1Sbrad 2681.1Sbrad err = mcp2210_set_spi_sram(sc, &set_req, &set_res); 2691.1Sbrad 2701.1Sbradout: 2711.1Sbrad 2721.1Sbrad DPRINTF(("mcp2210_spi_set_slave exit: err=%d\n", err)); 2731.1Sbrad 2741.1Sbrad return err; 2751.1Sbrad} 2761.1Sbrad 2771.1Sbrad/* Fill up the outgoing tranfer buffers. It is generally assumed that the state 2781.1Sbrad * of the req buffer is set coming into this function. It should either be 2791.1Sbrad * zero filled or a repeat buffer in a retry situation. 2801.1Sbrad */ 2811.1Sbrad 2821.1Sbradstatic void 2831.1Sbradmcp2210_spi_tx_fill(struct umcpmio_softc *sc, 2841.1Sbrad struct mcp2210_spi_transfer_req *req) 2851.1Sbrad{ 2861.1Sbrad struct spi_chunk *chunk = sc->sc_wchunk; 2871.1Sbrad size_t len; 2881.1Sbrad 2891.1Sbrad if (chunk == NULL) 2901.1Sbrad return; 2911.1Sbrad 2921.1Sbrad if (sc->sc_dying) 2931.1Sbrad return; 2941.1Sbrad 2951.1Sbrad len = MIN(MCP2210_MAX_SPI_BYTES, chunk->chunk_wresid); 2961.1Sbrad DPRINTF(("mcp2210_spi_tx_fill: len=%zd; chunk_wresid=%d\n", 2971.1Sbrad len, chunk->chunk_wresid)); 2981.1Sbrad chunk->chunk_wresid -= len; 2991.1Sbrad req->num_send_bytes += len; 3001.1Sbrad if (chunk->chunk_wptr) 3011.1Sbrad memcpy(&req->send_bytes[0], chunk->chunk_wptr, len); 3021.1Sbrad DPRINTF(("mcp2210_spi_tx_fill: checking sending values.. req->num_send_bytes=%d, chunk_wresid=%d\n", 3031.1Sbrad req->num_send_bytes, chunk->chunk_wresid)); 3041.1Sbrad if (chunk->chunk_wresid == 0) { 3051.1Sbrad DPRINTF(("mcp2210_spi_tx_fill: moving onto the next chunk\n")); 3061.1Sbrad sc->sc_wchunk = sc->sc_wchunk->chunk_next; 3071.1Sbrad if (sc->sc_wchunk) 3081.1Sbrad DPRINTF(("mcp2210_spi_tx_fill: new chunk EXISTS\n")); 3091.1Sbrad else 3101.1Sbrad DPRINTF(("mcp2210_spi_tx_fill: new chunk does not EXIST, NULL\n")); 3111.1Sbrad } 3121.1Sbrad} 3131.1Sbrad 3141.1Sbrad/* Drain the incoming buffer into the upstream structure. If there is no 3151.1Sbrad * upstream to drain into, then queue up the result for later. 3161.1Sbrad */ 3171.1Sbrad 3181.1Sbradstatic int 3191.1Sbradmcp2210_spi_rx_drain(struct umcpmio_softc *sc, int slave, 3201.1Sbrad struct mcp2210_spi_transfer_res *res) 3211.1Sbrad{ 3221.1Sbrad struct spi_chunk *chunk = sc->sc_rchunk; 3231.1Sbrad size_t len; 3241.1Sbrad struct umcpmio_spi_received *r; 3251.1Sbrad int err = 0; 3261.1Sbrad 3271.1Sbrad if (chunk == NULL) 3281.1Sbrad return err; 3291.1Sbrad 3301.1Sbrad if (sc->sc_dying) 3311.1Sbrad return err; 3321.1Sbrad 3331.1Sbrad len = MIN(res->num_receive_bytes, chunk->chunk_rresid); 3341.1Sbrad chunk->chunk_rresid -= len; 3351.1Sbrad DPRINTF(("mcp2210_spi_rx_drain: ENTER: len=%zd; res->num_receive_bytes=%d; chunk_rresid=%d\n", 3361.1Sbrad len, res->num_receive_bytes, chunk->chunk_rresid)); 3371.1Sbrad if (chunk->chunk_rptr) 3381.1Sbrad memcpy(chunk->chunk_rptr, &res->receive_bytes[0], len); 3391.1Sbrad if (chunk->chunk_rresid == 0) { 3401.1Sbrad DPRINTF(("mcp2210_spi_rx_drain: moving onto the next chunk\n")); 3411.1Sbrad sc->sc_rchunk = sc->sc_rchunk->chunk_next; 3421.1Sbrad if (sc->sc_rchunk) 3431.1Sbrad DPRINTF(("mcp2210_spi_rx_drain: new chunk EXISTS\n")); 3441.1Sbrad else 3451.1Sbrad DPRINTF(("mcp2210_spi_rx_drain: new chunk does not EXIST, NULL\n")); 3461.1Sbrad } 3471.1Sbrad DPRINTF(("mcp2210_spi_rx_drain: checking received values.. res->num_received_bytes=%d\n", 3481.1Sbrad res->num_receive_bytes)); 3491.1Sbrad if (len < res->num_receive_bytes) { 3501.1Sbrad DPRINTF(("mcp2210_spi_rx_drain: did not consume all that was received, Q it up.... res->num_received_bytes=%d\n", 3511.1Sbrad res->num_receive_bytes)); 3521.1Sbrad r = kmem_alloc(sizeof(struct umcpmio_spi_received), KM_NOSLEEP); 3531.1Sbrad if (r != NULL) { 3541.1Sbrad memcpy(&r->receive_bytes[0], &res->receive_bytes[len], res->num_receive_bytes - len); 3551.1Sbrad r->num_receive_bytes = res->num_receive_bytes - len; 3561.1Sbrad SIMPLEQ_INSERT_HEAD(&sc->sc_received[slave], r, umcpmio_spi_received_q); 3571.1Sbrad } else { 3581.1Sbrad err = ENOMEM; 3591.1Sbrad } 3601.1Sbrad } 3611.1Sbrad return err; 3621.1Sbrad} 3631.1Sbrad 3641.1Sbrad/* Very simular to receiving from the chip buffer, except from this 3651.1Sbrad * is from the local queue. Requeue if needed. 3661.1Sbrad */ 3671.1Sbrad 3681.1Sbradstatic int 3691.1Sbradmcp2210_spi_rx_q(struct umcpmio_softc *sc, int slave, 3701.1Sbrad struct umcpmio_spi_received *r) 3711.1Sbrad{ 3721.1Sbrad struct spi_chunk *chunk = sc->sc_rchunk; 3731.1Sbrad size_t len; 3741.1Sbrad struct umcpmio_spi_received *mr; 3751.1Sbrad int err = 0; 3761.1Sbrad 3771.1Sbrad if (chunk == NULL) 3781.1Sbrad return err; 3791.1Sbrad 3801.1Sbrad if (sc->sc_dying) 3811.1Sbrad return err; 3821.1Sbrad 3831.1Sbrad len = MIN(r->num_receive_bytes, chunk->chunk_rresid); 3841.1Sbrad chunk->chunk_rresid -= len; 3851.1Sbrad DPRINTF(("mcp2210_spi_rx_q: ENTER: len=%zd; r->num_receive_bytes=%d; chunk_rresid=%d\n", 3861.1Sbrad len, r->num_receive_bytes, chunk->chunk_rresid)); 3871.1Sbrad if (chunk->chunk_rptr) 3881.1Sbrad memcpy(chunk->chunk_rptr, &r->receive_bytes[0], len); 3891.1Sbrad if (chunk->chunk_rresid == 0) { 3901.1Sbrad DPRINTF(("mcp2210_spi_rx_q: moving onto the next chunk\n")); 3911.1Sbrad sc->sc_rchunk = sc->sc_rchunk->chunk_next; 3921.1Sbrad if (sc->sc_rchunk) 3931.1Sbrad DPRINTF(("mcp2210_spi_rx_q: new chunk EXISTS\n")); 3941.1Sbrad else 3951.1Sbrad DPRINTF(("mcp2210_spi_rx_q: new chunk does not EXIST, NULL\n")); 3961.1Sbrad } 3971.1Sbrad DPRINTF(("mcp2210_spi_rx_q: checking received values.. r->num_received_bytes=%d\n", 3981.1Sbrad r->num_receive_bytes)); 3991.1Sbrad if (len < r->num_receive_bytes) { 4001.1Sbrad DPRINTF(("mcp2210_spi_rx_q: did not consume all that was received, Q it up... r->num_received_bytes=%d\n", 4011.1Sbrad r->num_receive_bytes)); 4021.1Sbrad mr = kmem_alloc(sizeof(struct umcpmio_spi_received), KM_NOSLEEP); 4031.1Sbrad if (mr != NULL) { 4041.1Sbrad memcpy(&mr->receive_bytes[0], &r->receive_bytes[len], r->num_receive_bytes - len); 4051.1Sbrad mr->num_receive_bytes = r->num_receive_bytes - len; 4061.1Sbrad SIMPLEQ_INSERT_HEAD(&sc->sc_received[slave], mr, umcpmio_spi_received_q); 4071.1Sbrad } else { 4081.1Sbrad err = ENOMEM; 4091.1Sbrad } 4101.1Sbrad } 4111.1Sbrad return err; 4121.1Sbrad} 4131.1Sbrad 4141.1Sbrad/* Drain the chip buffers into the local queue. No upstream involved. */ 4151.1Sbrad 4161.1Sbradstatic int 4171.1Sbradmcp2210_spi_rx_drainchip(struct umcpmio_softc *sc, int slave, 4181.1Sbrad struct mcp2210_spi_transfer_res *res) 4191.1Sbrad{ 4201.1Sbrad int err = 0; 4211.1Sbrad struct umcpmio_spi_received *r; 4221.1Sbrad 4231.1Sbrad r = kmem_alloc(sizeof(struct umcpmio_spi_received), KM_NOSLEEP); 4241.1Sbrad if (r == NULL) 4251.1Sbrad return ENOMEM; 4261.1Sbrad memcpy(&r->receive_bytes[0], &res->receive_bytes[0], res->num_receive_bytes); 4271.1Sbrad r->num_receive_bytes = res->num_receive_bytes; 4281.1Sbrad SIMPLEQ_INSERT_TAIL(&sc->sc_received[slave], r, umcpmio_spi_received_q); 4291.1Sbrad 4301.1Sbrad return err; 4311.1Sbrad} 4321.1Sbrad 4331.1Sbrad/* Service a tranfer. We do the local queue first if there is something, then 4341.1Sbrad * send a tranfer, with an optional amount of data, and then process any 4351.1Sbrad * incoming chip data. 4361.1Sbrad */ 4371.1Sbrad 4381.1Sbradstatic int 4391.1Sbradmcp2210_spi_txrx(struct umcpmio_softc *sc, int slave) 4401.1Sbrad{ 4411.1Sbrad struct mcp2210_spi_transfer_req req; 4421.1Sbrad struct mcp2210_spi_transfer_res res; 4431.1Sbrad struct umcpmio_spi_received *r; 4441.1Sbrad int err = 0; 4451.1Sbrad int wretry = sc->sc_retry_busy_write; 4461.1Sbrad 4471.1Sbrad DPRINTF(("mcp2210_spi_txrx: ENTER\n")); 4481.1Sbrad 4491.1Sbrad if (sc->sc_dying) 4501.1Sbrad return err; 4511.1Sbrad 4521.1Sbrad /* There was local queue data and an upstream to receive it */ 4531.1Sbrad 4541.1Sbrad if (!SIMPLEQ_EMPTY(&sc->sc_received[slave]) && 4551.1Sbrad sc->sc_rchunk != NULL) { 4561.1Sbrad DPRINTF(("mcp2210_spi_txrx: previous received bytes to send to upstream\n")); 4571.1Sbrad while ((r = SIMPLEQ_FIRST(&sc->sc_received[slave])) != NULL) { 4581.1Sbrad SIMPLEQ_REMOVE_HEAD(&sc->sc_received[slave], umcpmio_spi_received_q); 4591.1Sbrad err = mcp2210_spi_rx_q(sc, slave, r); 4601.1Sbrad kmem_free(r, sizeof(struct umcpmio_spi_received)); 4611.1Sbrad if (err) 4621.1Sbrad break; 4631.1Sbrad } 4641.1Sbrad 4651.1Sbrad goto out; 4661.1Sbrad } 4671.1Sbrad if (sc->sc_dying) 4681.1Sbrad return err; 4691.1Sbrad 4701.1Sbrad /* Set up a transfer and fill it once */ 4711.1Sbrad 4721.1Sbrad memset(&req, 0, UMCPMIO_REQ_BUFFER_SIZE); 4731.1Sbrad 4741.1Sbrad if (sc->sc_wchunk != NULL) 4751.1Sbrad DPRINTF(("mcp2210_spi_txrx: filling up req for write transfer; chunk_wresid=%d\n", sc->sc_wchunk->chunk_wresid)); 4761.1Sbrad else 4771.1Sbrad DPRINTF(("mcp2210_spi_txrx: filling up req for write transfer; wchunk is NULL\n")); 4781.1Sbrad mcp2210_spi_tx_fill(sc, &req); 4791.1Sbrad 4801.1Sbradretry: 4811.1Sbrad 4821.1Sbrad memset(&res, 0, UMCPMIO_RES_BUFFER_SIZE); 4831.1Sbrad 4841.1Sbrad if (sc->sc_dying) 4851.1Sbrad return err; 4861.1Sbrad 4871.1Sbrad err = mcp2210_do_spi_transfer(sc, &req, &res); 4881.1Sbrad if (err) 4891.1Sbrad if (err != EBUSY) 4901.1Sbrad goto out; 4911.1Sbrad 4921.1Sbrad DPRINTF(("mcp2210_spi_txrx: did transfer res.completion=%02x ;" 4931.1Sbrad "res.spi_engine_status=%02x, res.num_receive_bytes=%d\n", 4941.1Sbrad res.completion, res.spi_engine_status, res.num_receive_bytes)); 4951.1Sbrad 4961.1Sbrad /* This error situation of MCP2210_SPI_STATUS_DATA (0x30) and 4971.1Sbrad * zero received data means either the chip is stuck because 4981.1Sbrad * upstream didn't send enough data, or the chip is working 4991.1Sbrad * on receiving some data. We only let this condution go on 5001.1Sbrad * a certain number of times before passing the error up. 5011.1Sbrad */ 5021.1Sbrad 5031.1Sbrad if (!err) { 5041.1Sbrad if (res.spi_engine_status == MCP2210_SPI_STATUS_DATA && 5051.1Sbrad res.num_receive_bytes == 0) { 5061.1Sbrad err = ECANCELED; 5071.1Sbrad } 5081.1Sbrad } 5091.1Sbrad 5101.1Sbrad /* A normal busy caused by the SPI bus being busy or the USB 5111.1Sbrad * bus being busy. Try the whole transfer again. 5121.1Sbrad */ 5131.1Sbrad 5141.1Sbrad if (err == EBUSY) { 5151.1Sbrad DPRINTF(("mcp2210_spi_txrx: transfer is busy\n")); 5161.1Sbrad wretry--; 5171.1Sbrad if (wretry > 0) { 5181.1Sbrad WAITMS(sc->sc_busy_delay); 5191.1Sbrad goto retry; 5201.1Sbrad } else { 5211.1Sbrad err = EIO; 5221.1Sbrad goto out; 5231.1Sbrad } 5241.1Sbrad } 5251.1Sbrad 5261.1Sbrad /* If the chip knows that there is data coming, but has not seen 5271.1Sbrad * any yet you get this error. Retry the transfer with a zero 5281.1Sbrad * length outgoing buffer. 5291.1Sbrad */ 5301.1Sbrad 5311.1Sbrad if (res.spi_engine_status == MCP2210_SPI_STATUS_NO_DATA_YET) { 5321.1Sbrad DPRINTF(("mcp2210_spi_txrx: transfer is NO DATA YET\n")); 5331.1Sbrad wretry--; 5341.1Sbrad if (wretry > 0) { 5351.1Sbrad WAITMS(sc->sc_busy_delay); 5361.1Sbrad memset(&req, 0, UMCPMIO_REQ_BUFFER_SIZE); 5371.1Sbrad goto retry; 5381.1Sbrad } else { 5391.1Sbrad err = EIO; 5401.1Sbrad goto out; 5411.1Sbrad } 5421.1Sbrad } 5431.1Sbrad DPRINTF(("mcp2210_spi_txrx: DOING RECEIVE: res.num_receive_bytes=%d\n", 5441.1Sbrad res.num_receive_bytes)); 5451.1Sbrad 5461.1Sbrad /* If we actually received some data, drain it somewhere */ 5471.1Sbrad 5481.1Sbrad if (res.num_receive_bytes > 0) { 5491.1Sbrad if (sc->sc_rchunk != NULL && 5501.1Sbrad sc->sc_rchunk->chunk_rptr) { 5511.1Sbrad DPRINTF(("mcp2210_spi_txrx: send data to upstream\n")); 5521.1Sbrad err = mcp2210_spi_rx_drain(sc, slave, &res); 5531.1Sbrad } else { 5541.1Sbrad DPRINTF(("mcp2210_spi_txrx: drain chip, send data to Q\n")); 5551.1Sbrad err = mcp2210_spi_rx_drainchip(sc, slave, &res); 5561.1Sbrad } 5571.1Sbrad } 5581.1Sbradout: 5591.1Sbrad 5601.1Sbrad DPRINTF(("mcp2210_spi_txrx exit. err=%d\n", err)); 5611.1Sbrad 5621.1Sbrad return err; 5631.1Sbrad} 5641.1Sbrad 5651.1Sbrad/* Cancel a SPI transfer that might be in progress, or at 5661.1Sbrad * least the chip thinks is in progress. 5671.1Sbrad */ 5681.1Sbrad 5691.1Sbradint 5701.1Sbradmcp2210_cancel_spi_transfer(struct umcpmio_softc *sc, 5711.1Sbrad struct mcp2210_cancel_spi_res *res) 5721.1Sbrad{ 5731.1Sbrad struct mcp2210_cancel_spi_req req; 5741.1Sbrad int err = 0; 5751.1Sbrad 5761.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 5771.1Sbrad 5781.1Sbrad memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 5791.1Sbrad req.cmd = MCP2210_CMD_SPI_CANCEL; 5801.1Sbrad 5811.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 5821.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 5831.1Sbrad "mcp2210_cancel_spi_transfer req"); 5841.1Sbrad 5851.1Sbrad err = umcpmio_send_report(sc, 5861.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 5871.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 5881.1Sbrad 5891.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 5901.1Sbrad (uint8_t *) res, MCP2210_RES_BUFFER_SIZE, 5911.1Sbrad "mcp2210_get_spi_sram res"); 5921.1Sbrad 5931.1Sbrad err = mcp2210_decode_errors(req.cmd, err, res->completion); 5941.1Sbrad 5951.1Sbrad return err; 5961.1Sbrad} 5971.1Sbrad 5981.1Sbrad/* As long as there are outgoing chunks to send, 5991.1Sbrad * or incoming chunks to receive, poll the SPI port. 6001.1Sbrad */ 6011.1Sbrad 6021.1Sbradstatic void 6031.1Sbradmcp2210_spi_poll(struct umcpmio_softc *sc, 6041.1Sbrad int slave, int *stuckcount) 6051.1Sbrad{ 6061.1Sbrad struct spi_transfer *st; 6071.1Sbrad struct mcp2210_cancel_spi_res cancel_res; 6081.1Sbrad int err = 0; 6091.1Sbrad 6101.1Sbrad err = mcp2210_spi_txrx(sc, slave); 6111.1Sbrad 6121.1Sbrad DPRINTF(("mcp2210_spi_poll: err from transfer: err=%d\n", err)); 6131.1Sbrad 6141.1Sbrad /* Give up if we exceed the stuck count. It is ok for this to happen 6151.1Sbrad * a couple of times during a transfer, but if it persists, something is 6161.1Sbrad * going wrong. 6171.1Sbrad */ 6181.1Sbrad if (err == ECANCELED) { 6191.1Sbrad int s; 6201.1Sbrad 6211.1Sbrad s = *stuckcount; 6221.1Sbrad s--; 6231.1Sbrad DPRINTF(("mcp2210_spi_poll: STUCK s=%d\n", s)); 6241.1Sbrad if (s > 0) 6251.1Sbrad err = 0; 6261.1Sbrad *stuckcount = s; 6271.1Sbrad } 6281.1Sbrad 6291.1Sbrad if (err) { 6301.1Sbrad if (err == ECANCELED) { 6311.1Sbrad if (sc->sc_spi_verbose) 6321.1Sbrad device_printf(sc->sc_dev, "The SPI transfer may be stuck. Canceling.\n"); 6331.1Sbrad mutex_enter(&sc->sc_action_mutex); 6341.1Sbrad mcp2210_cancel_spi_transfer(sc, &cancel_res); 6351.1Sbrad mutex_exit(&sc->sc_action_mutex); 6361.1Sbrad } 6371.1Sbrad sc->sc_rchunk = sc->sc_wchunk = NULL; 6381.1Sbrad } 6391.1Sbrad 6401.1Sbrad /* Finialize the transfer */ 6411.1Sbrad 6421.1Sbrad if (sc->sc_rchunk == NULL && 6431.1Sbrad sc->sc_wchunk == NULL) { 6441.1Sbrad st = sc->sc_transfer; 6451.1Sbrad sc->sc_transfer = NULL; 6461.1Sbrad KASSERT(st != NULL); 6471.1Sbrad spi_done(st, 0); 6481.1Sbrad sc->sc_running = false; 6491.1Sbrad } 6501.1Sbrad return; 6511.1Sbrad} 6521.1Sbrad 6531.1Sbrad/* Start a SPI transfer up and running */ 6541.1Sbrad 6551.1Sbradstatic void 6561.1Sbradmcp2210_spi_start(struct umcpmio_softc *sc) 6571.1Sbrad{ 6581.1Sbrad struct spi_transfer *st; 6591.1Sbrad struct spi_chunk *chunk; 6601.1Sbrad uint16_t max_transfer_size = 0; 6611.1Sbrad int transfer_size = 0; 6621.1Sbrad int err = 0; 6631.1Sbrad int stuckcount = 4; /* XXX - maybe this should be a sysctl */ 6641.1Sbrad struct mcp2210_cancel_spi_res cancel_res; 6651.1Sbrad 6661.1Sbrad while ((st = spi_transq_first(&sc->sc_q)) != NULL) { 6671.1Sbrad spi_transq_dequeue(&sc->sc_q); 6681.1Sbrad KASSERT(sc->sc_transfer == NULL); 6691.1Sbrad sc->sc_transfer = st; 6701.1Sbrad sc->sc_rchunk = sc->sc_wchunk = st->st_chunks; 6711.1Sbrad sc->sc_running = true; 6721.1Sbrad 6731.1Sbrad KASSERT(st->st_slave < sc->sc_spi.sct_nslaves); 6741.1Sbrad 6751.1Sbrad /* Figure out the maximum size for this transfer. 6761.1Sbrad * It doesn't matter if it is a incoming or outgoing 6771.1Sbrad * chunk. 6781.1Sbrad */ 6791.1Sbrad chunk = st->st_chunks; 6801.1Sbrad while (chunk != NULL) { 6811.1Sbrad if (chunk->chunk_wresid > transfer_size) 6821.1Sbrad transfer_size = chunk->chunk_wresid; 6831.1Sbrad if (chunk->chunk_rresid > transfer_size) 6841.1Sbrad transfer_size = chunk->chunk_rresid; 6851.1Sbrad chunk = chunk->chunk_next; 6861.1Sbrad } 6871.1Sbrad 6881.1Sbrad KASSERT(transfer_size > 0); 6891.1Sbrad 6901.1Sbrad /* The chip can do up to 65535 bytes in a transfer. We subtract 6911.1Sbrad * 1 so the slave device can send back a end byte. There is, 6921.1Sbrad * apparently some was to do larger transfers, but I could 6931.1Sbrad * not find documentation on how to do that. 6941.1Sbrad */ 6951.1Sbrad if (transfer_size > 65534) { 6961.1Sbrad if (sc->sc_spi_verbose) 6971.1Sbrad device_printf(sc->sc_dev, "Canceling transfer. " 6981.1Sbrad "The size of the requested transfer is too big. " 6991.1Sbrad "transfer_size=%d\n", 7001.1Sbrad transfer_size); 7011.1Sbrad 7021.1Sbrad st = sc->sc_transfer; 7031.1Sbrad sc->sc_transfer = NULL; 7041.1Sbrad spi_done(st, 0); 7051.1Sbrad sc->sc_running = false; 7061.1Sbrad 7071.1Sbrad return; 7081.1Sbrad } 7091.1Sbrad max_transfer_size = (uint16_t) transfer_size + 1; 7101.1Sbrad 7111.1Sbrad DPRINTF(("mcp2210_spi_start: transfer_size=%d; max_transfer_size=%d\n", transfer_size, max_transfer_size)); 7121.1Sbrad 7131.1Sbrad /* Set all of the defered setting now that we are commited to trying 7141.1Sbrad * to do the transfer. 7151.1Sbrad */ 7161.1Sbrad err = mcp2210_spi_set_slave_config(sc, max_transfer_size, st->st_slave); 7171.1Sbrad /* If we get EBUSY here, then it probably means that there was a incomplete 7181.1Sbrad * transfer. Cancel it, and try one more time. 7191.1Sbrad */ 7201.1Sbrad if (err == EBUSY) { 7211.1Sbrad mutex_enter(&sc->sc_action_mutex); 7221.1Sbrad mcp2210_cancel_spi_transfer(sc, &cancel_res); 7231.1Sbrad mutex_exit(&sc->sc_action_mutex); 7241.1Sbrad err = mcp2210_spi_set_slave_config(sc, max_transfer_size, st->st_slave); 7251.1Sbrad } 7261.1Sbrad if (err) { 7271.1Sbrad if (sc->sc_spi_verbose) 7281.1Sbrad device_printf(sc->sc_dev, "Canceling transfer. Error setting up slave config. error=%d\n", err); 7291.1Sbrad 7301.1Sbrad st = sc->sc_transfer; 7311.1Sbrad sc->sc_transfer = NULL; 7321.1Sbrad spi_done(st, 0); 7331.1Sbrad sc->sc_running = false; 7341.1Sbrad 7351.1Sbrad return; 7361.1Sbrad } 7371.1Sbrad 7381.1Sbrad for (;;) { 7391.1Sbrad mcp2210_spi_poll(sc, st->st_slave, &stuckcount); 7401.1Sbrad if (ISSET(st->st_flags, SPI_F_DONE)) 7411.1Sbrad break; 7421.1Sbrad if (sc->sc_dying) 7431.1Sbrad break; 7441.1Sbrad } 7451.1Sbrad } 7461.1Sbrad sc->sc_running = false; 7471.1Sbrad 7481.1Sbrad return; 7491.1Sbrad} 7501.1Sbrad 7511.1Sbradstatic int 7521.1Sbradmcp2210_spi_transfer(void *cookie, struct spi_transfer *st) 7531.1Sbrad{ 7541.1Sbrad struct umcpmio_softc *sc = cookie; 7551.1Sbrad 7561.1Sbrad mutex_enter(&sc->sc_spi_mutex); 7571.1Sbrad spi_transq_enqueue(&sc->sc_q, st); 7581.1Sbrad if (sc->sc_running == false) { 7591.1Sbrad mcp2210_spi_start(sc); 7601.1Sbrad } 7611.1Sbrad mutex_exit(&sc->sc_spi_mutex); 7621.1Sbrad 7631.1Sbrad return 0; 7641.1Sbrad} 7651.1Sbrad 7661.1Sbradint 7671.1Sbradumcpmio_spi_attach(struct umcpmio_softc *sc) 7681.1Sbrad{ 7691.1Sbrad struct mcp2210_get_spi_sram_res get_res; 7701.1Sbrad struct mcp2210_set_spi_sram_req set_req; 7711.1Sbrad struct mcp2210_set_spi_sram_res set_res; 7721.1Sbrad struct mcp2210_cancel_spi_res cancel_res; 7731.1Sbrad int err = 0; 7741.1Sbrad 7751.1Sbrad sc->sc_spi_verbose = true; 7761.1Sbrad sc->sc_busy_delay = 0; 7771.1Sbrad sc->sc_retry_busy_read = 50; 7781.1Sbrad sc->sc_retry_busy_write = 50; 7791.1Sbrad sc->sc_running = false; 7801.1Sbrad 7811.1Sbrad DPRINTF(("umcpmio_spi_attach: sc->sc_chipinfo->num_spi_slaves=%d\n", sc->sc_chipinfo->num_spi_slaves)); 7821.1Sbrad 7831.1Sbrad SIMPLEQ_INIT(&sc->sc_q); 7841.1Sbrad 7851.1Sbrad for (int i = 0; i < sc->sc_chipinfo->num_spi_slaves; i++){ 7861.1Sbrad SIMPLEQ_INIT(&sc->sc_received[i]); 7871.1Sbrad sc->sc_slave_configs[i].bit_rate = (uint32_t) SPI_FREQ_MHz(1); 7881.1Sbrad sc->sc_slave_configs[i].mode = MCP2210_SPI_MODE_0; 7891.1Sbrad } 7901.1Sbrad 7911.1Sbrad /* Set all of the active and idle CS directions here. */ 7921.1Sbrad err = mcp2210_get_spi_sram(sc, &get_res); 7931.1Sbrad if (err) { 7941.1Sbrad aprint_error_dev(sc->sc_dev, 7951.1Sbrad "%s: unable to read SPI sram: %d\n", 7961.1Sbrad __func__, err); 7971.1Sbrad goto out; 7981.1Sbrad } 7991.1Sbrad memset(&set_res, 0, MCP2210_RES_BUFFER_SIZE); 8001.1Sbrad memcpy(&set_req, &get_res, MCP2210_REQ_BUFFER_SIZE); 8011.1Sbrad 8021.1Sbrad set_req.idle_cs_value_lsb = set_req.idle_cs_value_msb = 0xff; 8031.1Sbrad set_req.active_cs_value_lsb = set_req.active_cs_value_msb = 0x00; 8041.1Sbrad 8051.1Sbrad err = mcp2210_set_spi_sram(sc, &set_req, &set_res); 8061.1Sbrad /* If there is a EBUSY here, then a transfer was incomplete 8071.1Sbrad * in the past. That can happen on attach if the chip stays 8081.1Sbrad * powered up, but is removed from the USB port and 8091.1Sbrad * reinserted. Cancel the transfer and try one more time. 8101.1Sbrad */ 8111.1Sbrad if (err == EBUSY) { 8121.1Sbrad mutex_enter(&sc->sc_action_mutex); 8131.1Sbrad mcp2210_cancel_spi_transfer(sc, &cancel_res); 8141.1Sbrad mutex_exit(&sc->sc_action_mutex); 8151.1Sbrad err = mcp2210_set_spi_sram(sc, &set_req, &set_res); 8161.1Sbrad } 8171.1Sbrad if (err) { 8181.1Sbrad aprint_error_dev(sc->sc_dev, 8191.1Sbrad "%s: unable to set SPI sram: %d\n", 8201.1Sbrad __func__, err); 8211.1Sbrad goto out; 8221.1Sbrad } 8231.1Sbrad sc->sc_spi.sct_cookie = sc; 8241.1Sbrad sc->sc_spi.sct_configure = mcp2210_spi_configure; 8251.1Sbrad sc->sc_spi.sct_transfer = mcp2210_spi_transfer; 8261.1Sbrad sc->sc_spi.sct_nslaves = sc->sc_chipinfo->num_spi_slaves; 8271.1Sbrad 8281.1Sbrad spibus_attach(sc->sc_dev, &sc->sc_spi); 8291.1Sbrad 8301.1Sbradout: 8311.1Sbrad 8321.1Sbrad return err; 8331.1Sbrad} 834