2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2011, 2012 Cavium, Inc.
9 #include <linux/spi/spi.h>
10 #include <linux/module.h>
11 #include <linux/delay.h>
14 #include "spi-cavium.h"
16 static void octeon_spi_wait_ready(struct octeon_spi
*p
)
18 union cvmx_mpi_sts mpi_sts
;
19 unsigned int loops
= 0;
24 mpi_sts
.u64
= readq(p
->register_base
+ OCTEON_SPI_STS(p
));
25 } while (mpi_sts
.s
.busy
);
28 static int octeon_spi_do_transfer(struct octeon_spi
*p
,
29 struct spi_message
*msg
,
30 struct spi_transfer
*xfer
,
33 struct spi_device
*spi
= msg
->spi
;
34 union cvmx_mpi_cfg mpi_cfg
;
35 union cvmx_mpi_tx mpi_tx
;
45 cpha
= mode
& SPI_CPHA
;
46 cpol
= mode
& SPI_CPOL
;
48 clkdiv
= p
->sys_freq
/ (2 * xfer
->speed_hz
);
52 mpi_cfg
.s
.clkdiv
= clkdiv
;
53 mpi_cfg
.s
.cshi
= (mode
& SPI_CS_HIGH
) ? 1 : 0;
54 mpi_cfg
.s
.lsbfirst
= (mode
& SPI_LSB_FIRST
) ? 1 : 0;
55 mpi_cfg
.s
.wireor
= (mode
& SPI_3WIRE
) ? 1 : 0;
56 mpi_cfg
.s
.idlelo
= cpha
!= cpol
;
57 mpi_cfg
.s
.cslate
= cpha
? 1 : 0;
60 if (spi
->chip_select
< 4)
61 p
->cs_enax
|= 1ull << (12 + spi
->chip_select
);
62 mpi_cfg
.u64
|= p
->cs_enax
;
64 if (mpi_cfg
.u64
!= p
->last_cfg
) {
65 p
->last_cfg
= mpi_cfg
.u64
;
66 writeq(mpi_cfg
.u64
, p
->register_base
+ OCTEON_SPI_CFG(p
));
68 tx_buf
= xfer
->tx_buf
;
69 rx_buf
= xfer
->rx_buf
;
71 while (len
> OCTEON_SPI_MAX_BYTES
) {
72 for (i
= 0; i
< OCTEON_SPI_MAX_BYTES
; i
++) {
78 writeq(d
, p
->register_base
+ OCTEON_SPI_DAT0(p
) + (8 * i
));
81 mpi_tx
.s
.csid
= spi
->chip_select
;
83 mpi_tx
.s
.txnum
= tx_buf
? OCTEON_SPI_MAX_BYTES
: 0;
84 mpi_tx
.s
.totnum
= OCTEON_SPI_MAX_BYTES
;
85 writeq(mpi_tx
.u64
, p
->register_base
+ OCTEON_SPI_TX(p
));
87 octeon_spi_wait_ready(p
);
89 for (i
= 0; i
< OCTEON_SPI_MAX_BYTES
; i
++) {
90 u64 v
= readq(p
->register_base
+ OCTEON_SPI_DAT0(p
) + (8 * i
));
93 len
-= OCTEON_SPI_MAX_BYTES
;
96 for (i
= 0; i
< len
; i
++) {
102 writeq(d
, p
->register_base
+ OCTEON_SPI_DAT0(p
) + (8 * i
));
106 mpi_tx
.s
.csid
= spi
->chip_select
;
108 mpi_tx
.s
.leavecs
= xfer
->cs_change
;
110 mpi_tx
.s
.leavecs
= !xfer
->cs_change
;
111 mpi_tx
.s
.txnum
= tx_buf
? len
: 0;
112 mpi_tx
.s
.totnum
= len
;
113 writeq(mpi_tx
.u64
, p
->register_base
+ OCTEON_SPI_TX(p
));
115 octeon_spi_wait_ready(p
);
117 for (i
= 0; i
< len
; i
++) {
118 u64 v
= readq(p
->register_base
+ OCTEON_SPI_DAT0(p
) + (8 * i
));
122 spi_transfer_delay_exec(xfer
);
127 int octeon_spi_transfer_one_message(struct spi_master
*master
,
128 struct spi_message
*msg
)
130 struct octeon_spi
*p
= spi_master_get_devdata(master
);
131 unsigned int total_len
= 0;
133 struct spi_transfer
*xfer
;
135 list_for_each_entry(xfer
, &msg
->transfers
, transfer_list
) {
136 bool last_xfer
= list_is_last(&xfer
->transfer_list
,
138 int r
= octeon_spi_do_transfer(p
, msg
, xfer
, last_xfer
);
146 msg
->status
= status
;
147 msg
->actual_length
= total_len
;
148 spi_finalize_current_message(master
);