Skip to content

Commit

Permalink
merge: Rpmsg gpiodrv
Browse files Browse the repository at this point in the history
fixes: beagleboard/linux#247
Signed-off-by: Robert Nelson <[email protected]>
  • Loading branch information
RobertCNelson committed Sep 9, 2020
1 parent 2c3e67e commit ec94960
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 1 deletion.
1 change: 1 addition & 0 deletions patch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ drivers () {
dir 'drivers/uio_pruss_shmem'
dir 'drivers/greybus'
dir 'RPi'
dir 'gsoc'
dir 'fixes'
}

Expand Down
1 change: 1 addition & 0 deletions patches/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5493,6 +5493,7 @@ CONFIG_RPMSG=y
CONFIG_RPMSG_VIRTIO=m
CONFIG_RPMSG_RPC=m
CONFIG_RPMSG_PRU=m
CONFIG_CONFIG_RPMSG_GPIOHIP_INTERFACE=m

#
# Rpmsg virtual device drivers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
From 50ad0fc3083890661113180aa3a849958d0c0787 Mon Sep 17 00:00:00 2001
From: deebot <[email protected]>
Date: Sun, 23 Aug 2020 13:40:44 +0200
Subject: [PATCH] - Added driver to use rpmsg with gpiochip interface.Requires
PRU firmware Please follow instructions to load PRU firmware
https://github.com/deebot/Beaglebone-BidirectionBus/blob/dev/bidirec_299/README.md
- Added rule to compile rpmsg-gpio driver in Make and Kconfig

---
drivers/rpmsg/Kconfig | 12 ++
drivers/rpmsg/Makefile | 2 +
drivers/rpmsg/rpmsg_gpio.c | 222 +++++++++++++++++++++++++++++++++++++
3 files changed, 236 insertions(+)
create mode 100644 drivers/rpmsg/rpmsg_gpio.c

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index c41d8157b079..ef2c47c017bb 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -81,4 +81,16 @@ config RPMSG_PRU

If unsure, say N.

+config CONFIG_RPMSG_GPIOHIP_INTERFACE
+ tristate "A rpmsg driver with gpiochip interface"
+ default m
+ depends on RPMSG_VIRTIO
+ depends on REMOTEPROC
+ help
+ This driver provides provides gpiochip inteface which can be accessed
+ in userspace using libgpiod. You would see a char dev interface in
+ "/dev" using this driver. Follow the README from the following
+ repo for more info.
+ https://github.com/deebot/Beaglebone-BidirectionBus
+
endmenu
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 6666c8d6327e..3b93ea58ae36 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -9,4 +9,6 @@ obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o

