misc: add qrc ioctl functions

1,add qrc gpio init functions.
2,add qrc ioctl functions to control gpios.

Change-Id: I539c3d934b6fab1e68e78b910982e482e9f8151f
Signed-off-by: jionzhao <jionzhao@codeaurora.org>
This commit is contained in:
jionzhao
2021-02-05 11:06:56 +08:00
committed by Gerrit - the friendly Code Review server
parent 459fb44e93
commit 518e2976b3
3 changed files with 136 additions and 9 deletions

View File

@@ -13,6 +13,10 @@
#include <linux/poll.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include "qrc_core.h"
@@ -54,20 +58,114 @@ static int qrc_cdev_release(struct inode *inode, struct file *filp)
return 0;
}
/* GPIO control */
static int
qrc_control_gpio_init(struct qrc_dev *qdev, struct device_node *node)
{
int ret;
/* QRC BOOT0 GPIO */
qdev->qrc_boot0_gpio = of_get_named_gpio(node,
"qcom,qrc-boot-gpio", 0);
if (qdev->qrc_boot0_gpio < 0)
pr_err("qrc_boot0_gpio is not available\n");
/* UART RESET GPIO */
qdev->qrc_reset_gpio = of_get_named_gpio(node,
"qcom,qrc-reset-gpio", 0);
if (qdev->qrc_reset_gpio < 0)
pr_err("qrc_reset_gpio is not available\n");
if (gpio_is_valid(qdev->qrc_boot0_gpio)) {
ret = gpio_request(qdev->qrc_boot0_gpio, "QRC_BOOT0_GPIO");
if (unlikely(ret)) {
pr_err("gpio request qrc_boot0_gpio failed for:%d\n",
qdev->qrc_boot0_gpio);
return ret;
}
}
if (gpio_is_valid(qdev->qrc_reset_gpio)) {
ret = gpio_request(qdev->qrc_reset_gpio, "QRC_RESET_GPIO");
if (unlikely(ret)) {
pr_err("gpio request qrc_reset_gpio failed for:%d\n",
qdev->qrc_reset_gpio);
return ret;
}
}
ret = gpio_direction_output(qdev->qrc_reset_gpio, 0);
ret += gpio_export(qdev->qrc_reset_gpio, 0);
if (ret) {
pr_err("Unable to configure GPIO%d (RESET)\n",
qdev->qrc_reset_gpio);
ret = -EBUSY;
gpio_free(qdev->qrc_reset_gpio);
return ret;
}
ret = gpio_direction_output(qdev->qrc_boot0_gpio, 1);
ret += gpio_export(qdev->qrc_boot0_gpio, 0);
if (ret) {
pr_err("Unable to configure GPIO%d (BOOT0)\n",
qdev->qrc_boot0_gpio);
ret = -EBUSY;
gpio_free(qdev->qrc_boot0_gpio);
return ret;
}
/* default config gpio status.boot=1,reset=0 */
gpio_set_value(qdev->qrc_boot0_gpio, 1);
gpio_set_value(qdev->qrc_reset_gpio, 0);
return 0;
}
static void
qrc_control_gpio_uninit(struct qrc_dev *qdev)
{
gpio_free(qdev->qrc_boot0_gpio);
gpio_free(qdev->qrc_reset_gpio);
}
static void qrc_gpio_reboot(struct qrc_dev *qdev)
{
gpio_set_value(qdev->qrc_reset_gpio, 0);
msleep(100);
gpio_set_value(qdev->qrc_reset_gpio, 1);
}
static long qrc_cdev_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct qrc_dev *qrc;
struct qrc_dev *qdev;
qrc = filp->private_data;
qdev = filp->private_data;
switch (cmd) {
case FIFO_CLEAR:
mutex_lock(&qrc->mutex);
//check kfifo if have data
mutex_unlock(&qrc->mutex);
break;
case QRC_FIFO_CLEAR:
mutex_lock(&qdev->mutex);
qdev->qrc_ops->qrcops_data_clean(qdev);
mutex_unlock(&qdev->mutex);
return 0;
case QRC_REBOOT:
if (gpio_is_valid(qdev->qrc_reset_gpio)) {
qrc_gpio_reboot(qdev);
return 0;
} else
return -EFAULT;
case QRC_BOOT_TO_MEM:
if (gpio_is_valid(qdev->qrc_boot0_gpio)) {
gpio_set_value(qdev->qrc_boot0_gpio, 1);
qrc_gpio_reboot(qdev);
return 0;
} else
return -EFAULT;
case QRC_BOOT_TO_FLASH:
if (gpio_is_valid(qdev->qrc_boot0_gpio)) {
gpio_set_value(qdev->qrc_boot0_gpio, 0);
qrc_gpio_reboot(qdev);
return 0;
} else
return -EFAULT;
default:
return -EINVAL;
}
@@ -186,6 +284,7 @@ int qrc_register_device(struct qrc_dev *qdev, struct device *dev)
devt = MKDEV(MAJOR(qrc_devt), 0);
cdev_init(&qdev->cdev, &qrc_cdev_fops);
ret = qrc_control_gpio_init(qdev, dev->of_node);
ret = cdev_add(&qdev->cdev, devt, 1);
if (ret) {
@@ -211,5 +310,6 @@ int qrc_register_device(struct qrc_dev *qdev, struct device *dev)
void qrc_unregister(struct qrc_dev *qdev)
{
device_destroy(qrc_class, qdev->dev->devt);
qrc_control_gpio_uninit(qdev);
dev_info(qdev->dev, "qrc drv unregistered\n");
}

View File

@@ -14,6 +14,7 @@
#include <linux/kfifo.h>
#include <linux/sched/signal.h>
#include <linux/uaccess.h>
#include <linux/ioctl.h>
#define QRC_NAME_SIZE 30
#define QRC_INTERFACE_SIZE 30
@@ -21,6 +22,19 @@
struct qrc_dev;
/* IOCTL commands */
#define QRC_IOC_MAGIC 'q'
/* Clear read fifo */
#define QRC_FIFO_CLEAR _IO(QRC_IOC_MAGIC, 1)
/* Reboot QRC controller */
#define QRC_REBOOT _IO(QRC_IOC_MAGIC, 2)
/* QRC boot from memory */
#define QRC_BOOT_TO_MEM _IO(QRC_IOC_MAGIC, 3)
/* QRC boot from flash */
#define QRC_BOOT_TO_FLASH _IO(QRC_IOC_MAGIC, 4)
enum qrcdev_state_t {
__STATE_IDLE,
__STATE_READING,
@@ -62,6 +76,7 @@ struct qrc_device_ops {
int (*qrcops_data_status)
(struct qrc_dev *dev);
int (*qrcops_config)(struct qrc_dev *dev);
void (*qrcops_data_clean)(struct qrc_dev *dev);
};
/* qrc char device */
@@ -76,6 +91,8 @@ struct qrc_dev {
struct cdev cdev;
struct device *dev;
void *data;
int qrc_boot0_gpio;
int qrc_reset_gpio;
};
/**

View File

@@ -168,6 +168,14 @@ static int qrcuart_data_status(struct qrc_dev *dev)
return kfifo_len(&qrc->qrc_rx_fifo);
}
static void qrcuart_data_clean(struct qrc_dev *dev)
{
struct qrcuart *qrc = qrc_get_data(dev);
kfifo_reset(&qrc->qrc_rx_fifo);
}
static enum qrcdev_tx qrcuart_xmit(const char __user *buf,
size_t data_length, struct qrc_dev *dev)
{
@@ -220,6 +228,7 @@ static const struct qrc_device_ops qrcuart_qrc_ops = {
.qrcops_config = qrcuart_config,
.qrcops_setup = qrcuart_setup,
.qrcops_data_status = qrcuart_data_status,
.qrcops_data_clean = qrcuart_data_clean,
};
static int qrcuart_setup(struct qrc_dev *dev)
@@ -269,6 +278,7 @@ static int qrc_uart_probe(struct serdev_device *serdev)
serdev_device_set_flow_control(serdev, false);
ret = qrc_register_device(qdev, &serdev->dev);
if (ret) {
pr_err("qrcuart: Unable to register qrc device %s\n");
serdev_device_close(serdev);