add mt6229 for rk30
author赵子初 <zzc@rock-chips.com>
Tue, 10 Jul 2012 03:22:48 +0000 (11:22 +0800)
committer赵子初 <zzc@rock-chips.com>
Tue, 10 Jul 2012 03:23:13 +0000 (11:23 +0800)
arch/arm/mach-rk30/board-rk30-sdk.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/mt6229.c [new file with mode: 0755]
drivers/misc/mw100.c
drivers/usb/serial/usb-serial.c
include/linux/mt6229.h [new file with mode: 0644]

index 101361bdc1d1f9bd26ce88bf14fab9ece20539a8..7d4b43e87c9f7b26e4b29d7be33f657a57300e5e 100755 (executable)
@@ -57,6 +57,9 @@
 #if defined(CONFIG_MW100)
 #include <linux/mw100.h>
 #endif
+#if defined(CONFIG_MT6229)
+#include <linux/mt6229.h>
+#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
index 04505e6198251249841f8666e9a02cc4eac56790..626ff9a81d530dd68ef887ed0708ba45c63cfb29 100644 (file)
@@ -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"
 
index bfb009e4e53ba462e858eab7de8db520620d1120..e5b97a33c72409127f75f71d85c6abbd0161178c 100644 (file)
@@ -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 (executable)
index 0000000..164012b
--- /dev/null
@@ -0,0 +1,353 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/circ_buf.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <mach/iomux.h>
+#include <mach/gpio.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+#include <linux/mt6229.h>
+#include <linux/slab.h>
+#include <linux/earlysuspend.h>
+
+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);
index 355a6eef89c8bba20b740e15391b91bfbf08bc4e..484cd977b47d68bb33b277bb3d5758b228d5e350 100644 (file)
@@ -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);
index 0fdebd4bf293d7bfb9fa7cba9258e61665c6dabd..bf8a940a353a63c971d434f221e79fb28e351b3f 100755 (executable)
@@ -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 (file)
index 0000000..21750e8
--- /dev/null
@@ -0,0 +1,25 @@
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/miscdevice.h>
+
+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"