From 9f1e202b42205dfd0f2e83360a8f0b83d3bcfc71 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E8=B5=B5=E5=AD=90=E5=88=9D?= Date: Tue, 10 Jul 2012 11:22:48 +0800 Subject: [PATCH] add mt6229 for rk30 --- arch/arm/mach-rk30/board-rk30-sdk.c | 40 ++++ drivers/misc/Kconfig | 3 + drivers/misc/Makefile | 1 + drivers/misc/mt6229.c | 353 ++++++++++++++++++++++++++++ drivers/misc/mw100.c | 4 +- drivers/usb/serial/usb-serial.c | 14 ++ include/linux/mt6229.h | 25 ++ 7 files changed, 439 insertions(+), 1 deletion(-) create mode 100755 drivers/misc/mt6229.c create mode 100644 include/linux/mt6229.h diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 101361bdc1d1..7d4b43e87c9f 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -57,6 +57,9 @@ #if defined(CONFIG_MW100) #include #endif +#if defined(CONFIG_MT6229) +#include +#endif #if defined(CONFIG_ANDROID_TIMED_GPIO) #include "../../../drivers/staging/android/timed_gpio.h" #endif @@ -739,6 +742,7 @@ static int mw100_io_deinit(void) struct rk29_mw100_data rk29_mw100_info = { .io_init = mw100_io_init, .io_deinit = mw100_io_deinit, + .modem_power_en = RK30_PIN6_PB2, .bp_power = RK30_PIN2_PB6, .bp_reset = RK30_PIN4_PD2, .ap_wakeup_bp = RK30_PIN2_PB7, @@ -752,6 +756,39 @@ struct platform_device rk29_device_mw100 = { } }; #endif +#if defined(CONFIG_MT6229) +static int mt6229_io_init(void) +{ + rk30_mux_api_set(GPIO2B6_LCDC1DATA14_SMCADDR18_TSSYNC_NAME, GPIO2B_GPIO2B6); + rk30_mux_api_set(GPIO4D2_SMCDATA10_TRACEDATA10_NAME, GPIO4D_GPIO4D2); + rk30_mux_api_set(GPIO2B7_LCDC1DATA15_SMCADDR19_HSADCDATA7_NAME, GPIO2B_GPIO2B7); + rk30_mux_api_set(GPIO2C0_LCDCDATA16_GPSCLK_HSADCCLKOUT_NAME, GPIO2C_GPIO2C0); + return 0; +} + +static int mt6229_io_deinit(void) +{ + + return 0; +} + +struct rk29_mt6229_data rk29_mt6229_info = { + .io_init = mt6229_io_init, + .io_deinit = mt6229_io_deinit, + .modem_power_en = RK30_PIN6_PB2, + .bp_power = RK30_PIN2_PB7,//RK30_PIN2_PB6, + .bp_reset = RK30_PIN4_PD2, + .ap_wakeup_bp = RK30_PIN2_PC0, + .bp_wakeup_ap = RK30_PIN6_PA0, +}; +struct platform_device rk29_device_mt6229 = { + .name = "mt6229", + .id = -1, + .dev = { + .platform_data = &rk29_mt6229_info, + } + }; +#endif /*MMA8452 gsensor*/ #if defined (CONFIG_GS_MMA8452) @@ -1357,6 +1394,9 @@ static struct platform_device *devices[] __initdata = { #if defined(CONFIG_MW100) &rk29_device_mw100, #endif +#if defined(CONFIG_MT6229) + &rk29_device_mt6229, +#endif #ifdef CONFIG_BATTERY_RK30_ADC &rk30_device_adc_battery, #endif diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 04505e619825..626ff9a81d53 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -544,6 +544,9 @@ config MU509 config MW100 bool "MW100 modem control driver" +config MT6229 + bool "MT6229 modem control driver" + config RK29_NEWTON bool "RK29_NEWTON misc driver" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index bfb009e4e53b..e5b97a33c724 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_MTK23D) += mtk23d.o obj-$(CONFIG_FM580X) += fm580x.o obj-$(CONFIG_MU509) += mu509.o obj-$(CONFIG_MW100) += mw100.o +obj-$(CONFIG_MT6229) += mt6229.o obj-$(CONFIG_STE) += ste.o obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem/ obj-$(CONFIG_GPS_GNS7560) += gps/ diff --git a/drivers/misc/mt6229.c b/drivers/misc/mt6229.c new file mode 100755 index 000000000000..164012bacaaa --- /dev/null +++ b/drivers/misc/mt6229.c @@ -0,0 +1,353 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +#define DEBUG +#ifdef DEBUG +#define MODEMDBG(x...) printk(x) +#else +#define MODEMDBG(fmt,argss...) +#endif +#define SLEEP 1 +#define READY 0 +static struct wake_lock modem_wakelock; +//#define IRQ_BB_WAKEUP_AP_TRIGGER IRQF_TRIGGER_FALLING +#define IRQ_BB_WAKEUP_AP_TRIGGER IRQF_TRIGGER_RISING +#define MT6229_RESET 0x01 +struct rk29_mt6229_data *gpdata = NULL; +struct class *modem_class = NULL; +static int do_wakeup_irq = 0; +static int modem_status; +int suspend_int =0; +static void ap_wakeup_bp(struct platform_device *pdev, int wake) +{ + struct rk29_mt6229_data *pdata = pdev->dev.platform_data; + + gpio_set_value(pdata->ap_wakeup_bp, wake); + +} +extern void rk28_send_wakeup_key(void); + +static void do_wakeup(struct work_struct *work) +{ + if(suspend_int) + { + gpio_set_value(gpdata->ap_wakeup_bp, 0); + suspend_int = 0; + } + +} + +static DECLARE_DELAYED_WORK(wakeup_work, do_wakeup); +static irqreturn_t detect_irq_handler(int irq, void *dev_id) +{ + if(do_wakeup_irq) + { + do_wakeup_irq = 0; + // MODEMDBG("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + wake_lock_timeout(&modem_wakelock, 10 * HZ); + schedule_delayed_work(&wakeup_work, 2*HZ); + } + return IRQ_HANDLED; +} +int modem_poweron_off(int on_off) +{ + struct rk29_mt6229_data *pdata = gpdata; + if(on_off) + { + MODEMDBG("------------modem_poweron\n"); + //gpio_set_value(pdata->bp_reset, GPIO_HIGH); + //msleep(100); + //gpio_set_value(pdata->bp_reset, GPIO_LOW); + gpio_set_value(pdata->bp_power, GPIO_LOW); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + msleep(10); + gpio_set_value(pdata->bp_power, GPIO_LOW); + gpio_set_value(pdata->ap_wakeup_bp, GPIO_LOW); + } + else + { + MODEMDBG("------------modem_poweroff\n"); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + gpio_set_value(pdata->ap_wakeup_bp, GPIO_HIGH); + } + return 0; +} +static int mt6229_open(struct inode *inode, struct file *file) +{ + //MODEMDBG("-------------%s\n",__FUNCTION__); + struct rk29_mt6229_data *pdata = gpdata; +// struct platform_data *pdev = container_of(pdata, struct device, platform_data); + device_init_wakeup(pdata->dev, 1); + return 0; +} + +static int mt6229_release(struct inode *inode, struct file *file) +{ + //MODEMDBG("-------------%s\n",__FUNCTION__); + return 0; +} + +static long mt6229_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct rk29_mt6229_data *pdata = gpdata; + //MODEMDBG("-------------%s\n",__FUNCTION__); + switch(cmd) + { + case MT6229_RESET: + //gpio_set_value(pdata->bp_reset, GPIO_HIGH); + //msleep(100); + //gpio_set_value(pdata->bp_reset, GPIO_LOW); + //msleep(100); + gpio_set_value(pdata->bp_power, GPIO_LOW); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + msleep(10); + gpio_set_value(pdata->bp_power, GPIO_LOW); + gpio_set_value(pdata->ap_wakeup_bp, GPIO_LOW); + break; + default: + break; + } + return 0; +} + +static struct file_operations mt6229_fops = { + .owner = THIS_MODULE, + .open = mt6229_open, + .release = mt6229_release, + .unlocked_ioctl = mt6229_ioctl +}; + +static struct miscdevice mt6229_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = MODEM_NAME, + .fops = &mt6229_fops +}; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +static ssize_t modem_status_read(struct class *cls, struct class_attribute *attr, char *_buf) +#else +static ssize_t modem_status_read(struct class *cls, char *_buf) +#endif +{ + + return sprintf(_buf, "%d\n", modem_status); + +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +static ssize_t modem_status_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count) +#else +static ssize_t modem_status_write(struct class *cls, const char *_buf, size_t _count) +#endif +{ + int new_state = simple_strtoul(_buf, NULL, 16); + if(new_state == modem_status) return _count; + if (new_state == 1){ + printk("%s, c(%d), open modem \n", __FUNCTION__, new_state); + modem_poweron_off(1); + }else if(new_state == 0){ + printk("%s, c(%d), close modem \n", __FUNCTION__, new_state); + modem_poweron_off(0); + }else{ + printk("%s, invalid parameter \n", __FUNCTION__); + } + modem_status = new_state; + return _count; +} +static CLASS_ATTR(modem_status, 0777, modem_status_read, modem_status_write); +static void rk29_early_suspend(struct early_suspend *h) +{ + printk("*********************mt6229____suspend\n"); + +} +static void rk29_early_resume(struct early_suspend *h) +{ + if(suspend_int) + { + printk("***************mt6229____resume\n"); + gpio_set_value(gpdata->ap_wakeup_bp, 0); + suspend_int = 0; + } +} + +static struct early_suspend mt6229_early_suspend = { + .suspend = rk29_early_suspend, + .resume = rk29_early_resume, + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1, + }; +static int mt6229_probe(struct platform_device *pdev) +{ + struct rk29_mt6229_data *pdata = gpdata = pdev->dev.platform_data; + struct modem_dev *mt6229_data = NULL; + int result, irq = 0; + //MODEMDBG("-------------%s\n",__FUNCTION__); + + pdata->dev = &pdev->dev; + if(pdata->io_init) + pdata->io_init(); + gpio_set_value(pdata->modem_power_en, GPIO_HIGH); + msleep(1000); + modem_poweron_off(1); + modem_status = 1; + + register_early_suspend(&mt6229_early_suspend); + mt6229_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL); + if(mt6229_data == NULL) + { + printk("failed to request mt6229_data\n"); + goto err2; + } + platform_set_drvdata(pdev, mt6229_data); + result = gpio_request(pdata->ap_wakeup_bp, "mt6229"); + if (result) { + printk("failed to request AP_BP_WAKEUP gpio\n"); + goto err1; + } + irq = gpio_to_irq(pdata->bp_wakeup_ap); + enable_irq_wake(irq); + if(irq < 0) + { + gpio_free(pdata->bp_wakeup_ap); + printk("failed to request bp_wakeup_ap\n"); + } + result = gpio_request(pdata->bp_wakeup_ap, "bp_wakeup_ap"); + if (result < 0) { + printk("%s: gpio_request(%d) failed\n", __func__, pdata->bp_wakeup_ap); + } + wake_lock_init(&modem_wakelock, WAKE_LOCK_SUSPEND, "bp_wakeup_ap"); + gpio_direction_input(pdata->bp_wakeup_ap); + gpio_pull_updown(pdata->bp_wakeup_ap, 1); + result = request_irq(irq, detect_irq_handler, IRQ_BB_WAKEUP_AP_TRIGGER, "bp_wakeup_ap", NULL); + if (result < 0) { + printk("%s: request_irq(%d) failed\n", __func__, irq); + gpio_free(pdata->bp_wakeup_ap); + goto err0; + } + enable_irq_wake(gpio_to_irq(pdata->bp_wakeup_ap)); + + result = misc_register(&mt6229_misc); + if(result) + { + printk("misc_register err\n"); + } + return result; +err0: + cancel_work_sync(&mt6229_data->work); + gpio_free(pdata->bp_wakeup_ap); +err1: + gpio_free(pdata->ap_wakeup_bp); +err2: + kfree(mt6229_data); + return 0; +} + +int mt6229_suspend(struct platform_device *pdev, pm_message_t state) +{ + suspend_int = 1; + do_wakeup_irq = 1; + //MODEMDBG("-------------%s\n",__FUNCTION__); + ap_wakeup_bp(pdev, 1); +#if defined(CONFIG_ARCH_RK29) + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_GPIO1C1); + //gpio_direction_output(RK29_PIN1_PC1, 1); +#endif +#if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO1A7_UART1RTSN_SPI0TXD_NAME, GPIO1A_GPIO1A7); +#endif + return 0; +} + +int mt6229_resume(struct platform_device *pdev) +{ + //MODEMDBG("-------------%s\n",__FUNCTION__); + //ap_wakeup_bp(pdev, 0); +#if defined(CONFIG_ARCH_RK29) + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N); +#endif +#if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO1A7_UART1RTSN_SPI0TXD_NAME, GPIO1A_UART1_RTS_N); +#endif + if(gpio_get_value(gpdata->bp_wakeup_ap)) + { + schedule_delayed_work(&wakeup_work, 2*HZ); + } + return 0; +} + +void mt6229_shutdown(struct platform_device *pdev) +{ + struct rk29_mt6229_data *pdata = pdev->dev.platform_data; + struct modem_dev *mt6229_data = platform_get_drvdata(pdev); + + //MODEMDBG("-------------%s\n",__FUNCTION__); + modem_poweron_off(0); + + if(pdata->io_deinit) + pdata->io_deinit(); + cancel_work_sync(&mt6229_data->work); + gpio_free(pdata->modem_power_en); + gpio_free(pdata->bp_power); + gpio_free(pdata->bp_reset); + gpio_free(pdata->ap_wakeup_bp); + gpio_free(pdata->bp_wakeup_ap); + kfree(mt6229_data); +} + +static struct platform_driver mt6229_driver = { + .probe = mt6229_probe, + .shutdown = mt6229_shutdown, + .suspend = mt6229_suspend, + .resume = mt6229_resume, + .driver = { + .name = "mt6229", + .owner = THIS_MODULE, + }, +}; + +static int __init mt6229_init(void) +{ + //MODEMDBG("-------------%s\n",__FUNCTION__); + int ret ; + + + modem_class = class_create(THIS_MODULE, "rk291x_modem"); + ret = class_create_file(modem_class, &class_attr_modem_status); + if (ret) + { + printk("Fail to class rk291x_modem.\n"); + } + return platform_driver_register(&mt6229_driver); +} + +static void __exit mt6229_exit(void) +{ + //MODEMDBG("-------------%s\n",__FUNCTION__); + platform_driver_unregister(&mt6229_driver); + class_remove_file(modem_class, &class_attr_modem_status); +} + +module_init(mt6229_init); + +module_exit(mt6229_exit); diff --git a/drivers/misc/mw100.c b/drivers/misc/mw100.c index 355a6eef89c8..484cd977b47d 100644 --- a/drivers/misc/mw100.c +++ b/drivers/misc/mw100.c @@ -139,6 +139,8 @@ static int mw100_probe(struct platform_device *pdev) gpio_request(pdata->bp_reset,"bp_reset"); gpio_request(pdata->bp_wakeup_ap,"bp_wakeup_ap"); gpio_request(pdata->ap_wakeup_bp,"ap_wakeup_bp"); + gpio_set_value(pdata->modem_power_en, GPIO_HIGH); + msleep(1000); #if defined(CONFIG_ARCH_RK29) rk29_mux_api_set(GPIO6C76_CPUTRACEDATA76_NAME, GPIO4H_GPIO6C76); #endif @@ -245,7 +247,7 @@ void mw100_shutdown(struct platform_device *pdev) MODEMDBG("%s::%d--bruins--\n",__func__,__LINE__); gpio_set_value(pdata->bp_power, GPIO_HIGH); mdelay(2010); - + gpio_free(pdata->modem_power_en); gpio_free(pdata->bp_power); gpio_free(pdata->bp_reset); gpio_free(pdata->ap_wakeup_bp); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 0fdebd4bf293..bf8a940a353a 100755 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -61,6 +61,10 @@ static int MU509_USB = 0; static int MW100_USB = 0; #define MW100_USB_PORT (SERIAL_TTY_MINORS - 10) #endif +#ifdef CONFIG_MT6229 +static int MT6229_USB = 0; +#define MT6229_USB_PORT (SERIAL_TTY_MINORS - 10) +#endif /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead the MODULE_DEVICE_TABLE declarations in each serial driver @@ -118,6 +122,10 @@ static struct usb_serial *get_free_serial(struct usb_serial *serial, #ifdef CONFIG_MW100 if (MW100_USB) a= MW100_USB_PORT; +#endif +#ifdef CONFIG_MT6229 + if (MT6229_USB) + a= MT6229_USB_PORT; #endif for (i = a; i < SERIAL_TTY_MINORS; ++i) { if (serial_table[i]) @@ -1087,6 +1095,12 @@ int usb_serial_probe(struct usb_interface *interface, else MW100_USB = 0; #endif +#ifdef CONFIG_MT6229 + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0E8D) && (le16_to_cpu(dev->descriptor.idProduct) == 0x00A2)) + MT6229_USB =1; + else + MT6229_USB = 0; +#endif if (get_free_serial(serial, num_ports, &minor) == NULL) { dev_err(&interface->dev, "No more free serial devices\n"); diff --git a/include/linux/mt6229.h b/include/linux/mt6229.h new file mode 100644 index 000000000000..21750e814f51 --- /dev/null +++ b/include/linux/mt6229.h @@ -0,0 +1,25 @@ +#include +#include +#include + +struct modem_dev +{ + const char *name; + struct miscdevice miscdev; + struct work_struct work; +}; + +struct rk29_mt6229_data { + struct device *dev; + int (*io_init)(void); + int (*io_deinit)(void); + unsigned int bp_power; + unsigned int bp_power_active_low; + unsigned int bp_reset; + unsigned int bp_reset_active_low; + unsigned int bp_wakeup_ap; + unsigned int ap_wakeup_bp; + unsigned int modem_power_en; +}; + +#define MODEM_NAME "mt6229" -- 2.34.1