1cb18f3f3SLuiz Otavio O Souza /*-
2cb18f3f3SLuiz Otavio O Souza * Copyright (c) 2016 Rubicon Communications, LLC (Netgate)
3cb18f3f3SLuiz Otavio O Souza * All rights reserved.
4cb18f3f3SLuiz Otavio O Souza *
5cb18f3f3SLuiz Otavio O Souza * Redistribution and use in source and binary forms, with or without
6cb18f3f3SLuiz Otavio O Souza * modification, are permitted provided that the following conditions
7cb18f3f3SLuiz Otavio O Souza * are met:
8cb18f3f3SLuiz Otavio O Souza * 1. Redistributions of source code must retain the above copyright
9cb18f3f3SLuiz Otavio O Souza * notice, this list of conditions and the following disclaimer.
10cb18f3f3SLuiz Otavio O Souza * 2. Redistributions in binary form must reproduce the above copyright
11cb18f3f3SLuiz Otavio O Souza * notice, this list of conditions and the following disclaimer in the
12cb18f3f3SLuiz Otavio O Souza * documentation and/or other materials provided with the distribution.
13cb18f3f3SLuiz Otavio O Souza *
14cb18f3f3SLuiz Otavio O Souza * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15cb18f3f3SLuiz Otavio O Souza * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16cb18f3f3SLuiz Otavio O Souza * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17cb18f3f3SLuiz Otavio O Souza * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18cb18f3f3SLuiz Otavio O Souza * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19cb18f3f3SLuiz Otavio O Souza * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20cb18f3f3SLuiz Otavio O Souza * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21cb18f3f3SLuiz Otavio O Souza * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22cb18f3f3SLuiz Otavio O Souza * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23cb18f3f3SLuiz Otavio O Souza * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24cb18f3f3SLuiz Otavio O Souza * SUCH DAMAGE.
25cb18f3f3SLuiz Otavio O Souza *
26cb18f3f3SLuiz Otavio O Souza */
27fdafd315SWarner Losh
28cb18f3f3SLuiz Otavio O Souza #include <sys/param.h>
29cb18f3f3SLuiz Otavio O Souza #include <sys/systm.h>
30cb18f3f3SLuiz Otavio O Souza #include <sys/bus.h>
31cb18f3f3SLuiz Otavio O Souza
32cb18f3f3SLuiz Otavio O Souza #include <sys/kernel.h>
33cb18f3f3SLuiz Otavio O Souza #include <sys/module.h>
34cb18f3f3SLuiz Otavio O Souza #include <sys/rman.h>
35cb18f3f3SLuiz Otavio O Souza #include <sys/lock.h>
36cb18f3f3SLuiz Otavio O Souza #include <sys/mutex.h>
37cb18f3f3SLuiz Otavio O Souza #include <sys/sysctl.h>
38cb18f3f3SLuiz Otavio O Souza
39cb18f3f3SLuiz Otavio O Souza #include <machine/bus.h>
40cb18f3f3SLuiz Otavio O Souza #include <machine/resource.h>
41cb18f3f3SLuiz Otavio O Souza #include <machine/intr.h>
42cb18f3f3SLuiz Otavio O Souza
43cb18f3f3SLuiz Otavio O Souza #include <dev/ofw/ofw_bus.h>
44cb18f3f3SLuiz Otavio O Souza #include <dev/ofw/ofw_bus_subr.h>
45cb18f3f3SLuiz Otavio O Souza
46cb18f3f3SLuiz Otavio O Souza #include <dev/spibus/spi.h>
47cb18f3f3SLuiz Otavio O Souza #include <dev/spibus/spibusvar.h>
48cb18f3f3SLuiz Otavio O Souza
490050ea24SMichal Meloun #include <arm/ti/ti_sysc.h>
50cb18f3f3SLuiz Otavio O Souza #include <arm/ti/ti_spireg.h>
51cb18f3f3SLuiz Otavio O Souza #include <arm/ti/ti_spivar.h>
52cb18f3f3SLuiz Otavio O Souza
53cb18f3f3SLuiz Otavio O Souza #include "spibus_if.h"
54cb18f3f3SLuiz Otavio O Souza
55cb18f3f3SLuiz Otavio O Souza static void ti_spi_intr(void *);
56cb18f3f3SLuiz Otavio O Souza static int ti_spi_detach(device_t);
57cb18f3f3SLuiz Otavio O Souza
58cb18f3f3SLuiz Otavio O Souza #undef TI_SPI_DEBUG
59cb18f3f3SLuiz Otavio O Souza #ifdef TI_SPI_DEBUG
60cb18f3f3SLuiz Otavio O Souza #define IRQSTATUSBITS \
61cb18f3f3SLuiz Otavio O Souza "\020\1TX0_EMPTY\2TX0_UNDERFLOW\3RX0_FULL\4RX0_OVERFLOW" \
62cb18f3f3SLuiz Otavio O Souza "\5TX1_EMPTY\6TX1_UNDERFLOW\7RX1_FULL\11TX2_EMPTY" \
63cb18f3f3SLuiz Otavio O Souza "\12TX1_UNDERFLOW\13RX2_FULL\15TX3_EMPTY\16TX3_UNDERFLOW" \
64cb18f3f3SLuiz Otavio O Souza "\17RX3_FULL\22EOW"
65cb18f3f3SLuiz Otavio O Souza #define CONFBITS \
66cb18f3f3SLuiz Otavio O Souza "\020\1PHA\2POL\7EPOL\17DMAW\20DMAR\21DPE0\22DPE1\23IS" \
67cb18f3f3SLuiz Otavio O Souza "\24TURBO\25FORCE\30SBE\31SBPOL\34FFEW\35FFER\36CLKG"
68cb18f3f3SLuiz Otavio O Souza #define STATBITS \
69cb18f3f3SLuiz Otavio O Souza "\020\1RXS\2TXS\3EOT\4TXFFE\5TXFFF\6RXFFE\7RXFFFF"
70cb18f3f3SLuiz Otavio O Souza #define MODULCTRLBITS \
71cb18f3f3SLuiz Otavio O Souza "\020\1SINGLE\2NOSPIEN\3SLAVE\4SYST\10MOA\11FDAA"
72cb18f3f3SLuiz Otavio O Souza #define CTRLBITS \
73cb18f3f3SLuiz Otavio O Souza "\020\1ENABLED"
74cb18f3f3SLuiz Otavio O Souza
75cb18f3f3SLuiz Otavio O Souza static void
ti_spi_printr(device_t dev)76cb18f3f3SLuiz Otavio O Souza ti_spi_printr(device_t dev)
77cb18f3f3SLuiz Otavio O Souza {
78cb18f3f3SLuiz Otavio O Souza int clk, conf, ctrl, div, i, j, wl;
79cb18f3f3SLuiz Otavio O Souza struct ti_spi_softc *sc;
80cb18f3f3SLuiz Otavio O Souza uint32_t reg;
81cb18f3f3SLuiz Otavio O Souza
82cb18f3f3SLuiz Otavio O Souza sc = device_get_softc(dev);
83cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_SYSCONFIG);
84cb18f3f3SLuiz Otavio O Souza device_printf(dev, "SYSCONFIG: %#x\n", reg);
85cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_SYSSTATUS);
86cb18f3f3SLuiz Otavio O Souza device_printf(dev, "SYSSTATUS: %#x\n", reg);
87cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_IRQSTATUS);
88cb18f3f3SLuiz Otavio O Souza device_printf(dev, "IRQSTATUS: 0x%b\n", reg, IRQSTATUSBITS);
89cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_IRQENABLE);
90cb18f3f3SLuiz Otavio O Souza device_printf(dev, "IRQENABLE: 0x%b\n", reg, IRQSTATUSBITS);
91cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_MODULCTRL);
92cb18f3f3SLuiz Otavio O Souza device_printf(dev, "MODULCTRL: 0x%b\n", reg, MODULCTRLBITS);
93cb18f3f3SLuiz Otavio O Souza for (i = 0; i < sc->sc_numcs; i++) {
94cb18f3f3SLuiz Otavio O Souza ctrl = TI_SPI_READ(sc, MCSPI_CTRL_CH(i));
95cb18f3f3SLuiz Otavio O Souza conf = TI_SPI_READ(sc, MCSPI_CONF_CH(i));
96cb18f3f3SLuiz Otavio O Souza device_printf(dev, "CH%dCONF: 0x%b\n", i, conf, CONFBITS);
97cb18f3f3SLuiz Otavio O Souza if (conf & MCSPI_CONF_CLKG) {
98cb18f3f3SLuiz Otavio O Souza div = (conf >> MCSPI_CONF_CLK_SHIFT) & MCSPI_CONF_CLK_MSK;
99cb18f3f3SLuiz Otavio O Souza div |= ((ctrl >> MCSPI_CTRL_EXTCLK_SHIFT) & MCSPI_CTRL_EXTCLK_MSK) << 4;
100cb18f3f3SLuiz Otavio O Souza } else {
101cb18f3f3SLuiz Otavio O Souza div = 1;
102cb18f3f3SLuiz Otavio O Souza j = (conf >> MCSPI_CONF_CLK_SHIFT) & MCSPI_CONF_CLK_MSK;
103cb18f3f3SLuiz Otavio O Souza while (j-- > 0)
104cb18f3f3SLuiz Otavio O Souza div <<= 1;
105cb18f3f3SLuiz Otavio O Souza }
106cb18f3f3SLuiz Otavio O Souza clk = TI_SPI_GCLK / div;
107cb18f3f3SLuiz Otavio O Souza wl = ((conf >> MCSPI_CONF_WL_SHIFT) & MCSPI_CONF_WL_MSK) + 1;
108cb18f3f3SLuiz Otavio O Souza device_printf(dev, "wordlen: %-2d clock: %d\n", wl, clk);
109cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_STAT_CH(i));
110cb18f3f3SLuiz Otavio O Souza device_printf(dev, "CH%dSTAT: 0x%b\n", i, reg, STATBITS);
111cb18f3f3SLuiz Otavio O Souza device_printf(dev, "CH%dCTRL: 0x%b\n", i, ctrl, CTRLBITS);
112cb18f3f3SLuiz Otavio O Souza }
113cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_XFERLEVEL);
114cb18f3f3SLuiz Otavio O Souza device_printf(dev, "XFERLEVEL: %#x\n", reg);
115cb18f3f3SLuiz Otavio O Souza }
116cb18f3f3SLuiz Otavio O Souza #endif
117cb18f3f3SLuiz Otavio O Souza
118cb18f3f3SLuiz Otavio O Souza static void
ti_spi_set_clock(struct ti_spi_softc * sc,int ch,int freq)119cb18f3f3SLuiz Otavio O Souza ti_spi_set_clock(struct ti_spi_softc *sc, int ch, int freq)
120cb18f3f3SLuiz Otavio O Souza {
121cb18f3f3SLuiz Otavio O Souza uint32_t clkdiv, conf, div, extclk, reg;
122cb18f3f3SLuiz Otavio O Souza
123cb18f3f3SLuiz Otavio O Souza clkdiv = TI_SPI_GCLK / freq;
124cb18f3f3SLuiz Otavio O Souza if (clkdiv > MCSPI_EXTCLK_MSK) {
125cb18f3f3SLuiz Otavio O Souza extclk = 0;
126cb18f3f3SLuiz Otavio O Souza clkdiv = 0;
127cb18f3f3SLuiz Otavio O Souza div = 1;
128cb18f3f3SLuiz Otavio O Souza while (TI_SPI_GCLK / div > freq && clkdiv <= 0xf) {
129cb18f3f3SLuiz Otavio O Souza clkdiv++;
130cb18f3f3SLuiz Otavio O Souza div <<= 1;
131cb18f3f3SLuiz Otavio O Souza }
132cb18f3f3SLuiz Otavio O Souza conf = clkdiv << MCSPI_CONF_CLK_SHIFT;
133cb18f3f3SLuiz Otavio O Souza } else {
134cb18f3f3SLuiz Otavio O Souza extclk = clkdiv >> 4;
135cb18f3f3SLuiz Otavio O Souza clkdiv &= MCSPI_CONF_CLK_MSK;
136cb18f3f3SLuiz Otavio O Souza conf = MCSPI_CONF_CLKG | clkdiv << MCSPI_CONF_CLK_SHIFT;
137cb18f3f3SLuiz Otavio O Souza }
138cb18f3f3SLuiz Otavio O Souza
139cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(ch));
140cb18f3f3SLuiz Otavio O Souza reg &= ~(MCSPI_CTRL_EXTCLK_MSK << MCSPI_CTRL_EXTCLK_SHIFT);
141cb18f3f3SLuiz Otavio O Souza reg |= extclk << MCSPI_CTRL_EXTCLK_SHIFT;
142cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CTRL_CH(ch), reg);
143cb18f3f3SLuiz Otavio O Souza
144cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CONF_CH(ch));
145cb18f3f3SLuiz Otavio O Souza reg &= ~(MCSPI_CONF_CLKG | MCSPI_CONF_CLK_MSK << MCSPI_CONF_CLK_SHIFT);
146cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CONF_CH(ch), reg | conf);
147cb18f3f3SLuiz Otavio O Souza }
148cb18f3f3SLuiz Otavio O Souza
149cb18f3f3SLuiz Otavio O Souza static int
ti_spi_probe(device_t dev)150cb18f3f3SLuiz Otavio O Souza ti_spi_probe(device_t dev)
151cb18f3f3SLuiz Otavio O Souza {
152cb18f3f3SLuiz Otavio O Souza
153cb18f3f3SLuiz Otavio O Souza if (!ofw_bus_status_okay(dev))
154cb18f3f3SLuiz Otavio O Souza return (ENXIO);
155cb18f3f3SLuiz Otavio O Souza if (!ofw_bus_is_compatible(dev, "ti,omap4-mcspi"))
156cb18f3f3SLuiz Otavio O Souza return (ENXIO);
157cb18f3f3SLuiz Otavio O Souza
158cb18f3f3SLuiz Otavio O Souza device_set_desc(dev, "TI McSPI controller");
159cb18f3f3SLuiz Otavio O Souza
160cb18f3f3SLuiz Otavio O Souza return (BUS_PROBE_DEFAULT);
161cb18f3f3SLuiz Otavio O Souza }
162cb18f3f3SLuiz Otavio O Souza
163cb18f3f3SLuiz Otavio O Souza static int
ti_spi_attach(device_t dev)164cb18f3f3SLuiz Otavio O Souza ti_spi_attach(device_t dev)
165cb18f3f3SLuiz Otavio O Souza {
1660050ea24SMichal Meloun int err, i, rid, timeout;
167cb18f3f3SLuiz Otavio O Souza struct ti_spi_softc *sc;
168cb18f3f3SLuiz Otavio O Souza uint32_t rev;
169cb18f3f3SLuiz Otavio O Souza
170cb18f3f3SLuiz Otavio O Souza sc = device_get_softc(dev);
171cb18f3f3SLuiz Otavio O Souza sc->sc_dev = dev;
172cb18f3f3SLuiz Otavio O Souza
173cb18f3f3SLuiz Otavio O Souza /* Activate the McSPI module. */
1740050ea24SMichal Meloun err = ti_sysc_clock_enable(device_get_parent(dev));
175cb18f3f3SLuiz Otavio O Souza if (err) {
176cb18f3f3SLuiz Otavio O Souza device_printf(dev, "Error: failed to activate source clock\n");
177cb18f3f3SLuiz Otavio O Souza return (err);
178cb18f3f3SLuiz Otavio O Souza }
179cb18f3f3SLuiz Otavio O Souza
180cb18f3f3SLuiz Otavio O Souza /* Get the number of available channels. */
181cb18f3f3SLuiz Otavio O Souza if ((OF_getencprop(ofw_bus_get_node(dev), "ti,spi-num-cs",
182cb18f3f3SLuiz Otavio O Souza &sc->sc_numcs, sizeof(sc->sc_numcs))) <= 0) {
183cb18f3f3SLuiz Otavio O Souza sc->sc_numcs = 2;
184cb18f3f3SLuiz Otavio O Souza }
185cb18f3f3SLuiz Otavio O Souza
186cb18f3f3SLuiz Otavio O Souza rid = 0;
187cb18f3f3SLuiz Otavio O Souza sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
188cb18f3f3SLuiz Otavio O Souza RF_ACTIVE);
189cb18f3f3SLuiz Otavio O Souza if (!sc->sc_mem_res) {
190cb18f3f3SLuiz Otavio O Souza device_printf(dev, "cannot allocate memory window\n");
191cb18f3f3SLuiz Otavio O Souza return (ENXIO);
192cb18f3f3SLuiz Otavio O Souza }
193cb18f3f3SLuiz Otavio O Souza
194cb18f3f3SLuiz Otavio O Souza sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
195cb18f3f3SLuiz Otavio O Souza sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
196cb18f3f3SLuiz Otavio O Souza
197cb18f3f3SLuiz Otavio O Souza rid = 0;
198cb18f3f3SLuiz Otavio O Souza sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
199cb18f3f3SLuiz Otavio O Souza RF_ACTIVE);
200cb18f3f3SLuiz Otavio O Souza if (!sc->sc_irq_res) {
201cb18f3f3SLuiz Otavio O Souza bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
202cb18f3f3SLuiz Otavio O Souza device_printf(dev, "cannot allocate interrupt\n");
203cb18f3f3SLuiz Otavio O Souza return (ENXIO);
204cb18f3f3SLuiz Otavio O Souza }
205cb18f3f3SLuiz Otavio O Souza
206cb18f3f3SLuiz Otavio O Souza /* Hook up our interrupt handler. */
207cb18f3f3SLuiz Otavio O Souza if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
208cb18f3f3SLuiz Otavio O Souza NULL, ti_spi_intr, sc, &sc->sc_intrhand)) {
209cb18f3f3SLuiz Otavio O Souza bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
210cb18f3f3SLuiz Otavio O Souza bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
211cb18f3f3SLuiz Otavio O Souza device_printf(dev, "cannot setup the interrupt handler\n");
212cb18f3f3SLuiz Otavio O Souza return (ENXIO);
213cb18f3f3SLuiz Otavio O Souza }
214cb18f3f3SLuiz Otavio O Souza
215cb18f3f3SLuiz Otavio O Souza mtx_init(&sc->sc_mtx, "ti_spi", NULL, MTX_DEF);
216cb18f3f3SLuiz Otavio O Souza
217cb18f3f3SLuiz Otavio O Souza /* Issue a softreset to the controller */
218cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
219cb18f3f3SLuiz Otavio O Souza timeout = 1000;
220cb18f3f3SLuiz Otavio O Souza while (!(TI_SPI_READ(sc, MCSPI_SYSSTATUS) &
221cb18f3f3SLuiz Otavio O Souza MCSPI_SYSSTATUS_RESETDONE)) {
222cb18f3f3SLuiz Otavio O Souza if (--timeout == 0) {
223cb18f3f3SLuiz Otavio O Souza device_printf(dev,
224cb18f3f3SLuiz Otavio O Souza "Error: Controller reset operation timed out\n");
225cb18f3f3SLuiz Otavio O Souza ti_spi_detach(dev);
226cb18f3f3SLuiz Otavio O Souza return (ENXIO);
227cb18f3f3SLuiz Otavio O Souza }
228cb18f3f3SLuiz Otavio O Souza DELAY(100);
229cb18f3f3SLuiz Otavio O Souza }
230cb18f3f3SLuiz Otavio O Souza
231cb18f3f3SLuiz Otavio O Souza /* Print the McSPI module revision. */
2320050ea24SMichal Meloun rev = TI_SPI_READ(sc,
2330050ea24SMichal Meloun ti_sysc_get_rev_address_offset_host(device_get_parent(dev)));
234cb18f3f3SLuiz Otavio O Souza device_printf(dev,
235cb18f3f3SLuiz Otavio O Souza "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n",
236cb18f3f3SLuiz Otavio O Souza (rev >> MCSPI_REVISION_SCHEME_SHIFT) & MCSPI_REVISION_SCHEME_MSK,
237cb18f3f3SLuiz Otavio O Souza (rev >> MCSPI_REVISION_FUNC_SHIFT) & MCSPI_REVISION_FUNC_MSK,
238cb18f3f3SLuiz Otavio O Souza (rev >> MCSPI_REVISION_RTL_SHIFT) & MCSPI_REVISION_RTL_MSK,
239cb18f3f3SLuiz Otavio O Souza (rev >> MCSPI_REVISION_MAJOR_SHIFT) & MCSPI_REVISION_MAJOR_MSK,
240cb18f3f3SLuiz Otavio O Souza (rev >> MCSPI_REVISION_MINOR_SHIFT) & MCSPI_REVISION_MINOR_MSK,
241cb18f3f3SLuiz Otavio O Souza (rev >> MCSPI_REVISION_CUSTOM_SHIFT) & MCSPI_REVISION_CUSTOM_MSK);
242cb18f3f3SLuiz Otavio O Souza
243cb18f3f3SLuiz Otavio O Souza /* Set Master mode, single channel. */
244cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_MODULCTRL, MCSPI_MODULCTRL_SINGLE);
245cb18f3f3SLuiz Otavio O Souza
246cb18f3f3SLuiz Otavio O Souza /* Clear pending interrupts and disable interrupts. */
247cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQENABLE, 0x0);
248cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xffff);
249cb18f3f3SLuiz Otavio O Souza
250cb18f3f3SLuiz Otavio O Souza for (i = 0; i < sc->sc_numcs; i++) {
251cb18f3f3SLuiz Otavio O Souza /*
252cb18f3f3SLuiz Otavio O Souza * Default to SPI mode 0, CS active low, 8 bits word length and
253cb18f3f3SLuiz Otavio O Souza * 500kHz clock.
254cb18f3f3SLuiz Otavio O Souza */
255cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CONF_CH(i),
256cb18f3f3SLuiz Otavio O Souza MCSPI_CONF_DPE0 | MCSPI_CONF_EPOL |
257cb18f3f3SLuiz Otavio O Souza (8 - 1) << MCSPI_CONF_WL_SHIFT);
258cb18f3f3SLuiz Otavio O Souza /* Set initial clock - 500kHz. */
259cb18f3f3SLuiz Otavio O Souza ti_spi_set_clock(sc, i, 500000);
260cb18f3f3SLuiz Otavio O Souza }
261cb18f3f3SLuiz Otavio O Souza
262cb18f3f3SLuiz Otavio O Souza #ifdef TI_SPI_DEBUG
263cb18f3f3SLuiz Otavio O Souza ti_spi_printr(dev);
264cb18f3f3SLuiz Otavio O Souza #endif
265cb18f3f3SLuiz Otavio O Souza
2665b56413dSWarner Losh device_add_child(dev, "spibus", DEVICE_UNIT_ANY);
26718250ec6SJohn Baldwin bus_attach_children(dev);
268cb18f3f3SLuiz Otavio O Souza
26918250ec6SJohn Baldwin return (0);
270cb18f3f3SLuiz Otavio O Souza }
271cb18f3f3SLuiz Otavio O Souza
272cb18f3f3SLuiz Otavio O Souza static int
ti_spi_detach(device_t dev)273cb18f3f3SLuiz Otavio O Souza ti_spi_detach(device_t dev)
274cb18f3f3SLuiz Otavio O Souza {
275cb18f3f3SLuiz Otavio O Souza struct ti_spi_softc *sc;
276*64d1a02eSJohn Baldwin int error;
277*64d1a02eSJohn Baldwin
278*64d1a02eSJohn Baldwin error = bus_generic_detach(dev);
279*64d1a02eSJohn Baldwin if (error != 0)
280*64d1a02eSJohn Baldwin return (error);
281cb18f3f3SLuiz Otavio O Souza
282cb18f3f3SLuiz Otavio O Souza sc = device_get_softc(dev);
283cb18f3f3SLuiz Otavio O Souza
284cb18f3f3SLuiz Otavio O Souza /* Clear pending interrupts and disable interrupts. */
285cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQENABLE, 0);
286cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xffff);
287cb18f3f3SLuiz Otavio O Souza
288cb18f3f3SLuiz Otavio O Souza /* Reset controller. */
289cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
290cb18f3f3SLuiz Otavio O Souza
291cb18f3f3SLuiz Otavio O Souza mtx_destroy(&sc->sc_mtx);
292cb18f3f3SLuiz Otavio O Souza if (sc->sc_intrhand)
293cb18f3f3SLuiz Otavio O Souza bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
294cb18f3f3SLuiz Otavio O Souza if (sc->sc_irq_res)
295cb18f3f3SLuiz Otavio O Souza bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
296cb18f3f3SLuiz Otavio O Souza if (sc->sc_mem_res)
297cb18f3f3SLuiz Otavio O Souza bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
298cb18f3f3SLuiz Otavio O Souza
299cb18f3f3SLuiz Otavio O Souza return (0);
300cb18f3f3SLuiz Otavio O Souza }
301cb18f3f3SLuiz Otavio O Souza
302cb18f3f3SLuiz Otavio O Souza static int
ti_spi_fill_fifo(struct ti_spi_softc * sc)303cb18f3f3SLuiz Otavio O Souza ti_spi_fill_fifo(struct ti_spi_softc *sc)
304cb18f3f3SLuiz Otavio O Souza {
305cb18f3f3SLuiz Otavio O Souza int bytes, timeout;
306cb18f3f3SLuiz Otavio O Souza struct spi_command *cmd;
307cb18f3f3SLuiz Otavio O Souza uint32_t written;
308cb18f3f3SLuiz Otavio O Souza uint8_t *data;
309cb18f3f3SLuiz Otavio O Souza
310cb18f3f3SLuiz Otavio O Souza cmd = sc->sc_cmd;
311cb18f3f3SLuiz Otavio O Souza bytes = min(sc->sc_len - sc->sc_written, sc->sc_fifolvl);
312cb18f3f3SLuiz Otavio O Souza while (bytes-- > 0) {
313cb18f3f3SLuiz Otavio O Souza data = (uint8_t *)cmd->tx_cmd;
314cb18f3f3SLuiz Otavio O Souza written = sc->sc_written++;
315cb18f3f3SLuiz Otavio O Souza if (written >= cmd->tx_cmd_sz) {
316cb18f3f3SLuiz Otavio O Souza data = (uint8_t *)cmd->tx_data;
317cb18f3f3SLuiz Otavio O Souza written -= cmd->tx_cmd_sz;
318cb18f3f3SLuiz Otavio O Souza }
319cb18f3f3SLuiz Otavio O Souza if (sc->sc_fifolvl == 1) {
320cb18f3f3SLuiz Otavio O Souza /* FIFO disabled. */
321cb18f3f3SLuiz Otavio O Souza timeout = 1000;
322cb18f3f3SLuiz Otavio O Souza while (--timeout > 0 && (TI_SPI_READ(sc,
323cb18f3f3SLuiz Otavio O Souza MCSPI_STAT_CH(sc->sc_cs)) & MCSPI_STAT_TXS) == 0) {
324e5185f3eSLuiz Otavio O Souza DELAY(100);
325cb18f3f3SLuiz Otavio O Souza }
326cb18f3f3SLuiz Otavio O Souza if (timeout == 0)
327cb18f3f3SLuiz Otavio O Souza return (-1);
328cb18f3f3SLuiz Otavio O Souza }
329cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_TX_CH(sc->sc_cs), data[written]);
330cb18f3f3SLuiz Otavio O Souza }
331cb18f3f3SLuiz Otavio O Souza
332cb18f3f3SLuiz Otavio O Souza return (0);
333cb18f3f3SLuiz Otavio O Souza }
334cb18f3f3SLuiz Otavio O Souza
335cb18f3f3SLuiz Otavio O Souza static int
ti_spi_drain_fifo(struct ti_spi_softc * sc)336cb18f3f3SLuiz Otavio O Souza ti_spi_drain_fifo(struct ti_spi_softc *sc)
337cb18f3f3SLuiz Otavio O Souza {
338cb18f3f3SLuiz Otavio O Souza int bytes, timeout;
339cb18f3f3SLuiz Otavio O Souza struct spi_command *cmd;
340cb18f3f3SLuiz Otavio O Souza uint32_t read;
341cb18f3f3SLuiz Otavio O Souza uint8_t *data;
342cb18f3f3SLuiz Otavio O Souza
343cb18f3f3SLuiz Otavio O Souza cmd = sc->sc_cmd;
344cb18f3f3SLuiz Otavio O Souza bytes = min(sc->sc_len - sc->sc_read, sc->sc_fifolvl);
345cb18f3f3SLuiz Otavio O Souza while (bytes-- > 0) {
346cb18f3f3SLuiz Otavio O Souza data = (uint8_t *)cmd->rx_cmd;
347cb18f3f3SLuiz Otavio O Souza read = sc->sc_read++;
348cb18f3f3SLuiz Otavio O Souza if (read >= cmd->rx_cmd_sz) {
349cb18f3f3SLuiz Otavio O Souza data = (uint8_t *)cmd->rx_data;
350cb18f3f3SLuiz Otavio O Souza read -= cmd->rx_cmd_sz;
351cb18f3f3SLuiz Otavio O Souza }
352cb18f3f3SLuiz Otavio O Souza if (sc->sc_fifolvl == 1) {
353cb18f3f3SLuiz Otavio O Souza /* FIFO disabled. */
354cb18f3f3SLuiz Otavio O Souza timeout = 1000;
355cb18f3f3SLuiz Otavio O Souza while (--timeout > 0 && (TI_SPI_READ(sc,
356cb18f3f3SLuiz Otavio O Souza MCSPI_STAT_CH(sc->sc_cs)) & MCSPI_STAT_RXS) == 0) {
357e5185f3eSLuiz Otavio O Souza DELAY(100);
358cb18f3f3SLuiz Otavio O Souza }
359cb18f3f3SLuiz Otavio O Souza if (timeout == 0)
360cb18f3f3SLuiz Otavio O Souza return (-1);
361cb18f3f3SLuiz Otavio O Souza }
362cb18f3f3SLuiz Otavio O Souza data[read] = TI_SPI_READ(sc, MCSPI_RX_CH(sc->sc_cs));
363cb18f3f3SLuiz Otavio O Souza }
364cb18f3f3SLuiz Otavio O Souza
365cb18f3f3SLuiz Otavio O Souza return (0);
366cb18f3f3SLuiz Otavio O Souza }
367cb18f3f3SLuiz Otavio O Souza
368cb18f3f3SLuiz Otavio O Souza static void
ti_spi_intr(void * arg)369cb18f3f3SLuiz Otavio O Souza ti_spi_intr(void *arg)
370cb18f3f3SLuiz Otavio O Souza {
371cb18f3f3SLuiz Otavio O Souza struct ti_spi_softc *sc;
372cb18f3f3SLuiz Otavio O Souza uint32_t status;
373cb18f3f3SLuiz Otavio O Souza
374cb18f3f3SLuiz Otavio O Souza sc = (struct ti_spi_softc *)arg;
375cb18f3f3SLuiz Otavio O Souza TI_SPI_LOCK(sc);
376cb18f3f3SLuiz Otavio O Souza status = TI_SPI_READ(sc, MCSPI_IRQSTATUS);
377cb18f3f3SLuiz Otavio O Souza
378cb18f3f3SLuiz Otavio O Souza /*
379cb18f3f3SLuiz Otavio O Souza * No new TX_empty or RX_full event will be asserted while the CPU has
380cb18f3f3SLuiz Otavio O Souza * not performed the number of writes or reads defined by
381cb18f3f3SLuiz Otavio O Souza * MCSPI_XFERLEVEL[AEL] and MCSPI_XFERLEVEL[AFL]. It is responsibility
382cb18f3f3SLuiz Otavio O Souza * of CPU perform the right number of writes and reads.
383cb18f3f3SLuiz Otavio O Souza */
384cb18f3f3SLuiz Otavio O Souza if (status & MCSPI_IRQ_TX0_EMPTY)
385cb18f3f3SLuiz Otavio O Souza ti_spi_fill_fifo(sc);
386cb18f3f3SLuiz Otavio O Souza if (status & MCSPI_IRQ_RX0_FULL)
387cb18f3f3SLuiz Otavio O Souza ti_spi_drain_fifo(sc);
388cb18f3f3SLuiz Otavio O Souza
389cb18f3f3SLuiz Otavio O Souza /* Clear interrupt status. */
390cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, status);
391cb18f3f3SLuiz Otavio O Souza
392cb18f3f3SLuiz Otavio O Souza /* Check for end of transfer. */
393cb18f3f3SLuiz Otavio O Souza if (sc->sc_written == sc->sc_len && sc->sc_read == sc->sc_len) {
394cb18f3f3SLuiz Otavio O Souza sc->sc_flags |= TI_SPI_DONE;
395cb18f3f3SLuiz Otavio O Souza wakeup(sc->sc_dev);
396cb18f3f3SLuiz Otavio O Souza }
397cb18f3f3SLuiz Otavio O Souza
398cb18f3f3SLuiz Otavio O Souza TI_SPI_UNLOCK(sc);
399cb18f3f3SLuiz Otavio O Souza }
400cb18f3f3SLuiz Otavio O Souza
401cb18f3f3SLuiz Otavio O Souza static int
ti_spi_pio_transfer(struct ti_spi_softc * sc)402cb18f3f3SLuiz Otavio O Souza ti_spi_pio_transfer(struct ti_spi_softc *sc)
403cb18f3f3SLuiz Otavio O Souza {
404cb18f3f3SLuiz Otavio O Souza
405cb18f3f3SLuiz Otavio O Souza while (sc->sc_len - sc->sc_written > 0) {
406cb18f3f3SLuiz Otavio O Souza if (ti_spi_fill_fifo(sc) == -1)
407cb18f3f3SLuiz Otavio O Souza return (EIO);
408cb18f3f3SLuiz Otavio O Souza if (ti_spi_drain_fifo(sc) == -1)
409cb18f3f3SLuiz Otavio O Souza return (EIO);
410cb18f3f3SLuiz Otavio O Souza }
411cb18f3f3SLuiz Otavio O Souza
412cb18f3f3SLuiz Otavio O Souza return (0);
413cb18f3f3SLuiz Otavio O Souza }
414cb18f3f3SLuiz Otavio O Souza
415cb18f3f3SLuiz Otavio O Souza static int
ti_spi_gcd(int a,int b)416cb18f3f3SLuiz Otavio O Souza ti_spi_gcd(int a, int b)
417cb18f3f3SLuiz Otavio O Souza {
418cb18f3f3SLuiz Otavio O Souza int m;
419cb18f3f3SLuiz Otavio O Souza
420cb18f3f3SLuiz Otavio O Souza while ((m = a % b) != 0) {
421cb18f3f3SLuiz Otavio O Souza a = b;
422cb18f3f3SLuiz Otavio O Souza b = m;
423cb18f3f3SLuiz Otavio O Souza }
424cb18f3f3SLuiz Otavio O Souza
425cb18f3f3SLuiz Otavio O Souza return (b);
426cb18f3f3SLuiz Otavio O Souza }
427cb18f3f3SLuiz Otavio O Souza
428cb18f3f3SLuiz Otavio O Souza static int
ti_spi_transfer(device_t dev,device_t child,struct spi_command * cmd)429cb18f3f3SLuiz Otavio O Souza ti_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
430cb18f3f3SLuiz Otavio O Souza {
431718860e4SEmmanuel Vadot int err;
432cb18f3f3SLuiz Otavio O Souza struct ti_spi_softc *sc;
433584e3185SIan Lepore uint32_t clockhz, cs, mode, reg;
434cb18f3f3SLuiz Otavio O Souza
435cb18f3f3SLuiz Otavio O Souza sc = device_get_softc(dev);
436cb18f3f3SLuiz Otavio O Souza
437cb18f3f3SLuiz Otavio O Souza KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
438cb18f3f3SLuiz Otavio O Souza ("TX/RX command sizes should be equal"));
439cb18f3f3SLuiz Otavio O Souza KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
440cb18f3f3SLuiz Otavio O Souza ("TX/RX data sizes should be equal"));
441cb18f3f3SLuiz Otavio O Souza
442cb18f3f3SLuiz Otavio O Souza /* Get the proper chip select for this child. */
443cb18f3f3SLuiz Otavio O Souza spibus_get_cs(child, &cs);
444584e3185SIan Lepore spibus_get_clock(child, &clockhz);
445584e3185SIan Lepore spibus_get_mode(child, &mode);
4467073d12cSEmmanuel Vadot
4477073d12cSEmmanuel Vadot cs &= ~SPIBUS_CS_HIGH;
4487073d12cSEmmanuel Vadot
449718860e4SEmmanuel Vadot if (cs > sc->sc_numcs) {
450cb18f3f3SLuiz Otavio O Souza device_printf(dev, "Invalid chip select %d requested by %s\n",
451cb18f3f3SLuiz Otavio O Souza cs, device_get_nameunit(child));
452cb18f3f3SLuiz Otavio O Souza return (EINVAL);
453cb18f3f3SLuiz Otavio O Souza }
454cb18f3f3SLuiz Otavio O Souza
455584e3185SIan Lepore if (mode > 3)
456584e3185SIan Lepore {
457584e3185SIan Lepore device_printf(dev, "Invalid mode %d requested by %s\n", mode,
458584e3185SIan Lepore device_get_nameunit(child));
459584e3185SIan Lepore return (EINVAL);
460584e3185SIan Lepore }
461584e3185SIan Lepore
462cb18f3f3SLuiz Otavio O Souza TI_SPI_LOCK(sc);
463cb18f3f3SLuiz Otavio O Souza
464cb18f3f3SLuiz Otavio O Souza /* If the controller is in use wait until it is available. */
465cb18f3f3SLuiz Otavio O Souza while (sc->sc_flags & TI_SPI_BUSY)
466cb18f3f3SLuiz Otavio O Souza mtx_sleep(dev, &sc->sc_mtx, 0, "ti_spi", 0);
467cb18f3f3SLuiz Otavio O Souza
468cb18f3f3SLuiz Otavio O Souza /* Now we have control over SPI controller. */
469cb18f3f3SLuiz Otavio O Souza sc->sc_flags = TI_SPI_BUSY;
470cb18f3f3SLuiz Otavio O Souza
471cb18f3f3SLuiz Otavio O Souza /* Save the SPI command data. */
472cb18f3f3SLuiz Otavio O Souza sc->sc_cs = cs;
473cb18f3f3SLuiz Otavio O Souza sc->sc_cmd = cmd;
474cb18f3f3SLuiz Otavio O Souza sc->sc_read = 0;
475cb18f3f3SLuiz Otavio O Souza sc->sc_written = 0;
476cb18f3f3SLuiz Otavio O Souza sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz;
477cb18f3f3SLuiz Otavio O Souza sc->sc_fifolvl = ti_spi_gcd(sc->sc_len, TI_SPI_FIFOSZ);
478cb18f3f3SLuiz Otavio O Souza if (sc->sc_fifolvl < 2 || sc->sc_len > 0xffff)
479cb18f3f3SLuiz Otavio O Souza sc->sc_fifolvl = 1; /* FIFO disabled. */
480cb18f3f3SLuiz Otavio O Souza /* Disable FIFO for now. */
481cb18f3f3SLuiz Otavio O Souza sc->sc_fifolvl = 1;
482cb18f3f3SLuiz Otavio O Souza
483584e3185SIan Lepore /* Set the bus frequency. */
484584e3185SIan Lepore ti_spi_set_clock(sc, sc->sc_cs, clockhz);
485cb18f3f3SLuiz Otavio O Souza
486cb18f3f3SLuiz Otavio O Souza /* Disable the FIFO. */
487cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_XFERLEVEL, 0);
488cb18f3f3SLuiz Otavio O Souza
489cb18f3f3SLuiz Otavio O Souza /* 8 bits word, d0 miso, d1 mosi, mode 0 and CS active low. */
490cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
491cb18f3f3SLuiz Otavio O Souza reg &= ~(MCSPI_CONF_FFER | MCSPI_CONF_FFEW | MCSPI_CONF_SBPOL |
492cb18f3f3SLuiz Otavio O Souza MCSPI_CONF_SBE | MCSPI_CONF_TURBO | MCSPI_CONF_IS |
493cb18f3f3SLuiz Otavio O Souza MCSPI_CONF_DPE1 | MCSPI_CONF_DPE0 | MCSPI_CONF_DMAR |
494cb18f3f3SLuiz Otavio O Souza MCSPI_CONF_DMAW | MCSPI_CONF_EPOL);
495cb18f3f3SLuiz Otavio O Souza reg |= MCSPI_CONF_DPE0 | MCSPI_CONF_EPOL | MCSPI_CONF_WL8BITS;
496584e3185SIan Lepore reg |= mode; /* POL and PHA are the low bits, we can just OR-in mode */
497cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg);
498cb18f3f3SLuiz Otavio O Souza
499cb18f3f3SLuiz Otavio O Souza #if 0
500cb18f3f3SLuiz Otavio O Souza /* Enable channel interrupts. */
501cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_IRQENABLE);
502cb18f3f3SLuiz Otavio O Souza reg |= 0xf;
503cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQENABLE, reg);
504cb18f3f3SLuiz Otavio O Souza #endif
505cb18f3f3SLuiz Otavio O Souza
506cb18f3f3SLuiz Otavio O Souza /* Start the transfer. */
507cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(sc->sc_cs));
508cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CTRL_CH(sc->sc_cs), reg | MCSPI_CTRL_ENABLE);
509cb18f3f3SLuiz Otavio O Souza
510cb18f3f3SLuiz Otavio O Souza /* Force CS on. */
511cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
512cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg |= MCSPI_CONF_FORCE);
513cb18f3f3SLuiz Otavio O Souza
514cb18f3f3SLuiz Otavio O Souza err = 0;
515cb18f3f3SLuiz Otavio O Souza if (sc->sc_fifolvl == 1)
516cb18f3f3SLuiz Otavio O Souza err = ti_spi_pio_transfer(sc);
517cb18f3f3SLuiz Otavio O Souza
518cb18f3f3SLuiz Otavio O Souza /* Force CS off. */
519cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
520cb18f3f3SLuiz Otavio O Souza reg &= ~MCSPI_CONF_FORCE;
521cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg);
522cb18f3f3SLuiz Otavio O Souza
523cb18f3f3SLuiz Otavio O Souza /* Disable IRQs. */
524cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_IRQENABLE);
525cb18f3f3SLuiz Otavio O Souza reg &= ~0xf;
526cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQENABLE, reg);
527cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xf);
528cb18f3f3SLuiz Otavio O Souza
529cb18f3f3SLuiz Otavio O Souza /* Disable the SPI channel. */
530cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(sc->sc_cs));
531cb18f3f3SLuiz Otavio O Souza reg &= ~MCSPI_CTRL_ENABLE;
532cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CTRL_CH(sc->sc_cs), reg);
533cb18f3f3SLuiz Otavio O Souza
534cb18f3f3SLuiz Otavio O Souza /* Disable FIFO. */
535cb18f3f3SLuiz Otavio O Souza reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
536cb18f3f3SLuiz Otavio O Souza reg &= ~(MCSPI_CONF_FFER | MCSPI_CONF_FFEW);
537cb18f3f3SLuiz Otavio O Souza TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg);
538cb18f3f3SLuiz Otavio O Souza
539cb18f3f3SLuiz Otavio O Souza /* Release the controller and wakeup the next thread waiting for it. */
540cb18f3f3SLuiz Otavio O Souza sc->sc_flags = 0;
541cb18f3f3SLuiz Otavio O Souza wakeup_one(dev);
542cb18f3f3SLuiz Otavio O Souza TI_SPI_UNLOCK(sc);
543cb18f3f3SLuiz Otavio O Souza
544cb18f3f3SLuiz Otavio O Souza return (err);
545cb18f3f3SLuiz Otavio O Souza }
546cb18f3f3SLuiz Otavio O Souza
547cb18f3f3SLuiz Otavio O Souza static phandle_t
ti_spi_get_node(device_t bus,device_t dev)548cb18f3f3SLuiz Otavio O Souza ti_spi_get_node(device_t bus, device_t dev)
549cb18f3f3SLuiz Otavio O Souza {
550cb18f3f3SLuiz Otavio O Souza
551cb18f3f3SLuiz Otavio O Souza /* Share controller node with spibus. */
552cb18f3f3SLuiz Otavio O Souza return (ofw_bus_get_node(bus));
553cb18f3f3SLuiz Otavio O Souza }
554cb18f3f3SLuiz Otavio O Souza
555cb18f3f3SLuiz Otavio O Souza static device_method_t ti_spi_methods[] = {
556cb18f3f3SLuiz Otavio O Souza /* Device interface */
557cb18f3f3SLuiz Otavio O Souza DEVMETHOD(device_probe, ti_spi_probe),
558cb18f3f3SLuiz Otavio O Souza DEVMETHOD(device_attach, ti_spi_attach),
559cb18f3f3SLuiz Otavio O Souza DEVMETHOD(device_detach, ti_spi_detach),
560cb18f3f3SLuiz Otavio O Souza
561cb18f3f3SLuiz Otavio O Souza /* SPI interface */
562cb18f3f3SLuiz Otavio O Souza DEVMETHOD(spibus_transfer, ti_spi_transfer),
563cb18f3f3SLuiz Otavio O Souza
564cb18f3f3SLuiz Otavio O Souza /* ofw_bus interface */
565cb18f3f3SLuiz Otavio O Souza DEVMETHOD(ofw_bus_get_node, ti_spi_get_node),
566cb18f3f3SLuiz Otavio O Souza
567cb18f3f3SLuiz Otavio O Souza DEVMETHOD_END
568cb18f3f3SLuiz Otavio O Souza };
569cb18f3f3SLuiz Otavio O Souza
570cb18f3f3SLuiz Otavio O Souza static driver_t ti_spi_driver = {
571cb18f3f3SLuiz Otavio O Souza "spi",
572cb18f3f3SLuiz Otavio O Souza ti_spi_methods,
573cb18f3f3SLuiz Otavio O Souza sizeof(struct ti_spi_softc),
574cb18f3f3SLuiz Otavio O Souza };
575cb18f3f3SLuiz Otavio O Souza
5768537e671SJohn Baldwin DRIVER_MODULE(ti_spi, simplebus, ti_spi_driver, 0, 0);
5770050ea24SMichal Meloun MODULE_DEPEND(ti_spi, ti_sysc, 1, 1, 1);
578