OpenCores
URL https://opencores.org/ocsvn/tiny_spi/tiny_spi/trunk

Subversion Repositories tiny_spi

[/] [tiny_spi/] [trunk/] [driver/] [linux-2.6/] [oc_tiny_spi.c] - Blame information for rev 10

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 6 hippo5329
/*
2 10 hippo5329
 * OpenCores tiny SPI master driver
3 6 hippo5329
 *
4 10 hippo5329
 * http://opencores.org/project,tiny_spi
5
 *
6 6 hippo5329
 * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
7
 *
8
 * Based on spi_s3c24xx.c, which is:
9
 * Copyright (c) 2006 Ben Dooks
10
 * Copyright (c) 2006 Simtec Electronics
11
 *      Ben Dooks <ben@simtec.co.uk>
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License version 2 as
15
 * published by the Free Software Foundation.
16
 */
17 10 hippo5329
 
18 6 hippo5329
#include <linux/init.h>
19
#include <linux/spinlock.h>
20
#include <linux/interrupt.h>
21
#include <linux/delay.h>
22
#include <linux/errno.h>
23
#include <linux/err.h>
24
#include <linux/clk.h>
25
#include <linux/platform_device.h>
26
#include <linux/spi/spi.h>
27
#include <linux/spi/spi_bitbang.h>
28 10 hippo5329
#include <linux/spi/oc_tiny_spi.h>
29 6 hippo5329
#include <linux/io.h>
30
#include <linux/gpio.h>
31 10 hippo5329
#include <linux/of.h>
32 6 hippo5329
 
33
#define DRV_NAME "oc_tiny_spi"
34
 
35 10 hippo5329
#define TINY_SPI_RXDATA 0
36
#define TINY_SPI_TXDATA 4
37
#define TINY_SPI_STATUS 8
38
#define TINY_SPI_CONTROL 12
39
#define TINY_SPI_BAUD 16
40 6 hippo5329
 
41
#define TINY_SPI_STATUS_TXE 0x1
42
#define TINY_SPI_STATUS_TXR 0x2
43
 
44
struct tiny_spi {
45
        /* bitbang has to be first */
46
        struct spi_bitbang bitbang;
47
        struct completion done;
48
 
49
        void __iomem *base;
50
        int irq;
51 10 hippo5329
        unsigned int freq;
52
        unsigned int baudwidth;
53
        int interrupt; /* use interrupt driven data transfer, slow */
54
        unsigned int baud;
55
        unsigned int speed_hz;
56
        unsigned int mode;
57
        unsigned int len;
58
        unsigned int txc, rxc;
59
        const u8 *txp;
60
        u8 *rxp;
61 6 hippo5329
};
62
 
63
static inline struct tiny_spi *to_hw(struct spi_device *sdev)
64
{
65
        return spi_master_get_devdata(sdev->master);
66
}
67
 
68 10 hippo5329
static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz)
69 6 hippo5329
{
70
        struct tiny_spi *hw = to_hw(spi);
71 10 hippo5329
 
72
        return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1;
73 6 hippo5329
}
74
 
