Linux Audio

Check our new training course

Loading...
v3.5.6
  1/*
  2 * Altera SPI driver
  3 *
  4 * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
  5 *
  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>
 10 *
 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.
 14 */
 15
 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>
 23#include <linux/io.h>
 24#include <linux/of.h>
 25
 26#define DRV_NAME "spi_altera"
 27
 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
 33
 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
 40
 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
 47
 48struct altera_spi {
 49	/* bitbang has to be first */
 50	struct spi_bitbang bitbang;
 51	struct completion done;
 52
 53	void __iomem *base;
 54	int irq;
 55	int len;
 56	int count;
 57	int bytes_per_word;
 58	unsigned long imr;
 59
 60	/* data buffers */
 61	const unsigned char *tx;
 62	unsigned char *rx;
 63};
 64
 65static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
 66{
 67	return spi_master_get_devdata(sdev->master);
 68}
 69
 70static void altera_spi_chipsel(struct spi_device *spi, int value)
 71{
 72	struct altera_spi *hw = altera_spi_to_hw(spi);
 73
 74	if (spi->mode & SPI_CS_HIGH) {
 75		switch (value) {
 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);
 81			break;
 82
 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);
 87			break;
 88		}
 89	} else {
 90		switch (value) {
 91		case BITBANG_CS_INACTIVE:
 92			hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
 93			writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 94			break;
 95
 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);
101			break;
102		}
103	}
104}
105
106static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
107{
108	return 0;
109}
110
111static int altera_spi_setup(struct spi_device *spi)
112{
113	return 0;
114}
115
116static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
117{
118	if (hw->tx) {
119		switch (hw->bytes_per_word) {
120		case 1:
121			return hw->tx[count];
122		case 2:
123			return (hw->tx[count * 2]
124				| (hw->tx[count * 2 + 1] << 8));
125		}
126	}
127	return 0;
128}
129
130static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
131{
132	struct altera_spi *hw = altera_spi_to_hw(spi);
133
134	hw->tx = t->tx_buf;
135	hw->rx = t->rx_buf;
136	hw->count = 0;
137	hw->bytes_per_word = (t->bits_per_word ? : spi->bits_per_word) / 8;
138	hw->len = t->len / hw->bytes_per_word;
139
140	if (hw->irq >= 0) {
141		/* enable receive interrupt */
142		hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
143		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
144
145		/* send the first byte */
146		writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
147
148		wait_for_completion(&hw->done);
149		/* disable receive interrupt */
150		hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
151		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
152	} else {
153		/* send the first byte */
154		writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
155
156		while (1) {
157			unsigned int rxd;
158
 
 
 
159			while (!(readl(hw->base + ALTERA_SPI_STATUS) &
160				 ALTERA_SPI_STATUS_RRDY_MSK))
161				cpu_relax();
162
163			rxd = readl(hw->base + ALTERA_SPI_RXDATA);
164			if (hw->rx) {
165				switch (hw->bytes_per_word) {
166				case 1:
167					hw->rx[hw->count] = rxd;
168					break;
169				case 2:
170					hw->rx[hw->count * 2] = rxd;
171					hw->rx[hw->count * 2 + 1] = rxd >> 8;
172					break;
173				}
174			}
175
176			hw->count++;
177
178			if (hw->count < hw->len)
179				writel(hw_txbyte(hw, hw->count),
180				       hw->base + ALTERA_SPI_TXDATA);
181			else
182				break;
183		}
184
185	}
186
187	return hw->count * hw->bytes_per_word;
188}
189
190static irqreturn_t altera_spi_irq(int irq, void *dev)
191{
192	struct altera_spi *hw = dev;
193	unsigned int rxd;
194
195	rxd = readl(hw->base + ALTERA_SPI_RXDATA);
196	if (hw->rx) {
197		switch (hw->bytes_per_word) {
198		case 1:
199			hw->rx[hw->count] = rxd;
200			break;
201		case 2:
202			hw->rx[hw->count * 2] = rxd;
203			hw->rx[hw->count * 2 + 1] = rxd >> 8;
204			break;
205		}
206	}
207
208	hw->count++;
209
210	if (hw->count < hw->len)
211		writel(hw_txbyte(hw, hw->count), hw->base + ALTERA_SPI_TXDATA);
212	else
213		complete(&hw->done);
214
215	return IRQ_HANDLED;
216}
217
218static int __devinit altera_spi_probe(struct platform_device *pdev)
219{
220	struct altera_spi_platform_data *platp = pdev->dev.platform_data;
221	struct altera_spi *hw;
222	struct spi_master *master;
223	struct resource *res;
224	int err = -ENODEV;
225
226	master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
227	if (!master)
228		return err;
229
230	/* setup the master state. */
231	master->bus_num = pdev->id;
232	master->num_chipselect = 16;
233	master->mode_bits = SPI_CS_HIGH;
234	master->setup = altera_spi_setup;
 
235
236	hw = spi_master_get_devdata(master);
237	platform_set_drvdata(pdev, hw);
238
239	/* setup the state for the bitbang driver */
240	hw->bitbang.master = spi_master_get(master);
241	if (!hw->bitbang.master)
242		return err;
243	hw->bitbang.setup_transfer = altera_spi_setupxfer;
244	hw->bitbang.chipselect = altera_spi_chipsel;
245	hw->bitbang.txrx_bufs = altera_spi_txrx;
246
247	/* find and map our resources */
248	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
249	if (!res)
250		goto exit_busy;
251	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
252				     pdev->name))
253		goto exit_busy;
254	hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
255					resource_size(res));
256	if (!hw->base)
257		goto exit_busy;
258	/* program defaults into the registers */
259	hw->imr = 0;		/* disable spi interrupts */
260	writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
261	writel(0, hw->base + ALTERA_SPI_STATUS);	/* clear status reg */
262	if (readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)
263		readl(hw->base + ALTERA_SPI_RXDATA);	/* flush rxdata */
264	/* irq is optional */
265	hw->irq = platform_get_irq(pdev, 0);
266	if (hw->irq >= 0) {
267		init_completion(&hw->done);
268		err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
269				       pdev->name, hw);
270		if (err)
271			goto exit;
272	}
273	/* find platform data */
274	if (!platp)
275		hw->bitbang.master->dev.of_node = pdev->dev.of_node;
276
277	/* register our spi controller */
278	err = spi_bitbang_start(&hw->bitbang);
279	if (err)
280		goto exit;
281	dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
282
283	return 0;
284
285exit_busy:
286	err = -EBUSY;
287exit:
288	platform_set_drvdata(pdev, NULL);
289	spi_master_put(master);
290	return err;
291}
292
293static int __devexit altera_spi_remove(struct platform_device *dev)
294{
295	struct altera_spi *hw = platform_get_drvdata(dev);
296	struct spi_master *master = hw->bitbang.master;
297
298	spi_bitbang_stop(&hw->bitbang);
299	platform_set_drvdata(dev, NULL);
300	spi_master_put(master);
301	return 0;
302}
303
304#ifdef CONFIG_OF
305static const struct of_device_id altera_spi_match[] = {
306	{ .compatible = "ALTR,spi-1.0", },
 
307	{},
308};
309MODULE_DEVICE_TABLE(of, altera_spi_match);
310#else /* CONFIG_OF */
311#define altera_spi_match NULL
312#endif /* CONFIG_OF */
313
314static struct platform_driver altera_spi_driver = {
315	.probe = altera_spi_probe,
316	.remove = __devexit_p(altera_spi_remove),
317	.driver = {
318		.name = DRV_NAME,
319		.owner = THIS_MODULE,
320		.pm = NULL,
321		.of_match_table = altera_spi_match,
322	},
323};
324module_platform_driver(altera_spi_driver);
325
326MODULE_DESCRIPTION("Altera SPI driver");
327MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
328MODULE_LICENSE("GPL");
329MODULE_ALIAS("platform:" DRV_NAME);
v4.10.11
  1/*
  2 * Altera SPI driver
  3 *
  4 * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
  5 *
  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>
 10 *
 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.
 14 */
 15
 
 16#include <linux/interrupt.h>
 17#include <linux/errno.h>
 18#include <linux/module.h>
 19#include <linux/platform_device.h>
 20#include <linux/spi/spi.h>
 21#include <linux/spi/spi_bitbang.h>
 22#include <linux/io.h>
 23#include <linux/of.h>
 24
 25#define DRV_NAME "spi_altera"
 26
 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
 32
 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
 39
 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
 46
 47struct altera_spi {
 48	/* bitbang has to be first */
 49	struct spi_bitbang bitbang;
 50	struct completion done;
 51
 52	void __iomem *base;
 53	int irq;
 54	int len;
 55	int count;
 56	int bytes_per_word;
 57	unsigned long imr;
 58
 59	/* data buffers */
 60	const unsigned char *tx;
 61	unsigned char *rx;
 62};
 63
 64static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
 65{
 66	return spi_master_get_devdata(sdev->master);
 67}
 68
 69static void altera_spi_chipsel(struct spi_device *spi, int value)
 70{
 71	struct altera_spi *hw = altera_spi_to_hw(spi);
 72
 73	if (spi->mode & SPI_CS_HIGH) {
 74		switch (value) {
 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);
 80			break;
 81
 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);
 86			break;
 87		}
 88	} else {
 89		switch (value) {
 90		case BITBANG_CS_INACTIVE:
 91			hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
 92			writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 93			break;
 94
 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);
100			break;
101		}
102	}
103}
104
 
 
 
 
 
 
 
 
 
 
105static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
106{
107	if (hw->tx) {
108		switch (hw->bytes_per_word) {
109		case 1:
110			return hw->tx[count];
111		case 2:
112			return (hw->tx[count * 2]
113				| (hw->tx[count * 2 + 1] << 8));
114		}
115	}
116	return 0;
117}
118
119static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
120{
121	struct altera_spi *hw = altera_spi_to_hw(spi);
122
123	hw->tx = t->tx_buf;
124	hw->rx = t->rx_buf;
125	hw->count = 0;
126	hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
127	hw->len = t->len / hw->bytes_per_word;
128
129	if (hw->irq >= 0) {
130		/* enable receive interrupt */
131		hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
132		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
133
134		/* send the first byte */
135		writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
136
137		wait_for_completion(&hw->done);
138		/* disable receive interrupt */
139		hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
140		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
141	} else {
142		while (hw->count < hw->len) {
 
 
 
143			unsigned int rxd;
144
145			writel(hw_txbyte(hw, hw->count),
146			       hw->base + ALTERA_SPI_TXDATA);
147
148			while (!(readl(hw->base + ALTERA_SPI_STATUS) &
149				 ALTERA_SPI_STATUS_RRDY_MSK))
150				cpu_relax();
151
152			rxd = readl(hw->base + ALTERA_SPI_RXDATA);
153			if (hw->rx) {
154				switch (hw->bytes_per_word) {
155				case 1:
156					hw->rx[hw->count] = rxd;
157					break;
158				case 2:
159					hw->rx[hw->count * 2] = rxd;
160					hw->rx[hw->count * 2 + 1] = rxd >> 8;
161					break;
162				}
163			}
164
165			hw->count++;
 
 
 
 
 
 
166		}
 
167	}
168
169	return hw->count * hw->bytes_per_word;
170}
171
172static irqreturn_t altera_spi_irq(int irq, void *dev)
173{
174	struct altera_spi *hw = dev;
175	unsigned int rxd;
176
177	rxd = readl(hw->base + ALTERA_SPI_RXDATA);
178	if (hw->rx) {
179		switch (hw->bytes_per_word) {
180		case 1:
181			hw->rx[hw->count] = rxd;
182			break;
183		case 2:
184			hw->rx[hw->count * 2] = rxd;
185			hw->rx[hw->count * 2 + 1] = rxd >> 8;
186			break;
187		}
188	}
189
190	hw->count++;
191
192	if (hw->count < hw->len)
193		writel(hw_txbyte(hw, hw->count), hw->base + ALTERA_SPI_TXDATA);
194	else
195		complete(&hw->done);
196
197	return IRQ_HANDLED;
198}
199
200static int altera_spi_probe(struct platform_device *pdev)
201{
 
202	struct altera_spi *hw;
203	struct spi_master *master;
204	struct resource *res;
205	int err = -ENODEV;
206
207	master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
208	if (!master)
209		return err;
210
211	/* setup the master state. */
212	master->bus_num = pdev->id;
213	master->num_chipselect = 16;
214	master->mode_bits = SPI_CS_HIGH;
215	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
216	master->dev.of_node = pdev->dev.of_node;
217
218	hw = spi_master_get_devdata(master);
219	platform_set_drvdata(pdev, hw);
220
221	/* setup the state for the bitbang driver */
222	hw->bitbang.master = master;
 
 
 
223	hw->bitbang.chipselect = altera_spi_chipsel;
224	hw->bitbang.txrx_bufs = altera_spi_txrx;
225
226	/* find and map our resources */
227	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
228	hw->base = devm_ioremap_resource(&pdev->dev, res);
229	if (IS_ERR(hw->base)) {
230		err = PTR_ERR(hw->base);
231		goto exit;
232	}
 
 
 
 
233	/* program defaults into the registers */
234	hw->imr = 0;		/* disable spi interrupts */
235	writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
236	writel(0, hw->base + ALTERA_SPI_STATUS);	/* clear status reg */
237	if (readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)
238		readl(hw->base + ALTERA_SPI_RXDATA);	/* flush rxdata */
239	/* irq is optional */
240	hw->irq = platform_get_irq(pdev, 0);
241	if (hw->irq >= 0) {
242		init_completion(&hw->done);
243		err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
244				       pdev->name, hw);
245		if (err)
246			goto exit;
247	}
 
 
 
