Skip to content

Commit ec94960

Browse files
committed
merge: Rpmsg gpiodrv
fixes: beagleboard/linux#247 Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
1 parent 2c3e67e commit ec94960

File tree

4 files changed

+281
-1
lines changed

4 files changed

+281
-1
lines changed

patch.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ drivers () {
617617
dir 'drivers/uio_pruss_shmem'
618618
dir 'drivers/greybus'
619619
dir 'RPi'
620+
dir 'gsoc'
620621
dir 'fixes'
621622
}
622623

patches/defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5493,6 +5493,7 @@ CONFIG_RPMSG=y
54935493
CONFIG_RPMSG_VIRTIO=m
54945494
CONFIG_RPMSG_RPC=m
54955495
CONFIG_RPMSG_PRU=m
5496+
CONFIG_CONFIG_RPMSG_GPIOHIP_INTERFACE=m
54965497

54975498
#
54985499
# Rpmsg virtual device drivers
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
From 50ad0fc3083890661113180aa3a849958d0c0787 Mon Sep 17 00:00:00 2001
2+
From: deebot <deepankar.maithani@stud.th-deg.de>
3+
Date: Sun, 23 Aug 2020 13:40:44 +0200
4+
Subject: [PATCH] - Added driver to use rpmsg with gpiochip interface.Requires
5+
PRU firmware Please follow instructions to load PRU firmware
6+
https://github.com/deebot/Beaglebone-BidirectionBus/blob/dev/bidirec_299/README.md
7+
- Added rule to compile rpmsg-gpio driver in Make and Kconfig
8+
9+
---
10+
drivers/rpmsg/Kconfig | 12 ++
11+
drivers/rpmsg/Makefile | 2 +
12+
drivers/rpmsg/rpmsg_gpio.c | 222 +++++++++++++++++++++++++++++++++++++
13+
3 files changed, 236 insertions(+)
14+
create mode 100644 drivers/rpmsg/rpmsg_gpio.c
15+
16+
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
17+
index c41d8157b079..ef2c47c017bb 100644
18+
--- a/drivers/rpmsg/Kconfig
19+
+++ b/drivers/rpmsg/Kconfig
20+
@@ -81,4 +81,16 @@ config RPMSG_PRU
21+
22+
If unsure, say N.
23+
24+
+config CONFIG_RPMSG_GPIOHIP_INTERFACE
25+
+ tristate "A rpmsg driver with gpiochip interface"
26+
+ default m
27+
+ depends on RPMSG_VIRTIO
28+
+ depends on REMOTEPROC
29+
+ help
30+
+ This driver provides provides gpiochip inteface which can be accessed
31+
+ in userspace using libgpiod. You would see a char dev interface in
32+
+ "/dev" using this driver. Follow the README from the following
33+
+ repo for more info.
34+
+ https://github.com/deebot/Beaglebone-BidirectionBus
35+
+
36+
endmenu
37+
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
38+
index 6666c8d6327e..3b93ea58ae36 100644
39+
--- a/drivers/rpmsg/Makefile
40+
+++ b/drivers/rpmsg/Makefile
41+
@@ -9,4 +9,6 @@ obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
42+
obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
43+
44+
obj-$(CONFIG_RPMSG_RPC) += rpmsg-rpc.o
45+
+obj-$(CONFIG_RPMSG_GPIOCHIP_INTERFACE) += rpmsg_gpio.o
46+
rpmsg-rpc-y := rpmsg_rpc.o rpmsg_rpc_sysfs.o rpmsg_rpc_dmabuf.o
47+
+
48+
diff --git a/drivers/rpmsg/rpmsg_gpio.c b/drivers/rpmsg/rpmsg_gpio.c
49+
new file mode 100644
50+
index 000000000000..92fd7e517c3c
51+
--- /dev/null
52+
+++ b/drivers/rpmsg/rpmsg_gpio.c
53+
@@ -0,0 +1,222 @@
54+
+/*
55+
+ * PRU Remote Processor Messaging Driver with gpiochip interface
56+
+ * copyright (c) 2020 Deepankar Maithani
57+
+ * Codes examples from Lab no 5 from TI and has been used as boiler plate for rpmsg communication
58+
+ * https://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs
59+
+ *
60+
+ * For learn more about the complete project visit:
61+
+ * https://github.com/deebot/Beaglebone-BidirectionBus/tree/dev
62+
+ * Steps to test the driver.
63+
+ * https://github.com/deebot/Beaglebone-BidirectionBus/blob/dev/bidirec_299/README.md
64+
+ *
65+
+ * This software is licensed under the terms of the GNU General Public
66+
+ * License version 2, as published by the Free Software Foundation, and
67+
+ * may be copied, distributed, and modified under those terms.
68+
+ *
69+
+ * This program is distributed in the hope that it will be useful,
70+
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
71+
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72+
+ * GNU General Public License for more details.
73+
+ */
74+
+#include <linux/kernel.h>
75+
+#include <linux/module.h>
76+
+#include <linux/slab.h>
77+
+#include <linux/gpio.h>
78+
+#include <linux/of.h>
79+
+#include <linux/rpmsg.h>
80+
+#include <linux/fs.h>
81+
+#include <linux/init.h>
82+
+#include <linux/kfifo.h>
83+
+#include <linux/uaccess.h>
84+
+#include <linux/poll.h>
85+
+#include <linux/rpmsg/virtio_rpmsg.h>
86+
+#include <linux/stat.h>
87+
+#include <linux/bitops.h>
88+
+#define PRU_MAX_DEVICES (16)
89+
+/* Matches the definition in virtio_rpmsg_bus.c */
90+
+#define RPMSG_BUF_SIZE (512)
91+
+#define MAX_FIFO_MSG (32)
92+
+#define FIFO_MSG_SIZE RPMSG_BUF_SIZE
93+
+#define GPIO_NUM 9
94+
+static DEFINE_MUTEX(rpmsg_pru_lock);
95+
+static char rpmsg_pru_buf[RPMSG_BUF_SIZE];
96+
+static struct gpio_chip chip;
97+
+struct rpmsg_pru_dev {
98+
+ struct rpmsg_device *rpdev;
99+
+ struct device *dev;
100+
+ bool locked;
101+
+ dev_t devt;
102+
+ struct kfifo msg_fifo;
103+
+ u32 msg_len[MAX_FIFO_MSG];
104+
+ int msg_idx_rd;
105+
+ int msg_idx_wr;
106+
+ wait_queue_head_t wait_list;
107+
+ uint32_t gpio_state;
108+
+ long input_state;
109+
+
110+
+};
111+
+
112+
+struct rpmsg_pru_dev *prudev;
113+
+/*Reads the lines which are set as input*/
114+
+static int mygpio_get_value(struct gpio_chip *gc, unsigned offset)
115+
+{
116+
+ uint32_t value;
117+
+ struct rpmsg_device *rpdev = container_of(gc->parent,
118+
+ struct rpmsg_device, dev);
119+
+ unsigned int mask = BIT(offset % 8);
120+
+ prudev = dev_get_drvdata(&rpdev->dev);
121+
+
122+
+ value = (prudev->input_state & mask)>>offset;
123+
+ return value;
124+
+}
125+
+/* Writes to the lines and creates the gpio_state which is then sent as RPmsg */
126+
+static void mygpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
127+
+{
128+
+ int ret;
129+
+ struct rpmsg_device *rpdev = container_of(gc->parent, struct rpmsg_device, dev);
130+
+ pr_info("set_value function triggered");
131+
+ pr_info("The bit number %d is set to value: %d", offset, val);
132+
+
133+
+ prudev = dev_get_drvdata(&rpdev->dev);
134+
+ if (val == 0) {
135+
+ prudev->gpio_state &= ~(1<<offset);
136+
+ } else {
137+
+ prudev->gpio_state |= (1<<offset);
138+
+ }
139+
+ if (offset == GPIO_NUM-1) {
140+
+ /* copy the gpiostate in rpmsg buffer which will be sent over to PRU*/
141+
+ memcpy((void *)&rpmsg_pru_buf, (void *)&(prudev->gpio_state),
142+
+ sizeof(&(prudev->gpio_state)));
143+
+ pr_info("A check for checking gpio_state: %d",
144+
+ prudev->gpio_state);
145+
+ /* This line actually sends the data to the other side*/
146+
+ ret = rpmsg_send(rpdev->ept, (void *)rpmsg_pru_buf, 2);
147+
+ if (ret)
148+
+ dev_err(gc->parent, "rpmsg_send failed: %d\n", ret);
149+
+ }
150+
+
151+
+}
152+
+
153+
+/*sets the pin to output. Will be called when user sets one
154+
+ * of the gpiochip line as output which can be done manually
155+
+ * in sysfs or using libgpiod */
156+
+
157+
+static int mygpio_direction_output(struct gpio_chip *gc,
158+
+ unsigned offset, int val)
159+
+{
160+
+ pr_info("Direction of GPIO set to: out\n");
161+
+ return 0;
162+
+}
163+
+/*Runs When direction of a line is set as output*/
164+
+static int mygpio_direction_input(struct gpio_chip *gc,
165+
+ unsigned offset)
166+
+{
167+
+
168+
+ pr_info("Direction of GPIO set to: in \n");
169+
+ return 0;
170+
+}
171+
+/*This function gets called every time
172+
+ *an rpmsg_channel is created with a name that matches the .name
173+
+ *attribute of the rpmsg_driver_sample_id_table. It sets up suitable memory
174+
+ *and the gpiochip interface that can be seen in /sys/class/gpio and /dev.
175+
+ */
176+
+static int mygpio_rpmsg_pru_probe (struct rpmsg_device *rpdev)
177+
+{
178+
+ int ret;
179+
+ struct rpmsg_pru_dev *prudev;
180+
+ prudev = devm_kzalloc(&rpdev->dev, sizeof(*prudev), GFP_KERNEL);
181+
+ if (!prudev)
182+
+ return -ENOMEM;
183+
+ prudev->rpdev = rpdev;
184+
+ ret = kfifo_alloc(&prudev->msg_fifo, MAX_FIFO_MSG * FIFO_MSG_SIZE,
185+
+ GFP_KERNEL);
186+
+ if (ret) {
187+
+ dev_err(&rpdev->dev, "Unable to allocate fifo for the rpmsg_pru device\n");
188+
+ return -ENOMEM;
189+
+ }
190+
+ init_waitqueue_head(&prudev->wait_list);
191+
+ dev_set_drvdata(&rpdev->dev, prudev);
192+
+ chip.label = rpdev->desc;
193+
+ chip.base = -1;
194+
+ chip.parent = &rpdev->dev;
195+
+ chip.owner = THIS_MODULE;
196+
+ chip.ngpio = GPIO_NUM;
197+
+ chip.can_sleep = 1;
198+
+ chip.get = mygpio_get_value;
199+
+ chip.set = mygpio_set_value;
200+
+ chip.direction_output = mygpio_direction_output;
201+
+ chip.direction_input = mygpio_direction_input;
202+
+ return gpiochip_add(&chip);
203+
+}
204+
+/* Callback function which gets called whenever a new rpmsg is received
205+
+ * The data received from the PRU is converted into long and then assigned to
206+
+ * input_state
207+
+ * @msg_fifo: kernel fifo used to buffer the messages between userspace and PRU
208+
+ * @msg_len: array storing the lengths of each message in the kernel fifo
209+
+ * @msg_idx_rd: kernel fifo read index
210+
+ * @msg_idx_wr: kernel fifo write index
211+
+ * */
212+
+static int mygpio_rpmsg_pru_cb(struct rpmsg_device *rpdev, void *data, int len,
213+
+ void *priv, u32 src)
214+
+{ int ret;
215+
+ u32 length;
216+
+ struct rpmsg_pru_dev *prudev;
217+
+
218+
+ prudev = dev_get_drvdata(&rpdev->dev);
219+
+
220+
+ if (kfifo_avail(&prudev->msg_fifo) < len) {
221+
+ dev_err(&rpdev->dev, "Not enough space on the FIFO\n");
222+
+ return -ENOSPC;
223+
+ }
224+
+
225+
+ if ((prudev->msg_idx_wr + 1) % MAX_FIFO_MSG ==
226+
+ prudev->msg_idx_rd) {
227+
+ dev_err(&rpdev->dev, "Message length table is full\n");
228+
+ return -ENOSPC;
229+
+ }
230+
+ /* adds the data received into a fifo*/
231+
+ length = kfifo_in(&prudev->msg_fifo, data, len);
232+
+ prudev->msg_len[prudev->msg_idx_wr] = length;
233+
+ prudev->msg_idx_wr = (prudev->msg_idx_wr + 1) % MAX_FIFO_MSG;
234+
+
235+
+ wake_up_interruptible(&prudev->wait_list);
236+
+ ret = kstrtol((char *) data, 10, &prudev->input_state);
237+
+ if (ret) {
238+
+ return ret;
239+
+ }
240+
+ pr_info("The shift register port state is: %ld", prudev->input_state);
241+
+ return 0;
242+
+}
243+
+static void mygpio_rpmsg_pru_remove(struct rpmsg_device *rpdev)
244+
+{
245+
+ struct rpmsg_pru_dev *prudev;
246+
+ prudev = dev_get_drvdata(&rpdev->dev);
247+
+
248+
+ kfifo_free(&prudev->msg_fifo);
249+
+ gpiochip_remove(&chip);
250+
+
251+
+}
252+
+/*
253+
+ * Matches this tag:If you change .name
254+
+ * PRU firmware should also be updated with same channel name
255+
+ */
256+
+static const struct rpmsg_device_id rpmsg_driver_pru_id_table[] = {
257+
+ { .name = "rpmsg-pru-gpio" },
258+
+ { },
259+
+};
260+
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pru_id_table);
261+
+
262+
+static struct rpmsg_driver rpmsg_pru_driver = {
263+
+ .drv.name = KBUILD_MODNAME,
264+
+ .id_table = rpmsg_driver_pru_id_table,
265+
+ .probe = mygpio_rpmsg_pru_probe,
266+
+ .callback = mygpio_rpmsg_pru_cb,
267+
+ .remove = mygpio_rpmsg_pru_remove,
268+
+};
269+
+
270+
+module_rpmsg_driver(rpmsg_pru_driver);
271+
+MODULE_AUTHOR("DeepankarMaithani <deepankar19910@gmail.com>");
272+
+MODULE_DESCRIPTION("A driver to send rpmsg data using sysfs and chardev interface");
273+
+MODULE_VERSION("0.1");
274+
+MODULE_LICENSE("GPL");
275+
+
276+
--
277+
2.28.0
278+

version.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ KERNEL_REL=4.19
3939
KERNEL_TAG=${KERNEL_REL}.94
4040
kernel_rt=".94-rt39"
4141
#Kernel Build
42-
BUILD=${build_prefix}50
42+
BUILD=${build_prefix}50.1
4343

4444
#v5.X-rcX + upto SHA
4545
#prev_KERNEL_SHA=""

0 commit comments

Comments
 (0)