75
static void tiny_spi_chipselect(struct spi_device *spi, int is_active)
76
{
77 10 hippo5329
        gpio_set_value(spi->chip_select,
78
                       (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
79 6 hippo5329
}
80
 
81 10 hippo5329
static int tiny_spi_setup_transfer(struct spi_device *spi,
82
                                   struct spi_transfer *t)
83 6 hippo5329
{
84
        struct tiny_spi *hw = to_hw(spi);
85 10 hippo5329
        unsigned int baud = hw->baud;
86
 
87 6 hippo5329
        if (t) {
88
                if (t->speed_hz && t->speed_hz != hw->speed_hz)
89
                        baud = tiny_spi_baud(spi, t->speed_hz);
90
        }
91
        writel(baud, hw->base + TINY_SPI_BAUD);
92 10 hippo5329
        writel(hw->mode, hw->base + TINY_SPI_CONTROL);
93 6 hippo5329
        return 0;
94
}
95
 
96
static int tiny_spi_setup(struct spi_device *spi)
97
{
98
        struct tiny_spi *hw = to_hw(spi);
99
 
100
        if (spi->max_speed_hz != hw->speed_hz) {
101
                hw->speed_hz = spi->max_speed_hz;
102
                hw->baud = tiny_spi_baud(spi, hw->speed_hz);
103
        }
104 10 hippo5329
        hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA);
105 6 hippo5329
        return 0;
106
}
107
 
108
#ifndef CONFIG_TINY_SPI_IDLE_VAL
109 10 hippo5329
# define CONFIG_TINY_SPI_IDLE_VAL 0x00
110 6 hippo5329
#endif
111
 
112
static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
113
{
114
        struct tiny_spi *hw = to_hw(spi);
115
        const u8 *txp = t->tx_buf;
116
        u8 *rxp = t->rx_buf;
117 10 hippo5329
        unsigned int i;
118 6 hippo5329
 
119 10 hippo5329
        if (hw->irq >= 0 && hw->interrupt) {
120
                /* use intrrupt driven data transfer */
121
                hw->len = t->len;
122
                hw->txp = t->tx_buf;
123
                hw->rxp = t->rx_buf;
124
                hw->txc = 0;
125
                hw->rxc = 0;
126
                init_completion(&hw->done);
127 6 hippo5329
 
128 10 hippo5329
                /* send the first byte */
129
                if (t->len > 1) {
130
                        writeb(hw->txp ? *hw->txp++ : CONFIG_TINY_SPI_IDLE_VAL,
131
                               hw->base + TINY_SPI_TXDATA);
132
                        hw->txc++;
133
                        writeb(hw->txp ? *hw->txp++ : CONFIG_TINY_SPI_IDLE_VAL,
134
                               hw->base + TINY_SPI_TXDATA);
135
                        hw->txc++;
136
                        writeb(TINY_SPI_STATUS_TXR, hw->base + TINY_SPI_STATUS);
137
                } else {
138
                        writeb(hw->txp ? *hw->txp++ : CONFIG_TINY_SPI_IDLE_VAL,
139
                               hw->base + TINY_SPI_TXDATA);
140
                        hw->txc++;
141
                        writeb(TINY_SPI_STATUS_TXE, hw->base + TINY_SPI_STATUS);
142
                }
143
 
144
                wait_for_completion(&hw->done);
145
        } else if (txp && rxp) {
146
                /* we need to tighten the transfer loop */
147 6 hippo5329
                writeb(*txp++, hw->base + TINY_SPI_TXDATA);
148
                if (t->len > 1) {
149
                        writeb(*txp++, hw->base + TINY_SPI_TXDATA);
150
                        for (i = 2; i < t->len; i++) {
151
                                u8 rx, tx = *txp++;
152
                                while (!(readb(hw->base + TINY_SPI_STATUS) &
153
                                         TINY_SPI_STATUS_TXR))
154
                                        cpu_relax();
155
                                rx = readb(hw->base + TINY_SPI_TXDATA);
156
                                writeb(tx, hw->base + TINY_SPI_TXDATA);
157
                                *rxp++ = rx;
158
                        }
159
                        while (!(readb(hw->base + TINY_SPI_STATUS) &
160
                                 TINY_SPI_STATUS_TXR))
161
                                cpu_relax();
162
                        *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
163
                }
164
                while (!(readb(hw->base + TINY_SPI_STATUS) &
165
                         TINY_SPI_STATUS_TXE))
166
                        cpu_relax();
167
                *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
168
        } else if (rxp) {
169
                writeb(CONFIG_TINY_SPI_IDLE_VAL, hw->base + TINY_SPI_TXDATA);
170
                if (t->len > 1) {
171
                        writeb(CONFIG_TINY_SPI_IDLE_VAL,
172
                               hw->base + TINY_SPI_TXDATA);
173
                        for (i = 2; i < t->len; i++) {
174
                                u8 rx;
175
                                while (!(readb(hw->base + TINY_SPI_STATUS) &
176
                                         TINY_SPI_STATUS_TXR))
177
                                        cpu_relax();
178
                                rx = readb(hw->base + TINY_SPI_TXDATA);
179
                                writeb(CONFIG_TINY_SPI_IDLE_VAL,
180
                                       hw->base + TINY_SPI_TXDATA);
181
                                *rxp++ = rx;
182
                        }
183
                        while (!(readb(hw->base + TINY_SPI_STATUS) &
184
                                 TINY_SPI_STATUS_TXR))
185
                                cpu_relax();
186
                        *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
187
                }
188
                while (!(readb(hw->base + TINY_SPI_STATUS) &
189
                         TINY_SPI_STATUS_TXE))
190
                        cpu_relax();
191
                *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
192
        } else if (txp) {
193
                writeb(*txp++, hw->base + TINY_SPI_TXDATA);
194
                if (t->len > 1) {
195
                        writeb(*txp++, hw->base + TINY_SPI_TXDATA);
196
                        for (i = 2; i < t->len; i++) {
197
                                u8 tx = *txp++;
198
                                while (!(readb(hw->base + TINY_SPI_STATUS) &
199
                                         TINY_SPI_STATUS_TXR))
200
                                        cpu_relax();
201
                                writeb(tx, hw->base + TINY_SPI_TXDATA);
202
                        }
203
                }
204
                while (!(readb(hw->base + TINY_SPI_STATUS) &
205
                         TINY_SPI_STATUS_TXE))
206
                        cpu_relax();
207
        } else {
208
                writeb(CONFIG_TINY_SPI_IDLE_VAL, hw->base + TINY_SPI_TXDATA);
209
                if (t->len > 1) {
210
                        writeb(CONFIG_TINY_SPI_IDLE_VAL,
211
                               hw->base + TINY_SPI_TXDATA);
212
                        for (i = 2; i < t->len; i++) {
213
                                while (!(readb(hw->base + TINY_SPI_STATUS) &
214
                                         TINY_SPI_STATUS_TXR))
215
                                        cpu_relax();
216
                                writeb(CONFIG_TINY_SPI_IDLE_VAL,
217
                                       hw->base + TINY_SPI_TXDATA);
218
                        }
219
                }
220
                while (!(readb(hw->base + TINY_SPI_STATUS) &
221
                         TINY_SPI_STATUS_TXE))
222
                        cpu_relax();
223
        }
224
        return t->len;
225
}
226
 
227
static irqreturn_t tiny_spi_irq(int irq, void *dev)
228
{
229
        struct tiny_spi *hw = dev;
230 10 hippo5329
 
231 6 hippo5329
        writeb(0, hw->base + TINY_SPI_STATUS);
232 10 hippo5329
        if (hw->rxc + 1 == hw->len) {
233
                if (hw->rxp)
234
                        *hw->rxp++ = readb(hw->base + TINY_SPI_RXDATA);
235
                hw->rxc++;
236
                complete(&hw->done);
237
        } else {
238
                if (hw->rxp)
239
                        *hw->rxp++ = readb(hw->base + TINY_SPI_TXDATA);
240
                hw->rxc++;
241
                if (hw->txc < hw->len) {
242
                        writeb(hw->txp ? *hw->txp++ : CONFIG_TINY_SPI_IDLE_VAL,
243
                               hw->base + TINY_SPI_TXDATA);
244
                        hw->txc++;
245
                        writeb(TINY_SPI_STATUS_TXR,
246
                               hw->base + TINY_SPI_STATUS);
247
                } else {
248
                        writeb(TINY_SPI_STATUS_TXE,
249
                               hw->base + TINY_SPI_STATUS);
250
                }
251
        }
252 6 hippo5329
        return IRQ_HANDLED;
253
}
254
 
255 10 hippo5329
#ifdef CONFIG_OF
256
static int __devinit tiny_spi_of_probe(struct platform_device *pdev,
257
                                       struct tiny_spi *hw)
258 6 hippo5329
{
259 10 hippo5329
        const __be32 *val;
260
 
261
        hw->bitbang.master->dev.of_node = pdev->dev.of_node;
262
        val = of_get_property(pdev->dev.of_node, "baud-width", NULL);
263
        if (val)
264
                hw->baudwidth = be32_to_cpup(val);
265
        val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
266
        if (val)
267
                hw->freq = be32_to_cpup(val);
268
        val = of_get_property(pdev->dev.of_node, "interrupt-driven", NULL);
269
        if (val)
270
                hw->interrupt = be32_to_cpup(val);
271
        return 0;
272
}
273
#else
274
static int __devinit tiny_spi_of_probe(struct platform_device *pdev,
275
                                       struct tiny_spi *hw)
276
{
277
        return 0;
278
}
279
#endif
280
 
281
static int __devinit tiny_spi_probe(struct platform_device *pdev)
282
{
283
        struct tiny_spi_platform_data *platp = pdev->dev.platform_data;
284 6 hippo5329
        struct tiny_spi *hw;
285
        struct spi_master *master;
286
        struct resource *res;
287
        int err = 0;
288
 
289
        master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi));
