Files
msm-5.15/drivers/misc/ayn/gpio.c

437 lines
11 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kobject.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <mydebug.h>
#define GPIO_NUM_MAX 4
struct gpio_info{
char name[64];
int pin;
int direction;
int out_def;
};
static struct gpio_info all_gpio_pin[GPIO_NUM_MAX]={
{
.name = "mcu_boot",
.pin = MCU_BOOT,
.direction = GPIO_DIR_OUT,
.out_def = GPIO_OUT_LOW,
},
{
.name = "mcu_reset",
.pin = MCU_RESET,
.direction = GPIO_DIR_OUT,
.out_def = GPIO_OUT_LOW,
},
{
.name = "mcu_pwr",
.pin = MCU_PWR,
.direction = GPIO_DIR_OUT,
.out_def = GPIO_OUT_LOW,
},
{
.name = "mcu_uart_pwr",
.pin = MCU_UART_PWR,
.direction = GPIO_DIR_OUT,
.out_def = GPIO_OUT_LOW,
},
};
static void rs_gpio_request(void)
{
int ret;
int index;
for(index=0; index<GPIO_NUM_MAX; index++){
if (gpio_is_valid(all_gpio_pin[index].pin)) {
ret = gpio_request(all_gpio_pin[index].pin, all_gpio_pin[index].name);
if (ret < 0) {
KERNEL_INFO("Unable to request gpio%d ret=%d\n", all_gpio_pin[index].pin, ret);
gpio_free(all_gpio_pin[index].pin);
}
if(all_gpio_pin[index].direction == GPIO_DIR_IN){
ret = gpio_direction_input(all_gpio_pin[index].pin);
if (ret < 0) {
KERNEL_INFO("Unable to set direction in for gpio%d ret=%d\n", all_gpio_pin[index].pin, ret);
gpio_free(all_gpio_pin[index].pin);
}
} else {
ret = gpio_direction_output(all_gpio_pin[index].pin, all_gpio_pin[index].out_def);
if (ret < 0) {
KERNEL_INFO("Unable to set direction out for gpio%d ret=%d\n", all_gpio_pin[index].pin, ret);
gpio_free(all_gpio_pin[index].pin);
}
}
ret = gpio_export(all_gpio_pin[index].pin, 1); // /sys/class/gpio/gpiox/
if (ret < 0) {
KERNEL_INFO("Unable to export gpio%d ret=%d\n", all_gpio_pin[index].pin, ret);
gpio_free(all_gpio_pin[index].pin);
}
KERNEL_INFO("request gpio%d success ret=%d\n", all_gpio_pin[index].pin, ret);
}
}
}
static void rs_gpio_free(void)
{
int index;
for(index=0; index<GPIO_NUM_MAX; index++){
if (gpio_is_valid(all_gpio_pin[index].pin)) {
gpio_unexport(all_gpio_pin[index].pin);
gpio_free(all_gpio_pin[index].pin);
KERNEL_INFO("free gpio%d success\n", all_gpio_pin[index].pin);
}
}
}
void rs_gpio_set(int pin, int value)
{
int index;
for(index=0; index<GPIO_NUM_MAX; index++){
if(all_gpio_pin[index].pin != pin)
continue;
if (gpio_is_valid(all_gpio_pin[index].pin)) {
gpio_set_value(all_gpio_pin[index].pin, value);
KERNEL_INFO("name:%s %d", all_gpio_pin[index].name, value);
}
break;
}
}
EXPORT_SYMBOL(rs_gpio_set);
int rs_gpio_get(int pin)
{
int index;
int value = -1;
for(index=0; index<GPIO_NUM_MAX; index++){
if(all_gpio_pin[index].pin != pin)
continue;
if (gpio_is_valid(all_gpio_pin[index].pin)) {
value = gpio_get_value(all_gpio_pin[index].pin);
}
break;
}
KERNEL_INFO("name:%s %d", all_gpio_pin[index].name, value);
return value;
}
EXPORT_SYMBOL(rs_gpio_get);
int gpio_index = 0;
// 当用户试图从设备空间读取数据时,调用这个函数
ssize_t rs_gpio_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
{
ssize_t cnt = 0;
char send_msg[64]={0};
if(gpio_index >= GPIO_NUM_MAX){
KERNEL_INFO("ERROR gpio=%d when reading!!\n", gpio_index);
return -EFAULT;
}
sprintf(send_msg, "%u\n", gpio_get_value(all_gpio_pin[gpio_index].pin));;
cnt = copy_to_user(buf, send_msg, sizeof(send_msg));// 将内核空间的数据copy到用户空间
if(cnt){
KERNEL_INFO("ERROR occur when reading!!\n");
return -EFAULT;
}
KERNEL_INFO("name:%s %d", all_gpio_pin[gpio_index].name, gpio_get_value(all_gpio_pin[gpio_index].pin));
return cnt;
}
// 当用户往设备文件写数据时,调用这个函数
// counter 10 intervalgpio 30 intervaladc 30 bufsize 2048 gpiopin 总个数 0 122 124 threshold
ssize_t rs_gpio_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
{
int gpio = 0;
KERNEL_INFO("%s\n", ubuf);
if(!strncmp(ubuf, "SETGPIO ", 8) && count > 8){ // SETGPIO 1 1
gpio = ubuf[8];
if(gpio < GPIO_NUM_MAX){
if (gpio_is_valid(all_gpio_pin[gpio].pin)) {
if(count > 10){
gpio_set_value(all_gpio_pin[gpio].pin, ubuf[10]);
} else {
KERNEL_INFO("error pin=%d", all_gpio_pin[gpio].pin);
}
}
} else {
KERNEL_INFO("error gpio=%d", gpio);
}
}else if(!strncmp(ubuf, "GETGPIO ", 8) && count > 8){ // GETGPIO 1
gpio = ubuf[8];
if(gpio < GPIO_NUM_MAX){
gpio_index = gpio;
}
}
return count;
}
// File opertion 结构体,我们通过这个结构体建立应用程序到内核之间操作的映射
static struct file_operations file_oprts = {
.owner = THIS_MODULE,
.read = rs_gpio_read,
.write = rs_gpio_write,
};
#define DEVICE_NAME "rsgpio" // Device 名称,对应/dev下的目录名称
static struct miscdevice rs_gpio_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &file_oprts
};
/*
static int rs_gpio_suspend(void)
{
bright = 0;
printk("bright %d gpio_get_value(88) = %d \n",bright,gpio_get_value(88));
return 0;
}
static int rs_gpio_resume(void)
{
bright = 1;
printk("bright %d gpio_get_value(88) = %d \n",bright,gpio_get_value(88));
return 0;
}
static struct dev_pm_ops rs_gpio_pm_ops = {
.suspend = rs_gpio_suspend,
.resume = rs_gpio_resume,
};
*/
static void mcu_power_on(void)
{
// Init MCU_Boot = 0 && MCU_Reset = 1'b0
if (gpio_is_valid(MCU_BOOT)) {
gpio_direction_output(MCU_BOOT, GPIO_OUT_LOW);
}
if (gpio_is_valid(MCU_RESET)) {
gpio_direction_output(MCU_RESET, GPIO_OUT_LOW);
}
// Enable MCU 3.3
if (gpio_is_valid(MCU_PWR)) {
gpio_direction_output(MCU_PWR, GPIO_OUT_HIGH);
msleep(20);
}
// Enable OE of AW3911 - Level shifter
if (gpio_is_valid(MCU_UART_PWR)) {
gpio_direction_output(MCU_UART_PWR, GPIO_OUT_HIGH);
msleep(20);
}
if (gpio_is_valid(MCU_RESET)) {
gpio_direction_output(MCU_RESET, GPIO_OUT_HIGH);
}
}
static void mcu_power_off(void)
{
//rs_gpio_set(MCU_PWR, GPIO_OUT_LOW);
if (gpio_is_valid(MCU_PWR)) {
gpio_direction_output(MCU_PWR, GPIO_OUT_LOW);
}
//rs_gpio_set(MCU_UART_PWR, GPIO_OUT_LOW);
if (gpio_is_valid(MCU_UART_PWR)) {
gpio_direction_output(MCU_UART_PWR, GPIO_OUT_LOW);
}
if (gpio_is_valid(MCU_BOOT)) {
gpio_direction_output(MCU_BOOT, GPIO_OUT_LOW);
}
if (gpio_is_valid(MCU_RESET)) {
gpio_direction_output(MCU_RESET, GPIO_OUT_LOW);
}
}
/*
// android_print 表示Android层LOG打印开关
#ifdef CONFIG_ANDROID_LOG_CLOSED
static char android_print = 0; // 0表示不打印user版本的默认不打印
#else
static char android_print = 1; // 1表示打印
#endif
#define LOG_SEEK_OFFSET 8*1024*1024
#define LOG_PATH "/dev/block/sde65"
static int rwdev(char* buf, int len, int flag) {
struct file *log_filp;
mm_segment_t old_fs;
int length=0;
log_filp=filp_open(LOG_PATH,O_RDWR,0);
if(IS_ERR(log_filp)){
KERNEL_ERROR("open %s err:%d !\n",LOG_PATH,PTR_ERR(log_filp));
return -1;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
log_filp->f_op->llseek(log_filp, LOG_SEEK_OFFSET, SEEK_SET);
if(flag==0)
length=vfs_read(log_filp, buf, len, &log_filp->f_pos);
else
length=vfs_write(log_filp, buf, len, &log_filp->f_pos);
set_fs(old_fs);
return length;
}
static int get_log_enable(void) {
char buf[2];
int length = rwdev(buf, 2, 0);
if(length < 2) {
KERNEL_ERROR("get_log_enable %s err!\n",LOG_PATH);
return -1;
}
if(buf[0] == '1') {
if(buf[1] == '1') {
return 1;
} else {
return 0;
}
} else {
return android_print;
}
}
static int write_log_enable(char is_enable) {
char buf[2] = {'1',is_enable};
int length = rwdev(buf, 2, 1);
if(length < 2) {
KERNEL_ERROR("write_log_enable %s err!\n",LOG_PATH);
return -1;
}
return 0;
}
*/
// 添加节点控制
static ssize_t sysfs_set_driver_ctl(struct device *dev, struct device_attribute *attr, const char *ubuf, size_t size)
{
KERNEL_ERROR("cmd_write:%s", ubuf);
if(!strncmp(ubuf, "mcupower ", 9) && size > 9){
if(ubuf[9] == '1'){
// 打开MCU的电
mcu_power_on();
} else {
// 关掉MCU的电
mcu_power_off();
}
} else if(!strncmp(ubuf, "logenable ", 10) && size > 10){
if(ubuf[10] == '1'){
//write_log_enable('1');
} else {
//write_log_enable('0');
}
} else {
KERNEL_ERROR(KERN_ERR "muxcmd error for cmd %s", ubuf);
}
return size;
}
static ssize_t sysfs_get_driver_ctl(struct device *dev, struct device_attribute *attr, char *ubuf)
{
ssize_t size = 0;//sprintf(ubuf, "%d", get_log_enable());
KERNEL_ERROR("cmd_read: size=%d, ubuf=%s", size, ubuf);
return size;
}
static DEVICE_ATTR(driver_ctl, 0644, sysfs_get_driver_ctl, sysfs_set_driver_ctl);
static void rs_gpio_shutdown(struct platform_device *device)
{
KERNEL_INFO("done!");
}
static int rs_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = misc_register(&rs_gpio_misc_device);
if (ret) {
KERNEL_INFO("rs_gpio: Unable to register misc device ret=%d\n", ret);
}
rs_gpio_request();
device_create_file(dev, &dev_attr_driver_ctl);
//mcu_power_on();
KERNEL_INFO("\n");
return ret;
}
static int __exit rs_gpio_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
KERNEL_INFO("\n");
rs_gpio_free();
misc_deregister(&rs_gpio_misc_device);
device_remove_file(dev, &dev_attr_driver_ctl);
return 0;
}
static struct platform_driver rs_gpio_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DEVICE_NAME,
//.pm = &rs_gpio_pm_ops,
},
.shutdown = rs_gpio_shutdown,
.probe = rs_gpio_probe,
.remove = rs_gpio_remove,
};
static struct platform_device rs_gpio_dev = {
.name = DEVICE_NAME,
.id = -1,
};
int __init rs_gpio_init(void)
{
platform_device_register(&rs_gpio_dev);
platform_driver_register(&rs_gpio_driver);
KERNEL_INFO("driver init success!!\n");
return 0;
}
void __exit rs_gpio_exit(void)
{
platform_device_unregister(&rs_gpio_dev);
platform_driver_unregister(&rs_gpio_driver);
KERNEL_INFO("driver %s removed\n", DEVICE_NAME);
}
module_init(rs_gpio_init);
module_exit(rs_gpio_exit);
MODULE_AUTHOR("kevin");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIO driver");