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/platform_device.h>
20 #include <linux/spi/spi.h>
21 #include <linux/spi/spi_bitbang.h>
25 #define DRV_NAME "spi_altera"
27 #define ALTERA_SPI_RXDATA 0
28 #define ALTERA_SPI_TXDATA 4
29 #define ALTERA_SPI_STATUS 8
30 #define ALTERA_SPI_CONTROL 12
31 #define ALTERA_SPI_SLAVE_SEL 20
33 #define ALTERA_SPI_STATUS_ROE_MSK 0x8
34 #define ALTERA_SPI_STATUS_TOE_MSK 0x10
35 #define ALTERA_SPI_STATUS_TMT_MSK 0x20
36 #define ALTERA_SPI_STATUS_TRDY_MSK 0x40
37 #define ALTERA_SPI_STATUS_RRDY_MSK 0x80
38 #define ALTERA_SPI_STATUS_E_MSK 0x100
40 #define ALTERA_SPI_CONTROL_IROE_MSK 0x8
41 #define ALTERA_SPI_CONTROL_ITOE_MSK 0x10
42 #define ALTERA_SPI_CONTROL_ITRDY_MSK 0x40
43 #define ALTERA_SPI_CONTROL_IRRDY_MSK 0x80
44 #define ALTERA_SPI_CONTROL_IE_MSK 0x100
45 #define ALTERA_SPI_CONTROL_SSO_MSK 0x400
48 /* bitbang has to be first */
49 struct spi_bitbang bitbang
;
50 struct completion done
;
60 const unsigned char *tx
;
64 static inline struct altera_spi
*altera_spi_to_hw(struct spi_device
*sdev
)
66 return spi_master_get_devdata(sdev
->master
);
69 static void altera_spi_chipsel(struct spi_device
*spi
, int value
)
71 struct altera_spi
*hw
= altera_spi_to_hw(spi
);
73 if (spi
->mode
& SPI_CS_HIGH
) {
75 case BITBANG_CS_INACTIVE
:
76 writel(1 << spi
->chip_select
,
77 hw
->base
+ ALTERA_SPI_SLAVE_SEL
);
78 hw
->imr
|= ALTERA_SPI_CONTROL_SSO_MSK
;
79 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
82 case BITBANG_CS_ACTIVE
:
83 hw
->imr
&= ~ALTERA_SPI_CONTROL_SSO_MSK
;
84 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
85 writel(0, hw
->base
+ ALTERA_SPI_SLAVE_SEL
);
90 case BITBANG_CS_INACTIVE
:
91 hw
->imr
&= ~ALTERA_SPI_CONTROL_SSO_MSK
;
92 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
95 case BITBANG_CS_ACTIVE
:
96 writel(1 << spi
->chip_select
,
97 hw
->base
+ ALTERA_SPI_SLAVE_SEL
);
98 hw
->imr
|= ALTERA_SPI_CONTROL_SSO_MSK
;
99 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
105 static int altera_spi_setupxfer(struct spi_device
*spi
, struct spi_transfer
*t
)
110 static int altera_spi_setup(struct spi_device
*spi
)
115 static inline unsigned int hw_txbyte(struct altera_spi
*hw
, int count
)
118 switch (hw
->bytes_per_word
) {
120 return hw
->tx
[count
];
122 return (hw
->tx
[count
* 2]
123 | (hw
->tx
[count
* 2 + 1] << 8));
129 static int altera_spi_txrx(struct spi_device
*spi
, struct spi_transfer
*t
)
131 struct altera_spi
*hw
= altera_spi_to_hw(spi
);
136 hw
->bytes_per_word
= (t
->bits_per_word
? : spi
->bits_per_word
) / 8;
137 hw
->len
= t
->len
/ hw
->bytes_per_word
;
140 /* enable receive interrupt */
141 hw
->imr
|= ALTERA_SPI_CONTROL_IRRDY_MSK
;
142 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
144 /* send the first byte */
145 writel(hw_txbyte(hw
, 0), hw
->base
+ ALTERA_SPI_TXDATA
);
147 wait_for_completion(&hw
->done
);
148 /* disable receive interrupt */
149 hw
->imr
&= ~ALTERA_SPI_CONTROL_IRRDY_MSK
;
150 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
152 /* send the first byte */
153 writel(hw_txbyte(hw
, 0), hw
->base
+ ALTERA_SPI_TXDATA
);
158 while (!(readl(hw
->base
+ ALTERA_SPI_STATUS
) &
159 ALTERA_SPI_STATUS_RRDY_MSK
))
162 rxd
= readl(hw
->base
+ ALTERA_SPI_RXDATA
);
164 switch (hw
->bytes_per_word
) {
166 hw
->rx
[hw
->count
] = rxd
;
169 hw
->rx
[hw
->count
* 2] = rxd
;
170 hw
->rx
[hw
->count
* 2 + 1] = rxd
>> 8;
177 if (hw
->count
< hw
->len
)
178 writel(hw_txbyte(hw
, hw
->count
),
179 hw
->base
+ ALTERA_SPI_TXDATA
);
186 return hw
->count
* hw
->bytes_per_word
;
189 static irqreturn_t
altera_spi_irq(int irq
, void *dev
)
191 struct altera_spi
*hw
= dev
;
194 rxd
= readl(hw
->base
+ ALTERA_SPI_RXDATA
);
196 switch (hw
->bytes_per_word
) {
198 hw
->rx
[hw
->count
] = rxd
;
201 hw
->rx
[hw
->count
* 2] = rxd
;
202 hw
->rx
[hw
->count
* 2 + 1] = rxd
>> 8;
209 if (hw
->count
< hw
->len
)
210 writel(hw_txbyte(hw
, hw
->count
), hw
->base
+ ALTERA_SPI_TXDATA
);
217 static int __devinit
altera_spi_probe(struct platform_device
*pdev
)
219 struct altera_spi_platform_data
*platp
= pdev
->dev
.platform_data
;
220 struct altera_spi
*hw
;
221 struct spi_master
*master
;
222 struct resource
*res
;
225 master
= spi_alloc_master(&pdev
->dev
, sizeof(struct altera_spi
));
229 /* setup the master state. */
230 master
->bus_num
= pdev
->id
;
231 master
->num_chipselect
= 16;
232 master
->mode_bits
= SPI_CS_HIGH
;
233 master
->setup
= altera_spi_setup
;
235 hw
= spi_master_get_devdata(master
);
236 platform_set_drvdata(pdev
, hw
);
238 /* setup the state for the bitbang driver */
239 hw
->bitbang
.master
= spi_master_get(master
);
240 if (!hw
->bitbang
.master
)
242 hw
->bitbang
.setup_transfer
= altera_spi_setupxfer
;
243 hw
->bitbang
.chipselect
= altera_spi_chipsel
;
244 hw
->bitbang
.txrx_bufs
= altera_spi_txrx
;
246 /* find and map our resources */
247 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
250 if (!devm_request_mem_region(&pdev
->dev
, res
->start
, resource_size(res
),
253 hw
->base
= devm_ioremap_nocache(&pdev
->dev
, res
->start
,
257 /* program defaults into the registers */
258 hw
->imr
= 0; /* disable spi interrupts */
259 writel(hw
->imr
, hw
->base
+ ALTERA_SPI_CONTROL
);
260 writel(0, hw
->base
+ ALTERA_SPI_STATUS
); /* clear status reg */
261 if (readl(hw
->base
+ ALTERA_SPI_STATUS
) & ALTERA_SPI_STATUS_RRDY_MSK
)
262 readl(hw
->base
+ ALTERA_SPI_RXDATA
); /* flush rxdata */
263 /* irq is optional */
264 hw
->irq
= platform_get_irq(pdev
, 0);
266 init_completion(&hw
->done
);
267 err
= devm_request_irq(&pdev
->dev
, hw
->irq
, altera_spi_irq
, 0,
272 /* find platform data */
274 hw
->bitbang
.master
->dev
.of_node
= pdev
->dev
.of_node
;
276 /* register our spi controller */
277 err
= spi_bitbang_start(&hw
->bitbang
);
280 dev_info(&pdev
->dev
, "base %p, irq %d\n", hw
->base
, hw
->irq
);
287 platform_set_drvdata(pdev
, NULL
);
288 spi_master_put(master
);
292 static int __devexit
altera_spi_remove(struct platform_device
*dev
)
294 struct altera_spi
*hw
= platform_get_drvdata(dev
);
295 struct spi_master
*master
= hw
->bitbang
.master
;
297 spi_bitbang_stop(&hw
->bitbang
);
298 platform_set_drvdata(dev
, NULL
);
299 spi_master_put(master
);
304 static const struct of_device_id altera_spi_match
[] = {
305 { .compatible
= "ALTR,spi-1.0", },
308 MODULE_DEVICE_TABLE(of
, altera_spi_match
);
309 #else /* CONFIG_OF */
310 #define altera_spi_match NULL
311 #endif /* CONFIG_OF */
313 static struct platform_driver altera_spi_driver
= {
314 .probe
= altera_spi_probe
,
315 .remove
= __devexit_p(altera_spi_remove
),
318 .owner
= THIS_MODULE
,
320 .of_match_table
= altera_spi_match
,
324 static int __init
altera_spi_init(void)
326 return platform_driver_register(&altera_spi_driver
);
328 module_init(altera_spi_init
);
330 static void __exit
altera_spi_exit(void)
332 platform_driver_unregister(&altera_spi_driver
);
334 module_exit(altera_spi_exit
);
336 MODULE_DESCRIPTION("Altera SPI driver");
337 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
338 MODULE_LICENSE("GPL");
339 MODULE_ALIAS("platform:" DRV_NAME
);