/**************************************************************************
* I.MX6 driver goto 使用
* 说明:
* 在绝大多数地方,我们都被告诉尽可能不要用goto,甚至都没学过goto,但
* 这种语法却在内核驱动中普遍使用。
*
* 2016-4-13 深圳 南山平山村 曾剑锋
*************************************************************************/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#define SABRESD_VO_PIN IMX_GPIO_NR(1, 4)
#define SABRESD_AMPE_PIN IMX_GPIO_NR(1, 5)
#define SABRESD_SD_PIN IMX_GPIO_NR(1, 19)
#define SABRESD_DT_PIN IMX_GPIO_NR(3, 20)
#define SPK_HEIGHT 66
#define SPK_LOW 67
#define AMP_HEIGHT 68
#define AMP_LOW 69
#define SD_HEIGHT 70
#define SD_LOW 71
#define DETECT 72
#define GPIO_CTRL_DEBUG
#ifdef GPIO_CTRL_DEBUG
#define mDebug(format, ...) printk("File:%s, Function:%s, Line:%d "format, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define mDebug(format, ...)
#endif
static int gpioCtrl_open(struct inode *inode, struct file *file)
{
mDebug("Dev open.\n");
return ;
}
static int gpioCtrl_close(struct inode *inode, struct file *file)
{
mDebug("Dev close.\n");
return ;
}
static ssize_t gpioCtrl_read(struct file *file,
char __user *buf,
size_t count,
loff_t *pos)
{
mDebug("Read data.\n");
return ;
}
static long gpioCtrl_ioctl(struct file * file, unsigned int cmd, unsigned long arg) {
int ret = ;
switch ( cmd ) {
case SPK_HEIGHT :
gpio_set_value(SABRESD_VO_PIN, );
mDebug("SPK_HEIGHT.\n");
break;
case SPK_LOW :
gpio_set_value(SABRESD_VO_PIN, );
mDebug("SPK_LOW.\n");
break;
case AMP_HEIGHT :
gpio_set_value(SABRESD_AMPE_PIN, );
mDebug("AMP_HEIGHT.\n");
break;
case AMP_LOW :
gpio_set_value(SABRESD_AMPE_PIN, );
mDebug("AMP_LOW.\n");
break;
case SD_HEIGHT :
gpio_set_value(SABRESD_SD_PIN, );
mDebug("SD_HEIGHT.\n");
break;
case SD_LOW :
gpio_set_value(SABRESD_SD_PIN, );
mDebug("SD_LOW.\n");
break;
case DETECT :
ret = gpio_get_value(SABRESD_DT_PIN);
(*(int *)arg) = ret;
mDebug("DETECT ret = %d.\n", ret);
ret = ;
break;
default :
mDebug("gpioCtrl control error.\n");
ret = -;
break;
}
return ret;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.open = gpioCtrl_open,
.release = gpioCtrl_close,
.read = gpioCtrl_read,
.unlocked_ioctl = gpioCtrl_ioctl,
};
struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "gpioCtrl",
.fops = &fops,
};
int __init gpioCtrl_init(void)
{
int ret;
ret = gpio_request(SABRESD_VO_PIN, "SABRESD_VO_PIN");
if ( ret ) {
mDebug("get SABRESD_VO_PIN gpio FAILED!\n");
return ret;
}
ret = gpio_request(SABRESD_AMPE_PIN, "SABRESD_AMPE_PIN");
if ( ret ) {
mDebug("get SABRESD_AMPE_PIN gpio FAILED!\n");
goto fail1;
}
ret = gpio_request(SABRESD_SD_PIN, "SABRESD_SD_PIN");
if ( ret ) {
mDebug("get SABRESD_SD_PIN gpio FAILED!\n");
goto fail2;
}
ret = gpio_request(SABRESD_DT_PIN, "SABRESD_DT_PIN");
if ( ret ) {
mDebug("get SABRESD_DETECT gpio FAILED!\n");
goto fail3;
}
gpio_direction_output(SABRESD_VO_PIN, );
gpio_direction_output(SABRESD_AMPE_PIN, );
gpio_direction_output(SABRESD_SD_PIN, );
gpio_direction_input(SABRESD_DT_PIN);
ret = misc_register(&misc);
if(ret) {
mDebug("gpioCtrl_misc_register FAILED!\n");
goto fail4;
}
mDebug("gpioCtrl_misc_register over!\n");
return ret;
fail4:
gpio_free(SABRESD_DT_PIN);
fail3:
gpio_free(SABRESD_SD_PIN);
fail2:
gpio_free(SABRESD_AMPE_PIN);
fail1:
gpio_free(SABRESD_VO_PIN);
return ret;
}
void __exit gpioCtrl_exit(void)
{
gpio_set_value(SABRESD_VO_PIN, );
gpio_set_value(SABRESD_AMPE_PIN, );
gpio_set_value(SABRESD_SD_PIN, );
gpio_free(SABRESD_VO_PIN);
gpio_free(SABRESD_AMPE_PIN);
gpio_free(SABRESD_SD_PIN);
gpio_free(SABRESD_DT_PIN);
misc_deregister(&misc);
}
module_init(gpioCtrl_init);
module_exit(gpioCtrl_exit);
MODULE_LICENSE("GPL");