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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [or32/] [drivers/] [sd_card.c] - Blame information for rev 18

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 xianfeng
/*
2
 *
3
 * Block driver for spiMaster to drive SD card
4
 *
5
 * Copyright (c) 2008 by:
6
 *      Xianfeng Zeng <xianfeng.zeng@gmail.com>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the BSD Licence, GNU General Public License
10
 * as published by the Free Software Foundation; either version 2 of the
11
 * License, or (at your option) any later version
12
 *
13
 * ChangeLog:
14
 *      2009-11-28 15:11:18   Xianfeng Zeng
15
 *          Init.
16
 *
17
 */
18
 
19
#include <linux/version.h>
20
#include <linux/module.h>
21
#include <linux/init.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/fs.h>
25
#include <linux/genhd.h>
26
#include <linux/delay.h>
27
 
28
#include <linux/slab.h>         /* kmalloc() */
29
#include <linux/errno.h>        /* error codes */
30
#include <linux/timer.h>
31
#include <linux/types.h>        /* size_t */
32
#include <linux/fcntl.h>        /* O_ACCMODE */
33
#include <linux/hdreg.h>        /* HDIO_GETGEO */
34
#include <linux/kdev_t.h>
35
#include <linux/vmalloc.h>
36
#include <linux/genhd.h>
37
#include <linux/blkdev.h>
38
#include <linux/buffer_head.h>  /* invalidate_bdev */
39
#include <linux/bio.h>
40
 
41
 
42
#include "sd_card.h"
43
 
44
#define SDC_DEBUG 1
45
 
46
#ifdef SDC_DEBUG
47
#       define SDC_PRINTK(fmt, args...) printk( KERN_WARNING "sd_card:" fmt, ## args)
48
#else
49
#       define SDC_PRINTK(fmt, args...)
50
#endif
51
 
52 18 xianfeng
#define DRIVER_NAME     "sd_card"
53
#define SD_CARD_MINORS  8
54
#define SD_CARD_SIZE    1995440128
55 16 xianfeng
 
56
static int major = 8;
57
 
58
 
59
/**
60
 * ============================================================
61
 *
62
 * ============================================================
63
 */
64
int spiMaster_init(void *vbase)
65
{
66
        unsigned char data;
67
        int   i;
68
 
69
        SDC_PRINTK("spiMaster_init begin\n");
70
 
71
        for (i = 0; i < 5; i++) {
72
                REG8(vbase + SD_TRANS_TYPE_REG) = SD_INIT_SD;
73
                REG8(vbase + SD_TRANS_CTRL_REG) = 1; // TRANS_START;
74
 
75
                mdelay(1);
76
 
77
                while (REG8(vbase + SD_TRANS_STS_REG) & 0x1) { // exit while !TRABS_BUSY
78
                        ;
79
                }
80
 
81
                data = REG8(vbase + SD_TRANS_ERROR_REG) & 0x3;
82
 
83
                if (data == 0) {
84
                        SDC_PRINTK("spiMaster_init done\n");
85
                        return 0;
86
                }
87
        }
88
 
89
        SDC_PRINTK("spiMaster_init failed\n");
90
 
91
        return data;
92
}
93
 
94
/**
95
 * ============================================================
96
 *             Request Handling
97
 * ============================================================
98
 */
99
 
100
static int read_sd_block(void *sd_vbase, unsigned long sector,
101
                unsigned long nsect, char *buffer)
102
{
103
        unsigned char data;
104
        unsigned char transError;
105
        int i;
106
        unsigned int buffer_offset = 0;
107
        unsigned int blockCnt;
108
 
109
        SDC_PRINTK("read_sd_block begin: sector=%d, nsect=%d\n", sector, nsect);
110
 
111
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
112
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
113
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((sector >> 8) & 0xff);
114
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((sector >> 16) & 0xff);
115
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((sector >> 24) & 0xff);
116
 
117
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_READ_SD_BLOCK;
118 18 xianfeng
                REG8(sd_vbase + SD_RX_FIFO_CONTROL_REG) = 0x1; /* Clean the RX FIFO */
119
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 0x1; /* TRANS_START */
120
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
121 16 xianfeng
                        ;
122
                }
123
 
124
                transError = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0xc;
125
                if ( transError == SD_READ_NO_ERROR) {
126
                        for (i = 0; i < 512; i++) {
127
                                data = REG8(sd_vbase + SD_RX_FIFO_DATA_REG) ;
128
                                REG8(buffer + buffer_offset + i) = data ;
129
                        }
130
                        buffer_offset += 512;
131
                        sector += 512;
132
                } else {
133
                        SDC_PRINTK("read_sd_block failed. Re-try\n");
134
                        spiMaster_init(sd_vbase); /* Init again and retry */
135
                        blockCnt--; /* read the same block again */
136
                }
137
        }
138
 
139
        SDC_PRINTK("read_sd_block done\n");
140
 
141
        return 0;
142
}
143
 
