/* 
 * Copyright (C) 2014 Rockchip Corporation.
 *
 * 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/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/iio/consumer.h>
#include <linux/of.h>
#include "nkio.h"

/* Debug */
#if 1
#define DBG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
#endif

struct ndj_io_pdata *NDJpdata_info;
u32 op0_enable,op1_enable,op2_enable,op3_enable,op4_enable,op5_enable,mic_enable;
u32 ip0_enable,ip1_enable,ip2_enable,ip3_enable,ip4_enable,ip5_enable;
u32 module_enable;
static struct class *ndj_class;

  
static int ndj_io_control_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	struct ndj_io_pdata *pdata;
	int ret;
	int i=0;
	enum of_gpio_flags flags;
	int ch342_reset, ch342_reset_2;
	printk(" ####### NDJ_io_control_probe####### \n");
	
	pdata = kzalloc(sizeof(struct ndj_io_pdata), GFP_KERNEL);
	if (pdata == NULL) {
		printk("%s failed to allocate driver data\n",__FUNCTION__);
		return -ENOMEM;
	}
	memset(pdata,0,sizeof(struct ndj_io_pdata));

	
	//mic_switch_gpio
		ret = of_get_named_gpio_flags(node, "mic_switch_gpio", 0, &flags);
		if (ret < 0) {
				printk("%s() Can not read property mic_switch_gpio\n", __FUNCTION__);
				goto err;
		} else {
				pdata->mic_switch_gpio = ret;
				ret = devm_gpio_request(&pdev->dev, pdata->mic_switch_gpio, "mic_switch_gpio");
				if(ret < 0){
						printk("%s() devm_gpio_request mic_switch_gpio request ERROR\n", __FUNCTION__);
						goto err;
				}
				ret = gpio_direction_output(pdata->mic_switch_gpio,0); 
				mic_enable = 0;
				if(ret < 0){
				printk("%s() gpio_direction_input mic_switch_gpio set ERROR\n", __FUNCTION__);
				goto err;
		}
				}

	//vcc_5v_io
	ret = of_get_named_gpio_flags(node, "vcc_5v_io", 0, &flags);
	if (ret < 0) {
		printk("%s() Can not read property vcc_5v_io\n", __FUNCTION__);
		goto err;
	} else {
		pdata->vcc_5v_io = ret;
		ret = devm_gpio_request(&pdev->dev, pdata->vcc_5v_io, "vcc_5v_io");
		if(ret < 0){
			printk("%s() devm_gpio_request vcc_5v_io request ERROR\n", __FUNCTION__);
			goto err;
		}

		ret = gpio_direction_output(pdata->vcc_5v_io,1); 
		if(ret < 0){
			printk("%s() gpio_direction_output vcc_5v_io set ERROR\n", __FUNCTION__);
			goto err;
		}
	}

		//vcc_12v_io
	ret = of_get_named_gpio_flags(node, "vcc_12v_io", 0, &flags);
	if (ret < 0) {
		printk("%s() Can not read property vcc_12v_io\n", __FUNCTION__);
		goto err;
	} else {
		pdata->vcc_12v_io = ret;
		ret = devm_gpio_request(&pdev->dev, pdata->vcc_12v_io, "vcc_12v_io");
		if(ret < 0){
			printk("%s() devm_gpio_request vcc_12v_io request ERROR\n", __FUNCTION__);
			goto err;
		}

		ret = gpio_direction_output(pdata->vcc_12v_io,1); 
		if(ret < 0){
			printk("%s() gpio_direction_output vcc_12v_io set ERROR\n", __FUNCTION__);
			goto err;
		}
	}
#if 0
		//hub_5V_gpio
	ret = of_get_named_gpio_flags(node, "hub_5V_gpio", 0, &flags);
	if (ret < 0) {
		printk("%s() Can not read property hub_5V_gpio\n", __FUNCTION__);
		goto err;
	} else {
		
		pdata->hub_5V_gpio = ret;
		gpio_free(ret);
		ret = devm_gpio_request(&pdev->dev, pdata->hub_5V_gpio, "hub_5V_gpio");
		if(ret < 0){
			printk("%s() devm_gpio_request hub_5V_gpio request ERROR\n", __FUNCTION__);
			goto err;
		}

		ret = gpio_direction_output(pdata->hub_5V_gpio,1); 
		if(ret < 0){
			printk("%s() gpio_direction_output hub_5V_gpio set ERROR\n", __FUNCTION__);
			goto err;
		}
	}
