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:
committed by
Gerrit - the friendly Code Review server
parent
459fb44e93
commit
518e2976b3
@@ -13,6 +13,10 @@
|
|||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/of_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"
|
#include "qrc_core.h"
|
||||||
|
|
||||||
@@ -54,20 +58,114 @@ static int qrc_cdev_release(struct inode *inode, struct file *filp)
|
|||||||
return 0;
|
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,
|
static long qrc_cdev_ioctl(struct file *filp, unsigned int cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
struct qrc_dev *qrc;
|
struct qrc_dev *qdev;
|
||||||
|
|
||||||
qrc = filp->private_data;
|
qdev = filp->private_data;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case FIFO_CLEAR:
|
case QRC_FIFO_CLEAR:
|
||||||
mutex_lock(&qrc->mutex);
|
mutex_lock(&qdev->mutex);
|
||||||
//check kfifo if have data
|
qdev->qrc_ops->qrcops_data_clean(qdev);
|
||||||
mutex_unlock(&qrc->mutex);
|
mutex_unlock(&qdev->mutex);
|
||||||
|
return 0;
|
||||||
break;
|
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:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -186,6 +284,7 @@ int qrc_register_device(struct qrc_dev *qdev, struct device *dev)
|
|||||||
devt = MKDEV(MAJOR(qrc_devt), 0);
|
devt = MKDEV(MAJOR(qrc_devt), 0);
|
||||||
|
|
||||||
cdev_init(&qdev->cdev, &qrc_cdev_fops);
|
cdev_init(&qdev->cdev, &qrc_cdev_fops);
|
||||||
|
ret = qrc_control_gpio_init(qdev, dev->of_node);
|
||||||
|
|
||||||
ret = cdev_add(&qdev->cdev, devt, 1);
|
ret = cdev_add(&qdev->cdev, devt, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -211,5 +310,6 @@ int qrc_register_device(struct qrc_dev *qdev, struct device *dev)
|
|||||||
void qrc_unregister(struct qrc_dev *qdev)
|
void qrc_unregister(struct qrc_dev *qdev)
|
||||||
{
|
{
|
||||||
device_destroy(qrc_class, qdev->dev->devt);
|
device_destroy(qrc_class, qdev->dev->devt);
|
||||||
|
qrc_control_gpio_uninit(qdev);
|
||||||
dev_info(qdev->dev, "qrc drv unregistered\n");
|
dev_info(qdev->dev, "qrc drv unregistered\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <linux/kfifo.h>
|
#include <linux/kfifo.h>
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
#define QRC_NAME_SIZE 30
|
#define QRC_NAME_SIZE 30
|
||||||
#define QRC_INTERFACE_SIZE 30
|
#define QRC_INTERFACE_SIZE 30
|
||||||
@@ -21,6 +22,19 @@
|
|||||||
|
|
||||||
struct qrc_dev;
|
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 {
|
enum qrcdev_state_t {
|
||||||
__STATE_IDLE,
|
__STATE_IDLE,
|
||||||
__STATE_READING,
|
__STATE_READING,
|
||||||
@@ -62,6 +76,7 @@ struct qrc_device_ops {
|
|||||||
int (*qrcops_data_status)
|
int (*qrcops_data_status)
|
||||||
(struct qrc_dev *dev);
|
(struct qrc_dev *dev);
|
||||||
int (*qrcops_config)(struct qrc_dev *dev);
|
int (*qrcops_config)(struct qrc_dev *dev);
|
||||||
|
void (*qrcops_data_clean)(struct qrc_dev *dev);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* qrc char device */
|
/* qrc char device */
|
||||||
@@ -76,6 +91,8 @@ struct qrc_dev {
|
|||||||
struct cdev cdev;
|
struct cdev cdev;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void *data;
|
void *data;
|
||||||
|
int qrc_boot0_gpio;
|
||||||
|
int qrc_reset_gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -168,6 +168,14 @@ static int qrcuart_data_status(struct qrc_dev *dev)
|
|||||||
return kfifo_len(&qrc->qrc_rx_fifo);
|
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,
|
static enum qrcdev_tx qrcuart_xmit(const char __user *buf,
|
||||||
size_t data_length, struct qrc_dev *dev)
|
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_config = qrcuart_config,
|
||||||
.qrcops_setup = qrcuart_setup,
|
.qrcops_setup = qrcuart_setup,
|
||||||
.qrcops_data_status = qrcuart_data_status,
|
.qrcops_data_status = qrcuart_data_status,
|
||||||
|
.qrcops_data_clean = qrcuart_data_clean,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qrcuart_setup(struct qrc_dev *dev)
|
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);
|
serdev_device_set_flow_control(serdev, false);
|
||||||
|
|
||||||
ret = qrc_register_device(qdev, &serdev->dev);
|
ret = qrc_register_device(qdev, &serdev->dev);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("qrcuart: Unable to register qrc device %s\n");
|
pr_err("qrcuart: Unable to register qrc device %s\n");
|
||||||
serdev_device_close(serdev);
|
serdev_device_close(serdev);
|
||||||
|
|||||||
Reference in New Issue
Block a user