144 18 xianfeng
static int write_sd_block(void *sd_vbase, unsigned long sector,
145
                unsigned long nsect, char *buffer)
146
{
147
        int i;
148
        unsigned char data;
149
        unsigned int blockCnt;
150
        char *p = buffer;
151 16 xianfeng
 
152 18 xianfeng
        SDC_PRINTK("write_sd_block begin: sector=%d, nsect=%d\n", sector, nsect);
153
 
154
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
155
 
156
                /* Clean the TX FIFO */
157
                REG8(sd_vbase + SD_TX_FIFO_CONTROL_REG) = 0x1;
158
 
159
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
160
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((sector >> 8) & 0xff);
161
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((sector >> 16) & 0xff);
162
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((sector >> 24) & 0xff);
163
 
164
 
165
                // Write data to TX_FIFO_DATA_REG
166
                for (i = 0; i < 512; i++) {
167
                        REG8(sd_vbase + SD_TX_FIFO_DATA_REG) = p[i];
168
                }
169
 
170
 
171
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_WRITE_SD_BLOCK;
172
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 1; /* TRANS_START */
173
 
174
 
175
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
176
                        ;
177
                }
178
 
179
                data = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0x30;
180
                if (data == 1) {
181
                        SDC_PRINTK("WRITE_CMD_ERROR\n\r");
182
                } else if (data == 2) {
183
                        SDC_PRINTK("WRITE_DATA_ERROR\n\r");
184
                } else if (data == 3) {
185
                        SDC_PRINTK("WRITE_BUSY_ERROR\n\r");
186
                }
187
 
188
                sector += 512;
189
                p += 512;
190
        }
191
 
192
        SDC_PRINTK("write_sd_block done\n");
193
        return 0;
194
}
195
 
196 16 xianfeng
/*
197
 * Handle an I/O request.
198
 */
199
static void sd_card_transfer(struct sd_card_dev *dev, unsigned long sector,
200
                unsigned long nsect, char *buffer, int write)
201
{
202
        unsigned long offset = sector*512;
203
        unsigned long nbytes = nsect*512;
204
 
205
        if ((offset + nbytes) > dev->size) {
206
                printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
207
                return;
208
        }
209
        if (write)
210 18 xianfeng
                write_sd_block(dev->vir_base, sector, nsect, buffer);
211 16 xianfeng
        else
212
                read_sd_block(dev->vir_base, sector, nsect, buffer);
213
}
214
 
215
 
216
/*
217
 * The simple form of the request function.
218
 */
219
static void sd_card_request(request_queue_t *q)
220
{
221
        struct request *req;
222
 
223
        while ((req = elv_next_request(q)) != NULL) {
224
                struct sd_card_dev *dev = req->rq_disk->private_data;
225
                if (! blk_fs_request(req)) {
226
                        printk (KERN_NOTICE "Skip non-fs request\n");
227
                        end_request(req, 0);
228
                        continue;
229
                }
230
    //          printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n",
231
    //                          dev - Devices, rq_data_dir(req),
232
    //                          req->sector, req->current_nr_sectors,
233
    //                          req->flags);
234
                sd_card_transfer(dev, req->sector, req->current_nr_sectors,
235
                                req->buffer, rq_data_dir(req));
236
                end_request(req, 1);
237
        }
238
}
239
 
240
/**
241
 * ============================================================
242
 *             Block device operations
243
 * ============================================================
244
 */
245
static int sd_card_open(struct inode *inode, struct file *filp)
246
{
247
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
248
 
249
        SDC_PRINTK("sd_card_open beging\n");
250
 
251
        filp->private_data = dev;
252
        spin_lock(&dev->lock);
253
        if (! dev->users)
254
                check_disk_change(inode->i_bdev);
255
 
256
        /* Init SD card controller */
257
        spiMaster_init(dev->vir_base);
258
 
259
        dev->users++;
260
        spin_unlock(&dev->lock);
261
 
262
        SDC_PRINTK("sd_card_open done\n");
263
 
264
        return 0;
265
}
266
 
267
static int sd_card_release(struct inode *inode, struct file *filp)
268
{
269
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
270
 
271
        SDC_PRINTK("sd_card_release beging\n");
272
 
273
        spin_lock(&dev->lock);
274
        dev->users--;
275
 
276
        spin_unlock(&dev->lock);
277
 
278
        SDC_PRINTK("sd_card_release done\n");
279
 
280
        return 0;
281
}
282
 
283
/*
284
 * Look for a (simulated) media change.
285
 */
286
int sd_card_media_changed(struct gendisk *gd)
287
{
288
        //struct sd_card_dev *dev = gd->private_data;
289
 
290
        return 0; //dev->media_change;
291
}
292
 
293
/*
294
 * Revalidate.  WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking
295
 * with open.  That needs to be reevaluated.
296
 */
297
int sd_card_revalidate(struct gendisk *gd)
298
{
299
        struct sd_card_dev *dev = gd->private_data;
300
 
301
        if (dev->media_change) {
302
                dev->media_change = 0;
303
//              memset (dev->data, 0, dev->size);
304
        }
305
        return 0;
306
}
307
 