#endif

	//hub_5V_rest_gpio
	ret = of_get_named_gpio_flags(node, "hub_5V_rest_gpio", 0, &flags);
	if (ret < 0) {
		printk("%s() Can not read property hub_5V_rest_gpio\n", __FUNCTION__);
		goto err;
	} else {
		pdata->hub_5V_rest_gpio = ret;
		ret = devm_gpio_request(&pdev->dev, pdata->hub_5V_rest_gpio, "hub_5V_rest_gpio");
		if(ret < 0){
			printk("%s() devm_gpio_request hub_5V_rest_gpio request ERROR\n", __FUNCTION__);
			goto err;
		}

		ret = gpio_direction_output(pdata->hub_5V_rest_gpio,0); 
		if(ret < 0){
			printk("%s() gpio_direction_output hub_5V_rest_gpio set ERROR\n", __FUNCTION__);
			goto err;
		}
		msleep(800);
		ret = gpio_direction_output(pdata->hub_5V_rest_gpio,1); 
		if(ret < 0){
			printk("%s() gpio_direction_output hub_5V_rest_gpio set ERROR\n", __FUNCTION__);
			goto err;
		}
	}

	   ret = of_get_named_gpio_flags(node, "ch342_power", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property ch342_power\n", __FUNCTION__);
           } else {
                   pdata->ch342_power = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->ch342_power, "wch342_power");
                   if(ret < 0){
                           printk("%s() devm_gpio_request ch342_power request ERROR\n", __FUNCTION__);
                   }
                   ret = gpio_direction_output(pdata->ch342_power,1);
                   if(ret < 0){
                           printk("%s() gpio_direction_input wake_4g_gpio set ERROR\n", __FUNCTION__);
                   }
           }

	#if 1
         // ch342_reset
           ret = of_get_named_gpio_flags(node, "ch342_reset", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property ch342_reset\n", __FUNCTION__);
           } else {
                   pdata->reset_ch342_gpio = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->reset_ch342_gpio, "ch342_reset");
                   if(ret < 0){
                           printk("%s() devm_gpio_request ch342_reset request ERROR\n", __FUNCTION__);
                   }
		
		    ret = gpio_direction_output(pdata->reset_ch342_gpio,0);
                if(ret < 0){
                        printk("%s() gpio_direction_output reset_ch342_gpio set ERROR\n", __FUNCTION__);
                        goto err;
                }
                msleep(200);
                ret = gpio_direction_output(pdata->reset_ch342_gpio,1);
                if(ret < 0){
                        printk("%s() gpio_direction_output reset_ch342_gpio set ERROR\n", __FUNCTION__);
                        goto err;
                }
           }

        ret = of_get_named_gpio_flags(node, "ch342_reset_2", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property ch342_reset_2\n", __FUNCTION__);
           } else {
                   pdata->reset_ch342_gpio_2 = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->reset_ch342_gpio_2, "ch342_reset_2");
                   if(ret < 0){
                           printk("%s() devm_gpio_request ch342_reset request ERROR\n", __FUNCTION__);
                   }
		    ret = gpio_direction_output(pdata->reset_ch342_gpio_2,0);
                if(ret < 0){
                        printk("%s() gpio_direction_output reset_ch342_gpio_2 set ERROR\n", __FUNCTION__);
                        goto err;
                }
                msleep(200);
                ret = gpio_direction_output(pdata->reset_ch342_gpio_2,1);
                if(ret < 0){
                        printk("%s() gpio_direction_output reset_ch342_gpio_2 set ERROR\n", __FUNCTION__);
                        goto err;
                }
           }
#endif
#if 1
           //reset_4g_gpio
           ret = of_get_named_gpio_flags(node, "reset_4g_gpio", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property reset_4g_gpio\n", __FUNCTION__);
           } else {
                   pdata->reset_4g_gpio = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->reset_4g_gpio, "reset_4g_gpio");
                   if(ret < 0){
                           printk("%s() devm_gpio_request reset_4g_gpio request ERROR\n", __FUNCTION__);
                   }
                   ret = gpio_direction_output(pdata->reset_4g_gpio,1);
                   if(ret < 0){
                           printk("%s() gpio_direction_input reset_4g_gpio set ERROR\n", __FUNCTION__);
                   }
	           mdelay(300);
                   ret = gpio_direction_output(pdata->reset_4g_gpio,0);
                   if(ret < 0){
                           printk("%s() gpio_direction_input reset_4g_gpio set ERROR\n", __FUNCTION__);
                   }
           }