248
249	/* register our spi controller */
250	err = spi_bitbang_start(&hw->bitbang);
251	if (err)
252		goto exit;
253	dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
254
255	return 0;
 
 
 
256exit:
 
257	spi_master_put(master);
258	return err;
259}
260
261static int altera_spi_remove(struct platform_device *dev)
262{
263	struct altera_spi *hw = platform_get_drvdata(dev);
264	struct spi_master *master = hw->bitbang.master;
265
266	spi_bitbang_stop(&hw->bitbang);
 
267	spi_master_put(master);
268	return 0;
269}
270
271#ifdef CONFIG_OF
272static const struct of_device_id altera_spi_match[] = {
273	{ .compatible = "ALTR,spi-1.0", },
274	{ .compatible = "altr,spi-1.0", },
275	{},
276};
277MODULE_DEVICE_TABLE(of, altera_spi_match);
 
 
278#endif /* CONFIG_OF */
279
280static struct platform_driver altera_spi_driver = {
281	.probe = altera_spi_probe,
282	.remove = altera_spi_remove,
283	.driver = {
284		.name = DRV_NAME,
 
285		.pm = NULL,
286		.of_match_table = of_match_ptr(altera_spi_match),
287	},
288};
289module_platform_driver(altera_spi_driver);
290
291MODULE_DESCRIPTION("Altera SPI driver");
292MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
293MODULE_LICENSE("GPL");
294MODULE_ALIAS("platform:" DRV_NAME);