308
 
309
/*
310
 * The ioctl() implementation
311
 */
312
 
313
int sd_card_ioctl (struct inode *inode, struct file *filp,
314
                 unsigned int cmd, unsigned long arg)
315
{
316
        long size;
317
        struct hd_geometry geo;
318
        struct sd_card_dev *dev = filp->private_data;
319
 
320
        switch(cmd) {
321
            case HDIO_GETGEO:
322
                /*
323
                 * Get geometry: since we are a virtual device, we have to make
324
                 * up something plausible.  So we claim 16 sectors, four heads,
325
                 * and calculate the corresponding number of cylinders.  We set the
326
                 * start of data at sector four.
327
                 */
328
                size = dev->size;
329 18 xianfeng
                geo.cylinders = (size & ~0x3f) >> 6;
330
                geo.heads = 62; //32;
331 16 xianfeng
                geo.sectors = 62; //63;
332 18 xianfeng
                geo.start = get_start_sect(inode->i_bdev);
333 16 xianfeng
                if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
334
                        return -EFAULT;
335
                return 0;
336
        }
337
 
338
        return -ENOTTY; /* unknown command */
339
}
340
 
341
 
342
/*
343
 * The device operations structure.
344
 */
345
static struct block_device_operations sd_card_ops = {
346
        .owner           = THIS_MODULE,
347
        .open            = sd_card_open,
348
        .release         = sd_card_release,
349
        .media_changed   = sd_card_media_changed,
350
        .revalidate_disk = sd_card_revalidate,
351
        .ioctl           = sd_card_ioctl
352
};
353
 
354
/**
355
 * ============================================================
356
 *                 Driver Entry and clean up
357
 * ============================================================
358
 */
359
static int __init sd_card_init(void)
360
{
361
        int ret;
362
        struct sd_card_dev  *dev;
363
 
364
        /* Put the init code here */
365
        printk(KERN_INFO "SD Card Driver Enter.\n");
366
 
367
        dev = (struct sd_card_dev *)kmalloc(sizeof(struct sd_card_dev), GFP_KERNEL);
368
        if (dev < 0) {
369
                printk(KERN_WARNING "lack of memory\n");
370
                return -1;
371
        }
372
        memset(dev, 0, sizeof(struct sd_card_dev));
373
 
374
        ret = register_blkdev(major, DRIVER_NAME);
375
        if (ret <0) {
376
                printk(KERN_WARNING "sd_card: unable to get major number\n");
377
                kfree(dev);
378
                return -EBUSY;
379
        }
380
 
381 18 xianfeng
        dev->size = SD_CARD_SIZE; //1015808000; /* 1GB */
382 16 xianfeng
        spin_lock_init(&dev->lock);
383
        dev->queue = blk_init_queue(sd_card_request, &dev->lock);
384
        blk_queue_hardsect_size(dev->queue, 512);
385
 
386
        dev->vir_base = ioremap(SD_BASE_ADD, 0x2000);
387
 
388 18 xianfeng
        /* Reset spiMaster controller */
389
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x1;  /* reset spiMaster */
390
        mdelay(1);
391
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x0;
392
        REG8(dev->vir_base + SD_CLK_DEL_REG) = 0x1;
393
 
394 16 xianfeng
        /* allocate gendsik and init it */
395
        dev->gd = alloc_disk(SD_CARD_MINORS);
396
        if (!dev->gd) {
397
                printk(KERN_WARNING "alloc_disk failed\n");
398
                kfree(dev);
399
                unregister_blkdev(major, DRIVER_NAME);
400
                return -1;
401
        }
402
        dev->gd->major          = major;
403
        dev->gd->first_minor    = 0;
404
        dev->gd->fops           = &sd_card_ops;
405
        dev->gd->queue          = dev->queue;
406
        dev->gd->private_data   = dev;
407
        snprintf(dev->gd->disk_name, 32, "sd%c", 'a');
408
 
409
        set_capacity(dev->gd, dev->size/512);
410
 
411
        add_disk(dev->gd);
412
 
413
        SDC_PRINTK("sd_card_init done\n");
414
 
415
        return 0;
416
}
417
 
418
 
419
static void __exit sd_card_exit(void)
420
{
421
        /* Put the driver clean up code here */
422
 
423
        unregister_blkdev(major, DRIVER_NAME);
424
 
425
        printk(KERN_INFO "SD Card Driver Exit.\n");
426
}
427
 
428
//module_init(sd_card_init);
429
late_initcall(sd_card_init);
430
module_exit(sd_card_exit);
431
 
432
MODULE_LICENSE("Dual BSD/GPL");
433
MODULE_AUTHOR("Xianfeng Zeng - Xianfeng.zeng@SierraAtlantic.com, http://www.LinuxExperts.cn");
434
MODULE_DESCRIPTION("spiMaster driver");
435
MODULE_VERSION("0.1");
436
 

powered by: WebSVN 2.1.0

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