#endif

	         //en_4g_gpio
           ret = of_get_named_gpio_flags(node, "en_4g_gpio", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property en_4g_gpio\n", __FUNCTION__);
           } else {
                   pdata->en_4g_gpio = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->en_4g_gpio, "en_4g_gpio");
                   if(ret < 0){
                           printk("%s() devm_gpio_request en_4g_gpio request ERROR\n", __FUNCTION__);
                   }
                   ret = gpio_direction_output(pdata->en_4g_gpio,1);
                   if(ret < 0){
                           printk("%s() gpio_direction_input en_4g_gpio set ERROR\n", __FUNCTION__);
                   }
           }


           //air_mode_4g_gpio
           ret = of_get_named_gpio_flags(node, "air_mode_4g_gpio", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property air_mode_4g_gpio\n", __FUNCTION__);
           } else {
                   pdata->air_mode_4g_gpio = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->air_mode_4g_gpio, "air_mode_4g_gpio");
                   if(ret < 0){
                           printk("%s() devm_gpio_request air_mode_4g_gpio request ERROR\n", __FUNCTION__);
                   }
                   ret = gpio_direction_output(pdata->air_mode_4g_gpio,0);
                   if(ret < 0){
                           printk("%s() gpio_direction_input air_mode_4g_gpio set ERROR\n", __FUNCTION__);
                   }
           }


	  //air_mode_4g_gpio
           ret = of_get_named_gpio_flags(node, "wake_4g_gpio", 0, &flags);
           if (ret < 0) {
                   printk("%s() Can not read property wake_4g_gpio\n", __FUNCTION__);
           } else {
                   pdata->air_mode_4g_gpio = ret;

                   ret = devm_gpio_request(&pdev->dev, pdata->air_mode_4g_gpio, "wake_4g_gpio");
                   if(ret < 0){
                           printk("%s() devm_gpio_request wake_4g_gpio request ERROR\n", __FUNCTION__);
                   }
                   ret = gpio_direction_output(pdata->wake_4g_gpio,0);
                   if(ret < 0){
                           printk("%s() gpio_direction_output wake_4g_gpio set ERROR\n", __FUNCTION__);
                   }
           }



	#if 0
		//audio_switch_gpio
	ret = of_get_named_gpio_flags(node, "audio_switch_gpio", 0, &flags);
	if (ret < 0) {
		printk("%s() Can not read property audio_switch_gpio\n", __FUNCTION__);
		goto err;
	} else {
		pdata->audio_switch_gpio = ret;
		ret = devm_gpio_request(&pdev->dev, pdata->audio_switch_gpio, "audio_switch_gpio");
		if(ret < 0){
			printk("%s() devm_gpio_request audio_switch_gpio request ERROR\n", __FUNCTION__);
			goto err;
		}
            ret = gpio_direction_output(pdata->audio_switch_gpio, !flags); 
		if(ret < 0){
		printk("%s() gpio_direction_input audio_switch_gpio set ERROR\n", __FUNCTION__);
		goto err;
	}
		}
		#endif

//    printk("fan_io_en ....\r\n"); 
    ret = of_get_named_gpio_flags(node, "fan_io_en", 0, &flags);
    if (ret < 0) {
        printk("%s() Can not read property fan_io_en\n", __FUNCTION__);
        goto err;
    } else {
        int gpio = ret;
        ret = devm_gpio_request(&pdev->dev, gpio, "fan_io_en");
        if(ret < 0){
            printk("%s() devm_gpio_request vcc_5v_io request ERROR\n", __FUNCTION__);
            goto err;
        }

        ret = gpio_direction_output(gpio, !flags); 
        if(ret < 0){
            printk("%s() gpio_direction_input fan_io_en set ERROR\n", __FUNCTION__);
            goto err;
        }
    }
 //   printk("fan_io_en ....ok!\r\n"); 

	
	   
	NDJpdata_info = pdata;

	printk(" #######ndj_io_control_probe end####### \n");
	return 0;
err:
	kfree(pdata);
	return ret;
}

static int ndj_io_control_remove(struct platform_device *pdev)
{
	if(NDJpdata_info)
		kfree(NDJpdata_info);
	return 0;
}

static int ndj_io_control_suspend(struct platform_device *pdev, pm_message_t state)
{
	printk("LED_early_suspend LED_early_suspend LED_early_suspend !!!!\n");

	//enable = 0;
	//LED_SET(0);
	return 0;
}

static int ndj_io_control_resume(struct platform_device *pdev)
{
	printk("LED_early_resume LED_early_resume LED_early_resume !!!!\n");

	//enable = 1;
    //LED_SET(11);
	return 0;
}

static const struct of_device_id ndj_io_control_of_match[] = {
        { .compatible = "ndj_io_control", },
        {},
};
MODULE_DEVICE_TABLE(of, ndj_io_control_of_match);

static struct platform_driver ndj_io_control_driver = {
	.probe	= ndj_io_control_probe,
	.remove = ndj_io_control_remove,
	.resume = ndj_io_control_resume,	
	.suspend = ndj_io_control_suspend,	
	.driver	= {
		.name	= "ndj_io_control",
		.owner	= THIS_MODULE,
		.of_match_table = of_match_ptr(ndj_io_control_of_match),		
	},
};

static int __init ndj_io_control_init(void)
{
	platform_driver_register(&ndj_io_control_driver);
	return 0;
}

static void __exit ndj_io_control_exit(void)
{
	platform_driver_unregister(&ndj_io_control_driver);
}

subsys_initcall(ndj_io_control_init);

//late_initcall(ndj_io_control_init);
MODULE_DESCRIPTION("ndj io Core Driver");
MODULE_LICENSE("GPL");
