1207753Smm/* $NetBSD: arspi.c,v 1.15 2021/08/07 16:18:58 thorpej Exp $ */
2207753Smm
3207753Smm/*-
4207753Smm * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5207753Smm * Copyright (c) 2006 Garrett D'Amore.
6207753Smm * All rights reserved.
7207753Smm *
8207753Smm * Portions of this code were written by Garrett D'Amore for the
9207753Smm * Champaign-Urbana Community Wireless Network Project.
10207753Smm *
11207753Smm * Redistribution and use in source and binary forms, with or
12207753Smm * without modification, are permitted provided that the following
13207753Smm * conditions are met:
14207753Smm * 1. Redistributions of source code must retain the above copyright
15207753Smm *    notice, this list of conditions and the following disclaimer.
16207753Smm * 2. Redistributions in binary form must reproduce the above
17207753Smm *    copyright notice, this list of conditions and the following
18207753Smm *    disclaimer in the documentation and/or other materials provided
19207753Smm *    with the distribution.
20207753Smm * 3. All advertising materials mentioning features or use of this
21207753Smm *    software must display the following acknowledgements:
22207753Smm *      This product includes software developed by the Urbana-Champaign
23207753Smm *      Independent Media Center.
24207753Smm *	This product includes software developed by Garrett D'Amore.
25207753Smm * 4. Urbana-Champaign Independent Media Center's name and Garrett
26207753Smm *    D'Amore's name may not be used to endorse or promote products
27207753Smm *    derived from this software without specific prior written permission.
28207753Smm *
29207753Smm * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
30207753Smm * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
31207753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32207753Smm * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33207753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34207753Smm * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35207753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36207753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37207753Smm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38223935Smm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39207753Smm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40207753Smm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41207753Smm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42207753Smm */
43207753Smm
44207753Smm#include <sys/cdefs.h>
45207753Smm__KERNEL_RCSID(0, "$NetBSD: arspi.c,v 1.15 2021/08/07 16:18:58 thorpej Exp $");
46207753Smm
47207753Smm#include "locators.h"
48207753Smm
49207753Smm#include <sys/param.h>
50207753Smm#include <sys/bus.h>
51207753Smm#include <sys/cpu.h>
52207753Smm#include <sys/device.h>
53207753Smm#include <sys/errno.h>
54207753Smm#include <sys/kernel.h>
55207753Smm#include <sys/kmem.h>
56207753Smm#include <sys/proc.h>
57207753Smm#include <sys/systm.h>
58207753Smm
59207753Smm#include <mips/atheros/include/ar5315reg.h>
60207753Smm#include <mips/atheros/include/arbusvar.h>
61207753Smm
62207753Smm#include <mips/atheros/dev/arspireg.h>
63207753Smm
64207753Smm#include <dev/spi/spiflash.h>
65207753Smm#include <dev/spi/spivar.h>
66207753Smm
67207753Smm/*
68207753Smm * This device is intended only to operate with specific SPI flash
69207753Smm * parts, and is not a general purpose SPI host.  (Or at least if it
70207753Smm * is, the Linux and eCos sources do not show how to use it as such.)
71207753Smm * And lack of documentation on the Atheros SoCs is less than helpful.
72207753Smm *
73207753Smm * So for now we just "emulate" enough of the host bus framework to
74207753Smm * make the SPI flash drivers happy.
75207753Smm */
76207753Smm
77207753Smmstruct arspi_job {
78207753Smm	uint8_t			job_opcode;
79213700Smm	struct spi_chunk	*job_chunk;
80207753Smm	uint32_t		job_flags;
81207753Smm	uint32_t		job_addr;
82207753Smm	uint32_t		job_data;
83207753Smm	int			job_rxcnt;
84207753Smm	int			job_txcnt;
85207753Smm	int			job_addrcnt;
86207753Smm	int			job_rresid;
87207753Smm	int			job_wresid;
88207753Smm};
89207753Smm
90207753Smm#define	JOB_READ		0x1
91207753Smm#define	JOB_WRITE		0x2
92207753Smm#define	JOB_LAST		0x4
93207753Smm#define	JOB_WAIT		0x8	/* job must wait for WIP bits */
94207753Smm#define	JOB_WREN		0x10	/* WREN needed */
95207753Smm
96207753Smmstruct arspi_softc {
97207753Smm	struct spi_controller	sc_spi;
98207753Smm	void			*sc_ih;
99207753Smm	bool			sc_interrupts;
100207753Smm
101207753Smm	struct spi_transfer	*sc_transfer;
102207753Smm	struct spi_chunk	*sc_wchunk;	/* for partial writes */
103207753Smm	struct spi_transq	sc_transq;
104207753Smm	bus_space_tag_t		sc_st;
105207753Smm	bus_space_handle_t	sc_sh;
106207753Smm	bus_size_t		sc_size;
107207753Smm};
108207753Smm
109207753Smm#define	STATIC
110207753Smm
111207753SmmSTATIC int arspi_match(device_t, cfdata_t, void *);
112207753SmmSTATIC void arspi_attach(device_t, device_t, void *);
113207753SmmSTATIC void arspi_interrupts(device_t);
114207753SmmSTATIC int arspi_intr(void *);
115207753Smm/* SPI service routines */
116207753SmmSTATIC int arspi_configure(void *, int, int, int);
117207753SmmSTATIC int arspi_transfer(void *, struct spi_transfer *);
118207753Smm/* internal support */
119207753SmmSTATIC void arspi_poll(struct arspi_softc *);
120207753SmmSTATIC void arspi_done(struct arspi_softc *, int);
121207753SmmSTATIC void arspi_sched(struct arspi_softc *);
122207753SmmSTATIC int arspi_get_byte(struct spi_chunk **, uint8_t *);
123207753SmmSTATIC int arspi_put_byte(struct spi_chunk **, uint8_t);
124207753SmmSTATIC int arspi_make_job(struct spi_transfer *);
125207753SmmSTATIC void arspi_update_job(struct spi_transfer *);
126207753SmmSTATIC void arspi_finish_job(struct spi_transfer *);
127207753Smm
128207753Smm
129207753SmmCFATTACH_DECL_NEW(arspi, sizeof(struct arspi_softc),
130207753Smm    arspi_match, arspi_attach, NULL, NULL);
131207753Smm
132207753Smm#define	GETREG(sc, o)		bus_space_read_4(sc->sc_st, sc->sc_sh, o)
133207753Smm#define	PUTREG(sc, o, v)	bus_space_write_4(sc->sc_st, sc->sc_sh, o, v)
134207753Smm
135207753Smmint
136207753Smmarspi_match(device_t parent, cfdata_t cf, void *aux)
137207753Smm{
138207753Smm	struct arbus_attach_args *aa = aux;
139207753Smm
140207753Smm	if (strcmp(aa->aa_name, cf->cf_name) != 0)
141207753Smm		return 0;
142207753Smm	return 1;
143207753Smm}
144207753Smm
145207753Smmvoid
146207753Smmarspi_attach(device_t parent, device_t self, void *aux)
147207753Smm{
148207753Smm	struct arspi_softc *sc = device_private(self);
149207753Smm	struct spibus_attach_args sba;
150207753Smm	struct arbus_attach_args *aa = aux;
151207753Smm
152207753Smm	/*
153207753Smm	 * Map registers.
154207753Smm	 */
155207753Smm	sc->sc_st = aa->aa_bst;
156207753Smm	sc->sc_size = aa->aa_size;
157207753Smm	if (bus_space_map(sc->sc_st, aa->aa_addr, sc->sc_size, 0,
158207753Smm		&sc->sc_sh) != 0) {
159207753Smm		printf(": unable to map registers!\n");
160207753Smm		return;
161207753Smm	}
162207753Smm
163207753Smm	aprint_normal(": Atheros SPI controller\n");
164207753Smm
165207753Smm	/*
166207753Smm	 * Initialize SPI controller.
167207753Smm	 */
168207753Smm	sc->sc_spi.sct_cookie = sc;
169207753Smm	sc->sc_spi.sct_configure = arspi_configure;
170207753Smm	sc->sc_spi.sct_transfer = arspi_transfer;
171207753Smm	sc->sc_spi.sct_nslaves = 1;
172207753Smm
173207753Smm
174207753Smm	/*
175207753Smm	 * Initialize the queue.
176207753Smm	 */
177207753Smm	spi_transq_init(&sc->sc_transq);
178207753Smm
179207753Smm	/*
180207753Smm	 * Enable device interrupts.
181207753Smm	 */
182207753Smm	sc->sc_ih = arbus_intr_establish(aa->aa_cirq, aa->aa_mirq,
183207753Smm	    arspi_intr, sc);
184207753Smm	if (sc->sc_ih == NULL) {
185215187Smm		aprint_error("%s: couldn't establish interrupt\n",
186215187Smm		    device_xname(self));
187215187Smm		/* just leave it in polled mode */
188215187Smm	} else
189215187Smm		config_interrupts(self, arspi_interrupts);
190215187Smm
191215187Smm	/*
192215187Smm	 * Initialize and attach bus attach.
193215187Smm	 */
194215187Smm	memset(&sba, 0, sizeof(sba));
195215187Smm	sba.sba_controller = &sc->sc_spi;
196215187Smm	config_found(self, &sba, spibus_print, CFARGS_NONE);
197215187Smm}
198215187Smm
199207753Smmvoid
200207753Smmarspi_interrupts(device_t self)
201207753Smm{
202207753Smm	/*
203207753Smm	 * we never leave polling mode, because, apparently, we
204207753Smm	 * are missing some data about how to drive the SPI in interrupt
205207753Smm	 * mode.
206207753Smm	 */
207207753Smm#if 0
208207753Smm	struct arspi_softc *sc = device_private(self);
209207753Smm	int	s;
210207753Smm
211207753Smm	s = splbio();
212207753Smm	sc->sc_interrupts = true;
213207753Smm	splx(s);
214207753Smm#endif
215207753Smm}
216207753Smm
217207753Smmint
218207753Smmarspi_intr(void *arg)
219207753Smm{
220207753Smm	struct arspi_softc *sc = arg;
221207753Smm
222207753Smm	while (GETREG(sc, ARSPI_REG_CTL) & ARSPI_CTL_BUSY);
223207753Smm
224207753Smm	arspi_done(sc, 0);
225207753Smm
226207753Smm	return 1;
227207753Smm}
228207753Smm
229207753Smmvoid
230207753Smmarspi_poll(struct arspi_softc *sc)
231207753Smm{
232207753Smm
233207753Smm	while (sc->sc_transfer) {
234207753Smm		arspi_intr(sc);
235207753Smm	}
236207753Smm}
237207753Smm
238207753Smmint
239207753Smmarspi_configure(void *cookie, int slave, int mode, int speed)
240207753Smm{
241207753Smm
242207753Smm	/*
243207753Smm	 * We don't support the full SPI protocol, and hopefully the
244207753Smm	 * firmware has programmed a reasonable mode already.  So
245207753Smm	 * just a couple of quick sanity checks, then bail.
246207753Smm	 */
247207753Smm	if ((mode != 0) || (slave != 0))
248207753Smm		return EINVAL;
249207753Smm
250207753Smm	return 0;
251207753Smm}
252207753Smm
253207753Smmint
254207753Smmarspi_transfer(void *cookie, struct spi_transfer *st)
255207753Smm{
256207753Smm	struct arspi_softc *sc = cookie;
257207753Smm	int rv;
258207753Smm	int s;
259207753Smm
260207753Smm	st->st_busprivate = NULL;
261207753Smm	if ((rv = arspi_make_job(st)) != 0) {
262207753Smm		if (st->st_busprivate) {
263207753Smm			struct arspi_job *job = st->st_busprivate;
264207753Smm			st->st_busprivate = NULL;
265207753Smm			kmem_free(job, sizeof(*job));
266207753Smm		}
267207753Smm		spi_done(st, rv);
268207753Smm		return rv;
269207753Smm	}
270207753Smm
271207753Smm	s = splbio();
272207753Smm	spi_transq_enqueue(&sc->sc_transq, st);
273207753Smm	if (sc->sc_transfer == NULL) {
274207753Smm		arspi_sched(sc);
275207753Smm		if (!sc->sc_interrupts)
276207753Smm			arspi_poll(sc);
277207753Smm	}
278207753Smm	splx(s);
279207753Smm	return 0;
280207753Smm}
281207753Smm
282207753Smmvoid
283207753Smmarspi_sched(struct arspi_softc *sc)
284207753Smm{
285207753Smm	struct spi_transfer *st;
286207753Smm	struct arspi_job *job;
287207753Smm	uint32_t ctl, cnt;
288207753Smm
289207753Smm	for (;;) {
290207753Smm		if ((st = sc->sc_transfer) == NULL) {
291207753Smm			if ((st = spi_transq_first(&sc->sc_transq)) == NULL) {
292207753Smm				/* no work left to do */
293207753Smm				break;
294207753Smm			}
295207753Smm			spi_transq_dequeue(&sc->sc_transq);
296207753Smm			sc->sc_transfer = st;
297207753Smm		}
298207753Smm
299207753Smm		arspi_update_job(st);
300207753Smm		job = st->st_busprivate;
301207753Smm
302207753Smm		/* there shouldn't be anything running, but ensure it */
303207753Smm		do {
304207753Smm			ctl = GETREG(sc, ARSPI_REG_CTL);
305207753Smm		}  while (ctl & ARSPI_CTL_BUSY);
306207753Smm		/* clear all of the tx and rx bits */
307207753Smm		ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK);
308207753Smm
309207753Smm		if (job->job_flags & JOB_WAIT) {
310207753Smm			PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_RDSR);
311207753Smm			/* only the opcode for tx */
312207753Smm			ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT);
313207753Smm			/* and one rx byte */
314207753Smm			ctl |= (1 << ARSPI_CTL_RXCNT_SHIFT);
315207753Smm		} else if (job->job_flags & JOB_WREN) {
316207753Smm			PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_WREN);
317207753Smm			/* just the opcode */
318207753Smm			ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT);
319207753Smm			/* no rx bytes */
320207753Smm		} else {
321207753Smm			/* set the data */
322207753Smm			PUTREG(sc, ARSPI_REG_DATA, job->job_data);
323207753Smm
324207753Smm			/* set the opcode and the address */
325207753Smm			PUTREG(sc, ARSPI_REG_OPCODE, job->job_opcode |
326207753Smm			    (job->job_addr << 8));
327207753Smm
328207753Smm			/* now set txcnt */
329207753Smm			cnt = 1;	/* opcode */
330207753Smm			cnt += job->job_addrcnt + job->job_txcnt;
331207753Smm			ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT);
332207753Smm
333207753Smm			/* now set rxcnt */
334207753Smm			cnt = job->job_rxcnt;
335207753Smm			ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT);
336207753Smm		}
337207753Smm
338207753Smm		/* set the start bit */
339207753Smm		ctl |= ARSPI_CTL_START;
340207753Smm
341207753Smm		PUTREG(sc, ARSPI_REG_CTL, ctl);
342207753Smm		break;
343207753Smm	}
344207753Smm}
345207753Smm
346207753Smmvoid
347207753Smmarspi_done(struct arspi_softc *sc, int err)
348207753Smm{
349207753Smm	struct spi_transfer *st;
350207753Smm	struct arspi_job *job;
351207753Smm
352207753Smm	if ((st = sc->sc_transfer) != NULL) {
353207753Smm		job = st->st_busprivate;
354207753Smm
355207753Smm		if (job->job_flags & JOB_WAIT) {
356207753Smm			if (err == 0) {
357207753Smm				if ((GETREG(sc, ARSPI_REG_DATA) &
358207753Smm				    SPIFLASH_SR_BUSY) == 0) {
359207753Smm					/* intermediate wait done */
360207753Smm					job->job_flags &= ~JOB_WAIT;
361207753Smm					goto done;
362207753Smm				}
363207753Smm			}
364207753Smm		} else if (job->job_flags & JOB_WREN) {
365207753Smm			if (err == 0) {
366207753Smm				job->job_flags &= ~JOB_WREN;
367207753Smm				goto done;
368207753Smm			}
369207753Smm		} else if (err == 0) {
370207753Smm			/*
371207753Smm			 * When breaking up write jobs, we have to wait until
372207753Smm			 * the WIP bit is clear, and we have to separately
373207753Smm			 * send WREN for each chunk.  These flags facilitate
374207753Smm			 * that.
375207753Smm			 */
376207753Smm			if (job->job_flags & JOB_WRITE)
377207753Smm				job->job_flags |= (JOB_WAIT | JOB_WREN);
378207753Smm			job->job_data = GETREG(sc, ARSPI_REG_DATA);
379207753Smm			arspi_finish_job(st);
380207753Smm		}
381207753Smm
382207753Smm		if (err || (job->job_flags & JOB_LAST)) {
383207753Smm			sc->sc_transfer = NULL;
384207753Smm			st->st_busprivate = NULL;
385207753Smm			spi_done(st, err);
386207753Smm			kmem_free(job, sizeof(*job));
387207753Smm		}
388207753Smm	}
389done:
390	arspi_sched(sc);
391}
392
393int
394arspi_get_byte(struct spi_chunk **chunkp, uint8_t *bytep)
395{
396	struct spi_chunk *chunk;
397
398	chunk = *chunkp;
399
400	/* skip leading empty (or already consumed) chunks */
401	while (chunk && chunk->chunk_wresid == 0)
402		chunk = chunk->chunk_next;
403
404	if (chunk == NULL) {
405		return ENODATA;
406	}
407
408	/*
409	 * chunk must be write only.  SPI flash doesn't support
410	 * any full duplex operations.
411	 */
412	if ((chunk->chunk_rptr) || !(chunk->chunk_wptr)) {
413		return EINVAL;
414	}
415
416	*bytep = *chunk->chunk_wptr;
417	chunk->chunk_wptr++;
418	chunk->chunk_wresid--;
419	chunk->chunk_rresid--;
420	/* clearing wptr and rptr makes sanity checks later easier */
421	if (chunk->chunk_wresid == 0)
422		chunk->chunk_wptr = NULL;
423	if (chunk->chunk_rresid == 0)
424		chunk->chunk_rptr = NULL;
425	while (chunk && chunk->chunk_wresid == 0)
426		chunk = chunk->chunk_next;
427
428	*chunkp = chunk;
429	return 0;
430}
431
432int
433arspi_put_byte(struct spi_chunk **chunkp, uint8_t byte)
434{
435	struct spi_chunk *chunk;
436
437	chunk = *chunkp;
438
439	/* skip leading empty (or already consumed) chunks */
440	while (chunk && chunk->chunk_rresid == 0)
441		chunk = chunk->chunk_next;
442
443	if (chunk == NULL) {
444		return EOVERFLOW;
445	}
446
447	/*
448	 * chunk must be read only.  SPI flash doesn't support
449	 * any full duplex operations.
450	 */
451	if ((chunk->chunk_wptr) || !(chunk->chunk_rptr)) {
452		return EINVAL;
453	}
454
455	*chunk->chunk_rptr = byte;
456	chunk->chunk_rptr++;
457	chunk->chunk_wresid--;	/* technically this was done at send time */
458	chunk->chunk_rresid--;
459	while (chunk && chunk->chunk_rresid == 0)
460		chunk = chunk->chunk_next;
461
462	*chunkp = chunk;
463	return 0;
464}
465
466int
467arspi_make_job(struct spi_transfer *st)
468{
469	struct arspi_job *job;
470	struct spi_chunk *chunk;
471	uint8_t byte;
472	int i, rv;
473
474	job = kmem_zalloc(sizeof (struct arspi_job), KM_SLEEP);
475
476	st->st_busprivate = job;
477
478	/* skip any leading empty chunks (should not be any!) */
479	chunk = st->st_chunks;
480
481	/* get transfer opcode */
482	if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
483		return rv;
484
485	job->job_opcode = byte;
486	switch (job->job_opcode) {
487	case SPIFLASH_CMD_WREN:
488	case SPIFLASH_CMD_WRDI:
489	case SPIFLASH_CMD_CHIPERASE:
490		break;
491	case SPIFLASH_CMD_RDJI:
492		job->job_rxcnt = 3;
493		break;
494	case SPIFLASH_CMD_RDSR:
495		job->job_rxcnt = 1;
496		break;
497	case SPIFLASH_CMD_WRSR:
498		/*
499		 * is this in data, or in address?  stick it in data
500		 * for now.
501		 */
502		job->job_txcnt = 1;
503		break;
504	case SPIFLASH_CMD_RDID:
505		job->job_addrcnt = 3;	/* 3 dummy bytes */
506		job->job_rxcnt = 1;
507		break;
508	case SPIFLASH_CMD_ERASE:
509		job->job_addrcnt = 3;
510		break;
511	case SPIFLASH_CMD_READ:
512		job->job_addrcnt = 3;
513		job->job_flags |= JOB_READ;
514		break;
515	case SPIFLASH_CMD_PROGRAM:
516		job->job_addrcnt = 3;
517		job->job_flags |= JOB_WRITE;
518		break;
519	case SPIFLASH_CMD_READFAST:
520		/*
521		 * This is a pain in the arse to support, so we will
522		 * rewrite as an ordinary read.  But later, after we
523		 * obtain the address.
524		 */
525		job->job_addrcnt = 3;	/* 3 address */
526		job->job_flags |= JOB_READ;
527		break;
528	default:
529		return EINVAL;
530	}
531
532	for (i = 0; i < job->job_addrcnt; i++) {
533		if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
534			return rv;
535		job->job_addr <<= 8;
536		job->job_addr |= byte;
537	}
538
539
540	if (job->job_opcode == SPIFLASH_CMD_READFAST) {
541		/* eat the dummy timing byte */
542		if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
543			return rv;
544		/* rewrite this as a read */
545		job->job_opcode = SPIFLASH_CMD_READ;
546	}
547
548	job->job_chunk = chunk;
549
550	/*
551	 * Now quickly check a few other things.   Namely, we are not
552	 * allowed to have both READ and WRITE.
553	 */
554	for (chunk = job->job_chunk; chunk; chunk = chunk->chunk_next) {
555		if (chunk->chunk_wptr) {
556			job->job_wresid += chunk->chunk_wresid;
557		}
558		if (chunk->chunk_rptr) {
559			job->job_rresid += chunk->chunk_rresid;
560		}
561	}
562
563	if (job->job_rresid && job->job_wresid) {
564		return EINVAL;
565	}
566
567	return 0;
568}
569
570/*
571 * NB: The Atheros SPI controller runs in little endian mode. So all
572 * data accesses must be swapped appropriately.
573 *
574 * The controller auto-swaps read accesses done through the mapped memory
575 * region, but when using SPI directly, we have to do the right thing to
576 * swap to or from little endian.
577 */
578
579void
580arspi_update_job(struct spi_transfer *st)
581{
582	struct arspi_job *job = st->st_busprivate;
583	uint8_t byte;
584	int i;
585
586	if (job->job_flags & (JOB_WAIT|JOB_WREN))
587		return;
588
589	job->job_rxcnt = 0;
590	job->job_txcnt = 0;
591	job->job_data = 0;
592
593	job->job_txcnt = uimin(job->job_wresid, 4);
594	job->job_rxcnt = uimin(job->job_rresid, 4);
595
596	job->job_wresid -= job->job_txcnt;
597	job->job_rresid -= job->job_rxcnt;
598
599	for (i = 0; i < job->job_txcnt; i++) {
600		arspi_get_byte(&job->job_chunk, &byte);
601		job->job_data |= (byte << (i * 8));
602	}
603
604	if ((!job->job_wresid) && (!job->job_rresid)) {
605		job->job_flags |= JOB_LAST;
606	}
607}
608
609void
610arspi_finish_job(struct spi_transfer *st)
611{
612	struct arspi_job *job = st->st_busprivate;
613	uint8_t	byte;
614	int i;
615
616	job->job_addr += job->job_rxcnt;
617	job->job_addr += job->job_txcnt;
618	for (i = 0; i < job->job_rxcnt; i++) {
619		byte = job->job_data & 0xff;
620		job->job_data >>= 8;
621		arspi_put_byte(&job->job_chunk, byte);
622	}
623}
624
625