1300715Sadrian/*- 2300715Sadrian * Copyright (c) 2011, Aleksandr Rybalko <ray@dlink.ua> 3300715Sadrian * All rights reserved. 4300715Sadrian * 5300715Sadrian * Redistribution and use in source and binary forms, with or without 6300715Sadrian * modification, are permitted provided that the following conditions 7300715Sadrian * are met: 8300715Sadrian * 1. Redistributions of source code must retain the above copyright 9300715Sadrian * notice unmodified, this list of conditions, and the following 10300715Sadrian * disclaimer. 11300715Sadrian * 2. Redistributions in binary form must reproduce the above copyright 12300715Sadrian * notice, this list of conditions and the following disclaimer in the 13300715Sadrian * documentation and/or other materials provided with the distribution. 14300715Sadrian * 15300715Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16300715Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17300715Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18300715Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19300715Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20300715Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21300715Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22300715Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23300715Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24300715Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25300715Sadrian * SUCH DAMAGE. 26300715Sadrian */ 27300715Sadrian 28300715Sadrian#include <sys/cdefs.h> 29300715Sadrian__FBSDID("$FreeBSD: releng/11.0/sys/dev/gpio/gpiospi.c 300715 2016-05-26 07:20:33Z adrian $"); 30300715Sadrian 31300715Sadrian#include "opt_gpio.h" 32300715Sadrian 33300715Sadrian#include <sys/param.h> 34300715Sadrian#include <sys/systm.h> 35300715Sadrian 36300715Sadrian#include <sys/bus.h> 37300715Sadrian#include <sys/kernel.h> 38300715Sadrian#include <sys/module.h> 39300715Sadrian#include <sys/rman.h> 40300715Sadrian#include <sys/sysctl.h> 41300715Sadrian 42300715Sadrian#include <sys/gpio.h> 43300715Sadrian#include "gpiobus_if.h" 44300715Sadrian 45300715Sadrian#include <dev/gpio/gpiobusvar.h> 46300715Sadrian 47300715Sadrian#include <dev/spibus/spi.h> 48300715Sadrian#include <dev/spibus/spibusvar.h> 49300715Sadrian#include "spibus_if.h" 50300715Sadrian 51300715Sadrian#ifdef GPIO_SPI_DEBUG 52300715Sadrian#define dprintf printf 53300715Sadrian#else 54300715Sadrian#define dprintf(x, arg...) 55300715Sadrian#endif /* GPIO_SPI_DEBUG */ 56300715Sadrian 57300715Sadrianstruct gpio_spi_softc { 58300715Sadrian device_t sc_dev; 59300715Sadrian device_t sc_busdev; 60300715Sadrian int sc_freq; 61300715Sadrian uint8_t sc_sclk; 62300715Sadrian uint8_t sc_miso; 63300715Sadrian uint8_t sc_mosi; 64300715Sadrian uint8_t sc_cs0; 65300715Sadrian uint8_t sc_cs1; 66300715Sadrian uint8_t sc_cs2; 67300715Sadrian uint8_t sc_cs3; 68300715Sadrian}; 69300715Sadrian 70300715Sadrianstatic void gpio_spi_chip_activate(struct gpio_spi_softc *, int); 71300715Sadrianstatic void gpio_spi_chip_deactivate(struct gpio_spi_softc *, int); 72300715Sadrian 73300715Sadrianstatic int 74300715Sadriangpio_spi_probe(device_t dev) 75300715Sadrian{ 76300715Sadrian device_set_desc(dev, "GPIO SPI bit-banging driver"); 77300715Sadrian return (0); 78300715Sadrian} 79300715Sadrian 80300715Sadrianstatic void 81300715Sadriangpio_delay(struct gpio_spi_softc *sc) 82300715Sadrian{ 83300715Sadrian int d; 84300715Sadrian 85300715Sadrian d = sc->sc_freq / 1000000; 86300715Sadrian if (d == 0) 87300715Sadrian d = 1; 88300715Sadrian 89300715Sadrian DELAY(d); 90300715Sadrian} 91300715Sadrian 92300715Sadrianstatic int 93300715Sadriangpio_spi_attach(device_t dev) 94300715Sadrian{ 95300715Sadrian uint32_t value; 96300715Sadrian struct gpio_spi_softc *sc; 97300715Sadrian 98300715Sadrian sc = device_get_softc(dev); 99300715Sadrian sc->sc_dev = dev; 100300715Sadrian sc->sc_busdev = device_get_parent(dev); 101300715Sadrian 102300715Sadrian /* Required variables */ 103300715Sadrian if (resource_int_value(device_get_name(dev), 104300715Sadrian device_get_unit(dev), "sclk", &value)) 105300715Sadrian return (ENXIO); 106300715Sadrian sc->sc_sclk = value & 0xff; 107300715Sadrian 108300715Sadrian if (resource_int_value(device_get_name(dev), 109300715Sadrian device_get_unit(dev), "mosi", &value)) 110300715Sadrian return (ENXIO); 111300715Sadrian sc->sc_mosi = value & 0xff; 112300715Sadrian 113300715Sadrian /* Handle no miso; we just never read back from the device */ 114300715Sadrian if (resource_int_value(device_get_name(dev), 115300715Sadrian device_get_unit(dev), "miso", &value)) 116300715Sadrian value = 0xff; 117300715Sadrian sc->sc_miso = value & 0xff; 118300715Sadrian 119300715Sadrian if (resource_int_value(device_get_name(dev), 120300715Sadrian device_get_unit(dev), "cs0", &value)) 121300715Sadrian return (ENXIO); 122300715Sadrian sc->sc_cs0 = value & 0xff; 123300715Sadrian 124300715Sadrian /* Optional variables */ 125300715Sadrian if (resource_int_value(device_get_name(dev), 126300715Sadrian device_get_unit(dev), "cs1", &value)) 127300715Sadrian value = 0xff; 128300715Sadrian sc->sc_cs1 = value & 0xff; 129300715Sadrian 130300715Sadrian if (resource_int_value(device_get_name(dev), 131300715Sadrian device_get_unit(dev), "cs2", &value)) 132300715Sadrian value = 0xff; 133300715Sadrian sc->sc_cs2 = value & 0xff; 134300715Sadrian 135300715Sadrian if (resource_int_value(device_get_name(dev), 136300715Sadrian device_get_unit(dev), "cs3", &value)) 137300715Sadrian value = 0xff; 138300715Sadrian sc->sc_cs3 = value & 0xff; 139300715Sadrian 140300715Sadrian /* Default to 100KHz */ 141300715Sadrian if (resource_int_value(device_get_name(dev), 142300715Sadrian device_get_unit(dev), "freq", &value)) { 143300715Sadrian value = 100000; 144300715Sadrian } 145300715Sadrian sc->sc_freq = value; 146300715Sadrian 147300715Sadrian if (bootverbose) { 148300715Sadrian device_printf(dev, "frequency: %d Hz\n", 149300715Sadrian sc->sc_freq); 150300715Sadrian device_printf(dev, 151300715Sadrian "Use GPIO pins: sclk=%d, mosi=%d, miso=%d, " 152300715Sadrian "cs0=%d, cs1=%d, cs2=%d, cs3=%d\n", 153300715Sadrian sc->sc_sclk, sc->sc_mosi, sc->sc_miso, 154300715Sadrian sc->sc_cs0, sc->sc_cs1, sc->sc_cs2, sc->sc_cs3); 155300715Sadrian } 156300715Sadrian 157300715Sadrian /* Set directions */ 158300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_sclk, 159300715Sadrian GPIO_PIN_OUTPUT|GPIO_PIN_PULLDOWN); 160300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_mosi, 161300715Sadrian GPIO_PIN_OUTPUT|GPIO_PIN_PULLDOWN); 162300715Sadrian if (sc->sc_miso != 0xff) { 163300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_miso, 164300715Sadrian GPIO_PIN_INPUT|GPIO_PIN_PULLDOWN); 165300715Sadrian } 166300715Sadrian 167300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs0, 168300715Sadrian GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP); 169300715Sadrian 170300715Sadrian if (sc->sc_cs1 != 0xff) 171300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs1, 172300715Sadrian GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP); 173300715Sadrian if (sc->sc_cs2 != 0xff) 174300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs2, 175300715Sadrian GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP); 176300715Sadrian if (sc->sc_cs3 != 0xff) 177300715Sadrian GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs3, 178300715Sadrian GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP); 179300715Sadrian 180300715Sadrian gpio_spi_chip_deactivate(sc, -1); 181300715Sadrian 182300715Sadrian device_add_child(dev, "spibus", -1); 183300715Sadrian return (bus_generic_attach(dev)); 184300715Sadrian} 185300715Sadrian 186300715Sadrianstatic int 187300715Sadriangpio_spi_detach(device_t dev) 188300715Sadrian{ 189300715Sadrian 190300715Sadrian return (0); 191300715Sadrian} 192300715Sadrian 193300715Sadrianstatic void 194300715Sadriangpio_spi_chip_activate(struct gpio_spi_softc *sc, int cs) 195300715Sadrian{ 196300715Sadrian 197300715Sadrian /* called with locked gpiobus */ 198300715Sadrian switch (cs) { 199300715Sadrian case 0: 200300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 201300715Sadrian sc->sc_cs0, 0); 202300715Sadrian break; 203300715Sadrian case 1: 204300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 205300715Sadrian sc->sc_cs1, 0); 206300715Sadrian break; 207300715Sadrian case 2: 208300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 209300715Sadrian sc->sc_cs2, 0); 210300715Sadrian break; 211300715Sadrian case 3: 212300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 213300715Sadrian sc->sc_cs3, 0); 214300715Sadrian break; 215300715Sadrian default: 216300715Sadrian device_printf(sc->sc_dev, "don't have CS%d\n", cs); 217300715Sadrian } 218300715Sadrian 219300715Sadrian gpio_delay(sc); 220300715Sadrian} 221300715Sadrian 222300715Sadrianstatic void 223300715Sadriangpio_spi_chip_deactivate(struct gpio_spi_softc *sc, int cs) 224300715Sadrian{ 225300715Sadrian 226300715Sadrian /* called wth locked gpiobus */ 227300715Sadrian /* 228300715Sadrian * Put CSx to high 229300715Sadrian */ 230300715Sadrian switch (cs) { 231300715Sadrian case -1: 232300715Sadrian /* All CS */ 233300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 234300715Sadrian sc->sc_cs0, 1); 235300715Sadrian if (sc->sc_cs1 == 0xff) break; 236300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 237300715Sadrian sc->sc_cs1, 1); 238300715Sadrian if (sc->sc_cs2 == 0xff) break; 239300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 240300715Sadrian sc->sc_cs2, 1); 241300715Sadrian if (sc->sc_cs3 == 0xff) break; 242300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 243300715Sadrian sc->sc_cs3, 1); 244300715Sadrian break; 245300715Sadrian case 0: 246300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 247300715Sadrian sc->sc_cs0, 1); 248300715Sadrian break; 249300715Sadrian case 1: 250300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 251300715Sadrian sc->sc_cs1, 1); 252300715Sadrian break; 253300715Sadrian case 2: 254300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 255300715Sadrian sc->sc_cs2, 1); 256300715Sadrian break; 257300715Sadrian case 3: 258300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 259300715Sadrian sc->sc_cs3, 1); 260300715Sadrian break; 261300715Sadrian default: 262300715Sadrian device_printf(sc->sc_dev, "don't have CS%d\n", cs); 263300715Sadrian } 264300715Sadrian} 265300715Sadrian 266300715Sadrianstatic uint8_t 267300715Sadriangpio_spi_txrx(struct gpio_spi_softc *sc, int cs, int mode, uint8_t data) 268300715Sadrian{ 269300715Sadrian uint32_t mask, out = 0; 270300715Sadrian unsigned int bit; 271300715Sadrian 272300715Sadrian 273300715Sadrian /* called with locked gpiobus */ 274300715Sadrian 275300715Sadrian for (mask = 0x80; mask > 0; mask >>= 1) { 276300715Sadrian if ((mode == SPIBUS_MODE_CPOL) || 277300715Sadrian (mode == SPIBUS_MODE_CPHA)) { 278300715Sadrian /* If mode 1 or 2 */ 279300715Sadrian 280300715Sadrian /* first step */ 281300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 282300715Sadrian sc->sc_mosi, (data & mask)?1:0); 283300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 284300715Sadrian sc->sc_sclk, 0); 285300715Sadrian gpio_delay(sc); 286300715Sadrian /* second step */ 287300715Sadrian if (sc->sc_miso != 0xff) { 288300715Sadrian GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, 289300715Sadrian sc->sc_miso, &bit); 290300715Sadrian out |= bit?mask:0; 291300715Sadrian } 292300715Sadrian /* Data captured */ 293300715Sadrian gpio_delay(sc); 294300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 295300715Sadrian sc->sc_sclk, 1); 296300715Sadrian } else { 297300715Sadrian /* If mode 0 or 3 */ 298300715Sadrian 299300715Sadrian /* first step */ 300300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 301300715Sadrian sc->sc_mosi, (data & mask)?1:0); 302300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 303300715Sadrian sc->sc_sclk, 1); 304300715Sadrian gpio_delay(sc); 305300715Sadrian /* second step */ 306300715Sadrian if (sc->sc_miso != 0xff) { 307300715Sadrian GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, 308300715Sadrian sc->sc_miso, &bit); 309300715Sadrian out |= bit?mask:0; 310300715Sadrian } 311300715Sadrian /* Data captured */ 312300715Sadrian gpio_delay(sc); 313300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 314300715Sadrian sc->sc_sclk, 0); 315300715Sadrian } 316300715Sadrian } 317300715Sadrian 318300715Sadrian return (out & 0xff); 319300715Sadrian} 320300715Sadrian 321300715Sadrianstatic int 322300715Sadriangpio_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) 323300715Sadrian{ 324300715Sadrian struct gpio_spi_softc *sc; 325300715Sadrian uint8_t *buf_in, *buf_out; 326300715Sadrian struct spibus_ivar *devi = SPIBUS_IVAR(child); 327300715Sadrian int i; 328300715Sadrian 329300715Sadrian sc = device_get_softc(dev); 330300715Sadrian 331300715Sadrian KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 332300715Sadrian ("TX/RX command sizes should be equal")); 333300715Sadrian KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 334300715Sadrian ("TX/RX data sizes should be equal")); 335300715Sadrian 336300715Sadrian gpio_spi_chip_activate(sc, devi->cs); 337300715Sadrian 338300715Sadrian /* Preset pins */ 339300715Sadrian if ((devi->mode == SPIBUS_MODE_CPOL) || 340300715Sadrian (devi->mode == SPIBUS_MODE_CPHA)) { 341300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 342300715Sadrian sc->sc_sclk, 1); 343300715Sadrian } else { 344300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 345300715Sadrian sc->sc_sclk, 0); 346300715Sadrian } 347300715Sadrian 348300715Sadrian /* 349300715Sadrian * Transfer command 350300715Sadrian */ 351300715Sadrian buf_out = (uint8_t *)cmd->tx_cmd; 352300715Sadrian buf_in = (uint8_t *)cmd->rx_cmd; 353300715Sadrian 354300715Sadrian for (i = 0; i < cmd->tx_cmd_sz; i++) 355300715Sadrian buf_in[i] = gpio_spi_txrx(sc, devi->cs, devi->mode, buf_out[i]); 356300715Sadrian 357300715Sadrian /* 358300715Sadrian * Receive/transmit data (depends on command) 359300715Sadrian */ 360300715Sadrian buf_out = (uint8_t *)cmd->tx_data; 361300715Sadrian buf_in = (uint8_t *)cmd->rx_data; 362300715Sadrian for (i = 0; i < cmd->tx_data_sz; i++) 363300715Sadrian buf_in[i] = gpio_spi_txrx(sc, devi->cs, devi->mode, buf_out[i]); 364300715Sadrian 365300715Sadrian /* Return pins to mode default */ 366300715Sadrian if ((devi->mode == SPIBUS_MODE_CPOL) || 367300715Sadrian (devi->mode == SPIBUS_MODE_CPHA)) { 368300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 369300715Sadrian sc->sc_sclk, 1); 370300715Sadrian } else { 371300715Sadrian GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 372300715Sadrian sc->sc_sclk, 0); 373300715Sadrian } 374300715Sadrian 375300715Sadrian gpio_spi_chip_deactivate(sc, devi->cs); 376300715Sadrian 377300715Sadrian return (0); 378300715Sadrian} 379300715Sadrian 380300715Sadrianstatic device_method_t gpio_spi_methods[] = { 381300715Sadrian /* Device interface */ 382300715Sadrian DEVMETHOD(device_probe, gpio_spi_probe), 383300715Sadrian DEVMETHOD(device_attach, gpio_spi_attach), 384300715Sadrian DEVMETHOD(device_detach, gpio_spi_detach), 385300715Sadrian 386300715Sadrian DEVMETHOD(spibus_transfer, gpio_spi_transfer), 387300715Sadrian 388300715Sadrian {0, 0} 389300715Sadrian}; 390300715Sadrian 391300715Sadrianstatic driver_t gpio_spi_driver = { 392300715Sadrian "gpiospi", 393300715Sadrian gpio_spi_methods, 394300715Sadrian sizeof(struct gpio_spi_softc), 395300715Sadrian}; 396300715Sadrian 397300715Sadrianstatic devclass_t gpio_spi_devclass; 398300715Sadrian 399300715SadrianDRIVER_MODULE(gpiospi, gpiobus, gpio_spi_driver, gpio_spi_devclass, 0, 0); 400300715SadrianDRIVER_MODULE(spibus, gpiospi, spibus_driver, spibus_devclass, 0, 0); 401300715SadrianMODULE_DEPEND(spi, gpiospi, 1, 1, 1); 402300715SadrianMODULE_DEPEND(gpiobus, gpiospi, 1, 1, 1); 403