obj-$(CONFIG_RPMSG_RPC) += rpmsg-rpc.o
+obj-$(CONFIG_RPMSG_GPIOCHIP_INTERFACE) += rpmsg_gpio.o
rpmsg-rpc-y := rpmsg_rpc.o rpmsg_rpc_sysfs.o rpmsg_rpc_dmabuf.o
+
diff --git a/drivers/rpmsg/rpmsg_gpio.c b/drivers/rpmsg/rpmsg_gpio.c
new file mode 100644
index 000000000000..92fd7e517c3c
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_gpio.c
@@ -0,0 +1,222 @@
+/*
+ * PRU Remote Processor Messaging Driver with gpiochip interface
+ * copyright (c) 2020 Deepankar Maithani
+ * Codes examples from Lab no 5 from TI and has been used as boiler plate for rpmsg communication
+ * https://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs
+ *
+ * For learn more about the complete project visit:
+ * https://github.com/deebot/Beaglebone-BidirectionBus/tree/dev
+ * Steps to test the driver.
+ * https://github.com/deebot/Beaglebone-BidirectionBus/blob/dev/bidirec_299/README.md
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/rpmsg.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kfifo.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/rpmsg/virtio_rpmsg.h>
+#include <linux/stat.h>
+#include <linux/bitops.h>
+#define PRU_MAX_DEVICES (16)
+/* Matches the definition in virtio_rpmsg_bus.c */
+#define RPMSG_BUF_SIZE (512)
+#define MAX_FIFO_MSG (32)
+#define FIFO_MSG_SIZE RPMSG_BUF_SIZE
+#define GPIO_NUM 9
+static DEFINE_MUTEX(rpmsg_pru_lock);
+static char rpmsg_pru_buf[RPMSG_BUF_SIZE];
+static struct gpio_chip chip;
+struct rpmsg_pru_dev {
+ struct rpmsg_device *rpdev;
+ struct device *dev;
+ bool locked;
+ dev_t devt;
+ struct kfifo msg_fifo;
+ u32 msg_len[MAX_FIFO_MSG];
+ int msg_idx_rd;
+ int msg_idx_wr;
+ wait_queue_head_t wait_list;
+ uint32_t gpio_state;
+ long input_state;
+
+};
+
+struct rpmsg_pru_dev *prudev;
+/*Reads the lines which are set as input*/
+static int mygpio_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ uint32_t value;
+ struct rpmsg_device *rpdev = container_of(gc->parent,
+ struct rpmsg_device, dev);
+ unsigned int mask = BIT(offset % 8);
+ prudev = dev_get_drvdata(&rpdev->dev);
+
+ value = (prudev->input_state & mask)>>offset;
+ return value;
+}
+/* Writes to the lines and creates the gpio_state which is then sent as RPmsg */
+static void mygpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+ int ret;
+ struct rpmsg_device *rpdev = container_of(gc->parent, struct rpmsg_device, dev);
+ pr_info("set_value function triggered");
+ pr_info("The bit number %d is set to value: %d", offset, val);
+
+ prudev = dev_get_drvdata(&rpdev->dev);
+ if (val == 0) {
+ prudev->gpio_state &= ~(1<<offset);
+ } else {
+ prudev->gpio_state |= (1<<offset);
+ }
+ if (offset == GPIO_NUM-1) {
+ /* copy the gpiostate in rpmsg buffer which will be sent over to PRU*/
+ memcpy((void *)&rpmsg_pru_buf, (void *)&(prudev->gpio_state),
+ sizeof(&(prudev->gpio_state)));
+ pr_info("A check for checking gpio_state: %d",
+ prudev->gpio_state);
+ /* This line actually sends the data to the other side*/
+ ret = rpmsg_send(rpdev->ept, (void *)rpmsg_pru_buf, 2);
+ if (ret)
+ dev_err(gc->parent, "rpmsg_send failed: %d\n", ret);
+ }
+
+}
+
+/*sets the pin to output. Will be called when user sets one
+ * of the gpiochip line as output which can be done manually
+ * in sysfs or using libgpiod */
+
+static int mygpio_direction_output(struct gpio_chip *gc,
+ unsigned offset, int val)
+{
+ pr_info("Direction of GPIO set to: out\n");
+ return 0;
+}
+/*Runs When direction of a line is set as output*/
+static int mygpio_direction_input(struct gpio_chip *gc,
+ unsigned offset)
+{
+
+ pr_info("Direction of GPIO set to: in \n");
+ return 0;
+}
+/*This function gets called every time
+ *an rpmsg_channel is created with a name that matches the .name
+ *attribute of the rpmsg_driver_sample_id_table. It sets up suitable memory
+ *and the gpiochip interface that can be seen in /sys/class/gpio and /dev.
+ */
+static int mygpio_rpmsg_pru_probe (struct rpmsg_device *rpdev)
+{
+ int ret;
+ struct rpmsg_pru_dev *prudev;
+ prudev = devm_kzalloc(&rpdev->dev, sizeof(*prudev), GFP_KERNEL);
+ if (!prudev)
+ return -ENOMEM;
+ prudev->rpdev = rpdev;
+ ret = kfifo_alloc(&prudev->msg_fifo, MAX_FIFO_MSG * FIFO_MSG_SIZE,
+ GFP_KERNEL);
+ if (ret) {
+ dev_err(&rpdev->dev, "Unable to allocate fifo for the rpmsg_pru device\n");
+ return -ENOMEM;
+ }
+ init_waitqueue_head(&prudev->wait_list);
+ dev_set_drvdata(&rpdev->dev, prudev);
+ chip.label = rpdev->desc;
+ chip.base = -1;
+ chip.parent = &rpdev->dev;
+ chip.owner = THIS_MODULE;
+ chip.ngpio = GPIO_NUM;
+ chip.can_sleep = 1;
+ chip.get = mygpio_get_value;
+ chip.set = mygpio_set_value;
+ chip.direction_output = mygpio_direction_output;
+ chip.direction_input = mygpio_direction_input;
+ return gpiochip_add(&chip);
+}
+/* Callback function which gets called whenever a new rpmsg is received
+ * The data received from the PRU is converted into long and then assigned to
+ * input_state
+ * @msg_fifo: kernel fifo used to buffer the messages between userspace and PRU
+ * @msg_len: array storing the lengths of each message in the kernel fifo
+ * @msg_idx_rd: kernel fifo read index
+ * @msg_idx_wr: kernel fifo write index
+ * */
+static int mygpio_rpmsg_pru_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
+{ int ret;
+ u32 length;
+ struct rpmsg_pru_dev *prudev;
+
+ prudev = dev_get_drvdata(&rpdev->dev);
+
+ if (kfifo_avail(&prudev->msg_fifo) < len) {
+ dev_err(&rpdev->dev, "Not enough space on the FIFO\n");
+ return -ENOSPC;
+ }
+
+ if ((prudev->msg_idx_wr + 1) % MAX_FIFO_MSG ==
+ prudev->msg_idx_rd) {
+ dev_err(&rpdev->dev, "Message length table is full\n");
+ return -ENOSPC;
+ }
+ /* adds the data received into a fifo*/
+ length = kfifo_in(&prudev->msg_fifo, data, len);
+ prudev->msg_len[prudev->msg_idx_wr] = length;
+ prudev->msg_idx_wr = (prudev->msg_idx_wr + 1) % MAX_FIFO_MSG;
+
+ wake_up_interruptible(&prudev->wait_list);
+ ret = kstrtol((char *) data, 10, &prudev->input_state);
+ if (ret) {
+ return ret;
+ }
+ pr_info("The shift register port state is: %ld", prudev->input_state);
+ return 0;
+}
+static void mygpio_rpmsg_pru_remove(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_pru_dev *prudev;
+ prudev = dev_get_drvdata(&rpdev->dev);
+
+ kfifo_free(&prudev->msg_fifo);
+ gpiochip_remove(&chip);
+
+}
+/*
+ * Matches this tag:If you change .name
+ * PRU firmware should also be updated with same channel name
+ */
+static const struct rpmsg_device_id rpmsg_driver_pru_id_table[] = {
+ { .name = "rpmsg-pru-gpio" },
+ { },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pru_id_table);
+
+static struct rpmsg_driver rpmsg_pru_driver = {
+ .drv.name = KBUILD_MODNAME,
+ .id_table = rpmsg_driver_pru_id_table,
+ .probe = mygpio_rpmsg_pru_probe,
+ .callback = mygpio_rpmsg_pru_cb,
+ .remove = mygpio_rpmsg_pru_remove,
+};
+
+module_rpmsg_driver(rpmsg_pru_driver);
+MODULE_AUTHOR("DeepankarMaithani <[email protected]>");
+MODULE_DESCRIPTION("A driver to send rpmsg data using sysfs and chardev interface");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+
--
2.28.0

2 changes: 1 addition & 1 deletion version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ KERNEL_REL=4.19
KERNEL_TAG=${KERNEL_REL}.94
kernel_rt=".94-rt39"
#Kernel Build
BUILD=${build_prefix}50
BUILD=${build_prefix}50.1

#v5.X-rcX + upto SHA
#prev_KERNEL_SHA=""
Expand Down

0 comments on commit ec94960

Please sign in to comment.