aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/patches/010-Add-SRAM-char-device-driver-support-for-MCF5445x.patch
blob: ed0516fcd9f73da2371f275acb801eae7f6d70c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
From f54ba59d355f59e4c01b5b9c7dbc2d27b47302d2 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:41 +0800
Subject: [PATCH 10/52] Add SRAM char device driver support for MCF5445x

Created "/dev/sram" device file and implemented the sram mmap() operation to
provide interface for userspace access.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
 drivers/char/Kconfig  |   11 ++++
 drivers/char/Makefile |    2 +
 drivers/char/sram.c   |  151 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+), 0 deletions(-)
 create mode 100644 drivers/char/sram.c

--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -97,6 +97,17 @@ config DEVKMEM
 	  kind of kernel debugging operations.
 	  When in doubt, say "N".
 
+config DEVSRAM
+	tristate "/dev/sram virtual device support"
+	depends on M5445X
+	default m
+	help
+	  Say Y here if you want to suppot the SRAM char device. When in
+	  doubt, say "N".
+
+	  It implements mmap system call to provide interface for
+	  user space access.
+
 config BFIN_JTAG_COMM
 	tristate "Blackfin JTAG Communication"
 	depends on BLACKFIN
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -87,3 +87,5 @@ obj-$(CONFIG_RAMOOPS)		+= ramoops.o
 
 obj-$(CONFIG_JS_RTC)		+= js-rtc.o
 js-rtc-y = rtc.o
+
+obj-$(CONFIG_DEVSRAM)		+= sram.o
--- /dev/null
+++ b/drivers/char/sram.c
@@ -0,0 +1,151 @@
+/*
+ * linux/drivers/char/sram.c
+ *
+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Lanttor.Guo@freescale.com
+ *
+ * SRAM char device driver, implements mmap() system call to provide
+ * interface for user space access.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kdev_t.h>
+#include <asm/page.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+
+MODULE_LICENSE("GPL");
+
+static struct class *sram_class;
+static int sram_major;
+static int sram_minor;
+static struct cdev sram_cdev;
+
+/*
+ * Set up the cdev structure for sram.
+ */
+static void sram_setup_cdev(struct cdev *dev, int minor,
+		const struct file_operations *fops)
+{
+	int err, devno = MKDEV(sram_major, minor);
+
+	cdev_init(dev, fops);
+	dev->owner = THIS_MODULE;
+	dev->ops = fops;
+	err = cdev_add(dev, devno, 1);
+	/* Fail gracefully if need be */
+	if (err)
+		printk(KERN_NOTICE "Error %d adding sram%d", err, minor);
+}
+
+static int sram_open(struct inode *inode, struct file *filp)
+{
+	filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi;
+	return 0;
+}
+
+static int sram_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+void sram_vma_open(struct vm_area_struct *vma)
+{
+	printk(KERN_DEBUG "Sram VMA open, virt %lx, phys %lx\n",
+			   vma->vm_start,
+			   CONFIG_SRAM_BASE + (vma->vm_pgoff << PAGE_SHIFT));
+}
+
+void sram_vma_close(struct vm_area_struct *vma)
+{
+	printk(KERN_DEBUG "Sram VMA close.\n");
+}
+
+
+static struct vm_operations_struct sram_remap_vm_ops = {
+	.open =  sram_vma_open,
+	.close = sram_vma_close,
+};
+
+static int sram_remap_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	size_t size = vma->vm_end - vma->vm_start;
+
+	if (PAGE_ALIGN(size) > CONFIG_SRAM_SIZE) {
+		printk(KERN_ERR "required length exceed the size "
+		       "of physical sram (%x)\n", CONFIG_SRAM_SIZE);
+		return -EAGAIN;
+	}
+
+	if ((CONFIG_SRAM_BASE + (vma->vm_pgoff << PAGE_SHIFT) + size)
+	    > (CONFIG_SRAM_BASE + CONFIG_SRAM_SIZE)) {
+		printk(KERN_ERR "required sram range exceed the size "
+		       "of phisical sram\n");
+		return -EAGAIN;
+	}
+
+	if (remap_pfn_range(vma, vma->vm_start,
+			    (CONFIG_SRAM_BASE >> PAGE_SHIFT) + vma->vm_pgoff,
+			    size,
+			    vma->vm_page_prot)) {
+		printk(KERN_ERR "remap_pfn_range faile at %s()\n", __func__);
+		return -EAGAIN;
+	}
+
+	vma->vm_ops = &sram_remap_vm_ops;
+	return 0;
+}
+
+static const struct file_operations sram_ops = {
+	.owner   = THIS_MODULE,
+	.open    = sram_open,
+	.release = sram_release,
+	.mmap    = sram_remap_mmap,
+};
+
+static int __init sram_chrdev_init(void)
+{
+	int minor_devs = 1;
+	int result;
+	dev_t dev = 0;
+	sram_minor = 0;
+
+	result = alloc_chrdev_region(&dev, sram_minor, minor_devs, "sram");
+	sram_major = MAJOR(dev);
+	if (result < 0) {
+		printk(KERN_WARNING "sram: can't get major %d\n", sram_major);
+		return result;
+	}
+
+	sram_setup_cdev(&sram_cdev, 0, &sram_ops);
+
+	sram_class = class_create(THIS_MODULE, "sram");
+	device_create(sram_class, NULL, MKDEV(sram_major, sram_minor),
+		      NULL, "sram");
+
+	return 0;
+}
+
+static void sram_chrdev_cleanup(void)
+{
+	cdev_del(&sram_cdev);
+	device_destroy(sram_class, MKDEV(sram_major, sram_minor));
+	class_destroy(sram_class);
+	unregister_chrdev_region(MKDEV(sram_major, 0), 1);
+}
+
+module_init(sram_chrdev_init);
+module_exit(sram_chrdev_cleanup);