phonepad: commit phonepad(i30) audio switch code
authorlinjh <linjh@rock-chips.com>
Thu, 27 Sep 2012 09:43:05 +0000 (17:43 +0800)
committerlinjh <linjh@rock-chips.com>
Thu, 27 Sep 2012 10:04:00 +0000 (18:04 +0800)
[reference file]
modified:
drivers/misc/Kconfig
drivers/misc/Makefile
new file:
drivers/misc/rk2928_callpad_misc/Kconfig
drivers/misc/rk2928_callpad_misc/Makefile
drivers/misc/rk2928_callpad_misc/audio_switch.c
drivers/misc/rk2928_callpad_misc/audio_switch.h
drivers/misc/rk2928_callpad_misc/gpio_exp_callpad.c

drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/rk2928_callpad_misc/Kconfig [new file with mode: 0755]
drivers/misc/rk2928_callpad_misc/Makefile [new file with mode: 0755]
drivers/misc/rk2928_callpad_misc/audio_switch.c [new file with mode: 0755]
drivers/misc/rk2928_callpad_misc/audio_switch.h [new file with mode: 0755]
drivers/misc/rk2928_callpad_misc/gpio_exp_callpad.c [new file with mode: 0755]

index 0642367c33bdea9ec7d0f14fcff8761b62044e76..964597fd1c494eb5f4760a11a642e5209962ec95 100644 (file)
@@ -552,5 +552,6 @@ source "drivers/misc/ti-st/Kconfig"
 source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
 source "drivers/misc/3g_module/Kconfig"
+source "drivers/misc/rk2928_callpad_misc/Kconfig"
 
 endif # MISC_DEVICES
index 0bbfe1e012f03f0b8923f04133f4e566764a7a57..ea32927a092e51037516d74d1a6d875d718bc9b8 100755 (executable)
@@ -58,3 +58,4 @@ obj-$(CONFIG_GPS_DEVICES)     += gps/
 obj-y += inv_mpu/
 obj-$(CONFIG_TDSC8800) += tdsc8800.o
 obj-$(CONFIG_RK29_SC8800)      +=      sc8800.o
