#include <asm/atomic.h>
#include <asm/mach-types.h>
#include "rk2818_headset.h"
+#include <linux/earlysuspend.h>
/* Debug */
-#if 0
-#define DBG(x...) printk(KERN_INFO x)
+#if 1
+#define DBG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
#endif
-/* ¶ú»ú״̬ */
-#define BIT_HEADSET (1 << 0)//´øMICµÄ¶ú»ú
-#define BIT_HEADSET_NO_MIC (1 << 1)//²»´øMICµÄ¶ú»ú
+#define BIT_HEADSET (1 << 0)
+#define BIT_HEADSET_NO_MIC (1 << 1)
struct rk2818_headset_dev{
struct switch_dev sdev;
};
static struct rk2818_headset_dev Headset_dev;
-static struct work_struct g_headsetobserve_work;
+static struct delayed_work g_headsetobserve_work;
static struct rk2818_headset_data *prk2818_headset_info;
-static irqreturn_t headset_interrupt(int irq, void *dev_id);
-unsigned int headset_irq_type;
+#if defined(CONFIG_MACH_BENGO_V2) || defined(CONFIG_MACH_BENGO) || defined(CONFIG_MACH_Z5) || defined(CONFIG_MACH_Z5_V2) || defined(CONFIG_MACH_A22)
+extern void detect_HSMic(void);
+#endif
int headset_status(void)
{
- if(Headset_dev.cur_headset_status & BIT_HEADSET)
- return 1;
- else
- return 0;
+ if(Headset_dev.cur_headset_status & BIT_HEADSET)
+ return 1;
+ else
+ return 0;
}
EXPORT_SYMBOL_GPL(headset_status);
-static void headsetobserve_work(void)
+static irqreturn_t headset_interrupt(int irq, void *dev_id)
{
- if(gpio_get_value(prk2818_headset_info->irq)){
- if(prk2818_headset_info->headset_in_type)
- {DBG("headset in-----cjq------/n");Headset_dev.cur_headset_status = BIT_HEADSET;}
- else
- Headset_dev.cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+ DBG("---headset_interrupt---\n");
+ schedule_delayed_work(&g_headsetobserve_work, msecs_to_jiffies(20));
+ return IRQ_HANDLED;
+}
- if(headset_irq_type != (IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING))
- headset_irq_type = IRQF_TRIGGER_FALLING;
+static int headset_change_irqtype(unsigned int irq_type)
+{
+ int ret = 0;
+ DBG("--------%s----------",__FUNCTION__);
+ free_irq(prk2818_headset_info->irq,NULL);
+
+ ret = request_irq(prk2818_headset_info->irq, headset_interrupt, irq_type, NULL, NULL);
+ if (ret)
+ {
+ DBG("headsetobserve: request irq failed\n");
+ return ret;
}
- else{
- if(prk2818_headset_info->headset_in_type)
- {DBG("headset out-----cjq------/n");Headset_dev.cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);}
- else
- Headset_dev.cur_headset_status = BIT_HEADSET;
+ return ret;
+}
+
+static void headsetobserve_work(struct work_struct *work)
+{
+ int i,level = 0;
- if(headset_irq_type != (IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING))
- headset_irq_type = IRQF_TRIGGER_RISING;
+ DBG("---headsetobserve_work---\n");
+ mutex_lock(&Headset_dev.mutex_lock);
+
+ for(i=0; i<3; i++)
+ {
+ level = gpio_get_value(prk2818_headset_info->gpio);
+ if(level < 0)
+ {
+ printk("%s:get pin level again,pin=%d,i=%d\n",__FUNCTION__,prk2818_headset_info->irq,i);
+ msleep(1);
+ continue;
+ }
+ else
+ break;
+ }
+ if(level < 0)
+ {
+ printk("%s:get pin level err!\n",__FUNCTION__);
+ return;
+ }
+
+ switch(prk2818_headset_info->headset_in_type)
+ {
+ case HEADSET_IN_HIGH:
+ if(level > 0)
+ {//插入--高电平
+ DBG("---headset in---\n");
+ Headset_dev.cur_headset_status = BIT_HEADSET;
+ headset_change_irqtype(IRQF_TRIGGER_FALLING);//设置为下降沿
+ }
+ else if(level == 0)
+ {//拔出--低电平
+ DBG("---headset out---\n");
+ Headset_dev.cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+ headset_change_irqtype(IRQF_TRIGGER_RISING);//设置为上升沿
+ }
+ break;
+ case HEADSET_IN_LOW:
+ if(level == 0)
+ {//插入--低电平
+ DBG("---headset in---\n");
+ Headset_dev.cur_headset_status = BIT_HEADSET;
+ headset_change_irqtype(IRQF_TRIGGER_RISING);///设置为上升沿
+ }
+ else if(level > 0)
+ {//拔出--高电平
+ DBG("---headset out---\n");
+ Headset_dev.cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+ headset_change_irqtype(IRQF_TRIGGER_FALLING);//设置为下降沿
+ }
+ break;
+ default:
+ DBG("---- ERROR: on headset headset_in_type error -----\n");
+ break;
}
if(Headset_dev.cur_headset_status != Headset_dev.pre_headset_status)
{
- Headset_dev.pre_headset_status = Headset_dev.cur_headset_status;
- mutex_lock(&Headset_dev.mutex_lock);
- switch_set_state(&Headset_dev.sdev, Headset_dev.cur_headset_status);
- mutex_unlock(&Headset_dev.mutex_lock);
- DBG("---------------cur_headset_status = [0x%x]\n", Headset_dev.cur_headset_status);
+ Headset_dev.pre_headset_status = Headset_dev.cur_headset_status;
+ switch_set_state(&Headset_dev.sdev, Headset_dev.cur_headset_status);
+ DBG("Headset_dev.cur_headset_status = %d\n",Headset_dev.cur_headset_status);
+#if defined(CONFIG_MACH_BENGO_V2) || defined(CONFIG_MACH_BENGO) || defined(CONFIG_MACH_Z5) || defined(CONFIG_MACH_Z5_V2) || defined(CONFIG_MACH_A22)
+ detect_HSMic();
+#endif
}
-
- if(headset_irq_type == (IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING))return;
-
- free_irq(prk2818_headset_info->irq,NULL);
- if (request_irq(prk2818_headset_info->irq, headset_interrupt, headset_irq_type, NULL, NULL))
- DBG("headsetobserve: request irq failed\n");
+ mutex_unlock(&Headset_dev.mutex_lock);
}
-static irqreturn_t headset_interrupt(int irq, void *dev_id)
+static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
{
- schedule_work(&g_headsetobserve_work);
- DBG("---------------headset_interrupt---------------\n");
-
- return IRQ_HANDLED;
+ return sprintf(buf, "Headset\n");
}
-static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void headset_early_resume(struct early_suspend *h)
{
- return sprintf(buf, "Headset\n");
+ schedule_delayed_work(&g_headsetobserve_work, msecs_to_jiffies(10));
+ //DBG(">>>>>headset_early_resume\n");
}
+static struct early_suspend hs_early_suspend;
+#endif
+
static int rockchip_headsetobserve_probe(struct platform_device *pdev)
{
int ret;
-
+
DBG("RockChip headset observe driver\n");
prk2818_headset_info = pdev->dev.platform_data;
ret = switch_dev_register(&Headset_dev.sdev);
if (ret < 0)
- return 0;
+ return ret;
- INIT_WORK(&g_headsetobserve_work, headsetobserve_work);
+ INIT_DELAYED_WORK(&g_headsetobserve_work, headsetobserve_work);
- ret = gpio_request(prk2818_headset_info->irq, "headset_det");
- if (ret) {
- DBG( "headsetobserve: failed to request FPGA_PIO0_00\n");
+ ret = gpio_request(prk2818_headset_info->gpio, "headset_det");
+ if (ret)
+ {
+ DBG("headsetobserve: request gpio_request failed\n");
return ret;
}
-
- gpio_direction_input(prk2818_headset_info->irq);
-
- prk2818_headset_info->irq = gpio_to_irq(prk2818_headset_info->irq);
- headset_irq_type = prk2818_headset_info->irq_type;
- ret = request_irq(prk2818_headset_info->irq, headset_interrupt, headset_irq_type, NULL, NULL);
- if (ret ) {
+ gpio_pull_updown(prk2818_headset_info->gpio, GPIONormal);//不上拉也不下拉
+ gpio_direction_input(prk2818_headset_info->gpio);
+ prk2818_headset_info->irq = gpio_to_irq(prk2818_headset_info->gpio);
+
+ if(prk2818_headset_info->headset_in_type == HEADSET_IN_HIGH)
+ prk2818_headset_info->irq_type = IRQF_TRIGGER_RISING;
+ else
+ prk2818_headset_info->irq_type = IRQF_TRIGGER_FALLING;
+ ret = request_irq(prk2818_headset_info->irq, headset_interrupt, prk2818_headset_info->irq_type, NULL, NULL);
+ if (ret)
+ {
DBG("headsetobserve: request irq failed\n");
- return ret;
+ return ret;
}
- headsetobserve_work();
+
+ schedule_delayed_work(&g_headsetobserve_work, msecs_to_jiffies(500));
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ hs_early_suspend.suspend = NULL;
+ hs_early_suspend.resume = headset_early_resume;
+ hs_early_suspend.level = ~0x0;
+ register_early_suspend(&hs_early_suspend);
+#endif
return 0;
}