2 * Copyright (c) 2011, Aleksandr Rybalko <ray@dlink.ua>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
40 #include <sys/sysctl.h>
43 #include "gpiobus_if.h"
45 #include <dev/gpio/gpiobusvar.h>
47 #include <dev/spibus/spi.h>
48 #include <dev/spibus/spibusvar.h>
49 #include "spibus_if.h"
52 #define dprintf printf
54 #define dprintf(x, arg...)
55 #endif /* GPIO_SPI_DEBUG */
57 struct gpio_spi_softc {
70 static void gpio_spi_chip_activate(struct gpio_spi_softc *, int);
71 static void gpio_spi_chip_deactivate(struct gpio_spi_softc *, int);
74 gpio_spi_probe(device_t dev)
76 device_set_desc(dev, "GPIO SPI bit-banging driver");
81 gpio_delay(struct gpio_spi_softc *sc)
85 d = sc->sc_freq / 1000000;
93 gpio_spi_attach(device_t dev)
96 struct gpio_spi_softc *sc;
98 sc = device_get_softc(dev);
100 sc->sc_busdev = device_get_parent(dev);
102 /* Required variables */
103 if (resource_int_value(device_get_name(dev),
104 device_get_unit(dev), "sclk", &value))
106 sc->sc_sclk = value & 0xff;
108 if (resource_int_value(device_get_name(dev),
109 device_get_unit(dev), "mosi", &value))
111 sc->sc_mosi = value & 0xff;
113 /* Handle no miso; we just never read back from the device */
114 if (resource_int_value(device_get_name(dev),
115 device_get_unit(dev), "miso", &value))
117 sc->sc_miso = value & 0xff;
119 if (resource_int_value(device_get_name(dev),
120 device_get_unit(dev), "cs0", &value))
122 sc->sc_cs0 = value & 0xff;
124 /* Optional variables */
125 if (resource_int_value(device_get_name(dev),
126 device_get_unit(dev), "cs1", &value))
128 sc->sc_cs1 = value & 0xff;
130 if (resource_int_value(device_get_name(dev),
131 device_get_unit(dev), "cs2", &value))
133 sc->sc_cs2 = value & 0xff;
135 if (resource_int_value(device_get_name(dev),
136 device_get_unit(dev), "cs3", &value))
138 sc->sc_cs3 = value & 0xff;
140 /* Default to 100KHz */
141 if (resource_int_value(device_get_name(dev),
142 device_get_unit(dev), "freq", &value)) {
148 device_printf(dev, "frequency: %d Hz\n",
151 "Use GPIO pins: sclk=%d, mosi=%d, miso=%d, "
152 "cs0=%d, cs1=%d, cs2=%d, cs3=%d\n",
153 sc->sc_sclk, sc->sc_mosi, sc->sc_miso,
154 sc->sc_cs0, sc->sc_cs1, sc->sc_cs2, sc->sc_cs3);
158 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_sclk,
159 GPIO_PIN_OUTPUT|GPIO_PIN_PULLDOWN);
160 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_mosi,
161 GPIO_PIN_OUTPUT|GPIO_PIN_PULLDOWN);
162 if (sc->sc_miso != 0xff) {
163 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_miso,
164 GPIO_PIN_INPUT|GPIO_PIN_PULLDOWN);
167 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs0,
168 GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP);
170 if (sc->sc_cs1 != 0xff)
171 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs1,
172 GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP);
173 if (sc->sc_cs2 != 0xff)
174 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs2,
175 GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP);
176 if (sc->sc_cs3 != 0xff)
177 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sc_cs3,
178 GPIO_PIN_OUTPUT|GPIO_PIN_PULLUP);
180 gpio_spi_chip_deactivate(sc, -1);
182 device_add_child(dev, "spibus", -1);
183 return (bus_generic_attach(dev));
187 gpio_spi_detach(device_t dev)
194 gpio_spi_chip_activate(struct gpio_spi_softc *sc, int cs)
197 /* called with locked gpiobus */
200 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
204 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
208 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
212 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
216 device_printf(sc->sc_dev, "don't have CS%d\n", cs);
223 gpio_spi_chip_deactivate(struct gpio_spi_softc *sc, int cs)
226 /* called wth locked gpiobus */
233 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
235 if (sc->sc_cs1 == 0xff) break;
236 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
238 if (sc->sc_cs2 == 0xff) break;
239 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
241 if (sc->sc_cs3 == 0xff) break;
242 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
246 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
250 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
254 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
258 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
262 device_printf(sc->sc_dev, "don't have CS%d\n", cs);
267 gpio_spi_txrx(struct gpio_spi_softc *sc, int cs, int mode, uint8_t data)
269 uint32_t mask, out = 0;
273 /* called with locked gpiobus */
275 for (mask = 0x80; mask > 0; mask >>= 1) {
276 if ((mode == SPIBUS_MODE_CPOL) ||
277 (mode == SPIBUS_MODE_CPHA)) {
281 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
282 sc->sc_mosi, (data & mask)?1:0);
283 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
287 if (sc->sc_miso != 0xff) {
288 GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev,
294 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
300 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
301 sc->sc_mosi, (data & mask)?1:0);
302 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
306 if (sc->sc_miso != 0xff) {
307 GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev,
313 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
322 gpio_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
324 struct gpio_spi_softc *sc;
325 uint8_t *buf_in, *buf_out;
326 struct spibus_ivar *devi = SPIBUS_IVAR(child);
329 sc = device_get_softc(dev);
331 KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
332 ("TX/RX command sizes should be equal"));
333 KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
334 ("TX/RX data sizes should be equal"));
336 gpio_spi_chip_activate(sc, devi->cs);
339 if ((devi->mode == SPIBUS_MODE_CPOL) ||
340 (devi->mode == SPIBUS_MODE_CPHA)) {
341 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
344 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
351 buf_out = (uint8_t *)cmd->tx_cmd;
352 buf_in = (uint8_t *)cmd->rx_cmd;
354 for (i = 0; i < cmd->tx_cmd_sz; i++)
355 buf_in[i] = gpio_spi_txrx(sc, devi->cs, devi->mode, buf_out[i]);
358 * Receive/transmit data (depends on command)
360 buf_out = (uint8_t *)cmd->tx_data;
361 buf_in = (uint8_t *)cmd->rx_data;
362 for (i = 0; i < cmd->tx_data_sz; i++)
363 buf_in[i] = gpio_spi_txrx(sc, devi->cs, devi->mode, buf_out[i]);
365 /* Return pins to mode default */
366 if ((devi->mode == SPIBUS_MODE_CPOL) ||
367 (devi->mode == SPIBUS_MODE_CPHA)) {
368 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
371 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev,
375 gpio_spi_chip_deactivate(sc, devi->cs);
380 static device_method_t gpio_spi_methods[] = {
381 /* Device interface */
382 DEVMETHOD(device_probe, gpio_spi_probe),
383 DEVMETHOD(device_attach, gpio_spi_attach),
384 DEVMETHOD(device_detach, gpio_spi_detach),
386 DEVMETHOD(spibus_transfer, gpio_spi_transfer),
391 static driver_t gpio_spi_driver = {
394 sizeof(struct gpio_spi_softc),
397 static devclass_t gpio_spi_devclass;
399 DRIVER_MODULE(gpiospi, gpiobus, gpio_spi_driver, gpio_spi_devclass, 0, 0);
400 DRIVER_MODULE(spibus, gpiospi, spibus_driver, spibus_devclass, 0, 0);
401 MODULE_DEPEND(spi, gpiospi, 1, 1, 1);
402 MODULE_DEPEND(gpiobus, gpiospi, 1, 1, 1);