Skip to content

Commit f6f7407

Browse files
Ecce_Liscorpiochang
authored andcommitted
Implement gpiomem for Debian. DEVMOD=0666
Change-Id: Id8e132a79c4f9379899d2d29fbd89af17e035c3e Reviewed-on: https://tp-biosrd-v02/gerrit/81067 Reviewed-by: Scorpio Chang(張志賢) <Scorpio_Chang@asus.com> Tested-by: Scorpio Chang(張志賢) <Scorpio_Chang@asus.com>
1 parent 885e2ae commit f6f7407

File tree

7 files changed

+330
-0
lines changed

7 files changed

+330
-0
lines changed

arch/arm/boot/dts/rk3288-miniarm.dts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@
236236
regulator-max-microvolt = <1000000>;
237237
regulator-name = "vdd_logic";
238238
};
239+
rk3288-gpiomem {
240+
compatible = "rockchip,rk3288-gpiomem";
241+
reg = <0x0 0xff750000 0x0 0x1000>;
242+
status = "okay";
243+
};
239244
/*
240245
vcc_cam: vcc-cam {
241246
compatible = "regulator-fixed";

arch/arm/configs/miniarm-rk3288_defconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,3 +780,6 @@ CONFIG_PPS_CLIENT_GPIO=y
780780
CONFIG_POSIX_MQUEUE=y
781781
CONFIG_W1=y
782782
CONFIG_W1_MASTER_GPIO=y
783+
CONFIG_RK_CHAR_DRIVERS=y
784+
CONFIG_RK3288_DEVGPIOMEM=y
785+

drivers/char/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
menu "Character devices"
66

7+
source "drivers/char/rockchip/Kconfig"
78
source "drivers/tty/Kconfig"
89

910
config DEVMEM

drivers/char/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ js-rtc-y = rtc.o
6060

6161
obj-$(CONFIG_TILE_SROM) += tile-srom.o
6262
obj-$(CONFIG_XILLYBUS) += xillybus/
63+
obj-$(CONFIG_RK_CHAR_DRIVERS) += rockchip/

drivers/char/rockchip/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Broadcom char driver config
3+
#
4+
5+
menuconfig RK_CHAR_DRIVERS
6+
bool "Rockchip Char Drivers"
7+
help
8+
Rockchip's char drivers
9+
10+
config RK3288_DEVGPIOMEM
11+
tristate "/dev/gpiomem rootless GPIO access via mmap() on the RK3288"
12+
default y
13+
help
14+
Provides users with root-free access to the GPIO registers
15+
on the 3288. Calling mmap(/dev/gpiomem) will map the GPIO
16+
register page to the user's pointer.

drivers/char/rockchip/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-$(CONFIG_RK3288_DEVGPIOMEM)+= rk3288-gpiomem.o
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/**
2+
* GPIO memory device driver
3+
*
4+
* Creates a chardev /dev/gpiomem which will provide user access to
5+
* the rk3288's GPIO registers when it is mmap()'d.
6+
* No longer need root for user GPIO access, but without relaxing permissions
7+
* on /dev/mem.
8+
*
9+
* Written by Luke Wren <luke@raspberrypi.org>
10+
* Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
11+
*
12+
* Redistribution and use in source and binary forms, with or without
13+
* modification, are permitted provided that the following conditions
14+
* are met:
15+
* 1. Redistributions of source code must retain the above copyright
16+
* notice, this list of conditions, and the following disclaimer,
17+
* without modification.
18+
* 2. Redistributions in binary form must reproduce the above copyright
19+
* notice, this list of conditions and the following disclaimer in the
20+
* documentation and/or other materials provided with the distribution.
21+
* 3. The names of the above-listed copyright holders may not be used
22+
* to endorse or promote products derived from this software without
23+
* specific prior written permission.
24+
*
25+
* ALTERNATIVELY, this software may be distributed under the terms of the
26+
* GNU General Public License ("GPL") version 2, as published by the Free
27+
* Software Foundation.
28+
*
29+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
30+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
31+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
33+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40+
*/
41+
42+
#include <linux/kernel.h>
43+
#include <linux/module.h>
44+
#include <linux/of.h>
45+
#include <linux/platform_device.h>
46+
#include <linux/mm.h>
47+
#include <linux/slab.h>
48+
#include <linux/cdev.h>
49+
#include <linux/pagemap.h>
50+
#include <linux/io.h>
51+
52+
#define DEVICE_NAME "rk3288-gpiomem"
53+
#define DRIVER_NAME "gpiomem-rk3288"
54+
#define DEVICE_MINOR 0
55+
56+
struct rk3288_gpiomem_instance {
57+
unsigned long gpio_regs_phys;
58+
struct device *dev;
59+
};
60+
61+
static struct cdev rk3288_gpiomem_cdev;
62+
static dev_t rk3288_gpiomem_devid;
63+
static struct class *rk3288_gpiomem_class;
64+
static struct device *rk3288_gpiomem_dev;
65+
static struct rk3288_gpiomem_instance *inst;
66+
67+
68+
/****************************************************************************
69+
*
70+
* GPIO mem chardev file ops
71+
*
72+
***************************************************************************/
73+
74+
static int rk3288_gpiomem_open(struct inode *inode, struct file *file)
75+
{
76+
int dev = iminor(inode);
77+
int ret = 0;
78+
79+
if (dev != DEVICE_MINOR) {
80+
dev_err(inst->dev, "Unknown minor device: %d", dev);
81+
ret = -ENXIO;
82+
}
83+
return ret;
84+
}
85+
86+
static int rk3288_gpiomem_release(struct inode *inode, struct file *file)
87+
{
88+
int dev = iminor(inode);
89+
int ret = 0;
90+
91+
if (dev != DEVICE_MINOR) {
92+
dev_err(inst->dev, "Unknown minor device %d", dev);
93+
ret = -ENXIO;
94+
}
95+
return ret;
96+
}
97+
98+
static const struct vm_operations_struct rk3288_gpiomem_vm_ops = {
99+
#ifdef CONFIG_HAVE_IOREMAP_PROT
100+
.access = generic_access_phys
101+
#endif
102+
};
103+
static int address_is_allowed(unsigned long pfn, unsigned long size)
104+
{
105+
unsigned long address = pfn << PAGE_SHIFT;
106+
107+
dev_info(inst->dev, "address_is_allowed.pfn: 0x%08lx", address);
108+
109+
switch(address) {
110+
111+
case 0xff750000:
112+
case 0xff760000:
113+
case 0xff780000:
114+
case 0xff790000:
115+
case 0xff7a0000:
116+
case 0xff7b0000:
117+
case 0xff7c0000:
118+
case 0xff7d0000:
119+
case 0xff7e0000:
120+
case 0xff7f0000:
121+
case 0xff7f2000:
122+
case 0xff770000:
123+
case 0xff730000:
124+
case 0xff680000:
125+
dev_info(inst->dev, "address_is_allowed.return 1");
126+
return 1;
127+
break;
128+
default :
129+
dev_info(inst->dev, "address_is_allowed.return 0");
130+
return 0;
131+
}
132+
}
133+
134+
static int rk3288_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
135+
{
136+
137+
size_t size;
138+
139+
size = vma->vm_end - vma->vm_start;
140+
141+
142+
if (!address_is_allowed(vma->vm_pgoff, size))
143+
return -EPERM;
144+
145+
vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
146+
size,
147+
vma->vm_page_prot);
148+
149+
vma->vm_ops = &rk3288_gpiomem_vm_ops;
150+
151+
/* Remap-pfn-range will mark the range VM_IO */
152+
if (remap_pfn_range(vma,
153+
vma->vm_start,
154+
vma->vm_pgoff,
155+
size,
156+
vma->vm_page_prot)) {
157+
return -EAGAIN;
158+
}
159+
160+
return 0;
161+
}
162+
163+
static const struct file_operations
164+
rk3288_gpiomem_fops = {
165+
.owner = THIS_MODULE,
166+
.open = rk3288_gpiomem_open,
167+
.release = rk3288_gpiomem_release,
168+
.mmap = rk3288_gpiomem_mmap,
169+
};
170+
171+
static int rk3288_gpiomem_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
172+
{
173+
add_uevent_var(env, "DEVMODE=%#o", 0666);
174+
return 0;
175+
}
176+
177+
/****************************************************************************
178+
*
179+
* Probe and remove functions
180+
*
181+
***************************************************************************/
182+
183+
184+
static int rk3288_gpiomem_probe(struct platform_device *pdev)
185+
{
186+
int err;
187+
void *ptr_err;
188+
struct device *dev = &pdev->dev;
189+
struct resource *ioresource;
190+
191+
/* Allocate buffers and instance data */
192+
193+
inst = kzalloc(sizeof(struct rk3288_gpiomem_instance), GFP_KERNEL);
194+
195+
if (!inst) {
196+
err = -ENOMEM;
197+
goto failed_inst_alloc;
198+
}
199+
200+
inst->dev = dev;
201+
202+
ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
203+
if (ioresource) {
204+
inst->gpio_regs_phys = ioresource->start;
205+
} else {
206+
dev_err(inst->dev, "failed to get IO resource");
207+
err = -ENOENT;
208+
goto failed_get_resource;
209+
}
210+
211+
/* Create character device entries */
212+
213+
err = alloc_chrdev_region(&rk3288_gpiomem_devid,
214+
DEVICE_MINOR, 1, DEVICE_NAME);
215+
if (err != 0) {
216+
dev_err(inst->dev, "unable to allocate device number");
217+
goto failed_alloc_chrdev;
218+
}
219+
cdev_init(&rk3288_gpiomem_cdev, &rk3288_gpiomem_fops);
220+
rk3288_gpiomem_cdev.owner = THIS_MODULE;
221+
err = cdev_add(&rk3288_gpiomem_cdev, rk3288_gpiomem_devid, 1);
222+
if (err != 0) {
223+
dev_err(inst->dev, "unable to register device");
224+
goto failed_cdev_add;
225+
}
226+
227+
/* Create sysfs entries */
228+
229+
rk3288_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME);
230+
ptr_err = rk3288_gpiomem_class;
231+
if (IS_ERR(ptr_err))
232+
goto failed_class_create;
233+
rk3288_gpiomem_class->dev_uevent = rk3288_gpiomem_dev_uevent;
234+
rk3288_gpiomem_dev = device_create(rk3288_gpiomem_class, NULL,
235+
rk3288_gpiomem_devid, NULL,
236+
"gpiomem");
237+
ptr_err = rk3288_gpiomem_dev;
238+
if (IS_ERR(ptr_err))
239+
goto failed_device_create;
240+
241+
dev_info(inst->dev, "Initialised: Registers at 0x%08lx",
242+
inst->gpio_regs_phys);
243+
244+
return 0;
245+
246+
failed_device_create:
247+
class_destroy(rk3288_gpiomem_class);
248+
failed_class_create:
249+
cdev_del(&rk3288_gpiomem_cdev);
250+
err = PTR_ERR(ptr_err);
251+
failed_cdev_add:
252+
unregister_chrdev_region(rk3288_gpiomem_devid, 1);
253+
failed_alloc_chrdev:
254+
failed_get_resource:
255+
kfree(inst);
256+
failed_inst_alloc:
257+
dev_err(inst->dev, "could not load rk3288_gpiomem");
258+
return err;
259+
}
260+
261+
static int rk3288_gpiomem_remove(struct platform_device *pdev)
262+
{
263+
struct device *dev = inst->dev;
264+
265+
kfree(inst);
266+
device_destroy(rk3288_gpiomem_class, rk3288_gpiomem_devid);
267+
class_destroy(rk3288_gpiomem_class);
268+
cdev_del(&rk3288_gpiomem_cdev);
269+
unregister_chrdev_region(rk3288_gpiomem_devid, 1);
270+
271+
dev_info(dev, "GPIO mem driver removed - OK");
272+
return 0;
273+
}
274+
275+
/****************************************************************************
276+
*
277+
* Register the driver with device tree
278+
*
279+
***************************************************************************/
280+
281+
static const struct of_device_id rk3288_gpiomem_of_match[] = {
282+
{.compatible = "rockchip,rk3288-gpiomem",},
283+
{ /* sentinel */ },
284+
};
285+
286+
MODULE_DEVICE_TABLE(of, rk3288_gpiomem_of_match);
287+
288+
static struct platform_driver rk3288_gpiomem_driver = {
289+
.probe = rk3288_gpiomem_probe,
290+
.remove = rk3288_gpiomem_remove,
291+
.driver = {
292+
.name = DRIVER_NAME,
293+
.owner = THIS_MODULE,
294+
.of_match_table = rk3288_gpiomem_of_match,
295+
},
296+
};
297+
298+
module_platform_driver(rk3288_gpiomem_driver);
299+
300+
MODULE_ALIAS("platform:gpiomem-rk3288");
301+
MODULE_LICENSE("GPL");
302+
MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace");
303+
MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");

0 commit comments

Comments
 (0)