+obj-y += rk2928_callpad_misc/
diff --git a/drivers/misc/rk2928_callpad_misc/Kconfig b/drivers/misc/rk2928_callpad_misc/Kconfig
new file mode 100755 (executable)
index 0000000..d11316f
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# rk2928 callpad misc device configuration
+#
+
+menuconfig RK2928_CALLPAD_MISC
+       tristate "3G module for phonepad"
+       ---help---
+         Say Y here if you have a support modem
+
+config AUDIO_SWITCH
+       bool "RK2928 callpad audio switch"
+       default n
+config GPIOEXP_AW9523B
+  bool "RK2928 callpad gpio exp"
+  default n
diff --git a/drivers/misc/rk2928_callpad_misc/Makefile b/drivers/misc/rk2928_callpad_misc/Makefile
new file mode 100755 (executable)
index 0000000..05e5d7b
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_AUDIO_SWITCH)    += audio_switch.o
+obj-$(CONFIG_GPIOEXP_AW9523B)    += gpio_exp_callpad.o
diff --git a/drivers/misc/rk2928_callpad_misc/audio_switch.c b/drivers/misc/rk2928_callpad_misc/audio_switch.c
new file mode 100755 (executable)
index 0000000..34c7288
--- /dev/null
@@ -0,0 +1,143 @@
+#include <linux/module.h>\r
+#include <linux/kernel.h>\r
+#include <linux/i2c.h>\r
+#include <linux/irq.h>\r
+#include <linux/gpio.h>\r
+#include <linux/input.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/fs.h>\r
+#include <linux/uaccess.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/miscdevice.h>\r
+#include <mach/iomux.h>\r
+#include <mach/gpio.h>\r
+#include <linux/delay.h>\r
+#include <linux/poll.h>\r
+#include <linux/wait.h>\r
+#include <linux/wakelock.h>\r
+#include <linux/workqueue.h>\r
+#include <mach/iomux.h>\r
+#include<linux/ioctl.h>\r
+\r
+#include <linux/slab.h>\r
+   \r
+MODULE_LICENSE("GPL");\r
+\r
+struct rk29_audio_switch_data {\r
+       struct device *dev;\r
+       unsigned int gpio_switch_fm_ap;\r
+       unsigned int gpio_switch_bb_ap;\r
+       int state;\r
+};\r
+\r
+struct rk29_audio_switch_data *gpdata = NULL;\r
+\r
+#define AUDIO_SWTICH_IO        0XA2\r
+#define        AS_IOCTL_AP     _IO(AUDIO_SWTICH_IO,0X01)\r
+#define        AS_IOCTL_BP     _IO(AUDIO_SWTICH_IO,0X02)\r
+#define        AS_IOCTL_FM     _IO(AUDIO_SWTICH_IO,0X03)\r
+\r
+\r
+static int as_open(struct inode *inode, struct file *file)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int as_release(struct inode *inode, struct file *file)\r
+{\r
+       return 0;\r
+}\r
+\r
+static long as_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+    \r
+       switch(cmd)\r
+       {\r
+               case AS_IOCTL_AP:       \r
+                   gpio_set_value(gpdata->gpio_switch_fm_ap, GPIO_LOW);\r
+                   break;\r
+               case AS_IOCTL_BP:\r
+                   break;\r
+               case AS_IOCTL_FM:\r
+                   gpio_set_value(gpdata->gpio_switch_fm_ap, GPIO_HIGH);\r
+                   break;\r
+               default:\r
+                       break;\r
+       }\r
+       return 0;\r
+}\r
+\r
+static struct file_operations as_fops = {\r
+       .owner = THIS_MODULE,\r
+       .open = as_open,\r
+       .release = as_release,\r
+       .unlocked_ioctl = as_ioctl\r
+};\r
+\r
+static struct miscdevice as_misc = {\r
+       .minor = MISC_DYNAMIC_MINOR,\r
+       .name = "audio_switch",\r
+       .fops = &as_fops\r
+};\r
+\r
+static int as_probe(struct platform_device *pdev)\r
+{\r
+    int result=0;\r
+    gpdata = kzalloc(sizeof(struct rk29_audio_switch_data), GFP_KERNEL);\r
+\r
+    rk30_mux_api_set(GPIO1B0_SPI_CLK_UART1_CTSN_NAME, GPIO1B_GPIO1B0);\r
+    gpdata->gpio_switch_fm_ap = gpio_request(RK2928_PIN1_PB0,"switch_bb_ap");\r
+       gpio_direction_output(gpdata->gpio_switch_fm_ap,GPIO_LOW);      \r
+       \r
+       platform_set_drvdata(pdev, gpdata);     \r
+\r
+       result = misc_register(&as_misc);\r
+       if(result){\r
+               gpio_free(gpdata->gpio_switch_fm_ap);\r
+               kfree(gpdata);\r
+       }       \r
+       return result;\r
+}\r
+\r
+int as_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+       return 0;\r
+}\r
+\r
+int as_resume(struct platform_device *pdev)\r
+{\r
+       return 0;\r
+}\r
+\r
+void as_shutdown(struct platform_device *pdev)\r
+{\r
+    gpio_free(gpdata->gpio_switch_fm_ap);\r
+    kfree(gpdata);\r
+}\r
+\r
+static struct platform_driver as_driver = {\r
+       .probe  = as_probe,\r
+       .shutdown       = as_shutdown,\r
+       .suspend        = as_suspend,\r
+       .resume         = as_resume,\r
+       .driver = {\r
+               .name   = "audio_switch",\r
+               .owner  = THIS_MODULE,\r
+       },\r
+};\r
+\r
+static int __init audio_switch_init(void)\r
+{\r
+       return platform_driver_register(&as_driver);\r
+}\r
+\r
+static void __exit audio_switch_exit(void)\r
+{\r
+       platform_driver_unregister(&as_driver);\r
+}\r
+\r
+module_init(audio_switch_init);\r
+\r
+module_exit(audio_switch_exit);\r
diff --git a/drivers/misc/rk2928_callpad_misc/audio_switch.h b/drivers/misc/rk2928_callpad_misc/audio_switch.h
new file mode 100755 (executable)
index 0000000..eaf1d5e
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef RK2928_AUDIO_SWTICH_H\r
+#define RK2928_AUDIO_SWTICH_H\r
+\r
+\r
+#endif\r
diff --git a/drivers/misc/rk2928_callpad_misc/gpio_exp_callpad.c b/drivers/misc/rk2928_callpad_misc/gpio_exp_callpad.c
new file mode 100755 (executable)
index 0000000..0af3c51
--- /dev/null
@@ -0,0 +1,404 @@
+#include <linux/module.h>\r
+#include <linux/kernel.h>\r
+#include <linux/i2c.h>\r
+#include <linux/irq.h>\r
+#include <linux/gpio.h>\r
+#include <linux/input.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/fs.h>\r
+#include <linux/uaccess.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/miscdevice.h>\r
+#include <mach/gpio.h>\r
+#include <asm/gpio.h>\r
+#include <linux/delay.h>\r
+#include <linux/poll.h>\r
+#include <linux/wait.h>\r
+#include <linux/wakelock.h>\r
+#include <linux/workqueue.h>\r
+#include <linux/earlysuspend.h>\r
+#include <linux/slab.h>\r
+#include <mach/board.h>\r
+#include <linux/gpio_exp_callpad.h>\r
+\r
+//#define DEBUG_GPIO_EXP\r
+#ifdef DEBUG_GPIO_EXP\r
+#define DEBUGPRINT(x...) printk(x)\r
+#else\r
+#define DEBUGPRINT(x...)\r
+#endif\r
+\r
+struct gpioexp_data {\r
+       struct i2c_client *client;\r
+       int    irq;\r
+       struct work_struct      gpioexp_work;\r
+       struct workqueue_struct *gpioexp_workqueue;\r
+       u16 int_mask_bit;\r
+       u16 pre_int_bit;\r
+       gpioexp_int_handler_t interrupt_handlers [GPIOEXP_PIN_MAX];\r
+       unsigned long interrupt_trigger[GPIOEXP_PIN_MAX];\r
+};\r
+\r
+\r
+static struct gpioexp_data* gpioexp_ptr=NULL;\r
+\r
+int gpioexp_set_direction(unsigned gpio, int is_in)\r
+{\r
+       char buf[1];\r
+       unsigned char reg, gpiobit;\r
+\r
+       if(gpio >= GPIOEXP_PIN_MAX)\r
+               return -EINVAL;\r
+\r
+       reg = (gpio<8) ? 0x04 : 0x05;\r
+       gpiobit = (gpio<8) ? (0x01<<gpio) : (0x01<<(gpio-8));\r
+\r
+       buf[0] = 0;\r
+       i2c_master_reg8_recv(gpioexp_ptr->client, reg, buf, 1, 400*1000);\r
+       if(is_in)\r
+               buf[0] |= gpiobit;\r
+       else\r
+               buf[0] &= ~gpiobit;\r
+\r
+       i2c_master_reg8_send(gpioexp_ptr->client, reg, buf, 1, 400*1000);\r
+       \r
+       DEBUGPRINT("gpioexp_set_direction:gpio = %d, buf[0] = %d\n", gpio, buf[0]);\r
+\r
+       return 0;\r
+\r
+}      \r
+EXPORT_SYMBOL(gpioexp_set_direction);\r
+\r
+int gpioexp_set_output_level(unsigned gpio, int value)\r
+{\r
+    char buf[1];\r
+    unsigned char reg, gpiobit;\r
+    \r
+       if(gpio >= GPIOEXP_PIN_MAX)\r
+               return -EINVAL;\r
+\r
+    reg = (gpio<8) ? 0x02 : 0x03;\r
+    gpiobit = (gpio<8) ? (0x01<<gpio) : (0x01<<(gpio-8));\r
+\r
+    buf[0] = 0;\r
+    i2c_master_reg8_recv(gpioexp_ptr->client, reg, buf, 1, 400*1000);\r
+    if(value)\r
+       buf[0] |= gpiobit;\r
+   else\r
+       buf[0] &= ~gpiobit;\r
+       \r
+    i2c_master_reg8_send(gpioexp_ptr->client, reg, buf, 1, 400*1000);\r
+       DEBUGPRINT("gpioexp_set_output_level:gpio = %d, buf[0] = %d\n", gpio, buf[0]);\r
+\r
+       return 0;\r
+\r
+}      \r
+EXPORT_SYMBOL(gpioexp_set_output_level);\r
+\r
+\r
+int gpioexp_read_input_level(unsigned gpio)\r
+{\r
+    char buf[1];\r
+    unsigned char reg, gpiobit;\r
+    int ret;\r
+    \r
+       if(gpio >= GPIOEXP_PIN_MAX)\r
+               return -EINVAL;\r
+       \r
+    reg = (gpio<8) ? 0x00 : 0x01;\r
+    gpiobit = (gpio<8)?(0x01<<gpio):(0x01<<(gpio-8));\r
+\r
+    buf[0] = 0;\r
+    i2c_master_reg8_recv(gpioexp_ptr->client, reg, buf, 1, 400*1000);\r
+    \r
+    ret = (buf[0] & gpiobit)?1:0;\r
+       \r
+       DEBUGPRINT("gpioexp_read_input_level:gpio = %d, buf[0] = %d\n", gpio, buf[0]);\r
+    return ret;\r
+\r
+}\r
+EXPORT_SYMBOL(gpioexp_read_input_level);\r
+\r
+int gpioexp_request_irq(unsigned int irq, gpioexp_int_handler_t handler, unsigned long flags)\r
+{\r
+       char buf[1];\r
+       \r
+       if(irq > GPIOEXP_PIN_MAX || handler == NULL || !(flags & GPIOEXP_INT_TRIGGER_MASK))\r
+               return -EINVAL;\r
+       \r
+       if(gpioexp_ptr->int_mask_bit & (0x01 << irq) == 0)\r
+               return -EBUSY;\r
+       gpioexp_ptr->interrupt_handlers[irq] = handler;\r
+       gpioexp_ptr->interrupt_trigger[irq] = flags & GPIOEXP_INT_TRIGGER_MASK;\r
+       gpioexp_ptr->int_mask_bit &= ~(0x01 << irq);\r
+\r
+       if(irq >=8){\r
+               buf[0] = (gpioexp_ptr->int_mask_bit >> 8) & 0xff;\r
+               i2c_master_reg8_send(gpioexp_ptr->client, 0x07, buf, 1, 400*1000);\r
+       }\r
+       else{\r
+               buf[0] = gpioexp_ptr->int_mask_bit & 0xff;\r
+               i2c_master_reg8_send(gpioexp_ptr->client, 0x06, buf, 1, 400*1000);\r
+       }\r
+\r
+       return 0;\r
+}\r
+EXPORT_SYMBOL(gpioexp_request_irq);\r
+\r
+int gpioexp_free_irq(unsigned int irq)\r
+{\r
+       char buf[1];\r
+\r
+       if(irq > GPIOEXP_PIN_MAX)\r
+               return -EINVAL;\r
+       if(gpioexp_ptr->int_mask_bit & (0x01 << irq) == 0){\r
+               gpioexp_ptr->int_mask_bit &= ~(0x01 << irq);\r
+               if(irq >=8){\r
+                       buf[0] = (gpioexp_ptr->int_mask_bit >> 8) & 0xff;\r
+                       i2c_master_reg8_send(gpioexp_ptr->client, 0x07, buf, 1, 400*1000);\r
+               }\r
+               else{\r
+                       buf[0] = gpioexp_ptr->int_mask_bit & 0xff;\r
+                       i2c_master_reg8_send(gpioexp_ptr->client, 0x06, buf, 1, 400*1000);\r
+               }\r
+       }\r
+       gpioexp_ptr->interrupt_handlers[irq] = NULL;\r
+       gpioexp_ptr->interrupt_trigger[irq] = 0;\r
+       \r
+       return 0;\r
+}\rEXPORT_SYMBOL(gpioexp_free_irq);\r
+\r
+int gpioexp_enable_irq(unsigned int irq)\r
+{\r
+       char buf[1];\r
+       \r
+       if(irq > GPIOEXP_PIN_MAX)\r
+               return -EINVAL;\r
+       if(gpioexp_ptr->int_mask_bit & (0x01 << irq) == 0)\r
+               return 0;\r
+       gpioexp_ptr->int_mask_bit &= ~(0x01 << irq);\r
+       if(irq >=8){\r
+               buf[0] = (gpioexp_ptr->int_mask_bit >> 8) & 0xff;\r
+               i2c_master_reg8_send(gpioexp_ptr->client, 0x07, buf, 1, 400*1000);\r
+       }\r
+       else{\r
+               buf[0] = gpioexp_ptr->int_mask_bit & 0xff;\r
+               i2c_master_reg8_send(gpioexp_ptr->client, 0x06, buf, 1, 400*1000);\r
+       }\r
+       return 0;\r
+}\r
+EXPORT_SYMBOL(gpioexp_enable_irq);\r
+\r
+int gpioexp_disable_irq(unsigned int irq)\r
+{\r
+       char buf[1];\r
+       \r
+       if(irq > GPIOEXP_PIN_MAX)\r
+               return -EINVAL;\r
+       if(gpioexp_ptr->int_mask_bit & (0x01 << irq) == 1)\r
+               return 0;\r
+       gpioexp_ptr->int_mask_bit |= (0x01 << irq);\r
+       if(irq >=8){\r
+               buf[0] = (gpioexp_ptr->int_mask_bit >> 8) & 0xff;\r
+               i2c_master_reg8_send(gpioexp_ptr->client, 0x07, buf, 1, 400*1000);\r
+       }\r
+       else{\r
+               buf[0] = gpioexp_ptr->int_mask_bit & 0xff;\r
+               i2c_master_reg8_send(gpioexp_ptr->client, 0x06, buf, 1, 400*1000);\r
+       }\r
+       return 0;\r
+}\r
+EXPORT_SYMBOL(gpioexp_disable_irq);\r
+\r
+static inline void gpioexp_handle_interrupt(struct gpioexp_data *data, u16 int_pending_bit)\r
+{\r
+       int i;\r
+       u16 pre_int_bit = data->pre_int_bit;\r
+\r
+       for(i=0;i<GPIOEXP_PIN_MAX;i++){\r
+               if(int_pending_bit & 0x01){\r
+                       if((pre_int_bit >> i) & 0x01){\r
+                               if(data->interrupt_trigger[i] && GPIOEXP_INT_TRIGGER_FALLING)\\r
+                                       data->interrupt_handlers[i](data);\r
+                       }\r
+                       else{\r
+                               if(data->interrupt_trigger[i] && GPIOEXP_INT_TRIGGER_RISING)\\r
+                                       data->interrupt_handlers[i](data);\r
+                       }\r
+               }\r
+               int_pending_bit = int_pending_bit >> 1;\r
+       }\r
+}\r
+\r
+static inline u16 gpioexp_interrupt_pending(struct gpioexp_data *data,u16 cur_int_bit)\r
+{\r
+       u16 int_toggle_bit,int_pending_bit;\r
+       \r
+       int_toggle_bit = (data->pre_int_bit) ^ cur_int_bit;\r
+       int_pending_bit = (~data->int_mask_bit) & int_toggle_bit;\r
+\r
+       return int_pending_bit;\r
+}\r
+\r
+static void gpioexp_chip_init(void)\r
+{\r
+       char buf[1];\r
+\r
+       buf[0] = 0x10; //set P0 Push-Pull\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x11, buf, 1, 400*1000);\r
+       \r
+       buf[0] = 0xff; //set interrupt disable\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x06, buf, 1, 400*1000);    \r
+       buf[0] = 0xff; //set interrupt disable\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x07, buf, 1, 400*1000);    \r
+       gpioexp_ptr->int_mask_bit = 0xffff;\r
+\r
+       buf[0] = 0x00; //set input output P0 0b10111111\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x04, buf, 1, 400*1000);    \r
+       buf[0] = 0x00;  //set input output P1 0b01000000\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x05, buf, 1, 400*1000);    \r
+\r
+       buf[0] = 0x00; //set output value P0 0b00000000\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x02, buf, 1, 400*1000);    \r
+       buf[0] = 0x80; //set output value P1 0b00000011\r
+       i2c_master_reg8_send(gpioexp_ptr->client, 0x03, buf, 1, 400*1000);    \r
+       gpioexp_ptr->pre_int_bit = 0x0000;\r
+               \r
+       DEBUGPRINT("gpioexp_init\n");\r
+}      \r
+\r
+static void gpioexp_work(struct work_struct *work)\r
+{\r
+       struct gpioexp_data *data = container_of(work, struct gpioexp_data, gpioexp_work);\r
+       char buf[2] = {0};\r
+       u16 cur_int_bit,int_pending_bit;\r
+       \r
+       DEBUGPRINT("gpioexp_work: read io status\n");\r
+       \r
+       i2c_master_reg8_recv(gpioexp_ptr->client, 0x00, buf, 1, 400*1000);              //read p0 value\r
+       i2c_master_reg8_recv(gpioexp_ptr->client, 0x01, buf+1, 1, 400*1000);    //read p1 value\r
+       cur_int_bit = (u16)(buf[1]) << 8 | buf[0];\r
+       int_pending_bit = gpioexp_interrupt_pending(data,cur_int_bit);\r
+       if(int_pending_bit){\r
+               gpioexp_handle_interrupt(data,int_pending_bit);\r
+       }\r
+       data->pre_int_bit = cur_int_bit;\r
+\r
+       enable_irq(data->irq);\r
+}\r
+\r
+static irqreturn_t gpioexp_interrupt(int irq, void *dev_id)\r
+{\r
+       struct gpioexp_data *gpioexp = dev_id;\r
+\r
+       DEBUGPRINT("gpioexp_interrupt\n");\r
+       disable_irq_nosync(gpioexp->irq);\r
+       if (!work_pending(&gpioexp->gpioexp_work)) \r
+               queue_work(gpioexp->gpioexp_workqueue, &gpioexp->gpioexp_work);\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+static __devinit int gpioexp_probe(struct i2c_client *i2c,\r
+                           const struct i2c_device_id *id)\r
+{\r
+       struct gpio_exp_platform_data *pdata = i2c->dev.platform_data;\r
+       struct gpioexp_data *gpioexp;\r
+       int ret = 0;\r
+\r
+       DEBUGPRINT("gpioexp_probe\n");\r
+       if (!pdata) {\r
+               dev_err(&i2c->dev, "platform data is required!\n");\r
+               return -EINVAL;\r
+       }\r
+\r
+       gpioexp = kzalloc(sizeof(*gpioexp), GFP_KERNEL);\r
+       if (!gpioexp)   {\r
+               return -ENOMEM;
+       }\r
+\r
+       if (pdata->init_platform_hw)                              \r
+               pdata->init_platform_hw();\r
+\r
+       gpioexp->client = i2c;\r
+       gpioexp->irq = gpio_to_irq(i2c->irq);\r
+\r
+       INIT_WORK(&gpioexp->gpioexp_work, gpioexp_work);\r
+       gpioexp->gpioexp_workqueue = create_singlethread_workqueue("gpioexp_workqueue");\r
+       if (!gpioexp->gpioexp_workqueue) {\r
+               ret = -ESRCH;\r
+               goto gpioexp_wq_fail;\r
+       }\r
+\r
+\r
+       i2c_set_clientdata(gpioexp->client, gpioexp);\r
+       gpioexp_ptr = gpioexp;\r
+\r
+       gpioexp_chip_init();\r
+\r
+       ret = request_irq(gpioexp->irq, gpioexp_interrupt, IRQF_TRIGGER_FALLING, gpioexp->client->dev.driver->name, gpioexp);\r
+       if (ret < 0) {
+               ret = 1;\r
+               goto gpioexp_irq_fail;\r
+       }\r
+\r
+       DEBUGPRINT("gpioexp set modem power on!\n");\r
+       return 0;\r
+\r
+gpioexp_irq_fail:\r
+       destroy_workqueue(gpioexp->gpioexp_workqueue);\r
+       i2c_set_clientdata(gpioexp->client, NULL);\r
+       gpioexp_ptr = NULL;\r
+gpioexp_wq_fail:       \r
+       pdata->exit_platform_hw();\r
+       kfree(gpioexp);\r
+\r
+       return ret;\r
+}\r
+\r
+static __devexit int gpioexp_remove(struct i2c_client *client)\r
+{\r
+       struct gpio_exp_platform_data *pdata = client->dev.platform_data;\r
+       struct gpioexp_data *gpioexp = i2c_get_clientdata(client);\r
+       \r
+       DEBUGPRINT("gpioexp_remove");\r
+\r
+       destroy_workqueue(gpioexp->gpioexp_workqueue);\r
+       pdata->exit_platform_hw();\r
+       kfree(gpioexp);\r
+       gpioexp_ptr = NULL;\r
+       \r
+       return 0;\r
+}\r
+\r
+static const struct i2c_device_id gpioexp_i2c_id[] = {\r
+       { "gpioexp_aw9523b", 0 },{ }\r
+};\r
+\r
+static struct i2c_driver gpioexp_driver = {\r
+       .probe          = gpioexp_probe,\r
+       .remove         = __devexit_p(gpioexp_remove),\r
+       .id_table       = gpioexp_i2c_id,\r
+       .driver = {\r
+               .name   = "gpioexp_aw9523b",\r
+               .owner  = THIS_MODULE,\r
+       },\r
+};\r
+\r
+static int __init gpioexp_init(void)\r
+{\r
+    return i2c_add_driver(&gpioexp_driver);\r
+}\r
+\r
+static void __exit gpioexp_exit(void)\r
+{\r
+       i2c_del_driver(&gpioexp_driver);\r
+}\r
+\r
+subsys_initcall_sync(gpioexp_init);\r
+module_exit(gpioexp_exit);\r
+\r
+MODULE_LICENSE("GPL");\r
+\r
+\r