290
        if (master == NULL) {
291
                dev_err(&pdev->dev, "No memory for spi_master\n");
292
                err = -ENOMEM;
293 10 hippo5329
                goto err_no_mem;
294 6 hippo5329
        }
295
 
296 10 hippo5329
        /* setup the master state. */
297
        master->bus_num = pdev->id;
298
        master->num_chipselect = 255;
299
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
300
        master->setup = tiny_spi_setup;
301
 
302 6 hippo5329
        hw = spi_master_get_devdata(master);
303
        platform_set_drvdata(pdev, hw);
304
 
305
        /* setup the state for the bitbang driver */
306 10 hippo5329
        hw->bitbang.master = spi_master_get(master);
307
        if (hw->bitbang.master == NULL) {
308
                dev_err(&pdev->dev, "Cannot get device\n");
309
                err = -ENODEV;
310
                goto err_no_dev;
311
        }
312 6 hippo5329
        hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
313
        hw->bitbang.chipselect = tiny_spi_chipselect;
314
        hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
315
 
316
        /* find and map our resources */
317
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
318
        if (res == NULL) {
319
                dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
320
                err = -ENOENT;
321
                goto err_no_iores;
322
        }
323 10 hippo5329
        hw->base = ioremap(res->start, (res->end - res->start) + 1);
