| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746 |
- #include "accdet.h"
- #include "ts3a225e.h"
- #ifdef CONFIG_ACCDET_EINT
- #include <linux/gpio.h>
- #endif
- #include <upmu_common.h>
- #include <linux/timer.h>
- #include <linux/of.h>
- #include <linux/of_irq.h>
- #define DEBUG_THREAD 1
- /*----------------------------------------------------------------------
- static variable defination
- ----------------------------------------------------------------------*/
- #define REGISTER_VALUE(x) (x - 1)
- static int button_press_debounce = 0x400;
- int cur_key = 0;
- struct head_dts_data accdet_dts_data;
- s8 accdet_auxadc_offset;
- int accdet_irq;
- unsigned int gpiopin, headsetdebounce;
- unsigned int accdet_eint_type;
- struct headset_mode_settings *cust_headset_settings;
- #define ACCDET_DEBUG(format, args...) pr_debug(format, ##args)
- #define ACCDET_INFO(format, args...) pr_warn(format, ##args)
- #define ACCDET_ERROR(format, args...) pr_err(format, ##args)
- static struct switch_dev accdet_data;
- static struct input_dev *kpd_accdet_dev;
- static struct cdev *accdet_cdev;
- static struct class *accdet_class;
- static struct device *accdet_nor_device;
- static dev_t accdet_devno;
- static int pre_status;
- static int pre_state_swctrl;
- static int accdet_status = PLUG_OUT;
- static int cable_type;
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- /*add for new feature PIN recognition*/
- static int cable_pin_recognition;
- static int show_icon_delay;
- #endif
- #if defined(CONFIG_TS3A225E_ACCDET)
- #define TS3A225E_CONNECTOR_NONE 0
- #define TS3A225E_CONNECTOR_TRS 1
- #define TS3A225E_CONNECTOR_TRRS_STANDARD 2
- #define TS3A225E_CONNECTOR_TRRS_OMTP 3
- unsigned char ts3a225e_reg_value[7] = { 0 };
- unsigned char ts3a225e_connector_type = TS3A225E_CONNECTOR_NONE;
- #endif
- static int eint_accdet_sync_flag;
- static int g_accdet_first = 1;
- static bool IRQ_CLR_FLAG;
- static char call_status;
- static int button_status;
- struct wake_lock accdet_suspend_lock;
- struct wake_lock accdet_irq_lock;
- struct wake_lock accdet_key_lock;
- struct wake_lock accdet_timer_lock;
- static struct work_struct accdet_work;
- static struct workqueue_struct *accdet_workqueue;
- static DEFINE_MUTEX(accdet_eint_irq_sync_mutex);
- static inline void clear_accdet_interrupt(void);
- static inline void clear_accdet_eint_interrupt(void);
- static void send_key_event(int keycode, int flag);
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- static struct work_struct accdet_eint_work;
- static struct workqueue_struct *accdet_eint_workqueue;
- static inline void accdet_init(void);
- #define MICBIAS_DISABLE_TIMER (6 * HZ) /*6 seconds*/
- struct timer_list micbias_timer;
- static void disable_micbias(unsigned long a);
- /* Used to let accdet know if the pin has been fully plugged-in */
- #define EINT_PIN_PLUG_IN (1)
- #define EINT_PIN_PLUG_OUT (0)
- int cur_eint_state = EINT_PIN_PLUG_OUT;
- static struct work_struct accdet_disable_work;
- static struct workqueue_struct *accdet_disable_workqueue;
- #else
- /*static int g_accdet_working_in_suspend =0;*/
- #endif/*end CONFIG_ACCDET_EINT*/
- #ifndef CONFIG_ACCDET_EINT_IRQ
- struct pinctrl *accdet_pinctrl1;
- struct pinctrl_state *pins_eint_int;
- #endif
- #ifdef DEBUG_THREAD
- #endif
- static u32 pmic_pwrap_read(u32 addr);
- static void pmic_pwrap_write(u32 addr, unsigned int wdata);
- char *accdet_status_string[5] = {
- "Plug_out",
- "Headset_plug_in",
- /*"Double_check",*/
- "Hook_switch",
- /*"Tvout_plug_in",*/
- "Stand_by"
- };
- char *accdet_report_string[4] = {
- "No_device",
- "Headset_mic",
- "Headset_no_mic",
- /*"HEADSET_illegal",*/
- /* "Double_check"*/
- };
- /****************************************************************/
- /*** export function **/
- /****************************************************************/
- void accdet_detect(void)
- {
- int ret = 0;
- ACCDET_DEBUG("[Accdet]accdet_detect\n");
- accdet_status = PLUG_OUT;
- ret = queue_work(accdet_workqueue, &accdet_work);
- if (!ret)
- ACCDET_DEBUG("[Accdet]accdet_detect:accdet_work return:%d!\n", ret);
- }
- EXPORT_SYMBOL(accdet_detect);
- void accdet_state_reset(void)
- {
- ACCDET_DEBUG("[Accdet]accdet_state_reset\n");
- accdet_status = PLUG_OUT;
- cable_type = NO_DEVICE;
- }
- EXPORT_SYMBOL(accdet_state_reset);
- int accdet_get_cable_type(void)
- {
- return cable_type;
- }
- void accdet_auxadc_switch(int enable)
- {
- if (enable) {
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) | ACCDET_BF_ON);
- /*ACCDET_DEBUG("ACCDET enable switch\n");*/
- } else {
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) & ~(ACCDET_BF_ON));
- /*ACCDET_DEBUG("ACCDET disable switch\n");*/
- }
- }
- /****************************************************************/
- /*******static function defination **/
- /****************************************************************/
- static u64 accdet_get_current_time(void)
- {
- return sched_clock();
- }
- static bool accdet_timeout_ns(u64 start_time_ns, u64 timeout_time_ns)
- {
- u64 cur_time = 0;
- u64 elapse_time = 0;
- /*get current tick*/
- cur_time = accdet_get_current_time(); /*ns*/
- if (cur_time < start_time_ns) {
- ACCDET_DEBUG("@@@@Timer overflow! start%lld cur timer%lld\n", start_time_ns, cur_time);
- start_time_ns = cur_time;
- timeout_time_ns = 400 * 1000; /*400us*/
- ACCDET_DEBUG("@@@@reset timer! start%lld setting%lld\n", start_time_ns, timeout_time_ns);
- }
- elapse_time = cur_time - start_time_ns;
- /*check if timeout*/
- if (timeout_time_ns <= elapse_time) {
- /*timeout*/
- ACCDET_DEBUG("@@@@ACCDET IRQ clear Timeout\n");
- return false;
- }
- return true;
- }
- /*pmic wrap read and write func*/
- static u32 pmic_pwrap_read(u32 addr)
- {
- u32 val = 0;
- pwrap_read(addr, &val);
- return val;
- }
- static void pmic_pwrap_write(unsigned int addr, unsigned int wdata)
- {
- pwrap_write(addr, wdata);
- }
- static int Accdet_PMIC_IMM_GetOneChannelValue(int deCount)
- {
- unsigned int vol_val = 0;
- pmic_pwrap_write(ACCDET_AUXADC_CTL_SET, ACCDET_CH_REQ_EN);
- mdelay(3);
- while ((pmic_pwrap_read(ACCDET_AUXADC_REG) & ACCDET_DATA_READY) != ACCDET_DATA_READY)
- ;
- /*wait AUXADC data ready*/
- vol_val = (pmic_pwrap_read(ACCDET_AUXADC_REG) & ACCDET_DATA_MASK);
- vol_val = (vol_val * 1800) / 4096; /*mv*/
- vol_val -= accdet_auxadc_offset;
- ACCDET_DEBUG("ACCDET accdet_auxadc_offset: %d mv, MIC_Voltage1 = %d mv!\n\r", accdet_auxadc_offset, vol_val);
- return vol_val;
- }
- #ifdef CONFIG_ACCDET_PIN_SWAP
- static void accdet_FSA8049_enable(void)
- {
- mt_set_gpio_mode(GPIO_FSA8049_PIN, GPIO_FSA8049_PIN_M_GPIO);
- mt_set_gpio_dir(GPIO_FSA8049_PIN, GPIO_DIR_OUT);
- mt_set_gpio_out(GPIO_FSA8049_PIN, GPIO_OUT_ONE);
- }
- static void accdet_FSA8049_disable(void)
- {
- mt_set_gpio_mode(GPIO_FSA8049_PIN, GPIO_FSA8049_PIN_M_GPIO);
- mt_set_gpio_dir(GPIO_FSA8049_PIN, GPIO_DIR_OUT);
- mt_set_gpio_out(GPIO_FSA8049_PIN, GPIO_OUT_ZERO);
- }
- #endif
- static inline void headset_plug_out(void)
- {
- accdet_status = PLUG_OUT;
- cable_type = NO_DEVICE;
- /*update the cable_type*/
- if (cur_key != 0) {
- send_key_event(cur_key, 0);
- ACCDET_DEBUG(" [accdet] headset_plug_out send key = %d release\n", cur_key);
- cur_key = 0;
- }
- switch_set_state((struct switch_dev *)&accdet_data, cable_type);
- ACCDET_DEBUG(" [accdet] set state in cable_type = NO_DEVICE\n");
- }
- /*Accdet only need this func*/
- static inline void enable_accdet(u32 state_swctrl)
- {
- /*enable ACCDET unit*/
- ACCDET_DEBUG("accdet: enable_accdet\n");
- /*enable clock*/
- pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_CLK_CLR);
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL) | state_swctrl);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) | ACCDET_ENABLE);
- }
- static inline void disable_accdet(void)
- {
- int irq_temp = 0;
- /*sync with accdet_irq_handler set clear accdet irq bit to avoid set clear accdet irq bit after disable accdet
- disable accdet irq*/
- pmic_pwrap_write(INT_CON_ACCDET_CLR, RG_ACCDET_IRQ_CLR);
- clear_accdet_interrupt();
- udelay(200);
- mutex_lock(&accdet_eint_irq_sync_mutex);
- while (pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) {
- ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going....\n");
- msleep(20);
- }
- irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
- irq_temp = irq_temp & (~IRQ_CLR_BIT);
- pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- /*disable ACCDET unit*/
- ACCDET_DEBUG("accdet: disable_accdet\n");
- pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
- #ifdef CONFIG_ACCDET_EINT
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0);
- pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
- /*disable clock and Analog control*/
- /*mt6331_upmu_set_rg_audmicbias1vref(0x0);*/
- pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
- #endif
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, ACCDET_EINT_PWM_EN);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) & (~(ACCDET_ENABLE)));
- /*mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ZERO);*/
- #endif
- }
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- static void disable_micbias(unsigned long a)
- {
- int ret = 0;
- ret = queue_work(accdet_disable_workqueue, &accdet_disable_work);
- if (!ret)
- ACCDET_DEBUG("[Accdet]disable_micbias:accdet_work return:%d!\n", ret);
- }
- static void disable_micbias_callback(struct work_struct *work)
- {
- if (cable_type == HEADSET_NO_MIC) {
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- show_icon_delay = 0;
- cable_pin_recognition = 0;
- ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
- pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
- pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_thresh);
- #endif
- /*setting pwm idle;*/
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL) & ~ACCDET_SWCTRL_IDLE_EN);
- #ifdef CONFIG_ACCDET_PIN_SWAP
- /*accdet_FSA8049_disable(); disable GPIOxxx for PIN swap */
- /*ACCDET_DEBUG("[Accdet] FSA8049 disable!\n");*/
- #endif
- disable_accdet();
- ACCDET_DEBUG("[Accdet] more than 5s MICBIAS : Disabled\n");
- }
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- else if (cable_type == HEADSET_MIC) {
- pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
- pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_thresh);
- ACCDET_DEBUG("[Accdet]pin recog after 5s recover micbias polling!\n");
- }
- #endif
- }
- static void accdet_eint_work_callback(struct work_struct *work)
- {
- #ifdef CONFIG_ACCDET_EINT_IRQ
- int irq_temp = 0;
- if (cur_eint_state == EINT_PIN_PLUG_IN) {
- ACCDET_DEBUG("[Accdet]DCC EINT func :plug-in, cur_eint_state = %d\n", cur_eint_state);
- mutex_lock(&accdet_eint_irq_sync_mutex);
- eint_accdet_sync_flag = 1;
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- wake_lock_timeout(&accdet_timer_lock, 7 * HZ);
- #ifdef CONFIG_ACCDET_PIN_SWAP
- /*pmic_pwrap_write(0x0400, pmic_pwrap_read(0x0400)|(1<<14)); */
- msleep(800);
- accdet_FSA8049_enable(); /*enable GPIOxxx for PIN swap */
- ACCDET_DEBUG("[Accdet] FSA8049 enable!\n");
- msleep(250); /*PIN swap need ms*/
- #endif
- accdet_init(); /*do set pwm_idle on in accdet_init*/
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- show_icon_delay = 1;
- /*micbias always on during detected PIN recognition*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
- pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width);
- ACCDET_DEBUG("[Accdet]pin recog start! micbias always on!\n");
- #endif
- /*set PWM IDLE on*/
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL) | ACCDET_SWCTRL_IDLE_EN));
- /*enable ACCDET unit*/
- enable_accdet(ACCDET_SWCTRL_EN);
- } else {
- /*EINT_PIN_PLUG_OUT*/
- /*Disable ACCDET*/
- ACCDET_DEBUG("[Accdet]DCC EINT func :plug-out, cur_eint_state = %d\n", cur_eint_state);
- mutex_lock(&accdet_eint_irq_sync_mutex);
- eint_accdet_sync_flag = 0;
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- del_timer_sync(&micbias_timer);
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- show_icon_delay = 0;
- cable_pin_recognition = 0;
- #endif
- #ifdef CONFIG_ACCDET_PIN_SWAP
- /*pmic_pwrap_write(0x0400, pmic_pwrap_read(0x0400)&~(1<<14)); */
- accdet_FSA8049_disable(); /*disable GPIOxxx for PIN swap */
- ACCDET_DEBUG("[Accdet] FSA8049 disable!\n");
- #endif
- /*accdet_auxadc_switch(0);*/
- disable_accdet();
- headset_plug_out();
- /*recover EINT irq clear bit */
- /*TODO: need think~~~*/
- irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
- irq_temp = irq_temp & (~IRQ_EINT_CLR_BIT);
- pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
- }
- #else
- /*KE under fastly plug in and plug out*/
- if (cur_eint_state == EINT_PIN_PLUG_IN) {
- ACCDET_DEBUG("[Accdet]ACC EINT func :plug-in, cur_eint_state = %d\n", cur_eint_state);
- mutex_lock(&accdet_eint_irq_sync_mutex);
- eint_accdet_sync_flag = 1;
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- wake_lock_timeout(&accdet_timer_lock, 7 * HZ);
- #ifdef CONFIG_ACCDET_PIN_SWAP
- /*pmic_pwrap_write(0x0400, pmic_pwrap_read(0x0400)|(1<<14)); */
- msleep(800);
- accdet_FSA8049_enable(); /*enable GPIOxxx for PIN swap */
- ACCDET_DEBUG("[Accdet] FSA8049 enable!\n");
- msleep(250); /*PIN swap need ms */
- #endif
- #if defined(CONFIG_TS3A225E_ACCDET)
- ACCDET_DEBUG("[Accdet] TS3A225E enable!\n");
- msleep(300);
- ts3a225e_write_byte(0x04, 0x01);
- msleep(500);
- ts3a225e_read_byte(0x02, &ts3a225e_reg_value[1]);
- ts3a225e_read_byte(0x03, &ts3a225e_reg_value[2]);
- ts3a225e_read_byte(0x05, &ts3a225e_reg_value[4]);
- ts3a225e_read_byte(0x06, &ts3a225e_reg_value[5]);
- ACCDET_DEBUG("[Accdet] TS3A225E CTRL1=%x!\n", ts3a225e_reg_value[1]);
- ACCDET_DEBUG("[Accdet] TS3A225E CTRL2=%x!\n", ts3a225e_reg_value[2]);
- ACCDET_DEBUG("[Accdet] TS3A225E DAT1=%x!\n", ts3a225e_reg_value[4]);
- ACCDET_DEBUG("[Accdet] TS3A225E INT=%x!\n", ts3a225e_reg_value[5]);
- if (ts3a225e_reg_value[5] == 0x01) {
- ACCDET_DEBUG("[Accdet] TS3A225E A standard TSR headset detected, RING2 and SLEEVE shorted!\n");
- ts3a225e_connector_type = TS3A225E_CONNECTOR_TRS;
- ts3a225e_write_byte(0x02, 0x07);
- ts3a225e_write_byte(0x03, 0xf3);
- msleep(20);
- } else if (ts3a225e_reg_value[5] == 0x02) {
- ACCDET_DEBUG("[Accdet] TS3A225E A microphone detected on either RING2 or SLEEVE!\n");
- if ((ts3a225e_reg_value[4] & 0x40) == 0x00)
- ts3a225e_connector_type = TS3A225E_CONNECTOR_TRRS_STANDARD;
- else
- ts3a225e_connector_type = TS3A225E_CONNECTOR_TRRS_OMTP;
- } else {
- ACCDET_DEBUG("[Accdet] TS3A225E Detection sequence completed without successful!\n");
- }
- #endif
- accdet_init(); /* do set pwm_idle on in accdet_init*/
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- show_icon_delay = 1;
- /*micbias always on during detected PIN recognition*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
- pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width);
- ACCDET_DEBUG("[Accdet]pin recog start! micbias always on!\n");
- #endif
- /*set PWM IDLE on*/
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL) | ACCDET_SWCTRL_IDLE_EN));
- /*enable ACCDET unit*/
- enable_accdet(ACCDET_SWCTRL_EN);
- } else {
- /*EINT_PIN_PLUG_OUT*/
- /*Disable ACCDET*/
- ACCDET_DEBUG("[Accdet]ACC EINT func :plug-out, cur_eint_state = %d\n", cur_eint_state);
- mutex_lock(&accdet_eint_irq_sync_mutex);
- eint_accdet_sync_flag = 0;
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- del_timer_sync(&micbias_timer);
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- show_icon_delay = 0;
- cable_pin_recognition = 0;
- #endif
- #ifdef CONFIG_ACCDET_PIN_SWAP
- /*pmic_pwrap_write(0x0400, pmic_pwrap_read(0x0400)&~(1<<14));*/
- accdet_FSA8049_disable(); /*disable GPIOxxx for PIN swap*/
- ACCDET_DEBUG("[Accdet] FSA8049 disable!\n");
- #endif
- #if defined(CONFIG_TS3A225E_ACCDET)
- ACCDET_DEBUG("[Accdet] TS3A225E disable!\n");
- ts3a225e_connector_type = TS3A225E_CONNECTOR_NONE;
- #endif
- /*accdet_auxadc_switch(0);*/
- disable_accdet();
- headset_plug_out();
- }
- enable_irq(accdet_irq);
- ACCDET_DEBUG("[Accdet]enable_irq !!!!!!\n");
- #endif
- }
- static irqreturn_t accdet_eint_func(int irq, void *data)
- {
- int ret = 0;
- ACCDET_DEBUG("[Accdet]Enter accdet_eint_func !!!!!!\n");
- if (cur_eint_state == EINT_PIN_PLUG_IN) {
- /*
- To trigger EINT when the headset was plugged in
- We set the polarity back as we initialed.
- */
- #ifndef CONFIG_ACCDET_EINT_IRQ
- if (accdet_eint_type == IRQ_TYPE_LEVEL_HIGH)
- irq_set_irq_type(accdet_irq, IRQ_TYPE_LEVEL_HIGH);
- else
- irq_set_irq_type(accdet_irq, IRQ_TYPE_LEVEL_LOW);
- #endif
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_EINT_CTL, pmic_pwrap_read(ACCDET_EINT_CTL) & (~(7 << 4)));
- /*debounce=256ms*/
- pmic_pwrap_write(ACCDET_EINT_CTL, pmic_pwrap_read(ACCDET_EINT_CTL) | EINT_IRQ_DE_IN);
- pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3);
- #else
- gpio_set_debounce(gpiopin, headsetdebounce);
- #endif
- /* update the eint status */
- cur_eint_state = EINT_PIN_PLUG_OUT;
- } else {
- /*
- To trigger EINT when the headset was plugged out
- We set the opposite polarity to what we initialed.
- */
- #ifndef CONFIG_ACCDET_EINT_IRQ
- if (accdet_eint_type == IRQ_TYPE_LEVEL_HIGH)
- irq_set_irq_type(accdet_irq, IRQ_TYPE_LEVEL_LOW);
- else
- irq_set_irq_type(accdet_irq, IRQ_TYPE_LEVEL_HIGH);
- #endif
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_EINT_CTL, pmic_pwrap_read(ACCDET_EINT_CTL) & (~(7 << 4)));
- /*debounce=16ms*/
- pmic_pwrap_write(ACCDET_EINT_CTL, pmic_pwrap_read(ACCDET_EINT_CTL) | EINT_IRQ_DE_OUT);
- #else
- gpio_set_debounce(gpiopin, accdet_dts_data.accdet_plugout_debounce * 1000);
- #endif
- /* update the eint status */
- cur_eint_state = EINT_PIN_PLUG_IN;
- mod_timer(&micbias_timer, jiffies + MICBIAS_DISABLE_TIMER);
- }
- #ifndef CONFIG_ACCDET_EINT_IRQ
- disable_irq_nosync(accdet_irq);
- #endif
- ACCDET_DEBUG("[Accdet]accdet_eint_func after cur_eint_state=%d\n", cur_eint_state);
- ret = queue_work(accdet_eint_workqueue, &accdet_eint_work);
- return IRQ_HANDLED;
- }
- #ifndef CONFIG_ACCDET_EINT_IRQ
- static inline int accdet_setup_eint(struct platform_device *accdet_device)
- {
- int ret;
- u32 ints[2] = { 0, 0 };
- u32 ints1[2] = { 0, 0 };
- struct device_node *node = NULL;
- struct pinctrl_state *pins_default;
- /*configure to GPIO function, external interrupt */
- ACCDET_INFO("[Accdet]accdet_setup_eint\n");
- accdet_pinctrl1 = devm_pinctrl_get(&accdet_device->dev);
- if (IS_ERR(accdet_pinctrl1)) {
- ret = PTR_ERR(accdet_pinctrl1);
- dev_err(&accdet_device->dev, "fwq Cannot find accdet accdet_pinctrl1!\n");
- return ret;
- }
- pins_default = pinctrl_lookup_state(accdet_pinctrl1, "default");
- if (IS_ERR(pins_default)) {
- ret = PTR_ERR(pins_default);
- /*dev_err(&accdet_device->dev, "fwq Cannot find accdet pinctrl default!\n");*/
- }
- pins_eint_int = pinctrl_lookup_state(accdet_pinctrl1, "state_eint_as_int");
- if (IS_ERR(pins_eint_int)) {
- ret = PTR_ERR(pins_eint_int);
- dev_err(&accdet_device->dev, "fwq Cannot find accdet pinctrl state_eint_accdet!\n");
- return ret;
- }
- pinctrl_select_state(accdet_pinctrl1, pins_eint_int);
- /*node = of_find_matching_node(node, accdet_of_match);*/
- node = of_find_matching_node(node, accdet_of_match);
- if (node) {
- of_property_read_u32_array(node, "debounce", ints, ARRAY_SIZE(ints));
- of_property_read_u32_array(node, "interrupts", ints1, ARRAY_SIZE(ints1));
- gpiopin = ints[0];
- headsetdebounce = ints[1];
- accdet_eint_type = ints1[1];
- gpio_set_debounce(gpiopin, headsetdebounce);
- accdet_irq = irq_of_parse_and_map(node, 0);
- ret = request_irq(accdet_irq, accdet_eint_func, IRQF_TRIGGER_NONE, "accdet-eint", NULL);
- if (ret != 0) {
- ACCDET_ERROR("[Accdet]EINT IRQ LINE NOT AVAILABLE\n");
- } else {
- ACCDET_ERROR("[Accdet]accdet set EINT finished, accdet_irq=%d, headsetdebounce=%d\n",
- accdet_irq, headsetdebounce);
- }
- } else {
- ACCDET_ERROR("[Accdet]%s can't find compatible node\n", __func__);
- }
- return 0;
- }
- #endif /*CONFIG_ACCDET_EINT_IRQ*/
- #endif /*endif CONFIG_ACCDET_EINT*/
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- #define KEY_SAMPLE_PERIOD (60) /*ms*/
- #define MULTIKEY_ADC_CHANNEL (8)
- static DEFINE_MUTEX(accdet_multikey_mutex);
- #define NO_KEY (0x0)
- #define UP_KEY (0x01)
- #define MD_KEY (0x02)
- #define DW_KEY (0x04)
- #define AS_KEY (0x08)
- #ifndef CONFIG_FOUR_KEY_HEADSET
- static int key_check(int b)
- {
- /*ACCDET_DEBUG("adc_data: %d v\n",b);*/
- /* 0.24V ~ */
- /*ACCDET_DEBUG("[accdet] come in key_check!!\n");*/
- if ((b < accdet_dts_data.three_key.down_key) && (b >= accdet_dts_data.three_key.up_key))
- return DW_KEY;
- else if ((b < accdet_dts_data.three_key.up_key) && (b >= accdet_dts_data.three_key.mid_key))
- return UP_KEY;
- else if (b < accdet_dts_data.three_key.mid_key)
- return MD_KEY;
- ACCDET_DEBUG("[accdet] leave key_check!!\n");
- return NO_KEY;
- }
- #else
- static int key_check(int b)
- {
- /* 0.24V ~ */
- /*ACCDET_DEBUG("[accdet] come in key_check!!\n");*/
- if ((b < accdet_dts_data.four_key.down_key_four) && (b >= accdet_dts_data.four_key.up_key_four))
- return DW_KEY;
- else if ((b < accdet_dts_data.four_key.up_key_four) && (b >= accdet_dts_data.four_key.voice_key_four))
- return UP_KEY;
- else if ((b < accdet_dts_data.four_key.voice_key_four) && (b >= accdet_dts_data.four_key.mid_key_four))
- return AS_KEY;
- else if (b < accdet_dts_data.four_key.mid_key_four)
- return MD_KEY;
- ACCDET_DEBUG("[accdet] leave key_check!!\n");
- return NO_KEY;
- }
- #endif
- static void send_key_event(int keycode, int flag)
- {
- switch (keycode) {
- case DW_KEY:
- input_report_key(kpd_accdet_dev, KEY_VOLUMEDOWN, flag);
- input_sync(kpd_accdet_dev);
- ACCDET_DEBUG("[accdet]KEY_VOLUMEDOWN %d\n", flag);
- break;
- case UP_KEY:
- input_report_key(kpd_accdet_dev, KEY_VOLUMEUP, flag);
- input_sync(kpd_accdet_dev);
- ACCDET_DEBUG("[accdet]KEY_VOLUMEUP %d\n", flag);
- break;
- case MD_KEY:
- input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, flag);
- input_sync(kpd_accdet_dev);
- ACCDET_DEBUG("[accdet]KEY_PLAYPAUSE %d\n", flag);
- break;
- case AS_KEY:
- input_report_key(kpd_accdet_dev, KEY_VOICECOMMAND, flag);
- input_sync(kpd_accdet_dev);
- ACCDET_DEBUG("[accdet]KEY_VOICECOMMAND %d\n", flag);
- break;
- }
- }
- static void multi_key_detection(int current_status)
- {
- int m_key = 0;
- int cali_voltage = 0;
- if (0 == current_status) {
- cali_voltage = Accdet_PMIC_IMM_GetOneChannelValue(1);
- /*ACCDET_DEBUG("[Accdet]adc cali_voltage1 = %d mv\n", cali_voltage);*/
- m_key = cur_key = key_check(cali_voltage);
- }
- mdelay(30);
- #ifdef CONFIG_ACCDET_EINT_IRQ
- if (((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) != EINT_IRQ_STATUS_BIT) || eint_accdet_sync_flag) {
- #else /* ifdef CONFIG_ACCDET_EINT */
- if (((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) != IRQ_STATUS_BIT) || eint_accdet_sync_flag) {
- #endif
- send_key_event(cur_key, !current_status);
- } else {
- ACCDET_DEBUG("[Accdet]plug out side effect key press, do not report key = %d\n", cur_key);
- cur_key = NO_KEY;
- }
- if (current_status)
- cur_key = NO_KEY;
- }
- #endif
- static void accdet_workqueue_func(void)
- {
- int ret;
- ret = queue_work(accdet_workqueue, &accdet_work);
- if (!ret)
- ACCDET_DEBUG("[Accdet]accdet_work return:%d!\n", ret);
- }
- int accdet_irq_handler(void)
- {
- u64 cur_time = 0;
- cur_time = accdet_get_current_time();
- #ifdef CONFIG_ACCDET_EINT_IRQ
- ACCDET_DEBUG("[Accdet accdet_irq_handler]clear_accdet_eint_interrupt: ACCDET_IRQ_STS = 0x%x\n",
- pmic_pwrap_read(ACCDET_IRQ_STS));
- if ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)
- && ((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) != EINT_IRQ_STATUS_BIT)) {
- clear_accdet_interrupt();
- if (accdet_status == MIC_BIAS) {
- /*accdet_auxadc_switch(1);*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- }
- accdet_workqueue_func();
- while (((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)
- && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT))))
- ;
- } else if ((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT) == EINT_IRQ_STATUS_BIT) {
- if (cur_eint_state == EINT_PIN_PLUG_IN) {
- if (accdet_eint_type == IRQ_TYPE_LEVEL_HIGH)
- pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) | EINT_IRQ_POL_HIGH);
- else
- pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) & ~EINT_IRQ_POL_LOW);
- } else {
- if (accdet_eint_type == IRQ_TYPE_LEVEL_HIGH)
- pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) & ~EINT_IRQ_POL_LOW);
- else
- pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) | EINT_IRQ_POL_HIGH);
- }
- clear_accdet_eint_interrupt();
- while (((pmic_pwrap_read(ACCDET_IRQ_STS) & EINT_IRQ_STATUS_BIT)
- && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT))))
- ;
- accdet_eint_func(accdet_irq, NULL);
- } else {
- ACCDET_DEBUG("ACCDET IRQ and EINT IRQ don't be triggerred!!\n");
- }
- #else
- if ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT))
- clear_accdet_interrupt();
- if (accdet_status == MIC_BIAS) {
- /*accdet_auxadc_switch(1);*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- }
- accdet_workqueue_func();
- while (((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)
- && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT))))
- ;
- #endif
- #ifdef ACCDET_NEGV_IRQ
- cur_time = accdet_get_current_time();
- if ((pmic_pwrap_read(ACCDET_IRQ_STS) & NEGV_IRQ_STATUS_BIT) == NEGV_IRQ_STATUS_BIT) {
- ACCDET_DEBUG("[ACCDET NEGV detect]plug in a error Headset\n\r");
- pmic_pwrap_write(ACCDET_IRQ_STS, (IRQ_NEGV_CLR_BIT));
- while (((pmic_pwrap_read(ACCDET_IRQ_STS) & NEGV_IRQ_STATUS_BIT)
- && (accdet_timeout_ns(cur_time, ACCDET_TIME_OUT))))
- ;
- pmic_pwrap_write(ACCDET_IRQ_STS, (pmic_pwrap_read(ACCDET_IRQ_STS) & (~IRQ_NEGV_CLR_BIT)));
- }
- #endif
- return 1;
- }
- /*clear ACCDET IRQ in accdet register*/
- static inline void clear_accdet_interrupt(void)
- {
- /*it is safe by using polling to adjust when to clear IRQ_CLR_BIT*/
- pmic_pwrap_write(ACCDET_IRQ_STS, ((pmic_pwrap_read(ACCDET_IRQ_STS)) & 0x8000) | (IRQ_CLR_BIT));
- ACCDET_DEBUG("[Accdet]clear_accdet_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));
- }
- static inline void clear_accdet_eint_interrupt(void)
- {
- pmic_pwrap_write(ACCDET_IRQ_STS, (((pmic_pwrap_read(ACCDET_IRQ_STS)) & 0x8000) | IRQ_EINT_CLR_BIT));
- ACCDET_DEBUG("[Accdet]clear_accdet_eint_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));
- }
- static inline void check_cable_type(void)
- {
- int current_status = 0;
- int irq_temp = 0; /*for clear IRQ_bit*/
- int wait_clear_irq_times = 0;
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- int pin_adc_value = 0;
- #define PIN_ADC_CHANNEL 5
- #endif
- current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*A=bit1; B=bit0*/
- ACCDET_DEBUG("[Accdet]accdet interrupt happen:[%s]current AB = %d\n",
- accdet_status_string[accdet_status], current_status);
- button_status = 0;
- pre_status = accdet_status;
- /*ACCDET_DEBUG("[Accdet]check_cable_type: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));*/
- IRQ_CLR_FLAG = false;
- switch (accdet_status) {
- case PLUG_OUT:
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1);
- #endif
- if (current_status == 0) {
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- /*micbias always on during detected PIN recognition*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
- pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width);
- ACCDET_DEBUG("[Accdet]PIN recognition micbias always on!\n");
- ACCDET_DEBUG("[Accdet]before adc read, pin_adc_value = %d mv!\n", pin_adc_value);
- msleep(500);
- current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*A=bit1; B=bit0*/
- if (current_status == 0 && show_icon_delay != 0) {
- /*accdet_auxadc_switch(1);switch on when need to use auxadc read voltage*/
- pin_adc_value = Accdet_PMIC_IMM_GetOneChannelValue(1);
- ACCDET_DEBUG("[Accdet]pin_adc_value = %d mv!\n", pin_adc_value);
- /*accdet_auxadc_switch(0);*/
- if (180 > pin_adc_value && pin_adc_value > 90) { /*90mv ilegal headset*/
- /*mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ONE);*/
- /*ACCDET_DEBUG("[Accdet]PIN recognition change GPIO_OUT!\n");*/
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- cable_type = HEADSET_NO_MIC;
- accdet_status = HOOK_SWITCH;
- cable_pin_recognition = 1;
- ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n",
- cable_pin_recognition);
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- } else {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- cable_type = HEADSET_NO_MIC;
- accdet_status = HOOK_SWITCH;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- }
- }
- #else
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- cable_type = HEADSET_NO_MIC;
- accdet_status = HOOK_SWITCH;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #endif
- } else if (current_status == 1) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- accdet_status = MIC_BIAS;
- cable_type = HEADSET_MIC;
- /*AB=11 debounce=30ms*/
- pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3 * 30);
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce);
- /*recover polling set AB 00-01*/
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
- #endif
- } else if (current_status == 3) {
- ACCDET_DEBUG("[Accdet]PLUG_OUT state not change!\n");
- #ifdef CONFIG_ACCDET_EINT
- ACCDET_DEBUG("[Accdet] do not send plug out event in plug out\n");
- #else
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- accdet_status = PLUG_OUT;
- cable_type = NO_DEVICE;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #endif
- } else {
- ACCDET_DEBUG("[Accdet]PLUG_OUT can't change to this state!\n");
- }
- break;
- case MIC_BIAS:
- /*solution: resume hook switch debounce time*/
- pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0);
- if (current_status == 0) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)
- && (wait_clear_irq_times < 3)) {
- ACCDET_DEBUG("[Accdet]check_cable_type: MIC BIAS clear IRQ on-going1....\n");
- wait_clear_irq_times++;
- msleep(20);
- }
- irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
- irq_temp = irq_temp & (~IRQ_CLR_BIT);
- pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
- IRQ_CLR_FLAG = true;
- accdet_status = HOOK_SWITCH;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- button_status = 1;
- if (button_status) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag)
- multi_key_detection(current_status);
- else
- ACCDET_DEBUG("[Accdet] multi_key_detection: Headset has plugged out\n");
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- /*accdet_auxadc_switch(0);*/
- /*recover pwm frequency and duty*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
- }
- } else if (current_status == 1) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- accdet_status = MIC_BIAS;
- cable_type = HEADSET_MIC;
- ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n");
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- } else if (current_status == 3) {
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- ACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n");
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag)
- accdet_status = PLUG_OUT;
- else
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #else
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- accdet_status = PLUG_OUT;
- cable_type = NO_DEVICE;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #endif
- } else {
- ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n");
- }
- break;
- case HOOK_SWITCH:
- if (current_status == 0) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- /*for avoid 01->00 framework of Headset will report press key info for Audio*/
- /*cable_type = HEADSET_NO_MIC;*/
- /*accdet_status = HOOK_SWITCH;*/
- ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n");
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- } else if (current_status == 1) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- multi_key_detection(current_status);
- accdet_status = MIC_BIAS;
- cable_type = HEADSET_MIC;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- /*accdet_auxadc_switch(0);*/
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- cable_pin_recognition = 0;
- ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
- pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
- #endif
- /*solution: reduce hook switch debounce time to 0x400*/
- pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce);
- } else if (current_status == 3) {
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- cable_pin_recognition = 0;
- ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag)
- accdet_status = PLUG_OUT;
- else
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #endif
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n");
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag)
- accdet_status = PLUG_OUT;
- else
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #else
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- accdet_status = PLUG_OUT;
- cable_type = NO_DEVICE;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #endif
- } else {
- ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n");
- }
- break;
- case STAND_BY:
- if (current_status == 3) {
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- ACCDET_DEBUG("[Accdet]accdet do not send plug out event in stand by!\n");
- #else
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- accdet_status = PLUG_OUT;
- cable_type = NO_DEVICE;
- } else {
- ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
- }
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- #endif
- } else {
- ACCDET_DEBUG("[Accdet]STAND_BY can't change to this state!\n");
- }
- break;
- default:
- ACCDET_DEBUG("[Accdet]check_cable_type: accdet current status error!\n");
- break;
- }
- if (!IRQ_CLR_FLAG) {
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag) {
- while ((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times < 3)) {
- ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going2....\n");
- wait_clear_irq_times++;
- msleep(20);
- }
- }
- irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
- irq_temp = irq_temp & (~IRQ_CLR_BIT);
- pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- IRQ_CLR_FLAG = true;
- ACCDET_DEBUG("[Accdet]check_cable_type:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS));
- } else {
- IRQ_CLR_FLAG = false;
- }
- ACCDET_DEBUG("[Accdet]cable type:[%s], status switch:[%s]->[%s]\n",
- accdet_report_string[cable_type], accdet_status_string[pre_status],
- accdet_status_string[accdet_status]);
- }
- static void accdet_work_callback(struct work_struct *work)
- {
- wake_lock(&accdet_irq_lock);
- check_cable_type();
- #ifdef CONFIG_ACCDET_PIN_SWAP
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- if (cable_pin_recognition == 1) {
- cable_pin_recognition = 0;
- accdet_FSA8049_disable();
- cable_type = HEADSET_NO_MIC;
- accdet_status = PLUG_OUT;
- }
- #endif
- #endif
- mutex_lock(&accdet_eint_irq_sync_mutex);
- if (1 == eint_accdet_sync_flag)
- switch_set_state((struct switch_dev *)&accdet_data, cable_type);
- else
- ACCDET_DEBUG("[Accdet] Headset has plugged out don't set accdet state\n");
- mutex_unlock(&accdet_eint_irq_sync_mutex);
- ACCDET_DEBUG(" [accdet] set state in cable_type status\n");
- wake_unlock(&accdet_irq_lock);
- }
- void accdet_get_dts_data(void)
- {
- struct device_node *node = NULL;
- int debounce[7];
- #ifdef CONFIG_FOUR_KEY_HEADSET
- int four_key[5];
- #else
- int three_key[4];
- #endif
- ACCDET_INFO("[ACCDET]Start accdet_get_dts_data");
- node = of_find_matching_node(node, accdet_of_match);
- if (node) {
- of_property_read_u32_array(node, "headset-mode-setting", debounce, ARRAY_SIZE(debounce));
- of_property_read_u32(node, "accdet-mic-vol", &accdet_dts_data.mic_mode_vol);
- of_property_read_u32(node, "accdet-plugout-debounce", &accdet_dts_data.accdet_plugout_debounce);
- of_property_read_u32(node, "accdet-mic-mode", &accdet_dts_data.accdet_mic_mode);
- #ifdef CONFIG_FOUR_KEY_HEADSET
- of_property_read_u32_array(node, "headset-four-key-threshold", four_key, ARRAY_SIZE(four_key));
- memcpy(&accdet_dts_data.four_key, four_key+1, sizeof(struct four_key_threshold));
- ACCDET_INFO("[Accdet]mid-Key = %d, voice = %d, up_key = %d, down_key = %d\n",
- accdet_dts_data.four_key.mid_key_four, accdet_dts_data.four_key.voice_key_four,
- accdet_dts_data.four_key.up_key_four, accdet_dts_data.four_key.down_key_four);
- #else
- of_property_read_u32_array(node, "headset-three-key-threshold", three_key, ARRAY_SIZE(three_key));
- memcpy(&accdet_dts_data.three_key, three_key+1, sizeof(struct three_key_threshold));
- ACCDET_INFO("[Accdet]mid-Key = %d, up_key = %d, down_key = %d\n",
- accdet_dts_data.three_key.mid_key, accdet_dts_data.three_key.up_key,
- accdet_dts_data.three_key.down_key);
- #endif
- memcpy(&accdet_dts_data.headset_debounce, debounce, sizeof(debounce));
- cust_headset_settings = &accdet_dts_data.headset_debounce;
- ACCDET_INFO("[Accdet]pwm_width = %x, pwm_thresh = %x\n deb0 = %x, deb1 = %x, mic_mode = %d\n",
- cust_headset_settings->pwm_width, cust_headset_settings->pwm_thresh,
- cust_headset_settings->debounce0, cust_headset_settings->debounce1,
- accdet_dts_data.accdet_mic_mode);
- } else {
- ACCDET_ERROR("[Accdet]%s can't find compatible dts node\n", __func__);
- }
- }
- void accdet_pmic_Read_Efuse_HPOffset(void)
- {
- s16 efusevalue;
- efusevalue = (s16) pmic_Read_Efuse_HPOffset(0x10);
- accdet_auxadc_offset = (efusevalue >> 8) & 0xFF;
- accdet_auxadc_offset = (accdet_auxadc_offset / 2);
- ACCDET_INFO(" efusevalue = 0x%x, accdet_auxadc_offset = %d\n", efusevalue, accdet_auxadc_offset);
- }
- static inline void accdet_init(void)
- {
- ACCDET_DEBUG("[Accdet]accdet hardware init\n");
- /*clock*/
- pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_CLK_CLR);
- /*ACCDET_DEBUG("[Accdet]accdet TOP_CKPDN=0x%x!\n", pmic_pwrap_read(TOP_CKPDN)); */
- /*reset the accdet unit*/
- /*ACCDET_DEBUG("ACCDET reset : reset start!\n\r");*/
- pmic_pwrap_write(TOP_RST_ACCDET_SET, ACCDET_RESET_SET);
- /*ACCDET_DEBUG("ACCDET reset function test: reset finished!!\n\r");*/
- pmic_pwrap_write(TOP_RST_ACCDET_CLR, ACCDET_RESET_CLR);
- /*init pwm frequency and duty*/
- pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
- pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0x07);
- /*rise and fall delay of PWM*/
- pmic_pwrap_write(ACCDET_EN_DELAY_NUM,
- (cust_headset_settings->fall_delay << 15 | cust_headset_settings->rise_delay));
- /* init the debounce time*/
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0);
- pmic_pwrap_write(ACCDET_DEBOUNCE1, 0xFFFF); /*2.0s*/
- pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3);
- pmic_pwrap_write(ACCDET_DEBOUNCE4, ACCDET_DE4);
- #else
- pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0);
- pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1);
- pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3);
- pmic_pwrap_write(ACCDET_DEBOUNCE4, ACCDET_DE4);
- #endif
- /*enable INT */
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) & (~IRQ_EINT_CLR_BIT));
- #endif
- #ifdef CONFIG_ACCDET_EINT
- pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS) & (~IRQ_CLR_BIT));
- #endif
- pmic_pwrap_write(INT_CON_ACCDET_SET, RG_ACCDET_IRQ_SET);
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(INT_CON_ACCDET_SET, RG_ACCDET_EINT_IRQ_SET);
- #endif
- #ifdef ACCDET_NEGV_IRQ
- pmic_pwrap_write(INT_CON_ACCDET_SET, RG_ACCDET_NEGV_IRQ_SET);
- #endif
- /*********************ACCDET Analog Setting***********************************************************/
- pmic_set_register_value(PMIC_RG_AUDMICBIASVREF, accdet_dts_data.mic_mode_vol);
- pmic_pwrap_write(ACCDET_RSV, 0x1290); /*TODO: need confirm pull low,6328 bit[12]=1*/
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) | ACCDET_EINT_CON_EN);
- #endif
- #ifdef ACCDET_NEGV_IRQ
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) | ACCDET_NEGV_DT_EN);
- #endif
- if (accdet_dts_data.accdet_mic_mode == 1) /* ACC mode*/
- pmic_set_register_value(PMIC_RG_AUDMICBIAS1DCSWPEN, 0);
- else if (accdet_dts_data.accdet_mic_mode == 2) /* Low cost mode without internal bias*/
- pmic_pwrap_write(ACCDET_RSV, pmic_pwrap_read(ACCDET_RSV) | ACCDET_INPUT_MICP);
- else if (accdet_dts_data.accdet_mic_mode == 6) {/* Low cost mode with internal bias*/
- pmic_pwrap_write(ACCDET_RSV, pmic_pwrap_read(ACCDET_RSV) | ACCDET_INPUT_MICP);
- pmic_set_register_value(PMIC_RG_AUDMICBIAS1DCSWPEN, 1); /*switch P internal*/
- }
- /**************************************************************************************************/
- #if defined CONFIG_ACCDET_EINT
- /* disable ACCDET unit*/
- pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
- pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0x0);
- pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
- #elif defined CONFIG_ACCDET_EINT_IRQ
- if (cur_eint_state == EINT_PIN_PLUG_OUT)
- pmic_pwrap_write(ACCDET_EINT_CTL, pmic_pwrap_read(ACCDET_EINT_CTL) | EINT_IRQ_DE_IN);/*debounce=256ms*/
- pmic_pwrap_write(ACCDET_EINT_CTL, pmic_pwrap_read(ACCDET_EINT_CTL) | EINT_PWM_THRESH);
- /* disable ACCDET unit, except CLK of ACCDET*/
- pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) | ACCDET_DISABLE);
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL) & (~ACCDET_SWCTRL_EN));
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL) | ACCDET_EINT_PWM_EN);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) | ACCDET_EINT_EN);
- #else
- /* enable ACCDET unit*/
- pmic_pwrap_write(ACCDET_CTRL, ACCDET_ENABLE);
- #endif
- #ifdef ACCDET_NEGV_IRQ
- pmic_pwrap_write(ACCDET_EINT_PWM_DELAY, pmic_pwrap_read(ACCDET_EINT_PWM_DELAY) & (~0x1F));
- pmic_pwrap_write(ACCDET_EINT_PWM_DELAY, pmic_pwrap_read(ACCDET_EINT_PWM_DELAY) | 0x0F);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) | ACCDET_NEGV_EN);
- #endif
- /**************************************AUXADC enable auto sample****************************************/
- pmic_pwrap_write(ACCDET_AUXADC_AUTO_SPL, (pmic_pwrap_read(ACCDET_AUXADC_AUTO_SPL) | ACCDET_AUXADC_AUTO_SET));
- }
- /*-----------------------------------sysfs-----------------------------------------*/
- #if DEBUG_THREAD
- static int dump_register(void)
- {
- int i = 0;
- for (i = ACCDET_RSV; i <= ACCDET_RSV_CON1; i += 2)
- ACCDET_DEBUG(" ACCDET_BASE + %x=%x\n", i, pmic_pwrap_read(ACCDET_BASE + i));
- ACCDET_DEBUG(" TOP_RST_ACCDET(0x%x) =%x\n", TOP_RST_ACCDET, pmic_pwrap_read(TOP_RST_ACCDET));
- ACCDET_DEBUG(" INT_CON_ACCDET(0x%x) =%x\n", INT_CON_ACCDET, pmic_pwrap_read(INT_CON_ACCDET));
- ACCDET_DEBUG(" TOP_CKPDN(0x%x) =%x\n", TOP_CKPDN, pmic_pwrap_read(TOP_CKPDN));
- ACCDET_DEBUG(" ACCDET_ADC_REG(0x%x) =%x\n", ACCDET_ADC_REG, pmic_pwrap_read(ACCDET_ADC_REG));
- #ifdef CONFIG_ACCDET_PIN_SWAP
- /*ACCDET_DEBUG(" 0x00004000 =%x\n",pmic_pwrap_read(0x00004000));*/
- /*VRF28 power for PIN swap feature*/
- #endif
- return 0;
- }
- #if defined(CONFIG_TS3A225E_ACCDET)
- static ssize_t show_TS3A225EConnectorType(struct device_driver *ddri, char *buf)
- {
- ACCDET_DEBUG("[Accdet] TS3A225E ts3a225e_connector_type=%d\n", ts3a225e_connector_type);
- return sprintf(buf, "%u\n", ts3a225e_connector_type);
- }
- static DRIVER_ATTR(TS3A225EConnectorType, 0664, show_TS3A225EConnectorType, NULL);
- #endif
- static ssize_t accdet_store_call_state(struct device_driver *ddri, const char *buf, size_t count)
- {
- int ret = 0;
- int value = 0;
- if (buf == NULL) {
- ACCDET_INFO("[%s] Invalid input!!\n", __func__);
- return 0;
- }
- ret = kstrtoint(buf, sizeof(int), &value);
- if (ret < 0) {
- ACCDET_INFO("accdet: Invalid values\n");
- return 0;
- }
- call_status = (char)value;
- switch (call_status) {
- case CALL_IDLE:
- ACCDET_DEBUG("[Accdet]accdet call: Idle state!\n");
- break;
- case CALL_RINGING:
- ACCDET_DEBUG("[Accdet]accdet call: ringing state!\n");
- break;
- case CALL_ACTIVE:
- ACCDET_DEBUG("[Accdet]accdet call: active or hold state!\n");
- ACCDET_DEBUG("[Accdet]accdet_ioctl : Button_Status=%d (state:%d)\n", button_status, accdet_data.state);
- /*return button_status;*/
- break;
- default:
- ACCDET_DEBUG("[Accdet]accdet call : Invalid values\n");
- break;
- }
- return count;
- }
- static ssize_t show_pin_recognition_state(struct device_driver *ddri, char *buf)
- {
- if (buf == NULL) {
- ACCDET_INFO("[%s] Invalid input!!\n", __func__);
- return 0;
- }
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- ACCDET_DEBUG("ACCDET show_pin_recognition_state = %d\n", cable_pin_recognition);
- return snprintf(buf, (size_t)sizeof(cable_pin_recognition), "%u\n", cable_pin_recognition);
- #else
- return snprintf(buf, 4, "%u\n", 0);
- #endif
- }
- static DRIVER_ATTR(accdet_pin_recognition, 0664, show_pin_recognition_state, NULL);
- static DRIVER_ATTR(accdet_call_state, 0664, NULL, accdet_store_call_state);
- static int g_start_debug_thread;
- static struct task_struct *thread;
- static int g_dump_register;
- static int dbug_thread(void *unused)
- {
- while (g_start_debug_thread) {
- if (g_dump_register) {
- dump_register();
- /*dump_pmic_register();*/
- }
- msleep(500);
- }
- return 0;
- }
- static ssize_t store_accdet_start_debug_thread(struct device_driver *ddri, const char *buf, size_t count)
- {
- int ret = 0;
- int error = 0;
- int start_flag = 0;
- if (buf == NULL) {
- ACCDET_INFO("[%s] Invalid input!!\n", __func__);
- return 0;
- }
- ret = kstrtoint(buf, sizeof(int), &start_flag);
- if (ret != 0) {
- ACCDET_DEBUG("accdet: Invalid values\n");
- return 0;
- }
- if (start_flag) {/* if write 0, Invalid; otherwise, valid */
- g_start_debug_thread = 1;
- thread = kthread_run(dbug_thread, 0, "ACCDET");
- if (IS_ERR(thread)) {
- error = PTR_ERR(thread);
- ACCDET_DEBUG("[store_accdet_start_debug_thread] failed to create kernel thread: %d\n", error);
- } else {
- ACCDET_INFO("[store_accdet_start_debug_thread] start debug thread!\n");
- }
- } else {
- g_start_debug_thread = 0;
- ACCDET_INFO("[store_accdet_start_debug_thread] stop debug thread!\n");
- }
- return count;
- }
- static ssize_t store_accdet_set_headset_mode(struct device_driver *ddri, const char *buf, size_t count)
- {
- ACCDET_INFO("[%s] Not Support\n", __func__);
- return count;
- }
- static ssize_t store_accdet_dump_register(struct device_driver *ddri, const char *buf, size_t count)
- {
- int ret = 0;
- int value = 0;
- if (buf == NULL) {
- ACCDET_INFO("[%s] Invalid input!!\n", __func__);
- return 0;
- }
- /* if write 0, Invalid; otherwise, valid */
- ret = kstrtoint(buf, sizeof(int), &value);
- if (ret != 0) {
- ACCDET_DEBUG("accdet: Invalid values\n");
- return 0;
- }
- g_dump_register = value;
- ACCDET_INFO("[store_accdet_dump_register] start flag:%d\n", g_dump_register);
- return count;
- }
- /*----------------------------------------------------------------------------*/
- static DRIVER_ATTR(dump_register, S_IWUSR | S_IRUGO, NULL, store_accdet_dump_register);
- static DRIVER_ATTR(set_headset_mode, S_IWUSR | S_IRUGO, NULL, store_accdet_set_headset_mode);
- static DRIVER_ATTR(start_debug, S_IWUSR | S_IRUGO, NULL, store_accdet_start_debug_thread);
- /*----------------------------------------------------------------------------*/
- static struct driver_attribute *accdet_attr_list[] = {
- &driver_attr_start_debug,
- &driver_attr_set_headset_mode,
- &driver_attr_dump_register,
- &driver_attr_accdet_call_state,
- /*#ifdef CONFIG_ACCDET_PIN_RECOGNIZATION*/
- &driver_attr_accdet_pin_recognition,
- /*#endif*/
- #if defined(CONFIG_TS3A225E_ACCDET)
- &driver_attr_TS3A225EConnectorType,
- #endif
- };
- static int accdet_create_attr(struct device_driver *driver)
- {
- int idx, err = 0;
- int num = (int)(sizeof(accdet_attr_list) / sizeof(accdet_attr_list[0]));
- if (driver == NULL)
- return -EINVAL;
- for (idx = 0; idx < num; idx++) {
- err = driver_create_file(driver, accdet_attr_list[idx]);
- if (err) {
- ACCDET_DEBUG("driver_create_file (%s) = %d\n", accdet_attr_list[idx]->attr.name, err);
- break;
- }
- }
- return err;
- }
- #endif
- void accdet_int_handler(void)
- {
- int ret = 0;
- ACCDET_DEBUG("[accdet_int_handler]....\n");
- ret = accdet_irq_handler();
- if (0 == ret)
- ACCDET_DEBUG("[accdet_int_handler] don't finished\n");
- }
- void accdet_eint_int_handler(void)
- {
- int ret = 0;
- ACCDET_DEBUG("[accdet_eint_int_handler]....\n");
- ret = accdet_irq_handler();
- if (0 == ret)
- ACCDET_DEBUG("[accdet_int_handler] don't finished\n");
- }
- int mt_accdet_probe(struct platform_device *dev)
- {
- int ret = 0;
- #if DEBUG_THREAD
- struct platform_driver accdet_driver_hal = accdet_driver_func();
- #endif
- #if defined(CONFIG_TS3A225E_ACCDET)
- if (ts3a225e_i2c_client == NULL) {
- ACCDET_DEBUG("[Accdet]ts3a225e_i2c_client is NULL!\n");
- return -EPROBE_DEFER;
- }
- #endif
- ACCDET_INFO("[Accdet]accdet_probe begin!\n");
- /*--------------------------------------------------------------------
- // below register accdet as switch class
- //------------------------------------------------------------------*/
- accdet_data.name = "h2w";
- accdet_data.index = 0;
- accdet_data.state = NO_DEVICE;
- ret = switch_dev_register(&accdet_data);
- if (ret) {
- ACCDET_ERROR("[Accdet]switch_dev_register returned:%d!\n", ret);
- return 1;
- }
- /*----------------------------------------------------------------------
- // Create normal device for auido use
- //--------------------------------------------------------------------*/
- ret = alloc_chrdev_region(&accdet_devno, 0, 1, ACCDET_DEVNAME);
- if (ret)
- ACCDET_ERROR("[Accdet]alloc_chrdev_region: Get Major number error!\n");
- accdet_cdev = cdev_alloc();
- accdet_cdev->owner = THIS_MODULE;
- accdet_cdev->ops = accdet_get_fops();
- ret = cdev_add(accdet_cdev, accdet_devno, 1);
- if (ret)
- ACCDET_ERROR("[Accdet]accdet error: cdev_add\n");
- accdet_class = class_create(THIS_MODULE, ACCDET_DEVNAME);
- /* if we want auto creat device node, we must call this*/
- accdet_nor_device = device_create(accdet_class, NULL, accdet_devno, NULL, ACCDET_DEVNAME);
- /*--------------------------------------------------------------------
- // Create input device
- //------------------------------------------------------------------*/
- kpd_accdet_dev = input_allocate_device();
- if (!kpd_accdet_dev) {
- ACCDET_ERROR("[Accdet]kpd_accdet_dev : fail!\n");
- return -ENOMEM;
- }
- /*INIT the timer to disable micbias.*/
- init_timer(&micbias_timer);
- micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;
- micbias_timer.function = &disable_micbias;
- micbias_timer.data = ((unsigned long)0);
- /*define multi-key keycode*/
- __set_bit(EV_KEY, kpd_accdet_dev->evbit);
- __set_bit(KEY_PLAYPAUSE, kpd_accdet_dev->keybit);
- __set_bit(KEY_VOLUMEDOWN, kpd_accdet_dev->keybit);
- __set_bit(KEY_VOLUMEUP, kpd_accdet_dev->keybit);
- __set_bit(KEY_VOICECOMMAND, kpd_accdet_dev->keybit);
- kpd_accdet_dev->id.bustype = BUS_HOST;
- kpd_accdet_dev->name = "ACCDET";
- if (input_register_device(kpd_accdet_dev))
- ACCDET_ERROR("[Accdet]kpd_accdet_dev register : fail!\n");
- /*------------------------------------------------------------------
- // Create workqueue
- //------------------------------------------------------------------ */
- accdet_workqueue = create_singlethread_workqueue("accdet");
- INIT_WORK(&accdet_work, accdet_work_callback);
- /*------------------------------------------------------------------
- // wake lock
- //------------------------------------------------------------------*/
- wake_lock_init(&accdet_suspend_lock, WAKE_LOCK_SUSPEND, "accdet wakelock");
- wake_lock_init(&accdet_irq_lock, WAKE_LOCK_SUSPEND, "accdet irq wakelock");
- wake_lock_init(&accdet_key_lock, WAKE_LOCK_SUSPEND, "accdet key wakelock");
- wake_lock_init(&accdet_timer_lock, WAKE_LOCK_SUSPEND, "accdet timer wakelock");
- #if DEBUG_THREAD
- ret = accdet_create_attr(&accdet_driver_hal.driver);
- if (ret != 0)
- ACCDET_ERROR("create attribute err = %d\n", ret);
- #endif
- pmic_register_interrupt_callback(12, accdet_int_handler);
- pmic_register_interrupt_callback(13, accdet_eint_int_handler);
- ACCDET_INFO("[Accdet]accdet_probe : ACCDET_INIT\n");
- if (g_accdet_first == 1) {
- eint_accdet_sync_flag = 1;
- #ifdef CONFIG_ACCDET_EINT_IRQ
- accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint");
- INIT_WORK(&accdet_eint_work, accdet_eint_work_callback);
- accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable");
- INIT_WORK(&accdet_disable_work, disable_micbias_callback);
- #endif
- /*Accdet Hardware Init*/
- accdet_get_dts_data();
- accdet_init();
- accdet_pmic_Read_Efuse_HPOffset();
- /*schedule a work for the first detection*/
- queue_work(accdet_workqueue, &accdet_work);
- #ifdef CONFIG_ACCDET_EINT
- accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable");
- INIT_WORK(&accdet_disable_work, disable_micbias_callback);
- accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint");
- INIT_WORK(&accdet_eint_work, accdet_eint_work_callback);
- accdet_setup_eint(dev);
- #endif
- g_accdet_first = 0;
- }
- ACCDET_INFO("[Accdet]accdet_probe done!\n");
- return 0;
- }
- void mt_accdet_remove(void)
- {
- ACCDET_DEBUG("[Accdet]accdet_remove begin!\n");
- /*cancel_delayed_work(&accdet_work);*/
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- destroy_workqueue(accdet_eint_workqueue);
- #endif
- destroy_workqueue(accdet_workqueue);
- switch_dev_unregister(&accdet_data);
- device_del(accdet_nor_device);
- class_destroy(accdet_class);
- cdev_del(accdet_cdev);
- unregister_chrdev_region(accdet_devno, 1);
- input_unregister_device(kpd_accdet_dev);
- ACCDET_DEBUG("[Accdet]accdet_remove Done!\n");
- }
- void mt_accdet_suspend(void) /*only one suspend mode*/
- {
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- ACCDET_DEBUG("[Accdet] in suspend1: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));
- #else
- ACCDET_DEBUG("[Accdet]accdet_suspend: ACCDET_CTRL=[0x%x], STATE=[0x%x]->[0x%x]\n",
- pmic_pwrap_read(ACCDET_CTRL), pre_state_swctrl, pmic_pwrap_read(ACCDET_STATE_SWCTRL));
- #endif
- }
- void mt_accdet_resume(void) /*wake up*/
- {
- #if defined CONFIG_ACCDET_EINT || defined CONFIG_ACCDET_EINT_IRQ
- ACCDET_DEBUG("[Accdet] in resume1: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));
- #else
- ACCDET_DEBUG("[Accdet]accdet_resume: ACCDET_CTRL=[0x%x], STATE_SWCTRL=[0x%x]\n",
- pmic_pwrap_read(ACCDET_CTRL), pmic_pwrap_read(ACCDET_STATE_SWCTRL));
- #endif
- }
- /**********************************************************************
- //add for IPO-H need update headset state when resume
- ***********************************************************************/
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- struct timer_list accdet_disable_ipoh_timer;
- static void mt_accdet_pm_disable(unsigned long a)
- {
- if (cable_type == NO_DEVICE && eint_accdet_sync_flag == 0) {
- /*disable accdet*/
- pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0);
- #ifdef CONFIG_ACCDET_EINT
- pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
- /*disable clock*/
- pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
- #endif
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) & (~(ACCDET_ENABLE)));
- #endif
- ACCDET_DEBUG("[Accdet]daccdet_pm_disable: disable!\n");
- } else {
- ACCDET_DEBUG("[Accdet]daccdet_pm_disable: enable!\n");
- }
- }
- #endif
- void mt_accdet_pm_restore_noirq(void)
- {
- int current_status_restore = 0;
- ACCDET_DEBUG("[Accdet]accdet_pm_restore_noirq start!\n");
- /*enable ACCDET unit*/
- ACCDET_DEBUG("accdet: enable_accdet\n");
- /*enable clock*/
- pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_CLK_CLR);
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_EINT_IRQ_CLR);
- pmic_pwrap_write(ACCDET_RSV, pmic_pwrap_read(ACCDET_RSV) | ACCDET_INPUT_MICP);
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) | ACCDET_EINT_CON_EN);
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) | ACCDET_EINT_CON_EN);
- pmic_pwrap_write(ACCDET_CTRL, ACCDET_EINT_EN);
- #endif
- #ifdef ACCDET_NEGV_IRQ
- pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_NEGV_IRQ_CLR);
- pmic_pwrap_write(ACCDET_EINT_NV, pmic_pwrap_read(ACCDET_EINT_NV) | ACCDET_NEGV_DT_EN);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) | ACCDET_NEGV_EN);
- #endif
- enable_accdet(ACCDET_SWCTRL_EN);
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL) | ACCDET_SWCTRL_IDLE_EN));
- eint_accdet_sync_flag = 1;
- current_status_restore = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0) >> 6); /*AB*/
- switch (current_status_restore) {
- case 0: /*AB=0*/
- cable_type = HEADSET_NO_MIC;
- accdet_status = HOOK_SWITCH;
- break;
- case 1: /*AB=1*/
- cable_type = HEADSET_MIC;
- accdet_status = MIC_BIAS;
- break;
- case 3: /*AB=3*/
- cable_type = NO_DEVICE;
- accdet_status = PLUG_OUT;
- break;
- default:
- ACCDET_DEBUG("[Accdet]accdet_pm_restore_noirq: accdet current status error!\n");
- break;
- }
- switch_set_state((struct switch_dev *)&accdet_data, cable_type);
- if (cable_type == NO_DEVICE) {
- #ifdef CONFIG_ACCDET_PIN_RECOGNIZATION
- init_timer(&accdet_disable_ipoh_timer);
- accdet_disable_ipoh_timer.expires = jiffies + 3 * HZ;
- accdet_disable_ipoh_timer.function = &mt_accdet_pm_disable;
- accdet_disable_ipoh_timer.data = ((unsigned long)0);
- add_timer(&accdet_disable_ipoh_timer);
- ACCDET_DEBUG("[Accdet]enable! pm timer\n");
- #else
- /*disable accdet*/
- pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
- #ifdef CONFIG_ACCDET_EINT
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0);
- pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
- /*disable clock*/
- pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
- #endif
- #ifdef CONFIG_ACCDET_EINT_IRQ
- pmic_pwrap_write(ACCDET_STATE_SWCTRL, ACCDET_EINT_PWM_EN);
- pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL) & (~(ACCDET_ENABLE)));
- #endif
- #endif
- }
- }
- /*//////////////////////////////////IPO_H end/////////////////////////////////////////////*/
- long mt_accdet_unlocked_ioctl(unsigned int cmd, unsigned long arg)
- {
- switch (cmd) {
- case ACCDET_INIT:
- break;
- case SET_CALL_STATE:
- call_status = (int)arg;
- ACCDET_DEBUG("[Accdet]accdet_ioctl : CALL_STATE=%d\n", call_status);
- break;
- case GET_BUTTON_STATUS:
- ACCDET_DEBUG("[Accdet]accdet_ioctl : Button_Status=%d (state:%d)\n", button_status, accdet_data.state);
- return button_status;
- default:
- ACCDET_DEBUG("[Accdet]accdet_ioctl : default\n");
- break;
- }
- return 0;
- }
|