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