4 * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
6 * Based on spi_s3c24xx.c, which is:
7 * Copyright (c) 2006 Ben Dooks
8 * Copyright (c) 2006 Simtec Electronics
9 * Ben Dooks <ben@simtec.co.uk>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
16 #include <linux/init.h>
17 #include <linux/interrupt.h>
18 #include <linux/errno.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/spi/spi.h>
22 #include <linux/spi/spi_bitbang.h>
26 #define DRV_NAME "spi_altera"
28 #define ALTERA_SPI_RXDATA 0
29 #define ALTERA_SPI_TXDATA 4
30 #define ALTERA_SPI_STATUS 8
31 #define ALTERA_SPI_CONTROL 12
32 #define ALTERA_SPI_SLAVE_SEL 20
34 #define ALTERA_SPI_STATUS_ROE_MSK 0x8
35 #define ALTERA_SPI_STATUS_TOE_MSK 0x10
36 #define ALTERA_SPI_STATUS_TMT_MSK 0x20
37 #define ALTERA_SPI_STATUS_TRDY_MSK 0x40
38 #define ALTERA_SPI_STATUS_RRDY_MSK 0x80
39 #define ALTERA_SPI_STATUS_E_MSK 0x100
41 #define ALTERA_SPI_CONTROL_IROE_MSK 0x8
42 #define ALTERA_SPI_CONTROL_ITOE_MSK 0x10
43 #define ALTERA_SPI_CONTROL_ITRDY_MSK 0x40
44 #define ALTERA_SPI_CONTROL_IRRDY_MSK 0x80
45 #define ALTERA_SPI_CONTROL_IE_MSK 0x100
46 #define ALTERA_SPI_CONTROL_SSO_MSK 0x400
49 /* bitbang has to be first */
50 struct spi_bitbang bitbang
;
51 struct completion done
;
61 const unsigned char *tx
;
65 static inline struct altera_spi
*altera_spi_to_hw(struct spi_device
*sdev
)
67 return spi_master_get_devdata(sdev
->master
);
70 static void altera_spi_chipsel(struct spi_device
*spi
, int value
)
72 struct altera_spi
*hw
= altera_spi_to_hw(spi
);
74 if (spi
->mode
& SPI_CS_HIGH
) {
76 case BITBANG_CS_INACTIVE
:
77 writel(1 << spi
->chip_select
,
78 hw
->base
+ ALTERA_SPI_SLAVE_SEL
);
79 hw
->imr
|= ALTERA_SPI_CONTROL_SSO_MSK
;
80 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
83 case BITBANG_CS_ACTIVE
:
84 hw
->imr
&= ~ALTERA_SPI_CONTROL_SSO_MSK
;
85 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
86 writel(0, hw
->base
+ ALTERA_SPI_SLAVE_SEL
);
91 case BITBANG_CS_INACTIVE
:
92 hw
->imr
&= ~ALTERA_SPI_CONTROL_SSO_MSK
;
93 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
96 case BITBANG_CS_ACTIVE
:
97 writel(1 << spi
->chip_select
,
98 hw
->base
+ ALTERA_SPI_SLAVE_SEL
);
99 hw
->imr
|= ALTERA_SPI_CONTROL_SSO_MSK
;
100 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
106 static inline unsigned int hw_txbyte(struct altera_spi
*hw
, int count
)
109 switch (hw
->bytes_per_word
) {
111 return hw
->tx
[count
];
113 return (hw
->tx
[count
* 2]
114 | (hw
->tx
[count
* 2 + 1] << 8));
120 static int altera_spi_txrx(struct spi_device
*spi
, struct spi_transfer
*t
)
122 struct altera_spi
*hw
= altera_spi_to_hw(spi
);
127 hw
->bytes_per_word
= t
->bits_per_word
/ 8;
128 hw
->len
= t
->len
/ hw
->bytes_per_word
;
131 /* enable receive interrupt */
132 hw
->imr
|= ALTERA_SPI_CONTROL_IRRDY_MSK
;
133 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
135 /* send the first byte */
136 writel(hw_txbyte(hw
, 0), hw
->base
+ ALTERA_SPI_TXDATA
);
138 wait_for_completion(&hw
->done
);
139 /* disable receive interrupt */
140 hw
->imr
&= ~ALTERA_SPI_CONTROL_IRRDY_MSK
;
141 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
143 /* send the first byte */
144 writel(hw_txbyte(hw
, 0), hw
->base
+ ALTERA_SPI_TXDATA
);
149 while (!(readl(hw
->base
+ ALTERA_SPI_STATUS
) &
150 ALTERA_SPI_STATUS_RRDY_MSK
))
153 rxd
= readl(hw
->base
+ ALTERA_SPI_RXDATA
);
155 switch (hw
->bytes_per_word
) {
157 hw
->rx
[hw
->count
] = rxd
;
160 hw
->rx
[hw
->count
* 2] = rxd
;
161 hw
->rx
[hw
->count
* 2 + 1] = rxd
>> 8;
168 if (hw
->count
< hw
->len
)
169 writel(hw_txbyte(hw
, hw
->count
),
170 hw
->base
+ ALTERA_SPI_TXDATA
);
177 return hw
->count
* hw
->bytes_per_word
;
180 static irqreturn_t
altera_spi_irq(int irq
, void *dev
)
182 struct altera_spi
*hw
= dev
;
185 rxd
= readl(hw
->base
+ ALTERA_SPI_RXDATA
);
187 switch (hw
->bytes_per_word
) {
189 hw
->rx
[hw
->count
] = rxd
;
192 hw
->rx
[hw
->count
* 2] = rxd
;
193 hw
->rx
[hw
->count
* 2 + 1] = rxd
>> 8;
200 if (hw
->count
< hw
->len
)
201 writel(hw_txbyte(hw
, hw
->count
), hw
->base
+ ALTERA_SPI_TXDATA
);
208 static int altera_spi_probe(struct platform_device
*pdev
)
210 struct altera_spi_platform_data
*platp
= pdev
->dev
.platform_data
;
211 struct altera_spi
*hw
;
212 struct spi_master
*master
;
213 struct resource
*res
;
216 master
= spi_alloc_master(&pdev
->dev
, sizeof(struct altera_spi
));
220 /* setup the master state. */
221 master
->bus_num
= pdev
->id
;
222 master
->num_chipselect
= 16;
223 master
->mode_bits
= SPI_CS_HIGH
;
225 hw
= spi_master_get_devdata(master
);
226 platform_set_drvdata(pdev
, hw
);
228 /* setup the state for the bitbang driver */
229 hw
->bitbang
.master
= spi_master_get(master
);
230 if (!hw
->bitbang
.master
)
232 hw
->bitbang
.chipselect
= altera_spi_chipsel
;
233 hw
->bitbang
.txrx_bufs
= altera_spi_txrx
;
235 /* find and map our resources */
236 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
239 if (!devm_request_mem_region(&pdev
->dev
, res
->start
, resource_size(res
),
242 hw
->base
= devm_ioremap_nocache(&pdev
->dev
, res
->start
,
246 /* program defaults into the registers */
247 hw
->imr
= 0; /* disable spi interrupts */
248 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
249 writel(0, hw
->base
+ ALTERA_SPI_STATUS
); /* clear status reg */
250 if (readl(hw
->base
+ ALTERA_SPI_STATUS
) & ALTERA_SPI_STATUS_RRDY_MSK
)
251 readl(hw
->base
+ ALTERA_SPI_RXDATA
); /* flush rxdata */
252 /* irq is optional */
253 hw
->irq
= platform_get_irq(pdev
, 0);
255 init_completion(&hw
->done
);
256 err
= devm_request_irq(&pdev
->dev
, hw
->irq
, altera_spi_irq
, 0,
261 /* find platform data */
263 hw
->bitbang
.master
->dev
.of_node
= pdev
->dev
.of_node
;
265 /* register our spi controller */
266 err
= spi_bitbang_start(&hw
->bitbang
);
269 dev_info(&pdev
->dev
, "base %p, irq %d\n", hw
->base
, hw
->irq
);
276 spi_master_put(master
);
280 static int altera_spi_remove(struct platform_device
*dev
)
282 struct altera_spi
*hw
= platform_get_drvdata(dev
);
283 struct spi_master
*master
= hw
->bitbang
.master
;
285 spi_bitbang_stop(&hw
->bitbang
);
286 spi_master_put(master
);
291 static const struct of_device_id altera_spi_match
[] = {
292 { .compatible
= "ALTR,spi-1.0", },
295 MODULE_DEVICE_TABLE(of
, altera_spi_match
);
296 #endif /* CONFIG_OF */
298 static struct platform_driver altera_spi_driver
= {
299 .probe
= altera_spi_probe
,
300 .remove
= altera_spi_remove
,
303 .owner
= THIS_MODULE
,
305 .of_match_table
= of_match_ptr(altera_spi_match
),
308 module_platform_driver(altera_spi_driver
);
310 MODULE_DESCRIPTION("Altera SPI driver");
311 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
312 MODULE_LICENSE("GPL");
313 MODULE_ALIAS("platform:" DRV_NAME
);