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.17
  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/io.h>
 22#include <linux/of.h>
 23
 24#define DRV_NAME "spi_altera"
 25
 26#define ALTERA_SPI_RXDATA	0
 27#define ALTERA_SPI_TXDATA	4
 28#define ALTERA_SPI_STATUS	8
 29#define ALTERA_SPI_CONTROL	12
 30#define ALTERA_SPI_SLAVE_SEL	20
 31
 32#define ALTERA_SPI_STATUS_ROE_MSK	0x8
 33#define ALTERA_SPI_STATUS_TOE_MSK	0x10
 34#define ALTERA_SPI_STATUS_TMT_MSK	0x20
 35#define ALTERA_SPI_STATUS_TRDY_MSK	0x40
 36#define ALTERA_SPI_STATUS_RRDY_MSK	0x80
 37#define ALTERA_SPI_STATUS_E_MSK		0x100
 38
 39#define ALTERA_SPI_CONTROL_IROE_MSK	0x8
 40#define ALTERA_SPI_CONTROL_ITOE_MSK	0x10
 41#define ALTERA_SPI_CONTROL_ITRDY_MSK	0x40
 42#define ALTERA_SPI_CONTROL_IRRDY_MSK	0x80
 43#define ALTERA_SPI_CONTROL_IE_MSK	0x100
 44#define ALTERA_SPI_CONTROL_SSO_MSK	0x400
 45
 46struct altera_spi {
 
 
 
 
 47	void __iomem *base;
 48	int irq;
 49	int len;
 50	int count;
 51	int bytes_per_word;
 52	unsigned long imr;
 53
 54	/* data buffers */
 55	const unsigned char *tx;
 56	unsigned char *rx;
 57};
 58
 59static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
 60{
 61	return spi_master_get_devdata(sdev->master);
 62}
 63
 64static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
 65{
 66	struct altera_spi *hw = altera_spi_to_hw(spi);
 67
 68	if (is_high) {
 69		hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
 70		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 71		writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
 
 
 
 
 
 
 
 
 
 
 
 72	} else {
 73		writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL);
 74		hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
 75		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 76	}
 77}
 78
 79static void altera_spi_tx_word(struct altera_spi *hw)
 80{
 81	unsigned int txd = 0;
 82
 83	if (hw->tx) {
 84		switch (hw->bytes_per_word) {
 85		case 1:
 86			txd = hw->tx[hw->count];
 87			break;
 88		case 2:
 89			txd = (hw->tx[hw->count * 2]
 90				| (hw->tx[hw->count * 2 + 1] << 8));
 91			break;
 92		}
 93	}
 
 94
 95	writel(txd, hw->base + ALTERA_SPI_TXDATA);
 
 
 96}
 97
 98static void altera_spi_rx_word(struct altera_spi *hw)
 99{
100	unsigned int rxd;
 
101
102	rxd = readl(hw->base + ALTERA_SPI_RXDATA);
103	if (hw->rx) {
 
104		switch (hw->bytes_per_word) {
105		case 1:
106			hw->rx[hw->count] = rxd;
107			break;
108		case 2:
109			hw->rx[hw->count * 2] = rxd;
110			hw->rx[hw->count * 2 + 1] = rxd >> 8;
111			break;
112		}
113	}
114
115	hw->count++;
116}
117
118static int altera_spi_txrx(struct spi_master *master,
119	struct spi_device *spi, struct spi_transfer *t)
120{
121	struct altera_spi *hw = spi_master_get_devdata(master);
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		altera_spi_tx_word(hw);
 
 
 
 
 
136	} else {
137		while (hw->count < hw->len) {
138			altera_spi_tx_word(hw);
 
 
 
139
140			while (!(readl(hw->base + ALTERA_SPI_STATUS) &
141				 ALTERA_SPI_STATUS_RRDY_MSK))
142				cpu_relax();
143
144			altera_spi_rx_word(hw);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145		}
146		spi_finalize_current_transfer(master);
147	}
148
149	return t->len;
150}
151
152static irqreturn_t altera_spi_irq(int irq, void *dev)
153{
154	struct spi_master *master = dev;
155	struct altera_spi *hw = spi_master_get_devdata(master);
156
157	altera_spi_rx_word(hw);
 
 
 
 
 
 
 
 
 
 
 
158
159	if (hw->count < hw->len) {
160		altera_spi_tx_word(hw);
161	} else {
162		/* disable receive interrupt */
163		hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
164		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
165
166		spi_finalize_current_transfer(master);
167	}
 
 
168
169	return IRQ_HANDLED;
170}
171
172static int altera_spi_probe(struct platform_device *pdev)
173{
 
174	struct altera_spi *hw;
175	struct spi_master *master;
176	struct resource *res;
177	int err = -ENODEV;
178
179	master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
180	if (!master)
181		return err;
182
183	/* setup the master state. */
184	master->bus_num = pdev->id;
185	master->num_chipselect = 16;
186	master->mode_bits = SPI_CS_HIGH;
187	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
188	master->dev.of_node = pdev->dev.of_node;
189	master->transfer_one = altera_spi_txrx;
190	master->set_cs = altera_spi_set_cs;
191
192	hw = spi_master_get_devdata(master);
 
 
 
 
 
 
 
 
 
193
194	/* find and map our resources */
195	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
196	hw->base = devm_ioremap_resource(&pdev->dev, res);
197	if (IS_ERR(hw->base)) {
198		err = PTR_ERR(hw->base);
199		goto exit;
200	}
 
 
 
 
201	/* program defaults into the registers */
202	hw->imr = 0;		/* disable spi interrupts */
203	writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
204	writel(0, hw->base + ALTERA_SPI_STATUS);	/* clear status reg */
205	if (readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)
206		readl(hw->base + ALTERA_SPI_RXDATA);	/* flush rxdata */
207	/* irq is optional */
208	hw->irq = platform_get_irq(pdev, 0);
209	if (hw->irq >= 0) {
 
210		err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
211				       pdev->name, master);
212		if (err)
213			goto exit;
214	}
 
 
 
215
216	err = devm_spi_register_master(&pdev->dev, master);
 
217	if (err)
218		goto exit;
219	dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
220
221	return 0;
 
 
 
222exit:
 
223	spi_master_put(master);
224	return err;
225}
226
 
 
 
 
 
 
 
 
 
 
 
227#ifdef CONFIG_OF
228static const struct of_device_id altera_spi_match[] = {
229	{ .compatible = "ALTR,spi-1.0", },
230	{ .compatible = "altr,spi-1.0", },
231	{},
232};
233MODULE_DEVICE_TABLE(of, altera_spi_match);
 
 
234#endif /* CONFIG_OF */
235
236static struct platform_driver altera_spi_driver = {
237	.probe = altera_spi_probe,
 
238	.driver = {
239		.name = DRV_NAME,
 
240		.pm = NULL,
241		.of_match_table = of_match_ptr(altera_spi_match),
242	},
243};
244module_platform_driver(altera_spi_driver);
245
246MODULE_DESCRIPTION("Altera SPI driver");
247MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
248MODULE_LICENSE("GPL");
249MODULE_ALIAS("platform:" DRV_NAME);