基於linux switch模塊的HDMI檢測狀態驅動

/*
 * drivers\staging\android\switch\switch_hdmiset.c
 *
 * Copyright (C) 2008 Google, Inc.
 * Author: Johnny <[email protected]>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * 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.
 *
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include "switch.h"

#undef SWITCH_DBG
#if (1)
    #define SWITCH_DBG(format,args...)  printk("[SWITCH] "format,##args)    
#else
    #define SWITCH_DBG(...)    
#endif

static unsigned int hdmi_status;

static struct gpio_switch_data {
	struct switch_dev sdev;
	unsigned pio_hdle;
	int state;
	unsigned long delay_time;
	struct delayed_work  hdmi_work;
	struct workqueue_struct *mywork_queue;
	unsigned char switch_flag;
};

static void hdmi_work_func(struct delayed_work  *hdmi_work)
{
	int state = -1;
	
	SWITCH_DBG("enter:%s,line:%d\n", __func__, __LINE__);
	struct gpio_switch_data	*switch_data = container_of(hdmi_work, struct gpio_switch_data, hdmi_work);
	//state = gpio_get_value(switch_data->pio_hdle);//獲取GPIO輸入狀態值
	hdmi_status = gpio_get_value(switch_data->pio_hdle);//獲取GPIO輸入狀態值
	//hdmi_status = 1;
	//switch_set_state(&switch_data->sdev, state);
	
	queue_delayed_work(switch_data->mywork_queue, &switch_data->hdmi_work, switch_data->delay_time);
}

static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
{	
	SWITCH_DBG("enter:%s,line:%d\n", __func__, __LINE__);
	//struct gpio_switch_data	*switch_data =
	//	container_of(sdev, struct gpio_switch_data, sdev);
	return sprintf(buf, "%d\n", hdmi_status);	
}

static int gpio_switch_probe(struct platform_device *pdev)
{
	struct gpio_switch_platform_data *pdata = pdev->dev.platform_data;
	struct gpio_switch_data *switch_data;
	int ret = 0;
	
	SWITCH_DBG("enter:%s,line:%d\n", __func__, __LINE__);
	if (!pdata)
		return -EBUSY;

	switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
	if (!switch_data)
		return -ENOMEM;
	
	switch_data->delay_time = 100;
	switch_data->sdev.name = pdata->name;
	switch_data->pio_hdle = pdata->gpio;
	switch_data->state = 0;
	switch_data->switch_flag = 0;
	switch_data->sdev.print_state = switch_gpio_print_state;
	

#if 1	
	switch_data->pio_hdle = GPIOB(6);
	if(0 != gpio_request(switch_data->pio_hdle, NULL)) {
		    pr_err("ERROR: HDMI request gpio is failed\n");
			//goto err_request_gpio;
    }
	
	ret = gpio_direction_input(switch_data->pio_hdle);
	//if (ret < 0)
		//goto err_set_gpio_input;
#endif
	

	ret = switch_dev_register(&switch_data->sdev);
	if (ret < 0)
		goto err_switch_dev_register;

	
	INIT_DELAYED_WORK(&switch_data->hdmi_work, hdmi_work_func);//初始化工作隊列
	switch_data->mywork_queue = create_singlethread_workqueue("hdmi_gpio");//創建線程mywork_queue
	queue_delayed_work(switch_data->mywork_queue,&switch_data->hdmi_work,switch_data->delay_time);
	
	return 0;


//err_set_gpio_input:
//	gpio_free(switch_data->pio_hdle);
//err_request_gpio:
//	switch_dev_unregister(&switch_data->sdev);
err_switch_dev_register:
	kfree(switch_data);

	return ret;
}

static int switch_resume(struct platform_device *pdev)
{
	struct gpio_switch_data *switch_data;
	
	//switch_data = (struct gpio_switch_data *)platform_get_drvdata(pdev);
	//if (switch_data != NULL) {
	//	queue_delayed_work(switch_data->mywork_queue,&switch_data->hdmi_work,switch_data->delay_time);
	//}
}

static int switch_suspend(struct platform_device *pdev,pm_message_t state)
{
	struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
	
	//cancel_delayed_work_sync(&switch_data->hdmi_work);
	//flush_workqueue(switch_data->mywork_queue);
	
	return 0;
}

static int __devexit gpio_switch_remove(struct platform_device *pdev)
{
	struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);

	//銷燬工作隊列
	cancel_delayed_work_sync(&switch_data->hdmi_work);
	destroy_workqueue(switch_data->mywork_queue);
	gpio_free(switch_data->pio_hdle);
	switch_dev_unregister(&switch_data->sdev);
	kfree(switch_data);

	return 0;
}

static struct platform_driver gpio_switch_driver = {
	.probe		= gpio_switch_probe,
	.remove		= __exit_p(gpio_switch_remove),
	.driver		= {
		.name	= "switch-hdmi",
		.owner	= THIS_MODULE,
	},
	.suspend	= switch_suspend,
	.resume		= switch_resume,
};

static struct gpio_switch_platform_data hdmiset_switch_data = { 
    .name = "hdmi",
};

static struct platform_device gpio_switch_device = { 
    .name = "switch-hdmi",
    .dev = { 
    	.platform_data = &hdmiset_switch_data,
    }   
};

static int __init gpio_switch_init(void)
{
	int ret = 0;
		
	ret = platform_device_register(&gpio_switch_device);
	if (ret == 0) {
		ret = platform_driver_register(&gpio_switch_driver);
	}

	return ret;
}

static void __exit gpio_switch_exit(void)
{
	platform_driver_unregister(&gpio_switch_driver);
	platform_device_unregister(&gpio_switch_device);

}
module_init(gpio_switch_init);
module_exit(gpio_switch_exit);

MODULE_AUTHOR("[email protected]>");
MODULE_DESCRIPTION("Switch driver");
MODULE_LICENSE("GPL");


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章