324 6 hippo5329
        if (hw->base == 0) {
325
                dev_err(&pdev->dev, "Cannot map IO\n");
326
                err = -ENXIO;
327
                goto err_no_iomap;
328
        }
329 10 hippo5329
        /* irq is optional */
330 6 hippo5329
        hw->irq = platform_get_irq(pdev, 0);
331 10 hippo5329
        if (hw->irq >= 0) {
332
                init_completion(&hw->done);
333
                err = request_irq(hw->irq, tiny_spi_irq, 0, pdev->name, hw);
334
                if (err) {
335
                        dev_err(&pdev->dev, "Cannot claim IRQ\n");
336
                        goto err_no_irq;
337
                }
338 6 hippo5329
        }
339 10 hippo5329
        /* find platform data */
340
        if (platp) {
341
                hw->freq = platp->freq;
342
                hw->baudwidth = platp->baudwidth;
343
                hw->interrupt = platp->interrupt;
344
        } else {
345
                err = tiny_spi_of_probe(pdev, hw);
346
                if (err)
347
                        goto err_no_of;
348 6 hippo5329
        }
349
 
350
        /* register our spi controller */
351
        err = spi_bitbang_start(&hw->bitbang);
352
        if (err) {
353
                dev_err(&pdev->dev, "Failed to register SPI master\n");
354
                goto err_register;
355
        }
356 10 hippo5329
        dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
357 6 hippo5329
 
358
        return 0;
359
 
360
err_register:
361 10 hippo5329
        if (hw->irq >= 0)
362
                free_irq(hw->irq, hw);
363 6 hippo5329
err_no_irq:
364
        iounmap((void *)hw->base);
365
err_no_iomap:
366
err_no_iores:
367 10 hippo5329
        spi_master_put(master);
368
err_no_mem:
369
err_no_of:
370
err_no_dev:
371 6 hippo5329
        return err;
372
}
373
 
374 10 hippo5329
static int __devexit tiny_spi_remove(struct platform_device *dev)
375 6 hippo5329
{
376
        struct tiny_spi *hw = platform_get_drvdata(dev);
377 10 hippo5329
        struct spi_master *master = hw->bitbang.master;
378 6 hippo5329
 
379 10 hippo5329
        spi_bitbang_stop(&hw->bitbang);
380 6 hippo5329
 
381 10 hippo5329
        if (hw->irq >= 0)
382
                free_irq(hw->irq, hw);
383 6 hippo5329
        iounmap((void *)hw->base);
384
 
385 10 hippo5329
        platform_set_drvdata(dev, NULL);
386
        spi_master_put(master);
387 6 hippo5329
        return 0;
388
}
389
 
390 10 hippo5329
#ifdef CONFIG_OF
391
static struct of_device_id oc_tiny_spi_match[] = {
392
        {
393
                .compatible = "opencores,oc_tiny_spi",
394
        },
395
        {},
396
}
397
MODULE_DEVICE_TABLE(of, oc_tiny_spi_match);
398
#endif
399
 
400 6 hippo5329
static struct platform_driver tiny_spidrv = {
401 10 hippo5329
        .remove = __devexit_p(tiny_spi_remove),
402 6 hippo5329
        .driver = {
403
                .name = DRV_NAME,
404
                .owner = THIS_MODULE,
405
                .pm = NULL,
406 10 hippo5329
#ifdef CONFIG_OF
407
                .of_match_table = oc_tiny_spi_match,
408
#endif
409 6 hippo5329
        },
410
};
411
 
412
static int __init tiny_spi_init(void)
413
{
414
        return platform_driver_probe(&tiny_spidrv, tiny_spi_probe);
415
}
416
 
417
static void __exit tiny_spi_exit(void)
418
{
419
        platform_driver_unregister(&tiny_spidrv);
420
}
421
 
422
module_init(tiny_spi_init);
423
module_exit(tiny_spi_exit);
424
 
425 10 hippo5329
MODULE_DESCRIPTION("OpenCores tiny SPI driver");
426 6 hippo5329
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
427
MODULE_LICENSE("GPL");
428
MODULE_ALIAS("platform:" DRV_NAME);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.