From b9094677f7a1a4b6df741e59fb7f55eaa5f5836c Mon Sep 17 00:00:00 2001 From: CMY Date: Mon, 18 Jul 2011 17:59:11 +0800 Subject: [PATCH] =?utf8?q?=E6=96=B0=E7=9A=84modem=E9=A9=B1=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- drivers/misc/rk29_modem/Kconfig | 33 +- drivers/misc/rk29_modem/Makefile | 19 +- .../misc/rk29_modem/modem_longcheer_u6300v.c | 168 +++++++ drivers/misc/rk29_modem/modem_rockchip_demo.c | 154 ++---- .../misc/rk29_modem/modem_thinkwill_mw100g.c | 130 +++++ drivers/misc/rk29_modem/rk29_modem.c | 466 ++++++++++++------ drivers/misc/rk29_modem/rk29_modem.h | 92 ++-- 7 files changed, 726 insertions(+), 336 deletions(-) create mode 100644 drivers/misc/rk29_modem/modem_longcheer_u6300v.c mode change 100755 => 100644 drivers/misc/rk29_modem/modem_rockchip_demo.c create mode 100644 drivers/misc/rk29_modem/modem_thinkwill_mw100g.c mode change 100755 => 100644 drivers/misc/rk29_modem/rk29_modem.c mode change 100755 => 100644 drivers/misc/rk29_modem/rk29_modem.h diff --git a/drivers/misc/rk29_modem/Kconfig b/drivers/misc/rk29_modem/Kconfig index 70113c1f164b..9e11339a5bc5 100644 --- a/drivers/misc/rk29_modem/Kconfig +++ b/drivers/misc/rk29_modem/Kconfig @@ -4,7 +4,7 @@ menuconfig RK29_SUPPORT_MODEM tristate "RK29 support Modem" - depends on USB11_HOST_EN +# depends on USB11_HOST_EN ---help--- Say Y here if you have a support modem @@ -12,35 +12,14 @@ choice depends on RK29_SUPPORT_MODEM prompt "Select 3G Modem" - config MODEM_ROCKCHIP_DEMO + config MODEM_ROCKCHIP_DEMO bool "ROCKCHIP_GENERAL_MODEM_DEVICE" -# config MODEM_ZTE_MG3732 -# bool "ZTE_MG3732" + config MODEM_LONGCHEER_U6300V + bool "LONGCHEER_U6300V" -#config MODEM_ZTE_MF210 -# bool "ZTE_MF210" - -#config MODEM_ZTE_AD3812 -# bool "ZTE_AD3812" - -#config MODEM_THINKWILL_ME800 -# bool "THINKWILL_ME800" - -#config MODEM_HUAWEI_EM660 -# bool "HUAWEI_EM660" - -#config MODEM_HUAWEI_EM770 -# bool "HUAWEI_EM770" - -#config MODEM_HUAWEI_EM660C - # bool "HUAWEI_EM660C" - -#config MODEM_ZTE_MU301 -# bool "ZTE_MU301" - -#config MODEM_TDM_330 -# bool "TDM_330" + config MODEM_THINKWILL_MW100G + bool "THINKWILL_MW100G" endchoice diff --git a/drivers/misc/rk29_modem/Makefile b/drivers/misc/rk29_modem/Makefile index 6d5c5ad49636..a98c411d53ae 100644 --- a/drivers/misc/rk29_modem/Makefile +++ b/drivers/misc/rk29_modem/Makefile @@ -1,16 +1,5 @@ -obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem.o - -obj-$(CONFIG_MODEM_ROCKCHIP_DEMO) +=modem_rockchip_demo.o - -obj-$(CONFIG_MODEM_ZTE_MG3732) +=modem_zte_mg3732.o - -#obj-$(CONFIG_MODEM_ZTE_MF210) += modem_zte_mf210.o -#obj-$(CONFIG_MODEM_ZTE_AD3812) += modem_zte_ad3812.o -#obj-$(CONFIG_MODEM_THINKWILL_ME800) += modem_thinkwill_me800.o -#obj-$(CONFIG_MODEM_HUAWEI_EM660) += modem_huawei_em660.o -#obj-$(CONFIG_MODEM_HUAWEI_EM770) += modem_huawei_em770.o -#obj-$(CONFIG_MODEM_HUAWEI_EM660C) += modem_huawei_em660c.o -#obj-$(CONFIG_MODEM_ZTE_MU301) += modem_zte_mu301.o -#obj-$(CONFIG_MODEM_TDM_330) += modem_tdm_330.o - +obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem.o +obj-$(CONFIG_MODEM_ROCKCHIP_DEMO) += modem_rockchip_demo.o +obj-$(CONFIG_MODEM_LONGCHEER_U6300V) +=modem_longcheer_u6300v.o +obj-$(CONFIG_MODEM_THINKWILL_MW100G) +=modem_thinkwill_mw100g.o diff --git a/drivers/misc/rk29_modem/modem_longcheer_u6300v.c b/drivers/misc/rk29_modem/modem_longcheer_u6300v.c new file mode 100644 index 000000000000..350ae34df333 --- /dev/null +++ b/drivers/misc/rk29_modem/modem_longcheer_u6300v.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include /* permission constants */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "rk29_modem.h" + +// È·±£²»³öÏÖÖظ´´¦Àíwakeup +static int do_wakeup_handle = 0; +static irqreturn_t u6300v_irq_handler(int irq, void *dev_id); +static int __devinit u6300v_resume(struct platform_device *pdev); + +static struct rk29_io_t u6300v_io_ap_ready = { + .io_addr = RK29_PIN3_PC2, + .enable = GPIO_LOW, + .disable = GPIO_HIGH, +}; + +static struct rk29_io_t u6300v_io_power = { + .io_addr = RK29_PIN6_PB1, + .enable = GPIO_HIGH, + .disable = GPIO_LOW, +}; + +static struct rk29_irq_t u6300v_irq_bp_wakeup_ap= { + .irq_addr = RK29_PIN3_PD7, + .irq_trigger = IRQF_TRIGGER_FALLING, // ϽµÑØ´¥·¢ +}; + +static struct platform_driver u6300v_platform_driver = { + .driver = { + .name = "longcheer_u6300v", + }, + .suspend = rk29_modem_suspend, + .resume = rk29_modem_resume, +}; + +static struct rk29_modem_t u6300v_driver = { + .driver = &u6300v_platform_driver, + .modem_power = &u6300v_io_power, + .ap_ready = &u6300v_io_ap_ready, + .bp_wakeup_ap = &u6300v_irq_bp_wakeup_ap, + .status = MODEM_ENABLE, + .dev_init = NULL, + .dev_uninit = NULL, + .irq_handler = u6300v_irq_handler, + .suspend = NULL, + .resume = u6300v_resume, + + .enable = NULL, + .disable = NULL, + .sleep = NULL, + .wakeup = NULL, +}; + +static void do_test1(struct work_struct *work) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + // ±êÖ¾APÒѾÍÐ÷£¬BB¿ÉÒÔÉϱ¨Êý¾Ý¸øAP + gpio_direction_output(u6300v_driver.ap_ready->io_addr, u6300v_driver.ap_ready->enable); +} + +static DECLARE_DELAYED_WORK(test1, do_test1); + +static int __devinit u6300v_resume(struct platform_device *pdev) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + +/* cmy: Ä¿Ç°ÔÚϵͳ±»»½ÐѺó£¬ÔÚÕâ±ßÉèÖÃAP_RDY£¬µ«ÓÉÓÚͨÐÅÒÀÀµÓÚÆäËüµÄÉ豸Çý¶¯(±ÈÈçUSB»òÕß´®¿Ú) + ÐèÒªÑÓʱÉèÖÃAP_RDYÐźŠ+ ¸üºÃµÄ×ö·¨ÊÇÔÚËüËùÒÀÀµµÄÉ豸¾ÍÐ÷ºó(»½ÐÑ)£¬ÔÙÉèÖÃAP_RDY¡£×ö·¨Á½ÖÖ: + 1 ½«ÉèÖÃAP_RDYµÄº¯Êý×¢È뵽Ŀ±êÉ豸µÄresumeº¯ÊýÖÐ + 2 ÔÚrk29_modem_resumeÖУ¬µÈ´ýÄ¿±êÉ豸resumeÖ®ºó£¬ÔÙÉèÖÃAP_RDY + */ + schedule_delayed_work(&test1, 2*HZ); + + return 0; +} + +/* + u6300v Ä£×éµÄ IRQ ´¦Àíº¯Êý£¬¸Ãº¯ÊýÓÉrk29_modemÖеÄIRQ´¦Àíº¯Êýµ÷Óà + */ +static irqreturn_t u6300v_irq_handler(int irq, void *dev_id) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + if( irq == gpio_to_irq(u6300v_driver.bp_wakeup_ap->irq_addr) ) + { + if( !do_wakeup_handle ) + { + do_wakeup_handle = 1; + // µ±½ÓÊÕµ½ bb wakeup ap µÄIRQºó£¬ÉêÇëÒ»¸ö8ÃëµÄsuspendËø£¬Ê±¼äµ½ºó×Ô¶¯ÊÍ·Å + // ÊÍ·ÅʱÈç¹ûûÓÐÆäËüµÄËø£¬¾Í½«ÔٴιÒÆð. + wake_lock_timeout(&u6300v_driver.wakelock_bbwakeupap, 8 * HZ); + } else + printk("%s: already wakeup\n", __FUNCTION__); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int __init u6300v_init(void) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + return rk29_modem_init(&u6300v_driver); +} + +static void __exit u6300v_exit(void) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + rk29_modem_exit(); +} + +module_init(u6300v_init); +module_exit(u6300v_exit); + +MODULE_AUTHOR("lintao lintao@rock-chips.com"); +MODULE_DESCRIPTION("ROCKCHIP modem driver"); +MODULE_LICENSE("GPL"); + +#if 0 +int test(void) +{ + printk(">>>>>> test \n "); + int ret = gpio_request(IRQ_BB_WAKEUP_AP, NULL); + if(ret != 0) + { + printk(">>>>>> gpio_request failed! \n "); + gpio_free(IRQ_BB_WAKEUP_AP); + return ret; + } + +// printk(">>>>>> set GPIOPullUp \n "); +// gpio_pull_updown(IRQ_BB_WAKEUP_AP, GPIOPullUp); +// printk(">>>>>> set GPIO_HIGH \n "); +// gpio_direction_output(IRQ_BB_WAKEUP_AP, GPIO_HIGH); + +// printk(">>>>>> set GPIO_LOW \n "); +// gpio_direction_output(IRQ_BB_WAKEUP_AP, GPIO_LOW); +// msleep(1000); + + gpio_free(IRQ_BB_WAKEUP_AP); + + printk(">>>>>> END \n "); +} +#endif + diff --git a/drivers/misc/rk29_modem/modem_rockchip_demo.c b/drivers/misc/rk29_modem/modem_rockchip_demo.c old mode 100755 new mode 100644 index c5e6a68eb3a5..7a3fff84eee4 --- a/drivers/misc/rk29_modem/modem_rockchip_demo.c +++ b/drivers/misc/rk29_modem/modem_rockchip_demo.c @@ -5,142 +5,70 @@ #include #include #include -#include /* permission constants */ +#include #include #include #include #include #include #include -//#include #include -#include "rk29_modem.h" - -/**************************************************************** - huawei-em660/em660c/em770 - zte-ad3812/mf210/mu301 - thinkwill-me800 - -*****************************************************************/ - -static int modem_enable(void){ - printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); - // PG1: 3G reset - /*arch/arm/mach-rockchip/iomux.c*/ -// rockchip_mux_api_set(G3_RESET_IOMUX_NAME, G3_RESET_IOMUX_MODE); - // PB0: 3G poweron -// rockchip_mux_api_set(G3_POWER_ON_IOMUX_NAME, G3_POWER_ON_IOMUX_MODE); - // PG0: 3G Radio On/Off -// rockchip_mux_api_set(G3_RADIO_ON_OFF_IOMUX_NAME, G3_RADIO_ON_OFF_IOMUX_MODE); -// msleep(10); - - /*3G Modem Power On*/ - int ret = gpio_request(G3_POWER_ON, NULL); - if(ret != 0) - { - gpio_free(G3_POWER_ON); - printk(">>>>>> G3_POWER_ON gpio_request err \n "); - return ret; - } - gpio_direction_output(G3_POWER_ON, G3_POWER_ENABLE); -// gpio_set_value(FB_LCD_CABC_EN_PIN, GPIO_LOW); - -// GPIOSetPinDirection(G3_POWER_ON, GPIO_OUT); -// GPIOSetPinLevel(G3_POWER_ON, G3_POWER_ENABLE); - msleep(100); - gpio_free(G3_POWER_ON); - - /*3G Modem Radio On*/ -// GPIOSetPinDirection(G3_RADIO_ON_OFF, GPIO_OUT); -// GPIOSetPinLevel(G3_RADIO_ON_OFF, G3_RADIO_ENABLE); -// msleep(100); - - /*3G Modem Reset Controll if needed*/ -// if(G3_RESET){ -// GPIOSetPinDirection(G3_RESET, GPIO_OUT); -// GPIOSetPinLevel(G3_RESET, G3_RESET_ENABLE); -// msleep(120); -// GPIOSetPinLevel(G3_RESET, G3_RESET_DISABLE); -// } - return 0; -} - -static int modem_disable(void){ - printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); - // PG1: 3G reset -// rockchip_mux_api_set(G3_RESET_IOMUX_NAME, G3_RESET_IOMUX_MODE); - // PB0: 3G poweron -// rockchip_mux_api_set(G3_POWER_ON_IOMUX_NAME, G3_POWER_ON_IOMUX_MODE); - // PG0: 3G On/Off -// rockchip_mux_api_set(G3_RADIO_ON_OFF_IOMUX_NAME, G3_RADIO_ON_OFF_IOMUX_MODE); -// msleep(10); - -#if 1 - int ret = gpio_request(G3_POWER_ON, NULL); - if(ret != 0) - { - gpio_free(G3_POWER_ON); - printk(">>>>>> G3_POWER_ON gpio_request err \n "); - return ret; - } - gpio_direction_output(G3_POWER_ON, G3_POWER_DISABLE); -#else - /*3G Modem Power off*/ - GPIOSetPinDirection(G3_POWER_ON, GPIO_OUT); - GPIOSetPinLevel(G3_POWER_ON, G3_POWER_DISABLE); -#endif - msleep(100); - gpio_free(G3_POWER_ON); +#include +#include +#include +#include +#include - /*3G Modem Radio off*/ -// GPIOSetPinDirection(G3_RADIO_ON_OFF, GPIO_OUT); -// GPIOSetPinLevel(G3_RADIO_ON_OFF, G3_RADIO_DISABLE); -// msleep(10); +#include - /*3G Modem Reset enable if needed*/ -// if(G3_RESET){ -// GPIOSetPinDirection(G3_RESET, GPIO_OUT); -// GPIOSetPinLevel(G3_RESET, G3_RESET_ENABLE); -// } - return 0; -} +#include "rk29_modem.h" -static int modem_sleep(void){ - printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); - - return 0; -} +static struct rk29_io_t demo_io_power = { + .io_addr = RK29_PIN6_PB1, + .enable = GPIO_HIGH, + .disable = GPIO_LOW, +}; -static int modem_init(void){ - return modem_disable(); -} +static struct platform_driver demo_platform_driver = { + .driver = { + .name = "rk29_demo", + }, +}; -struct rk29_modem_t rk29_modem = { - .name = "ThinkWill_ME800", - .enable = modem_enable, - .disable = modem_disable, - .sleep = modem_sleep, - .init = modem_init, +static struct rk29_modem_t demo_driver = { + .driver = &demo_platform_driver, + .modem_power = &demo_io_power, + .ap_ready = NULL, + .bp_wakeup_ap = NULL, + .status = MODEM_ENABLE, + .dev_init = NULL, + .dev_uninit = NULL, + .irq_handler = NULL, + + .enable = NULL, + .disable = NULL, + .sleep = NULL, + .wakeup = NULL, }; -static int __init rk29_modem_init(void) +static int __init demo_init(void) { - return rk29_modem_register(&rk29_modem); + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + return rk29_modem_init(&demo_driver); } -static void __exit rk29_modem_exit(void) +static void __exit demo_exit(void) { - rk29_modem_unregister(&rk29_modem); + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + rk29_modem_exit(); } - -late_initcall(rk29_modem_init); -//module_init(rk29_modem_init); -module_exit(rk29_modem_exit); +module_init(demo_init); +module_exit(demo_exit); MODULE_AUTHOR("lintao lintao@rock-chips.com"); MODULE_DESCRIPTION("ROCKCHIP modem driver"); MODULE_LICENSE("GPL"); - diff --git a/drivers/misc/rk29_modem/modem_thinkwill_mw100g.c b/drivers/misc/rk29_modem/modem_thinkwill_mw100g.c new file mode 100644 index 000000000000..182fbf4e86d8 --- /dev/null +++ b/drivers/misc/rk29_modem/modem_thinkwill_mw100g.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include +#include /* permission constants */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "rk29_modem.h" + +// È·±£²»³öÏÖÖظ´´¦Àíwakeup +static int do_wakeup_handle = 0; +static irqreturn_t mw100g_irq_handler(int irq, void *dev_id); + +static int __devinit mw100g_suspend(struct platform_device *pdev, pm_message_t state) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + do_wakeup_handle = 0; + return rk29_modem_suspend(pdev, state); +} + +static int __devinit mw100g_resume(struct platform_device *pdev) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + return rk29_modem_resume(pdev); +} + +static struct rk29_io_t mw100g_io_power = { + .io_addr = RK29_PIN6_PB1, + .enable = GPIO_HIGH, + .disable = GPIO_LOW, +}; + +static struct rk29_irq_t mw100g_irq_bp_wakeup_ap= { + .irq_addr = RK29_PIN3_PC4, + .irq_trigger = IRQF_TRIGGER_FALLING, // ϽµÑØ´¥·¢ +}; + +static struct platform_driver mw100g_platform_driver = { + .driver = { + .name = "thinkwill_mw100g", + }, + .suspend = mw100g_suspend, + .resume = mw100g_resume, +}; + +static struct rk29_modem_t mw100g_driver = { + .driver = &mw100g_platform_driver, + .modem_power = &mw100g_io_power, + .ap_ready = NULL, + .bp_wakeup_ap = &mw100g_irq_bp_wakeup_ap, + .status = MODEM_ENABLE, + .dev_init = NULL, + .dev_uninit = NULL, + .irq_handler = mw100g_irq_handler, + + .enable = NULL, + .disable = NULL, + .sleep = NULL, + .wakeup = NULL, +}; + +static void do_wakeup(struct work_struct *work) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); +// rk28_send_wakeup_key(); +} + +static DECLARE_DELAYED_WORK(wakeup_work, do_wakeup); + +/* + mw100g Ä£×éµÄ IRQ ´¦Àíº¯Êý£¬¸Ãº¯ÊýÓÉrk29_modemÖеÄIRQ´¦Àíº¯Êýµ÷Óà + */ +static irqreturn_t mw100g_irq_handler(int irq, void *dev_id) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + if( irq == gpio_to_irq(mw100g_driver.bp_wakeup_ap->irq_addr) ) + { + if( !do_wakeup_handle ) + { + do_wakeup_handle = 1; + // µ±½ÓÊÕµ½ bb wakeup ap µÄIRQºó£¬ÉêÇëÒ»¸ö8ÃëµÄsuspendËø£¬Ê±¼äµ½ºó×Ô¶¯ÊÍ·Å + // ÊÍ·ÅʱÈç¹ûûÓÐÆäËüµÄËø£¬¾Í½«ÔٴιÒÆð. + wake_lock_timeout(&mw100g_driver.wakelock_bbwakeupap, 20 * HZ); + schedule_delayed_work(&wakeup_work, HZ / 10); + } else + printk("%s: already wakeup\n", __FUNCTION__); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int __init mw100g_init(void) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + return rk29_modem_init(&mw100g_driver); +} + +static void __exit mw100g_exit(void) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + rk29_modem_exit(); +} + +module_init(mw100g_init); +module_exit(mw100g_exit); + +MODULE_AUTHOR("lintao lintao@rock-chips.com"); +MODULE_DESCRIPTION("ROCKCHIP modem driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/misc/rk29_modem/rk29_modem.c b/drivers/misc/rk29_modem/rk29_modem.c old mode 100755 new mode 100644 index 0a3279d8298d..56de034c9693 --- a/drivers/misc/rk29_modem/rk29_modem.c +++ b/drivers/misc/rk29_modem/rk29_modem.c @@ -1,145 +1,331 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include /* permission constants */ - -#include -#include - -#include "rk29_modem.h" - -struct rk29_modem_t *g_rk29_modem = NULL; - -extern void rk29_host11_driver_enable(void); -extern void rk29_host11_driver_disable(void); - -static ssize_t modem_status_write(struct class *cls, const char *_buf, size_t _count) -{ - struct rk29_modem_t *rk29_modem = g_rk29_modem; - - int new_mode = simple_strtoul(_buf, NULL, 16); - printk("[%s] new_mode: %s\n", __func__, _buf); - - if(rk29_modem == NULL){ - printk("!!!! g_rk29_modem is NULL !!!!\n"); - return _count; - } - - if(new_mode == rk29_modem->cur_mode){ - printk("[%s] current already in %d mode\n", __func__, new_mode); - return _count; - } - - switch(new_mode){ - case MODEM_DISABLE: - if(rk29_modem->disable){ - printk("modem disable!\n"); -// rk29_host11_driver_disable(); - // mdelay(10); - rk29_modem->disable(); - rk29_modem->cur_mode = new_mode; - } - break; - - case MODEM_ENABLE : - if(rk29_modem->enable){ - printk("modem enable!\n"); -// rk29_host11_driver_enable(); -// mdelay(100); - rk29_modem->enable(); - rk29_modem->cur_mode = new_mode; - } - break; - - case MODEM_SLEEP: - if(rk29_modem->sleep){ - printk("modem sleep!\n"); - rk29_modem->sleep(); - rk29_modem->cur_mode = new_mode; - } - break; - - default: - printk("[%s] invalid new mode: %d\n", __func__, new_mode); - break; - } - - return _count; -} - -static ssize_t modem_status_read(struct class *cls, char *_buf) -{ - struct rk29_modem_t *rk29_modem = g_rk29_modem; - -// printk("Modem type: %s, cur_mode = %d\n", rk29_modem->name, rk29_modem->cur_mode); - - return sprintf(_buf, "%d\n", rk29_modem->cur_mode); -} - -static struct class *rk29_modem_class = NULL; -static CLASS_ATTR(modem_status, 0666, modem_status_read, modem_status_write); - -int modem_is_turn_on() -{ - return (g_rk29_modem->cur_mode != 0); -} - -void turn_off_modem() +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rk29_modem.h" + +struct rk29_modem_t *g_rk29_modem; +//static struct wake_lock wakelock_bbwakeupap; +static struct class *rk29_modem_class = NULL; +static void rk29_modem_turnon(struct rk29_io_t *modem_power, int onoff); + +int rk29_modem_change_status(struct rk29_modem_t *rk29_modem, int status) +{ + int ret = 0; + switch(status) + { + case MODEM_DISABLE: + rk29_modem_turnon(rk29_modem->modem_power, 0); + break; + case MODEM_ENABLE : + rk29_modem_turnon(rk29_modem->modem_power, 1); + break; + case MODEM_SLEEP: + ret = -1; + case MODEM_WAKEUP: + ret = -1; + break; + } + + return ret; +} + +static ssize_t modem_status_write(struct class *cls, const char *_buf, size_t _count) +{ + struct rk29_modem_t *rk29_modem = g_rk29_modem; + int ret = 0; + int new_state = simple_strtoul(_buf, NULL, 16); + + if(rk29_modem == NULL){ + printk("!!!! g_rk29_modem is NULL !!!!\n"); + return _count; + } + + printk("[%s] statue change: %d -> %d\n", __func__, rk29_modem->status, new_state); + + if(new_state == rk29_modem->status) return _count; + + + switch(new_state) + { + case MODEM_DISABLE: + if(rk29_modem->disable) + ret = rk29_modem->disable(rk29_modem); + else + ret = rk29_modem_change_status(rk29_modem, new_state); + break; + case MODEM_ENABLE : + if(rk29_modem->enable) + ret = rk29_modem->enable(rk29_modem); + else + ret = rk29_modem_change_status(rk29_modem, new_state); + break; + case MODEM_SLEEP: + if(rk29_modem->sleep) + ret = rk29_modem->sleep(rk29_modem); + else + ret = rk29_modem_change_status(rk29_modem, new_state); + break; + case MODEM_WAKEUP: + if(rk29_modem->wakeup) + ret = rk29_modem->wakeup(rk29_modem); + else + ret = rk29_modem_change_status(rk29_modem, new_state); + break; + default: + ret = -1; + printk("[%s] Invalid new status: %d\n", __func__, new_state); + break; + } + + if( !ret ) rk29_modem->status = new_state; + + return _count; +} + +static ssize_t modem_status_read(struct class *cls, char *_buf) +{ + struct rk29_modem_t *rk29_modem = g_rk29_modem; + + return sprintf(_buf, "%d\n", rk29_modem->status); +} +static CLASS_ATTR(modem_status, 0666, modem_status_read, modem_status_write); + +int __devinit rk29_modem_suspend(struct platform_device *pdev, pm_message_t state) { - modem_status_write( NULL, "0", sizeof("0") ); +#ifdef CONFIG_PM + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + if( g_rk29_modem->suspend ) + g_rk29_modem->suspend(pdev, state); + else + { + if(g_rk29_modem->ap_ready) // ±êÖ¾APÒѹÒÆð + gpio_direction_output(g_rk29_modem->ap_ready->io_addr, g_rk29_modem->ap_ready->disable); + } +#endif + return 0; } -void turn_on_modem() +int __devinit rk29_modem_resume(struct platform_device *pdev) { - modem_status_write( NULL, "1", sizeof("1") ); -} - -int rk29_modem_register(struct rk29_modem_t *rk29_modem){ - int ret = -1; - - if(rk29_modem == NULL) - return -1; - -#if 1 - if(rk29_modem->enable) rk29_modem->enable(); -#else - if(rk29_modem->disable) rk29_modem->disable(); -#endif - rk29_modem_class = class_create(THIS_MODULE, "rk291x_modem"); - if(rk29_modem_class == NULL){ - printk("create class rk291x_modem failed!\n"); - goto err1; - } - - ret = class_create_file(rk29_modem_class, &class_attr_modem_status); - if(ret != 0){ - printk("create rk291x_modem class file failed!\n"); - goto err2; - } - - g_rk29_modem = rk29_modem; - +#ifdef CONFIG_PM + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + if( g_rk29_modem->resume ) + g_rk29_modem->resume(pdev); + else + { + if(g_rk29_modem->ap_ready) // ±êÖ¾APÒѻָ´ + gpio_direction_output(g_rk29_modem->ap_ready->io_addr, g_rk29_modem->ap_ready->enable); + } +#endif return 0; - -err2: - class_destroy(rk29_modem_class); -err1: - return ret; -} - -void rk29_modem_unregister(struct rk29_modem_t *rk29_modem){ - /* disable 3G modem */ - if(rk29_modem->disable) - rk29_modem->disable(); - - class_remove_file(rk29_modem_class, &class_attr_modem_status); - class_destroy(rk29_modem_class); - - rk29_modem_class = NULL; -} - +} + +static irqreturn_t irq_bbwakeupap_handler(int irq, void *dev_id) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + irqreturn_t irqret = IRQ_NONE; + if( g_rk29_modem->irq_handler ) + { + irqret = g_rk29_modem->irq_handler(irq, dev_id); + if( irqret != IRQ_NONE ) return irqret; + } + + // ¾ßÌåÉ豸ûÓÐ irq_handler º¯Êý£¬»òÕßËüµÄirq_handlerº¯ÊýûÓд¦Àí¸Ã irq£¬ÔòʹÓà + // ÒÔÏµĹ«¹²irq´¦Àí. + + return IRQ_HANDLED; +} + +static void uninstall_irq(struct rk29_irq_t *irq) +{ + gpio_free(irq->irq_addr); +} + +static int install_irq(struct rk29_irq_t *rk29_irq, const char* label) +{ + int ret; + int irq; + + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + irq = gpio_to_irq(rk29_irq->irq_addr); + printk("%s: %d ==> %d\n", __func__, rk29_irq->irq_addr, irq); + + ret = gpio_request(rk29_irq->irq_addr, label); + if (ret < 0) { + pr_err("%s: gpio_request(%d) failed\n", __func__, rk29_irq->irq_addr); + return ret; + } + + gpio_direction_input(rk29_irq->irq_addr); + gpio_pull_updown(rk29_irq->irq_addr, 0); + ret = request_irq(irq, irq_bbwakeupap_handler, rk29_irq->irq_trigger, label, NULL); + if (ret < 0) { + pr_err("%s: request_irq(%d) failed\n", __func__, irq); + gpio_free(rk29_irq->irq_addr); + return ret; + } + + enable_irq_wake(irq); + return 0; +} + +// ¸ømodemÉϵç +static void rk29_modem_turnon(struct rk29_io_t *modem_power, int onoff) +{ + if( modem_power ) + gpio_direction_output(modem_power->io_addr, onoff?modem_power->enable:modem_power->disable); +} + +/* + RK29 modem ͨÓõÄÉ豸³õʼ»¯º¯Êý + Ö÷ÒªÉèÖø÷¸öGPIOÒÔ¼°IRQµÄÉêÇëµÈ + */ +static int rk29_modem_dev_init(struct rk29_modem_t *rk29_modem) +{ + int ret=0; + + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + +// ÉêÇë¿ØÖÆmodemµçÔ´µÄGPIO + if( rk29_modem->modem_power ) + { + ret = gpio_request(rk29_modem->modem_power->io_addr, "modem_power"); + if(ret != 0) + { + gpio_free(rk29_modem->modem_power->io_addr); + printk(">>>>>> Modem power io request failed!\n"); + return ret; + } + + // ÉèÖóõʼµÄmodem״̬ + rk29_modem_change_status(rk29_modem, rk29_modem->status); + } + +// ÉêÇë¿ØÖÆAP¾ÍÐ÷״̬µÄGPIO + if( rk29_modem->ap_ready ) + { + ret = gpio_request(rk29_modem->ap_ready->io_addr, "ap_ready"); + if(ret != 0) + { + gpio_free(rk29_modem->ap_ready->io_addr); + printk(">>>>>> AP ready io request failed!\n"); + return ret; + } + + // ĬÈÏ AP is ready + gpio_direction_output(rk29_modem->ap_ready->io_addr, rk29_modem->ap_ready->enable); + } + +// ÉèÖà bb_wakeup_ap µÄirq£¬ÓÃÓÚap¹ÒÆðÖ®ºó£¬ÓÉbbÀ´»½ÐÑap + if( rk29_modem->bp_wakeup_ap ) + { + ret = install_irq(rk29_modem->bp_wakeup_ap, "bb_wakeup_ap"); + } + + wake_lock_init(&rk29_modem->wakelock_bbwakeupap, WAKE_LOCK_SUSPEND, "bb_wakeup_ap"); + + return ret; +} + +/* + modemϵ硢ÊÍ·Ågpio wait_lock µÈ + */ +static void rk29_modem_dev_uninit(struct rk29_modem_t *rk29_modem) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + +// ¸ømodemϵç + if( rk29_modem->modem_power ) + rk29_modem_turnon(rk29_modem->modem_power, 0); + +// ÊÍ·ÅGPIO + if( rk29_modem->modem_power ) + gpio_free(rk29_modem->modem_power->io_addr); + + if(rk29_modem->ap_ready) + gpio_free(rk29_modem->ap_ready->io_addr); + + if(rk29_modem->bp_wakeup_ap) + uninstall_irq(rk29_modem->bp_wakeup_ap); + +// ÊÍ·Å wake lock + wake_lock_destroy(&rk29_modem->wakelock_bbwakeupap); +} + +/* + Çý¶¯¼ÓÔØ + */ +int rk29_modem_init(struct rk29_modem_t *rk29_modem) +{ + int retval = 0; + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + + retval = platform_driver_register(rk29_modem->driver); + if( retval ) + { + printk("could not register rk29_modem!\n"); + return retval; + } + + rk29_modem_class = class_create(THIS_MODULE, "rk291x_modem"); + if(rk29_modem_class == NULL){ + printk("create class rk291x_modem failed!\n"); + return -1; + } + retval = class_create_file(rk29_modem_class, &class_attr_modem_status); + if(retval != 0){ + printk("create rk291x_modem class file failed!\n"); + goto failed_create_class; + } + +// ¶Ômodem³õʼ»¯ + if( rk29_modem->dev_init ) + retval = rk29_modem->dev_init(rk29_modem); + else + retval = rk29_modem_dev_init(rk29_modem); + + if( retval ) + goto failed_device_init; + + g_rk29_modem = rk29_modem; + + return 0; + +failed_device_init: + platform_driver_unregister(rk29_modem->driver); + +failed_create_class: + class_destroy(rk29_modem_class); + + return retval; +} + +/* + Í˳öÇý¶¯Ê±µ÷Óà + Ä¿Ç°driverÊÇbuild-in£¬²»´æÔÚÍ˳öµÄÇé¿ö£¬²»»áµ÷Óõ½Õâ±ß + */ +void rk29_modem_exit(void) +{ + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + platform_driver_unregister(g_rk29_modem->driver); + +// ¶Ômodem·´³õʼ»¯ + if( g_rk29_modem->dev_uninit ) + g_rk29_modem->dev_uninit(g_rk29_modem); + else + rk29_modem_dev_uninit(g_rk29_modem); +} + diff --git a/drivers/misc/rk29_modem/rk29_modem.h b/drivers/misc/rk29_modem/rk29_modem.h old mode 100755 new mode 100644 index 5e681291e709..0e5f402ca7c8 --- a/drivers/misc/rk29_modem/rk29_modem.h +++ b/drivers/misc/rk29_modem/rk29_modem.h @@ -1,41 +1,51 @@ -#ifndef _rk29_MODEM_H -#define _rk29_MODEM_H - -/* Modem states */ -#define MODEM_DISABLE 0 -#define MODEM_ENABLE 1 -#define MODEM_SLEEP 2 -#define MODEM_MAX_STATUS 3 - -/*===================lintao@rock-chips====================*/ -#define G3_POWER_ON RK29_PIN6_PB1//GPIOPortB_Pin0 -//#define G3_POWER_ON_IOMUX_NAME GPIOB0_SPI0CSN1_MMC1PCA_NAME -//#define G3_POWER_ON_IOMUX_MODE IOMUXA_GPIO0_B0 -#define G3_POWER_ENABLE GPIO_HIGH -#define G3_POWER_DISABLE GPIO_LOW -/*===================================================*/ -//#define G3_RADIO_ON_OFF GPIOPortG_Pin0 -//#define G3_RADIO_ON_OFF_IOMUX_NAME GPIOG0_UART0_MMC1DET_NAME -//#define G3_RADIO_ON_OFF_IOMUX_MODE IOMUXA_GPIO1_C0 -//#define G3_RADIO_ENABLE GPIO_HIGH -//#define G3_RADIO_DISABLE GPIO_LOW -/*====================================================*/ -//#define G3_RESET GPIOPortG_Pin1 -//#define G3_RESET_IOMUX_NAME GPIOG1_UART0_MMC1WPT_NAME -//#define G3_RESET_IOMUX_MODE IOMUXA_GPIO1_C1 -//#define G3_RESET_ENABLE GPIO_LOW -//#define G3_RESET_DISABLE GPIO_HIGH -/*====================================================*/ -struct rk29_modem_t { - char *name; - int cur_mode; - int (*enable)(void); - int (*disable)(void); - int (*sleep)(void); - int (*init)(void); -}; - -int rk29_modem_register(struct rk29_modem_t *rk29_modem); -void rk29_modem_unregister(struct rk29_modem_t *rk29_modem); - -#endif +#include + +/* Modem states */ +#define MODEM_DISABLE 0 +#define MODEM_ENABLE 1 +#define MODEM_SLEEP 2 +#define MODEM_WAKEUP 3 +#define MODEM_MAX_STATUS 4 + +struct rk29_io_t { + unsigned long io_addr; + unsigned long enable; + unsigned long disable; +}; + +struct rk29_irq_t { + unsigned long irq_addr; + unsigned long irq_trigger; +}; + +struct rk29_modem_t { + struct platform_driver *driver; + // ¿ØÖÆmodemµçÔ´µÄIO + struct rk29_io_t *modem_power; + // µ±AP¾ÍÐ÷»òÕßδ¾ÍÐ÷ʱ£¬Í¨¹ý ap_ready Õâ¸öIOÀ´Í¨ÖªBP¡£ + struct rk29_io_t *ap_ready; + // µ±BP½ÓÊÕµ½¶ÌÐÅ»òÕßÀ´µçʱ£¬Í¨¹ý bp_wakeup_ap Õâ¸öIRQÀ´»½ÐÑAP + struct rk29_irq_t *bp_wakeup_ap; + // µ±Ç°modem״̬£¬Ä¿Ç°Ö»Óõ½MODEM_ENABLE(Éϵç)¡¢MODEM_DISABLE(ϵç) + // ͬʱ£¬statusµÄ³õʼֵҲ¾ö¶¨¿ª»úʱµÄmodemÊÇ·ñÉϵç + int status; + struct wake_lock wakelock_bbwakeupap; + + // É豸³õʼ»¯º¯Êý, Ö÷ÒªÉèÖø÷¸öGPIOÒÔ¼°IRQµÄÉêÇëµÈ + int (*dev_init)(struct rk29_modem_t *driver); + int (*dev_uninit)(struct rk29_modem_t *driver); + irqreturn_t (*irq_handler)(int irq, void *dev_id); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + + int (*enable)(struct rk29_modem_t *driver); + int (*disable)(struct rk29_modem_t *driver); + int (*sleep)(struct rk29_modem_t *driver); + int (*wakeup)(struct rk29_modem_t *driver); +}; + +void rk29_modem_exit(void); +int rk29_modem_init(struct rk29_modem_t *rk29_modem); +int rk29_modem_suspend(struct platform_device *pdev, pm_message_t state); +int rk29_modem_resume(struct platform_device *pdev); + -- 2.34.1