📄 misc_gpio.c
字号:
/*
* extdrv/peripheral/misc_gpio/msic_gpio.c
*
* Copyright (c) 2006 Hisilicon Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program;
*
* History:
* 10-April-2006 create this file
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/ioctl.h>
#include "hi_gpio.h"
#include "misc_gpio.h"
func_type sd_hook = NULL;
static int sd_state = 0;
unsigned int misc_gpio_major = 0;
static int ch = 0;
static struct timer_list usb_delay_timer;
static struct timer_list sd_delay_timer;
/*
* initalize gpio config
*/
void gpio_init(void)
{
unsigned int tmp;
gpio_dirgetbyte(GPIO_2_PORT,&tmp);
tmp |= 0x44;
tmp &= 0xfd;
/* set gpio_2 dir: in 2、6 out 1 */
gpio_dirsetbyte(GPIO_2_PORT,tmp);
/* set gpio_2 interrupt mode */
gpio_interruptset_byte(
GPIO_2_PORT,
0x02,
SENSE_BOTH,
SENSE_LEVEL,
EVENT_FALLING_EDGE
);
/* disable gpio_2_1 interrupt */
tmp = 0x02;
gpio_interruptdisable_byte(GPIO_2_PORT,tmp);
/* set gpio_2_2、6 low */
writew(0x00,(GPIO_2_PORT_ADDR+0x110));
/* clear the int_flags of gpio_2_1 */
tmp = 0x02;
gpio_interruptclear_byte(GPIO_2_PORT,tmp);
gpio_dirgetbyte(GPIO_3_PORT,&tmp);
tmp |= 0x02;
tmp &= 0xf7;
/* set gpio_3 dir: in 3 out 1 */
gpio_dirsetbyte(GPIO_3_PORT,tmp);
/* set gpio_3 interrupt mode */
gpio_interruptset_byte(
GPIO_3_PORT,
0x08,
SENSE_BOTH,
SENSE_EDGE,
EVENT_FALLING_EDGE
);
/* disable gpio_3_3 interrupt */
tmp = 0x08;
gpio_interruptdisable_byte(GPIO_3_PORT,tmp);
/* if SD card insert, open power gpio_3_1=0. else close power gpio_3_1=1*/
tmp=readw(GPIO_3_PORT_ADDR+0x20);
tmp &= 0x08;
if(!tmp)
writew(0x02,GPIO_3_PORT_ADDR+0x08);
else
writew(0x0,(GPIO_3_PORT_ADDR+0x08));
/* clear the int_flags of gpio_3_3 */
tmp = 0x08;
gpio_interruptclear_byte(GPIO_3_PORT,tmp);
/* enable interrupt gpio_3_3 */
tmp = 0x08;
gpio_interruptenable_byte(GPIO_3_PORT,tmp);
/* enable interrupt gpio_2_1 */
tmp = 0x02;
gpio_interruptenable_byte(GPIO_2_PORT,tmp);
}
/*
* usb power abnormal interrupt handle and start time_list
*/
static irqreturn_t usb_power_ctrl_inth(int irq, void *dev_id, struct pt_regs *reg)
{
unsigned int tmp;
unsigned char current_irq;
int handled = 0;
/* disable usb power abnormal interrupt*/
tmp = 0x02;
gpio_interruptdisable_byte(GPIO_2_PORT,tmp);
current_irq=readw(GPIO_2_PORT_ADDR+GPIO_RIS);
current_irq =current_irq & 0x02;
if (current_irq != 0x02)
{
printk("interrupt num of USB is wrong!\n");
handled = 1;
return IRQ_RETVAL(handled);
}
/* close usb power */
tmp = readw(GPIO_2_PORT_ADDR + 0x10);
tmp ^= 0x04;
writew(tmp,GPIO_2_PORT_ADDR + 0x10);
tmp &= 0x04;
printk("close USB power!\n");
/* set the time to wait */
usb_delay_timer.expires = jiffies + margin_usb;
/* start to wait */
add_timer (&usb_delay_timer);
handled = 1;
return IRQ_RETVAL(handled);
}
/*
* margin_usb later, open usb power
*/
static void usb_delay_timer_handler(unsigned long data)
{
unsigned int tmp;
tmp = 0x02;
gpio_interruptclear_byte (GPIO_2_PORT,tmp);
tmp = readw(GPIO_2_PORT_ADDR + 0x10);
tmp ^= 0x04;
writew(tmp,GPIO_2_PORT_ADDR + 0x10);
printk("open USB power!\n");
tmp = 0x02;
gpio_interruptenable_byte(GPIO_2_PORT,tmp);
}
/*
* sd insert detect interrupt handle and start time_list
*/
static irqreturn_t sd_detect_inth(int irq, void *dev_id, struct pt_regs *reg)
{
unsigned int tmp;
unsigned char current_irq;
int handled = 0;
tmp= 0x08;
gpio_interruptdisable_byte(GPIO_3_PORT,tmp);
current_irq = readw(GPIO_3_PORT_ADDR+GPIO_RIS);
current_irq = current_irq & 0x08;
if (current_irq != 0x08)
{
printk("the interrupt num of SD is wrong!\n");
handled = 1;
return IRQ_RETVAL(handled);
}
/*
tmp = readw(GPIO_3_PORT_ADDR + 0x20);
tmp &= 0x08;
if (!tmp)
{
printk("open SD power!\n");
writew(0x02,GPIO_3_PORT_ADDR+0x08);
sd_state = 1;
if (sd_hook)
sd_hook(sd_state);
}
else
{
printk("close SD power!\n");
writew(0x00,GPIO_3_PORT_ADDR+0x08);
sd_state = 0;
if (sd_hook)
sd_hook(sd_state);
}
*/
sd_delay_timer.expires = jiffies + margin_sd;
add_timer (&sd_delay_timer);
handled = 1;
return IRQ_RETVAL(handled);
}
static void sd_delay_timer_handler(unsigned long data)
{
unsigned int tmp;
tmp = readw(GPIO_3_PORT_ADDR + 0x20);
tmp &= 0x08;
if (!tmp)
{
printk("open SD power!\n");
writew(0x02,GPIO_3_PORT_ADDR+0x08);
sd_state = 1;
if (sd_hook)
sd_hook(sd_state);
}
else
{
printk("close SD power!\n");
writew(0x00,GPIO_3_PORT_ADDR+0x08);
sd_state = 0;
if (sd_hook)
sd_hook(sd_state);
}
tmp = 0x08;
gpio_interruptclear_byte(GPIO_3_PORT,tmp);
tmp = 0x08;
gpio_interruptenable_byte(GPIO_3_PORT,tmp);
}
/*
* open dev, init gpio
*/
static int misc_gpio_open(struct inode *inode ,struct file *file)
{
gpio_init();
return 0;
}
/*
* close device, do nothing
*/
static int misc_gpio_release(struct inode *inode ,struct file *file)
{
return 0;
}
/*
* ioctl method. to choose the Tw2834 or DC by arg
*/
static int twdc_choose_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int tmp;
switch(cmd)
{
case SULL_IOCMISCGPIO:
if (arg == CHOOSE_TW2834)
{
tmp = readw(GPIO_2_PORT_ADDR + 0x100);
tmp &= 0xbf;
writew(tmp,GPIO_2_PORT_ADDR + 0x100);
}
else if(arg == CHOOSE_DC)
{
tmp = readw(GPIO_2_PORT_ADDR + 0x100);
tmp |= 0x40;
writew(tmp,GPIO_2_PORT_ADDR + 0x100);
}
return 0;
default:
return -EINVAL;
}
}
static struct file_operations misc_gpio_fops =
{
owner: THIS_MODULE,
open: misc_gpio_open,
release: misc_gpio_release,
ioctl: twdc_choose_ioctl,
};
int get_sd_state(void)
{
return sd_state;
}
void sd_insert_hook(func_type function_ptr)
{
sd_hook = function_ptr;
}
static struct miscdevice misc_gpio_dev = {
MISC_DYNAMIC_MINOR,
"misc_gpio",
&misc_gpio_fops,
};
static int __init misc_gpio_init(void)
{
int ret;
unsigned int tmp;
ret = misc_register(&misc_gpio_dev);
if (ret)
{
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
gpio_remap();
gpio_init();
init_timer(&usb_delay_timer);
init_timer(&sd_delay_timer);
usb_delay_timer.function = usb_delay_timer_handler;
sd_delay_timer.function = sd_delay_timer_handler;
ret = request_irq(IRQ_2,&usb_power_ctrl_inth,0,"usb_power_int",NULL);
if (ret)
{
del_timer(&usb_delay_timer);
del_timer(&sd_delay_timer);
misc_deregister(&misc_gpio_dev);
gpio_unmap();
printk(DEVICE_NAME " can't request irq(%d)\n",IRQ_2);
return ret;
}
ret = request_irq(IRQ_3,&sd_detect_inth,0,"sd_power_int",NULL);
if (ret)
{
del_timer(&usb_delay_timer);
del_timer(&sd_delay_timer);
free_irq(IRQ_2,NULL);
misc_deregister(&misc_gpio_dev);
gpio_unmap();
printk(DEVICE_NAME " can't request irq(%d)\n",IRQ_2);
return ret;
}
tmp = readw(GPIO_3_PORT_ADDR + 0x20);
tmp &= 0x08;
if (!tmp)
{
printk("open SD power!\n");
writew(0x02,GPIO_3_PORT_ADDR+0x08);
sd_state = 1;
}
else
{
printk("close SD power!\n");
writew(0x00,GPIO_3_PORT_ADDR+0x08);
sd_state = 0;
}
if (ch == 0)
{
tmp = readw(GPIO_2_PORT_ADDR + 0x100);
tmp &= 0xbf;
writew(tmp,GPIO_2_PORT_ADDR + 0x100);
}
else if(ch == 1)
{
tmp = readw(GPIO_2_PORT_ADDR + 0x100);
tmp |= 0x40;
writew(tmp,GPIO_2_PORT_ADDR + 0x100);
}
printk("misc gpio control Driver v1.0\n");
return 0;
}
static void __exit misc_gpio_exit(void)
{
del_timer(&usb_delay_timer);
del_timer(&sd_delay_timer);
free_irq(IRQ_2,NULL);
free_irq(IRQ_3,NULL);
misc_deregister(&misc_gpio_dev);
gpio_unmap();
}
module_init(misc_gpio_init);
module_exit(misc_gpio_exit);
/* input param with insmod. */
module_param(ch, int, 0);
MODULE_PARM_DESC(ch, "'0'for 2834.'1'for DC");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(get_sd_state);
EXPORT_SYMBOL(sd_insert_hook);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -