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/platform_device.h>
10 #include <linux/interrupt.h>
11 #include <linux/spi/spi.h>
12 #include <linux/module.h>
13 #include <linux/delay.h>
17 #include <asm/octeon/octeon.h>
18 #include <asm/octeon/cvmx-mpi-defs.h>
20 #define OCTEON_SPI_CFG 0
21 #define OCTEON_SPI_STS 0x08
22 #define OCTEON_SPI_TX 0x10
23 #define OCTEON_SPI_DAT0 0x80
25 #define OCTEON_SPI_MAX_BYTES 9
27 #define OCTEON_SPI_MAX_CLOCK_HZ 16000000
35 static void octeon_spi_wait_ready(struct octeon_spi
*p
)
37 union cvmx_mpi_sts mpi_sts
;
38 unsigned int loops
= 0;
43 mpi_sts
.u64
= cvmx_read_csr(p
->register_base
+ OCTEON_SPI_STS
);
44 } while (mpi_sts
.s
.busy
);
47 static int octeon_spi_do_transfer(struct octeon_spi
*p
,
48 struct spi_message
*msg
,
49 struct spi_transfer
*xfer
,
52 struct spi_device
*spi
= msg
->spi
;
53 union cvmx_mpi_cfg mpi_cfg
;
54 union cvmx_mpi_tx mpi_tx
;
56 unsigned int speed_hz
;
65 cpha
= mode
& SPI_CPHA
;
66 cpol
= mode
& SPI_CPOL
;
68 speed_hz
= xfer
->speed_hz
? : spi
->max_speed_hz
;
70 clkdiv
= octeon_get_io_clock_rate() / (2 * speed_hz
);
74 mpi_cfg
.s
.clkdiv
= clkdiv
;
75 mpi_cfg
.s
.cshi
= (mode
& SPI_CS_HIGH
) ? 1 : 0;
76 mpi_cfg
.s
.lsbfirst
= (mode
& SPI_LSB_FIRST
) ? 1 : 0;
77 mpi_cfg
.s
.wireor
= (mode
& SPI_3WIRE
) ? 1 : 0;
78 mpi_cfg
.s
.idlelo
= cpha
!= cpol
;
79 mpi_cfg
.s
.cslate
= cpha
? 1 : 0;
82 if (spi
->chip_select
< 4)
83 p
->cs_enax
|= 1ull << (12 + spi
->chip_select
);
84 mpi_cfg
.u64
|= p
->cs_enax
;
86 if (mpi_cfg
.u64
!= p
->last_cfg
) {
87 p
->last_cfg
= mpi_cfg
.u64
;
88 cvmx_write_csr(p
->register_base
+ OCTEON_SPI_CFG
, mpi_cfg
.u64
);
90 tx_buf
= xfer
->tx_buf
;
91 rx_buf
= xfer
->rx_buf
;
93 while (len
> OCTEON_SPI_MAX_BYTES
) {
94 for (i
= 0; i
< OCTEON_SPI_MAX_BYTES
; i
++) {
100 cvmx_write_csr(p
->register_base
+ OCTEON_SPI_DAT0
+ (8 * i
), d
);
103 mpi_tx
.s
.csid
= spi
->chip_select
;
104 mpi_tx
.s
.leavecs
= 1;
105 mpi_tx
.s
.txnum
= tx_buf
? OCTEON_SPI_MAX_BYTES
: 0;
106 mpi_tx
.s
.totnum
= OCTEON_SPI_MAX_BYTES
;
107 cvmx_write_csr(p
->register_base
+ OCTEON_SPI_TX
, mpi_tx
.u64
);
109 octeon_spi_wait_ready(p
);
111 for (i
= 0; i
< OCTEON_SPI_MAX_BYTES
; i
++) {
112 u64 v
= cvmx_read_csr(p
->register_base
+ OCTEON_SPI_DAT0
+ (8 * i
));
115 len
-= OCTEON_SPI_MAX_BYTES
;
118 for (i
= 0; i
< len
; i
++) {
124 cvmx_write_csr(p
->register_base
+ OCTEON_SPI_DAT0
+ (8 * i
), d
);
128 mpi_tx
.s
.csid
= spi
->chip_select
;
130 mpi_tx
.s
.leavecs
= xfer
->cs_change
;
132 mpi_tx
.s
.leavecs
= !xfer
->cs_change
;
133 mpi_tx
.s
.txnum
= tx_buf
? len
: 0;
134 mpi_tx
.s
.totnum
= len
;
135 cvmx_write_csr(p
->register_base
+ OCTEON_SPI_TX
, mpi_tx
.u64
);
137 octeon_spi_wait_ready(p
);
139 for (i
= 0; i
< len
; i
++) {
140 u64 v
= cvmx_read_csr(p
->register_base
+ OCTEON_SPI_DAT0
+ (8 * i
));
144 if (xfer
->delay_usecs
)
145 udelay(xfer
->delay_usecs
);
150 static int octeon_spi_transfer_one_message(struct spi_master
*master
,
151 struct spi_message
*msg
)
153 struct octeon_spi
*p
= spi_master_get_devdata(master
);
154 unsigned int total_len
= 0;
156 struct spi_transfer
*xfer
;
158 list_for_each_entry(xfer
, &msg
->transfers
, transfer_list
) {
159 bool last_xfer
= list_is_last(&xfer
->transfer_list
,
161 int r
= octeon_spi_do_transfer(p
, msg
, xfer
, last_xfer
);
169 msg
->status
= status
;
170 msg
->actual_length
= total_len
;
171 spi_finalize_current_message(master
);
175 static int octeon_spi_probe(struct platform_device
*pdev
)
177 struct resource
*res_mem
;
178 struct spi_master
*master
;
179 struct octeon_spi
*p
;
182 master
= spi_alloc_master(&pdev
->dev
, sizeof(struct octeon_spi
));
185 p
= spi_master_get_devdata(master
);
186 platform_set_drvdata(pdev
, master
);
188 res_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
190 if (res_mem
== NULL
) {
191 dev_err(&pdev
->dev
, "found no memory resource\n");
195 if (!devm_request_mem_region(&pdev
->dev
, res_mem
->start
,
196 resource_size(res_mem
), res_mem
->name
)) {
197 dev_err(&pdev
->dev
, "request_mem_region failed\n");
200 p
->register_base
= (u64
)devm_ioremap(&pdev
->dev
, res_mem
->start
,
201 resource_size(res_mem
));
203 master
->num_chipselect
= 4;
204 master
->mode_bits
= SPI_CPHA
|
210 master
->transfer_one_message
= octeon_spi_transfer_one_message
;
211 master
->bits_per_word_mask
= SPI_BPW_MASK(8);
212 master
->max_speed_hz
= OCTEON_SPI_MAX_CLOCK_HZ
;
214 master
->dev
.of_node
= pdev
->dev
.of_node
;
215 err
= devm_spi_register_master(&pdev
->dev
, master
);
217 dev_err(&pdev
->dev
, "register master failed: %d\n", err
);
221 dev_info(&pdev
->dev
, "OCTEON SPI bus driver\n");
225 spi_master_put(master
);
229 static int octeon_spi_remove(struct platform_device
*pdev
)
231 struct spi_master
*master
= platform_get_drvdata(pdev
);
232 struct octeon_spi
*p
= spi_master_get_devdata(master
);
233 u64 register_base
= p
->register_base
;
235 /* Clear the CSENA* and put everything in a known state. */
236 cvmx_write_csr(register_base
+ OCTEON_SPI_CFG
, 0);
241 static const struct of_device_id octeon_spi_match
[] = {
242 { .compatible
= "cavium,octeon-3010-spi", },
245 MODULE_DEVICE_TABLE(of
, octeon_spi_match
);
247 static struct platform_driver octeon_spi_driver
= {
249 .name
= "spi-octeon",
250 .of_match_table
= octeon_spi_match
,
252 .probe
= octeon_spi_probe
,
253 .remove
= octeon_spi_remove
,
256 module_platform_driver(octeon_spi_driver
);
258 MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
259 MODULE_AUTHOR("David Daney");
260 MODULE_LICENSE("GPL");