extcon-arizona updates
Subsystems (3)
cover extcon-arizona updates
The following changes since commit 9931faca02c604c22335f5a935a501bb2ace6e20:
Linux 3.8-rc3 (2013-01-09 18:59:55 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git tags/extcon-arizona-3.8rc3
for you to fetch changes up to 708f5b582ea16b60701e275fe5233ec4c57859cd:
mfd: wm5102: Add microphone clamp control registers (2013-01-10 11:35:42 +0000)
----------------------------------------------------------------
extcon: arizona: Updates to arizona extcon driver
This patch series adds a number of new features to the arizona driver:
- Headphone measurements.
- Alternative detection mechanism for non-default system designs.
- Microphone clamp integration.
- Support for additional detection pin.
- MICBIAS rise time configuration.
There's one trivial MFD patch which is here because it depends on register definitions from the new features.
----------------------------------------------------------------
Mark Brown (11):
extcon: arizona: Convert to devm_input_allocate_device()
extcon: arizona: Remove duplicate mic ramp configuration
extcon: arizona: Only set GPIO if it has been requested
extcon: arizona: Allow configuration of MICBIAS rise time
extcon: arizona: Use microphone clamp function if available
extcon: arizona: Support use of GPIO5 as an input to jack detection
extcon: arizona: Enable basic headphone identification
extcon: arizona: Move start and stop mic functions earlier
extcon: arizona: Support HPDET based accessory identification
extcon: arizona: Support direct microphone measurement via HPDET
mfd: wm5102: Add microphone clamp control registers
drivers/extcon/extcon-arizona.c | 634 ++++++++++++++++++++++++++++++--- drivers/mfd/wm5102-tables.c | 10 + include/linux/mfd/arizona/core.h | 4 +- include/linux/mfd/arizona/pdata.h | 12 + include/linux/mfd/arizona/registers.h | 48 +++ 5 files changed, 658 insertions(+), 50 deletions(-)
PATCH 1/11 extcon: arizona: Convert to devm_input_allocate_device()
--- drivers/extcon/extcon-arizona.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/extcon/extcon-arizona.c +1 -3
@@ -418,7 +418,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)arizona_extcon_set_mode (info,0 ); - info->input =input_allocate_device (); + info->input =devm_input_allocate_device (&pdev->dev);if (!info->input) {dev_err (arizona->dev,"Can't allocate input dev\n" ); ret = -ENOMEM ;
@@ -510,7 +510,6 @@ err_rise_wake: err_rise:arizona_free_irq (arizona,ARIZONA_IRQ_JD_RISE , info); err_input: -input_free_device (info->input); err_register:pm_runtime_disable (&pdev->dev);extcon_dev_unregister (&info->edev);
@@ -533,7 +532,6 @@ static int arizona_extcon_remove(struct platform_device *pdev)regmap_update_bits (arizona->regmap,ARIZONA_JACK_DETECT_ANALOGUE ,ARIZONA_JD1_ENA ,0 );arizona_clk32k_disable (arizona); -input_unregister_device (info->input);extcon_dev_unregister (&info->edev);return 0 ;
Signature · 1 line
1.7.10.4
PATCH 2/11 extcon: arizona: Remove duplicate mic ramp configuration
Now this is configured by platform data remove the defualt configuration the driver had.
--- drivers/extcon/extcon-arizona.c | 2 -- 1 file changed, 2 deletions(-)
drivers/extcon/extcon-arizona.c +0 -2
@@ -473,9 +473,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) }regmap_update_bits (arizona->regmap,ARIZONA_MIC_DETECT_1 , -ARIZONA_MICD_BIAS_STARTTIME_MASK |ARIZONA_MICD_RATE_MASK , -7 <<ARIZONA_MICD_BIAS_STARTTIME_SHIFT |8 <<ARIZONA_MICD_RATE_SHIFT );arizona_clk32k_enable (arizona);
Signature · 1 line
1.7.10.4
PATCH 3/11 extcon: arizona: Only set GPIO if it has been requested
In reply to Mark BrownThe micd_pol GPIO is only requested if we've specified one greater than 0 so apply the same test before we set it.
--- drivers/extcon/extcon-arizona.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/extcon/extcon-arizona.c +3 -2
@@ -85,8 +85,9 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) {struct arizona *arizona = info->arizona; -gpio_set_value_cansleep (arizona->pdata.micd_pol_gpio, - info->micd_modes[mode].gpio); +if (arizona->pdata.micd_pol_gpio >0 ) +gpio_set_value_cansleep (arizona->pdata.micd_pol_gpio, + info->micd_modes[mode].gpio);regmap_update_bits (arizona->regmap,ARIZONA_MIC_DETECT_1 ,ARIZONA_MICD_BIAS_SRC_MASK , info->micd_modes[mode].bias);
Signature · 1 line
1.7.10.4
PATCH 4/11 extcon: arizona: Allow configuration of MICBIAS rise time
In reply to Mark BrownAllow configuration of the rise time for MICBIAS via platform data, the delay required depends on things like the external component selection.
--- drivers/extcon/extcon-arizona.c | 6 ++++++ include/linux/mfd/arizona/pdata.h | 3 +++ 2 files changed, 9 insertions(+)
drivers/extcon/extcon-arizona.c +6 -0
@@ -417,6 +417,12 @@ static int arizona_extcon_probe(struct platform_device *pdev) } } +if (arizona->pdata.micd_bias_start_time) +regmap_update_bits (arizona->regmap,ARIZONA_MIC_DETECT_1 , +ARIZONA_MICD_BIAS_STARTTIME_MASK , + arizona->pdata.micd_bias_start_time + <<ARIZONA_MICD_BIAS_STARTTIME_SHIFT ); +arizona_extcon_set_mode (info,0 ); info->input =devm_input_allocate_device (&pdev->dev);
include/linux/mfd/arizona/pdata.h +3 -0
@@ -99,6 +99,9 @@ struct arizona_pdata {/** GPIO for mic detection polarity */ int micd_pol_gpio; +/** Mic detect ramp rate */ +int micd_bias_start_time; +/** Headset polarity configurations */ struct arizona_micd_config *micd_configs;int num_micd_configs;
Signature · 1 line
1.7.10.4
PATCH 5/11 extcon: arizona: Use microphone clamp function if available
In reply to Mark BrownNewer Arizona devices include a microphone clamp function which is tied to jack detect. Activate this feature when present in order to ensure best performance of the subsystem.
--- drivers/extcon/extcon-arizona.c | 19 +++++++++++++++++++ include/linux/mfd/arizona/core.h | 4 +++- include/linux/mfd/arizona/registers.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-)
drivers/extcon/extcon-arizona.c +19 -0
@@ -45,6 +45,7 @@ struct arizona_extcon_info {int micd_num_modes;bool micd_reva; +bool micd_clamp;bool mic;bool detecting;
@@ -375,6 +376,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) info->micd_reva = true;break ;default : + info->micd_clamp = true;break ; }break ;
@@ -423,6 +425,19 @@ static int arizona_extcon_probe(struct platform_device *pdev) arizona->pdata.micd_bias_start_time << ARIZONA_MICD_BIAS_STARTTIME_SHIFT); +/* +* If we have a clamp use it. +*/ +if (info->micd_clamp) { +regmap_update_bits (arizona->regmap, +ARIZONA_MICD_CLAMP_CONTROL , +ARIZONA_MICD_CLAMP_MODE_MASK ,4 ); +regmap_update_bits (arizona->regmap, +ARIZONA_JACK_DETECT_DEBOUNCE , +ARIZONA_MICD_CLAMP_DB , +ARIZONA_MICD_CLAMP_DB ); + } +arizona_extcon_set_mode (info,0 ); info->input =devm_input_allocate_device (&pdev->dev);
@@ -529,6 +544,10 @@ static int arizona_extcon_remove(struct platform_device *pdev)pm_runtime_disable (&pdev->dev); +regmap_update_bits (arizona->regmap, +ARIZONA_MICD_CLAMP_CONTROL , +ARIZONA_MICD_CLAMP_MODE_MASK ,0 ); +arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_RISE ,0 );arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_FALL ,0 );arizona_free_irq (arizona,ARIZONA_IRQ_MICDET , info);
include/linux/mfd/arizona/core.h +3 -1
@@ -75,8 +75,10 @@ enum arizona_type {#define ARIZONA_IRQ_DCS_HP_DONE 47#define ARIZONA_IRQ_FLL2_CLOCK_OK 48#define ARIZONA_IRQ_FLL1_CLOCK_OK 49 +#define ARIZONA_IRQ_MICD_CLAMP_RISE 50 +#define ARIZONA_IRQ_MICD_CLAMP_FALL 51 -#define ARIZONA_NUM_IRQ 50 +#define ARIZONA_NUM_IRQ 52struct snd_soc_dapm_context ;
include/linux/mfd/arizona/registers.h +28 -0
@@ -119,6 +119,7 @@#define ARIZONA_ACCESSORY_DETECT_MODE_1 0x293#define ARIZONA_HEADPHONE_DETECT_1 0x29B#define ARIZONA_HEADPHONE_DETECT_2 0x29C +#define ARIZONA_MICD_CLAMP_CONTROL 0x2A2#define ARIZONA_MIC_DETECT_1 0x2A3#define ARIZONA_MIC_DETECT_2 0x2A4#define ARIZONA_MIC_DETECT_3 0x2A5
@@ -2070,6 +2071,13 @@#define ARIZONA_HP_LVL_WIDTH 7/* HP_LVL - [6:0] */ /* +* R674 (0x2A2) - MICD clamp control +*/ +#define ARIZONA_MICD_CLAMP_MODE_MASK 0x000F/* MICD_CLAMP_MODE - [3:0] */ +#define ARIZONA_MICD_CLAMP_MODE_SHIFT 0/* MICD_CLAMP_MODE - [3:0] */ +#define ARIZONA_MICD_CLAMP_MODE_WIDTH 4/* MICD_CLAMP_MODE - [3:0] */ + +/* * R675 (0x2A3) - Mic Detect 1 */ #define ARIZONA_MICD_BIAS_STARTTIME_MASK 0xF000/* MICD_BIAS_STARTTIME - [15:12] */
@@ -5267,6 +5275,12 @@/* * R3409 (0xD51) - AOD IRQ1 */ +#define ARIZONA_MICD_CLAMP_FALL_EINT1 0x0080/* MICD_CLAMP_FALL_EINT1 */ +#define ARIZONA_MICD_CLAMP_FALL_EINT1_MASK 0x0080/* MICD_CLAMP_FALL_EINT1 */ +#define ARIZONA_MICD_CLAMP_FALL_EINT1_SHIFT 7/* MICD_CLAMP_FALL_EINT1 */ +#define ARIZONA_MICD_CLAMP_RISE_EINT1 0x0040/* MICD_CLAMP_RISE_EINT1 */ +#define ARIZONA_MICD_CLAMP_RISE_EINT1_MASK 0x0040/* MICD_CLAMP_RISE_EINT1 */ +#define ARIZONA_MICD_CLAMP_RISE_EINT1_SHIFT 6/* MICD_CLAMP_RISE_EINT1 */ #define ARIZONA_GP5_FALL_EINT1 0x0020/* GP5_FALL_EINT1 */ #define ARIZONA_GP5_FALL_EINT1_MASK 0x0020/* GP5_FALL_EINT1 */ #define ARIZONA_GP5_FALL_EINT1_SHIFT 5/* GP5_FALL_EINT1 */
@@ -5295,6 +5309,12 @@/* * R3410 (0xD52) - AOD IRQ2 */ +#define ARIZONA_MICD_CLAMP_FALL_EINT2 0x0080/* MICD_CLAMP_FALL_EINT2 */ +#define ARIZONA_MICD_CLAMP_FALL_EINT2_MASK 0x0080/* MICD_CLAMP_FALL_EINT2 */ +#define ARIZONA_MICD_CLAMP_FALL_EINT2_SHIFT 7/* MICD_CLAMP_FALL_EINT2 */ +#define ARIZONA_MICD_CLAMP_RISE_EINT2 0x0040/* MICD_CLAMP_RISE_EINT2 */ +#define ARIZONA_MICD_CLAMP_RISE_EINT2_MASK 0x0040/* MICD_CLAMP_RISE_EINT2 */ +#define ARIZONA_MICD_CLAMP_RISE_EINT2_SHIFT 6/* MICD_CLAMP_RISE_EINT2 */ #define ARIZONA_GP5_FALL_EINT2 0x0020/* GP5_FALL_EINT2 */ #define ARIZONA_GP5_FALL_EINT2_MASK 0x0020/* GP5_FALL_EINT2 */ #define ARIZONA_GP5_FALL_EINT2_SHIFT 5/* GP5_FALL_EINT2 */
@@ -5379,6 +5399,10 @@/* * R3413 (0xD55) - AOD IRQ Raw Status */ +#define ARIZONA_MICD_CLAMP_STS 0x0008/* MICD_CLAMP_STS */ +#define ARIZONA_MICD_CLAMP_STS_MASK 0x0008/* MICD_CLAMP_STS */ +#define ARIZONA_MICD_CLAMP_STS_SHIFT 3/* MICD_CLAMP_STS */ +#define ARIZONA_MICD_CLAMP_STS_WIDTH 1/* MICD_CLAMP_STS */ #define ARIZONA_GP5_STS 0x0004/* GP5_STS */ #define ARIZONA_GP5_STS_MASK 0x0004/* GP5_STS */ #define ARIZONA_GP5_STS_SHIFT 2/* GP5_STS */
@@ -5395,6 +5419,10 @@/* * R3414 (0xD56) - Jack detect debounce */ +#define ARIZONA_MICD_CLAMP_DB 0x0008/* MICD_CLAMP_DB */ +#define ARIZONA_MICD_CLAMP_DB_MASK 0x0008/* MICD_CLAMP_DB */ +#define ARIZONA_MICD_CLAMP_DB_SHIFT 3/* MICD_CLAMP_DB */ +#define ARIZONA_MICD_CLAMP_DB_WIDTH 1/* MICD_CLAMP_DB */ #define ARIZONA_JD2_DB 0x0002/* JD2_DB */ #define ARIZONA_JD2_DB_MASK 0x0002/* JD2_DB */ #define ARIZONA_JD2_DB_SHIFT 1/* JD2_DB */
Signature · 1 line
1.7.10.4
PATCH 6/11 extcon: arizona: Support use of GPIO5 as an input to jack detection
In reply to Mark BrownSome system designs provide an input on GPIO5 which in conjunction with the jack detection feature indicates the presence of an accessory. Support such systems, using the microphone clamp feature to minimise wakeups of the processor.
--- drivers/extcon/extcon-arizona.c | 76 ++++++++++++++++++++++++++++--------- include/linux/mfd/arizona/pdata.h | 3 ++ 2 files changed, 61 insertions(+), 18 deletions(-)
drivers/extcon/extcon-arizona.c +58 -18
@@ -290,13 +290,21 @@ static irqreturn_t arizona_jackdet(int irq, void *data) {struct arizona_extcon_info *info = data;struct arizona *arizona = info->arizona; -unsigned int val; +unsigned int val, present, mask;int ret, i;pm_runtime_get_sync (info->dev);mutex_lock (&info->lock); +if (arizona->pdata.jd_gpio5) { + mask =ARIZONA_MICD_CLAMP_STS ; + present =0 ; + }else { + mask =ARIZONA_JD1_STS ; + present =ARIZONA_JD1_STS ; + } + ret =regmap_read (arizona->regmap,ARIZONA_AOD_IRQ_RAW_STATUS , &val);if (ret !=0 ) { dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
@@ -306,7 +314,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)return IRQ_NONE ; } -if (val &ARIZONA_JD1_STS ) { +if ((val & mask) == present) {dev_dbg (arizona->dev,"Detected jack\n" ); ret =extcon_set_cable_state_ (&info->edev,ARIZONA_CABLE_MECHANICAL , true);
@@ -321,6 +329,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)arizona_stop_mic (info); +for (i =0 ; i <ARIZONA_NUM_BUTTONS ; i++)input_report_key (info->input, arizona_lvl_to_key[i].report,0 );
@@ -345,6 +354,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)struct arizona *arizona =dev_get_drvdata (pdev->dev.parent);struct arizona_pdata *pdata;struct arizona_extcon_info *info; +int jack_irq_fall, jack_irq_rise;int ret, mode, i; pdata =dev_get_platdata (arizona->dev);
@@ -426,12 +436,24 @@ static int arizona_extcon_probe(struct platform_device *pdev) << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);/* -* If we have a clamp use it. +* If we have a clamp use it, activating in conjunction with +* GPIO5 if that is connected for jack detect operation. */ if (info->micd_clamp) { -regmap_update_bits (arizona->regmap, -ARIZONA_MICD_CLAMP_CONTROL , -ARIZONA_MICD_CLAMP_MODE_MASK ,4 ); +if (arizona->pdata.jd_gpio5) { +/* Put the GPIO into input mode */ +regmap_write (arizona->regmap,ARIZONA_GPIO5_CTRL , +0xc101 ); + +regmap_update_bits (arizona->regmap, +ARIZONA_MICD_CLAMP_CONTROL , +ARIZONA_MICD_CLAMP_MODE_MASK ,0x9 ); + }else { +regmap_update_bits (arizona->regmap, +ARIZONA_MICD_CLAMP_CONTROL , +ARIZONA_MICD_CLAMP_MODE_MASK ,0x4 ); + } + regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, ARIZONA_MICD_CLAMP_DB,
@@ -458,7 +480,15 @@ static int arizona_extcon_probe(struct platform_device *pdev)pm_runtime_idle (&pdev->dev);pm_runtime_get_sync (&pdev->dev); - ret =arizona_request_irq (arizona,ARIZONA_IRQ_JD_RISE , +if (arizona->pdata.jd_gpio5) { + jack_irq_rise =ARIZONA_IRQ_MICD_CLAMP_RISE ; + jack_irq_fall =ARIZONA_IRQ_MICD_CLAMP_FALL ; + }else { + jack_irq_rise =ARIZONA_IRQ_JD_RISE ; + jack_irq_fall =ARIZONA_IRQ_JD_FALL ; + } + + ret =arizona_request_irq (arizona, jack_irq_rise,"JACKDET rise" , arizona_jackdet, info);if (ret !=0 ) { dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
@@ -466,21 +496,21 @@ static int arizona_extcon_probe(struct platform_device *pdev) goto err_input; } - ret =arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_RISE ,1 ); + ret =arizona_set_irq_wake (arizona, jack_irq_rise,1 );if (ret !=0 ) {dev_err (&pdev->dev,"Failed to set JD rise IRQ wake: %d\n" , ret); goto err_rise; } - ret =arizona_request_irq (arizona,ARIZONA_IRQ_JD_FALL , + ret =arizona_request_irq (arizona, jack_irq_fall,"JACKDET fall" , arizona_jackdet, info);if (ret !=0 ) {dev_err (&pdev->dev,"Failed to get JD fall IRQ: %d\n" , ret); goto err_rise_wake; } - ret =arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_FALL ,1 ); + ret =arizona_set_irq_wake (arizona, jack_irq_fall,1 );if (ret !=0 ) {dev_err (&pdev->dev,"Failed to set JD fall IRQ wake: %d\n" , ret);
@@ -522,13 +552,13 @@ static int arizona_extcon_probe(struct platform_device *pdev) err_micdet:arizona_free_irq (arizona,ARIZONA_IRQ_MICDET , info); err_fall_wake: -arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_FALL ,0 ); +arizona_set_irq_wake (arizona, jack_irq_fall,0 ); err_fall: -arizona_free_irq (arizona,ARIZONA_IRQ_JD_FALL , info); +arizona_free_irq (arizona, jack_irq_fall, info); err_rise_wake: -arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_RISE ,0 ); +arizona_set_irq_wake (arizona, jack_irq_rise,0 ); err_rise: -arizona_free_irq (arizona,ARIZONA_IRQ_JD_RISE , info); +arizona_free_irq (arizona, jack_irq_rise, info); err_input: err_register:pm_runtime_disable (&pdev->dev);
@@ -541,6 +571,7 @@ static int arizona_extcon_remove(struct platform_device *pdev) {struct arizona_extcon_info *info =platform_get_drvdata (pdev);struct arizona *arizona = info->arizona; +int jack_irq_rise, jack_irq_fall;pm_runtime_disable (&pdev->dev);
@@ -548,11 +579,20 @@ static int arizona_extcon_remove(struct platform_device *pdev)ARIZONA_MICD_CLAMP_CONTROL , ARIZONA_MICD_CLAMP_MODE_MASK, 0); -arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_RISE ,0 ); -arizona_set_irq_wake (arizona,ARIZONA_IRQ_JD_FALL ,0 ); +if (arizona->pdata.jd_gpio5) { + jack_irq_rise =ARIZONA_IRQ_MICD_CLAMP_RISE ; + jack_irq_fall =ARIZONA_IRQ_MICD_CLAMP_FALL ; + }else { + jack_irq_rise =ARIZONA_IRQ_JD_RISE ; + jack_irq_fall =ARIZONA_IRQ_JD_FALL ; + } + +arizona_set_irq_wake (arizona, jack_irq_rise,0 ); +arizona_set_irq_wake (arizona, jack_irq_fall,0 ); +arizona_free_irq (arizona,ARIZONA_IRQ_HPDET , info);arizona_free_irq (arizona,ARIZONA_IRQ_MICDET , info); -arizona_free_irq (arizona,ARIZONA_IRQ_JD_RISE , info); -arizona_free_irq (arizona,ARIZONA_IRQ_JD_FALL , info); +arizona_free_irq (arizona, jack_irq_rise, info); +arizona_free_irq (arizona, jack_irq_fall, info);regmap_update_bits (arizona->regmap,ARIZONA_JACK_DETECT_ANALOGUE ,ARIZONA_JD1_ENA ,0 );arizona_clk32k_disable (arizona);
include/linux/mfd/arizona/pdata.h +3 -0
@@ -96,6 +96,9 @@ struct arizona_pdata {/** Pin state for GPIO pins */ int gpio_defaults[ARIZONA_MAX_GPIO ]; +/** GPIO5 is used for jack detection */ +bool jd_gpio5; +/** GPIO for mic detection polarity */ int micd_pol_gpio;
Signature · 1 line
1.7.10.4
PATCH 7/11 extcon: arizona: Enable basic headphone identification
In reply to Mark BrownUse the headphone detection to identify if the accessory is a headphone or line load. There are two different revisions of the IP with different register layouts, support both.
--- drivers/extcon/extcon-arizona.c | 341 +++++++++++++++++++++++++++++++-- drivers/mfd/wm5102-tables.c | 3 + include/linux/mfd/arizona/registers.h | 12 ++ 3 files changed, 335 insertions(+), 21 deletions(-)
drivers/extcon/extcon-arizona.c +320 -21
@@ -31,8 +31,14 @@#include <linux/mfd/arizona/pdata.h> #include <linux/mfd/arizona/registers.h> +#define ARIZONA_DEFAULT_HP 32 +#define ARIZONA_NUM_BUTTONS 6 +#define ARIZONA_ACCDET_MODE_MIC 0 +#define ARIZONA_ACCDET_MODE_HPL 1 +#define ARIZONA_ACCDET_MODE_HPR 2 +struct arizona_extcon_info {struct device *dev;struct arizona *arizona;
@@ -47,10 +53,14 @@ struct arizona_extcon_info {bool micd_reva;bool micd_clamp; +bool hpdet_active; +bool mic;bool detecting;int jack_flips; +int hpdet_ip; +struct extcon_dev edev; };
@@ -74,11 +84,13 @@ static struct {#define ARIZONA_CABLE_MECHANICAL 0#define ARIZONA_CABLE_MICROPHONE 1#define ARIZONA_CABLE_HEADPHONE 2 +#define ARIZONA_CABLE_LINEOUT 3static const char *arizona_cable[] = {"Mechanical" ,"Microphone" ,"Headphone" , +"Line-out" ,NULL , };
@@ -100,6 +112,290 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)dev_dbg (arizona->dev,"Set jack polarity to %d\n" , mode); } +static struct { +unsigned int factor_a; +unsigned int factor_b; +} arizona_hpdet_b_ranges[] = { + {5528 ,362464 }, + {11084 ,6186851 }, + {11065 ,65460395 }, +}; + +static struct { +int min; +int max; +} arizona_hpdet_c_ranges[] = { + {0 ,30 }, + {8 ,100 }, + {100 ,1000 }, + {1000 ,10000 }, +}; + +static int arizona_hpdet_read (struct arizona_extcon_info *info) +{ +struct arizona *arizona = info->arizona; +unsigned int val, range; +int ret; + + ret =regmap_read (arizona->regmap,ARIZONA_HEADPHONE_DETECT_2 , &val); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to read HPDET status: %d\n" , + ret); +return ret; + } + +switch (info->hpdet_ip) { +case 0 : +if (!(val &ARIZONA_HP_DONE )) { +dev_err (arizona->dev,"HPDET did not complete: %x\n" , + val); + val =ARIZONA_DEFAULT_HP ; + } + + val &=ARIZONA_HP_LVL_MASK ; +break ; + +case 1 : +if (!(val &ARIZONA_HP_DONE_B )) { +dev_err (arizona->dev,"HPDET did not complete: %x\n" , + val); +return ARIZONA_DEFAULT_HP ; + } + + ret =regmap_read (arizona->regmap,ARIZONA_HP_DACVAL , &val); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to read HP value: %d\n" , + ret); +return ARIZONA_DEFAULT_HP ; + } + +regmap_read (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , + &range); + range = (range &ARIZONA_HP_IMPEDANCE_RANGE_MASK ) + >>ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ; + +if (range <ARRAY_SIZE (arizona_hpdet_b_ranges) -1 && + (val <100 || val >0x3fb )) { + range++; +dev_dbg (arizona->dev,"Moving to HPDET range %d\n" , + range); +regmap_update_bits (arizona->regmap, +ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_IMPEDANCE_RANGE_MASK , + range << +ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ); +return -EAGAIN ; + } + +/* If we go out of range report top of range */ +if (val <100 || val >0x3fb ) { +dev_dbg (arizona->dev,"Measurement out of range\n" ); +return 10000 ; + } + +dev_dbg (arizona->dev,"HPDET read %d in range %d\n" , + val, range); + + val = arizona_hpdet_b_ranges[range].factor_b + / ((val *100 ) - + arizona_hpdet_b_ranges[range].factor_a); +break ; + +default : +dev_warn (arizona->dev,"Unknown HPDET IP revision %d\n" , + info->hpdet_ip); +case 2 : +if (!(val &ARIZONA_HP_DONE_B )) { +dev_err (arizona->dev,"HPDET did not complete: %x\n" , + val); +return ARIZONA_DEFAULT_HP ; + } + + val &=ARIZONA_HP_LVL_B_MASK ; + +regmap_read (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , + &range); + range = (range &ARIZONA_HP_IMPEDANCE_RANGE_MASK ) + >>ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ; + +/* Skip up or down a range? */ +if (range && (val < arizona_hpdet_c_ranges[range].min)) { + range--; +dev_dbg (arizona->dev,"Moving to HPDET range %d-%d\n" , + arizona_hpdet_c_ranges[range].min, + arizona_hpdet_c_ranges[range].max); +regmap_update_bits (arizona->regmap, +ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_IMPEDANCE_RANGE_MASK , + range << +ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ); +return -EAGAIN ; + } + +if (range <ARRAY_SIZE (arizona_hpdet_c_ranges) -1 && + (val >= arizona_hpdet_c_ranges[range].max)) { + range++; +dev_dbg (arizona->dev,"Moving to HPDET range %d-%d\n" , + arizona_hpdet_c_ranges[range].min, + arizona_hpdet_c_ranges[range].max); +regmap_update_bits (arizona->regmap, +ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_IMPEDANCE_RANGE_MASK , + range << +ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ); +return -EAGAIN ; + } + } + +dev_dbg (arizona->dev,"HP impedance %d ohms\n" , val); +return val; +} + +static irqreturn_t arizona_hpdet_irq (int irq,void *data) +{ +struct arizona_extcon_info *info = data; +struct arizona *arizona = info->arizona; +int report =ARIZONA_CABLE_HEADPHONE ; +int ret; + +mutex_lock (&info->lock); + +/* If we got a spurious IRQ for some reason then ignore it */ +if (!info->hpdet_active) { +dev_warn (arizona->dev,"Spurious HPDET IRQ\n" ); +mutex_unlock (&info->lock); +return IRQ_NONE ; + } + +/* If the cable was removed while measuring ignore the result */ + ret =extcon_get_cable_state_ (&info->edev,ARIZONA_CABLE_MECHANICAL ); +if (ret <0 ) { +dev_err (arizona->dev,"Failed to check cable state: %d\n" , + ret); + goto out; + }else if (!ret) { +dev_dbg (arizona->dev,"Ignoring HPDET for removed cable\n" ); + goto done; + } + + ret =arizona_hpdet_read (info); +if (ret == -EAGAIN ) { + goto out; + }else if (ret <0 ) { + goto done; + } + +/* Reset back to starting range */ +regmap_update_bits (arizona->regmap, +ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_IMPEDANCE_RANGE_MASK ,0 ); + +/* Report high impedence cables as line outputs */ +if (ret >=5000 ) + report =ARIZONA_CABLE_LINEOUT ; +else + report =ARIZONA_CABLE_HEADPHONE ; + + ret =extcon_set_cable_state_ (&info->edev, report, true); +if (ret !=0 ) +dev_err (arizona->dev,"Failed to report HP/line: %d\n" , + ret); + + ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 ,0 ); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to undo magic: %d\n" , ret); + + ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 ,0 ); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to undo magic: %d\n" , ret); + +done: +regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_POLL ,0 ); + +/* Revert back to MICDET mode */ +regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK ,ARIZONA_ACCDET_MODE_MIC ); + +/* If we have a mic then reenable MICDET */ +if (info->mic) +arizona_start_mic (info); + +if (info->hpdet_active) { +pm_runtime_put_autosuspend (info->dev); + info->hpdet_active = false; + } + +out: +mutex_unlock (&info->lock); + +return IRQ_HANDLED ; +} + +static void arizona_identify_headphone (struct arizona_extcon_info *info) +{ +struct arizona *arizona = info->arizona; +int ret; + +dev_dbg (arizona->dev,"Starting HPDET\n" ); + +/* Make sure we keep the device enabled during the measurement */ +pm_runtime_get (info->dev); + + info->hpdet_active = true; + +if (info->mic) +arizona_stop_mic (info); + + ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 ,0x4000 ); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); + + ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 ,0x4000 ); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); + + ret =regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK , +ARIZONA_ACCDET_MODE_HPL ); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to set HPDETL mode: %d\n" , ret); + goto err; + } + + ret =regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_POLL ,ARIZONA_HP_POLL ); +if (ret !=0 ) { +dev_err (arizona->dev,"Can't start HPDETL measurement: %d\n" , + ret); + goto err; + } + +return ; + +err: +regmap_update_bits (arizona->regmap,ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK ,ARIZONA_ACCDET_MODE_MIC ); + +/* Just report headphone */ + ret =extcon_update_state (&info->edev, +1 <<ARIZONA_CABLE_HEADPHONE , +1 <<ARIZONA_CABLE_HEADPHONE ); +if (ret !=0 ) +dev_err (arizona->dev,"Failed to report headphone: %d\n" , ret); + +if (info->mic) +arizona_start_mic (info); + + info->hpdet_active = false; +} + } + + info->hpdet_active = false; +} +static void arizona_start_mic (struct arizona_extcon_info *info) {struct arizona *arizona = info->arizona;
@@ -125,6 +421,10 @@ static void arizona_start_mic(struct arizona_extcon_info *info)regmap_write (arizona->regmap,0x80 ,0x0 ); } +regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK ,ARIZONA_ACCDET_MODE_MIC ); +regmap_update_bits_check (arizona->regmap,ARIZONA_MIC_DETECT_1 ,ARIZONA_MICD_ENA ,ARIZONA_MICD_ENA , &change);
@@ -189,11 +489,11 @@ static irqreturn_t arizona_micdet(int irq, void *data)/* If we got a high impedence we should have a headset, report it. */ if (info->detecting && (val &0x400 )) { +arizona_identify_headphone (info); + ret =extcon_update_state (&info->edev, -1 <<ARIZONA_CABLE_MICROPHONE | -1 <<ARIZONA_CABLE_HEADPHONE , -1 <<ARIZONA_CABLE_MICROPHONE | -1 <<ARIZONA_CABLE_HEADPHONE ); +1 <<ARIZONA_CABLE_MICROPHONE , +1 <<ARIZONA_CABLE_MICROPHONE );if (ret !=0 ) dev_err(arizona->dev, "Headset report failed: %d\n",
@@ -214,17 +514,12 @@ static irqreturn_t arizona_micdet(int irq, void *data) info->jack_flips++;if (info->jack_flips >= info->micd_num_modes) { -dev_dbg (arizona->dev,"Detected headphone\n" ); +dev_dbg (arizona->dev,"Detected HP/line\n" ); +arizona_identify_headphone (info); + info->detecting = false; -arizona_stop_mic (info); - ret =extcon_set_cable_state_ (&info->edev, -ARIZONA_CABLE_HEADPHONE , - true); -if (ret !=0 ) -dev_err (arizona->dev, -"Headphone report failed: %d\n" , - ret); +arizona_stop_mic (info); }else { info->micd_mode++;if (info->micd_mode == info->micd_num_modes)
@@ -260,13 +555,7 @@ static irqreturn_t arizona_micdet(int irq, void *data) info->detecting = false;arizona_stop_mic (info); - ret =extcon_set_cable_state_ (&info->edev, -ARIZONA_CABLE_HEADPHONE , - true); -if (ret !=0 ) -dev_err (arizona->dev, -"Headphone report failed: %d\n" , - ret); +arizona_identify_headphone (info); }else {dev_warn (arizona->dev,"Button with no mic: %x\n" , val);
@@ -387,6 +676,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)break ;default : info->micd_clamp = true; + info->hpdet_ip =1 ;break ; }break ;
@@ -524,6 +814,13 @@ static int arizona_extcon_probe(struct platform_device *pdev) goto err_fall_wake; } + ret =arizona_request_irq (arizona,ARIZONA_IRQ_HPDET , +"HPDET" , arizona_hpdet_irq, info); +if (ret !=0 ) { +dev_err (&pdev->dev,"Failed to get HPDET IRQ: %d\n" , ret); + goto err_micdet; + } +regmap_update_bits (arizona->regmap,ARIZONA_MIC_DETECT_1 ,ARIZONA_MICD_RATE_MASK ,8 <<ARIZONA_MICD_RATE_SHIFT );
@@ -544,11 +841,13 @@ static int arizona_extcon_probe(struct platform_device *pdev) ret =input_register_device (info->input);if (ret) {dev_err (&pdev->dev,"Can't register input device: %d\n" , ret); - goto err_micdet; + goto err_hpdet; }return 0 ; +err_hpdet: +arizona_free_irq (arizona,ARIZONA_IRQ_HPDET , info); err_micdet:arizona_free_irq (arizona,ARIZONA_IRQ_MICDET , info); err_fall_wake:
drivers/mfd/wm5102-tables.c +3 -0
@@ -1106,6 +1106,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)case ARIZONA_ACCESSORY_DETECT_MODE_1 :case ARIZONA_HEADPHONE_DETECT_1 :case ARIZONA_HEADPHONE_DETECT_2 : +case ARIZONA_HP_DACVAL : +case ARIZONA_MICD_CLAMP_CONTROL :case ARIZONA_MIC_DETECT_1 :case ARIZONA_MIC_DETECT_2 :case ARIZONA_MIC_DETECT_3 :
@@ -1875,6 +1877,7 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)case ARIZONA_DSP1_STATUS_2 :case ARIZONA_DSP1_STATUS_3 :case ARIZONA_HEADPHONE_DETECT_2 : +case ARIZONA_HP_DACVAL :case ARIZONA_MIC_DETECT_3 :return true;default :
include/linux/mfd/arizona/registers.h +12 -0
@@ -119,6 +119,7 @@#define ARIZONA_ACCESSORY_DETECT_MODE_1 0x293#define ARIZONA_HEADPHONE_DETECT_1 0x29B#define ARIZONA_HEADPHONE_DETECT_2 0x29C +#define ARIZONA_HP_DACVAL 0x29F#define ARIZONA_MICD_CLAMP_CONTROL 0x2A2#define ARIZONA_MIC_DETECT_1 0x2A3#define ARIZONA_MIC_DETECT_2 0x2A4
@@ -2036,6 +2037,9 @@/* * R667 (0x29B) - Headphone Detect 1 */ +#define ARIZONA_HP_IMPEDANCE_RANGE_MASK 0x0600/* HP_IMPEDANCE_RANGE - [10:9] */ +#define ARIZONA_HP_IMPEDANCE_RANGE_SHIFT 9/* HP_IMPEDANCE_RANGE - [10:9] */ +#define ARIZONA_HP_IMPEDANCE_RANGE_WIDTH 2/* HP_IMPEDANCE_RANGE - [10:9] */ #define ARIZONA_HP_STEP_SIZE 0x0100/* HP_STEP_SIZE */ #define ARIZONA_HP_STEP_SIZE_MASK 0x0100/* HP_STEP_SIZE */ #define ARIZONA_HP_STEP_SIZE_SHIFT 8/* HP_STEP_SIZE */
@@ -2070,6 +2074,14 @@#define ARIZONA_HP_LVL_SHIFT 0/* HP_LVL - [6:0] */ #define ARIZONA_HP_LVL_WIDTH 7/* HP_LVL - [6:0] */ +#define ARIZONA_HP_DONE_B 0x8000/* HP_DONE */ +#define ARIZONA_HP_DONE_B_MASK 0x8000/* HP_DONE */ +#define ARIZONA_HP_DONE_B_SHIFT 15/* HP_DONE */ +#define ARIZONA_HP_DONE_B_WIDTH 1/* HP_DONE */ +#define ARIZONA_HP_LVL_B_MASK 0x7FFF/* HP_LVL - [14:0] */ +#define ARIZONA_HP_LVL_B_SHIFT 0/* HP_LVL - [14:0] */ +#define ARIZONA_HP_LVL_B_WIDTH 15/* HP_LVL - [14:0] */ +/* * R674 (0x2A2) - MICD clamp control */
Signature · 1 line
1.7.10.4
PATCH 8/11 extcon: arizona: Move start and stop mic functions earlier
In reply to Mark BrownSimple code motion supporting future work.
--- drivers/extcon/extcon-arizona.c | 120 +++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 60 deletions(-)
drivers/extcon/extcon-arizona.c +60 -60
@@ -112,6 +112,66 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)dev_dbg (arizona->dev,"Set jack polarity to %d\n" , mode); } +static void arizona_start_mic (struct arizona_extcon_info *info) +{ +struct arizona *arizona = info->arizona; +bool change; +int ret; + + info->detecting = true; + info->mic = false; + info->jack_flips =0 ; + +/* Microphone detection can't use idle mode */ +pm_runtime_get (info->dev); + + ret =regulator_enable (info->micvdd); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to enable MICVDD: %d\n" , + ret); + } + +if (info->micd_reva) { +regmap_write (arizona->regmap,0x80 ,0x3 ); +regmap_write (arizona->regmap,0x294 ,0 ); +regmap_write (arizona->regmap,0x80 ,0x0 ); + } + +regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK ,ARIZONA_ACCDET_MODE_MIC ); + +regmap_update_bits_check (arizona->regmap,ARIZONA_MIC_DETECT_1 , +ARIZONA_MICD_ENA ,ARIZONA_MICD_ENA , + &change); +if (!change) { +regulator_disable (info->micvdd); +pm_runtime_put_autosuspend (info->dev); + } +} + +static void arizona_stop_mic (struct arizona_extcon_info *info) +{ +struct arizona *arizona = info->arizona; +bool change; + +regmap_update_bits_check (arizona->regmap,ARIZONA_MIC_DETECT_1 , +ARIZONA_MICD_ENA ,0 , + &change); + +if (info->micd_reva) { +regmap_write (arizona->regmap,0x80 ,0x3 ); +regmap_write (arizona->regmap,0x294 ,2 ); +regmap_write (arizona->regmap,0x80 ,0x0 ); + } + +if (change) { +regulator_disable (info->micvdd); +pm_runtime_mark_last_busy (info->dev); +pm_runtime_put_autosuspend (info->dev); + } +} + static struct { unsigned int factor_a; unsigned int factor_b;
@@ -396,66 +456,6 @@ err: info->hpdet_active = false; } -static void arizona_start_mic (struct arizona_extcon_info *info) -{ -struct arizona *arizona = info->arizona; -bool change; -int ret; - - info->detecting = true; - info->mic = false; - info->jack_flips =0 ; - -/* Microphone detection can't use idle mode */ -pm_runtime_get (info->dev); - - ret =regulator_enable (info->micvdd); -if (ret !=0 ) { -dev_err (arizona->dev,"Failed to enable MICVDD: %d\n" , - ret); - } - -if (info->micd_reva) { -regmap_write (arizona->regmap,0x80 ,0x3 ); -regmap_write (arizona->regmap,0x294 ,0 ); -regmap_write (arizona->regmap,0x80 ,0x0 ); - } - -regmap_update_bits (arizona->regmap, -ARIZONA_ACCESSORY_DETECT_MODE_1 , -ARIZONA_ACCDET_MODE_MASK ,ARIZONA_ACCDET_MODE_MIC ); - -regmap_update_bits_check (arizona->regmap,ARIZONA_MIC_DETECT_1 , -ARIZONA_MICD_ENA ,ARIZONA_MICD_ENA , - &change); -if (!change) { -regulator_disable (info->micvdd); -pm_runtime_put_autosuspend (info->dev); - } -} - -static void arizona_stop_mic (struct arizona_extcon_info *info) -{ -struct arizona *arizona = info->arizona; -bool change; - -regmap_update_bits_check (arizona->regmap,ARIZONA_MIC_DETECT_1 , -ARIZONA_MICD_ENA ,0 , - &change); - -if (info->micd_reva) { -regmap_write (arizona->regmap,0x80 ,0x3 ); -regmap_write (arizona->regmap,0x294 ,2 ); -regmap_write (arizona->regmap,0x80 ,0x0 ); - } - -if (change) { -regulator_disable (info->micvdd); -pm_runtime_mark_last_busy (info->dev); -pm_runtime_put_autosuspend (info->dev); - } -} -static irqreturn_t arizona_micdet (int irq,void *data) {struct arizona_extcon_info *info = data;
Signature · 1 line
1.7.10.4
PATCH 9/11 extcon: arizona: Support HPDET based accessory identification
In reply to Mark BrownThe accessory detection functionality in Arizona devices is flexible and supports several system designs in addition to the default one implemented by the existing driver. One such design uses the HPDET feature to determine what kind of accessory is present by comparing measurements taken with the two headphone grounds available on the device, implement that if selected by platform data.
--- drivers/extcon/extcon-arizona.c | 159 ++++++++++++++++++++++++++++++++++--- include/linux/mfd/arizona/pdata.h | 3 + 2 files changed, 150 insertions(+), 12 deletions(-)
drivers/extcon/extcon-arizona.c +147 -12
@@ -55,6 +55,9 @@ struct arizona_extcon_info {bool hpdet_active; +int num_hpdet_res; +unsigned int hpdet_res[2 ]; +bool mic;bool detecting;int jack_flips;
@@ -65,8 +68,8 @@ struct arizona_extcon_info { };static const struct arizona_micd_config micd_default_modes[] = { - {ARIZONA_ACCDET_SRC ,1 <<ARIZONA_MICD_BIAS_SRC_SHIFT ,0 }, {0 ,2 <<ARIZONA_MICD_BIAS_SRC_SHIFT ,1 }, + {ARIZONA_ACCDET_SRC ,1 <<ARIZONA_MICD_BIAS_SRC_SHIFT ,0 }, }; static struct {
@@ -118,10 +121,6 @@ static void arizona_start_mic(struct arizona_extcon_info *info)bool change;int ret; - info->detecting = true; - info->mic = false; - info->jack_flips =0 ; -/* Microphone detection can't use idle mode */ pm_runtime_get (info->dev);
@@ -311,12 +310,80 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)return val; } +static int arizona_hpdet_do_id (struct arizona_extcon_info *info,int *reading) +{ +struct arizona *arizona = info->arizona; +int ret; + +/* +* If we're using HPDET for accessory identification we need +* to take multiple measurements, step through them in sequence. +*/ +if (arizona->pdata.hpdet_acc_id) { + info->hpdet_res[info->num_hpdet_res++] = *reading; + +/* +* If the impedence is too high don't measure the +* second ground. +*/ +if (info->num_hpdet_res ==1 && *reading >=45 ) { +dev_dbg (arizona->dev,"Skipping ground flip\n" ); + info->hpdet_res[info->num_hpdet_res++] = *reading; + } + +if (info->num_hpdet_res ==1 ) { +dev_dbg (arizona->dev,"Flipping ground\n" ); + +regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_SRC , + ~info->micd_modes[0 ].src); +regmap_update_bits (arizona->regmap, +ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_POLL ,0 ); +regmap_update_bits (arizona->regmap, +ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_POLL ,ARIZONA_HP_POLL ); +return -EAGAIN ; + } + +/* OK, got both. Now, compare... */ +dev_dbg (arizona->dev,"HPDET measured %d %d\n" , + info->hpdet_res[0 ], info->hpdet_res[1 ]); + +if (info->hpdet_res[0 ] > info->hpdet_res[1 ] *2 ) { +dev_dbg (arizona->dev,"Detected mic\n" ); + info->mic = true; + ret =extcon_set_cable_state_ (&info->edev, +ARIZONA_CABLE_MICROPHONE , + true); +if (ret !=0 ) { +dev_err (arizona->dev, +"Failed to report mic: %d\n" , ret); + } + +/* Take the headphone impedance for the main report */ + *reading = info->hpdet_res[1 ]; + }else { +dev_dbg (arizona->dev,"Detected headphone\n" ); + } + +/* Make sure everything is reset back to the real polarity */ +regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_SRC , + info->micd_modes[0 ].src); + } + +return 0 ; +} +static irqreturn_t arizona_hpdet_irq (int irq,void *data) {struct arizona_extcon_info *info = data;struct arizona *arizona = info->arizona;int report =ARIZONA_CABLE_HEADPHONE ; -int ret; +int ret, reading;mutex_lock (&info->lock);
@@ -344,14 +411,23 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) }else if (ret <0 ) { goto done; } + reading = ret;/* Reset back to starting range */ regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , -ARIZONA_HP_IMPEDANCE_RANGE_MASK ,0 ); +ARIZONA_HP_IMPEDANCE_RANGE_MASK |ARIZONA_HP_POLL , +0 ); + + ret =arizona_hpdet_do_id (info, &reading); +if (ret == -EAGAIN ) { + goto out; + }else if (ret <0 ) { + goto done; + }/* Report high impedence cables as line outputs */ -if (ret >=5000 ) +if (reading >=5000 ) report =ARIZONA_CABLE_LINEOUT ;else report =ARIZONA_CABLE_HEADPHONE ;
@@ -370,8 +446,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)dev_warn (arizona->dev,"Failed to undo magic: %d\n" , ret); done: -regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , -ARIZONA_HP_POLL ,0 );/* Revert back to MICDET mode */ regmap_update_bits(arizona->regmap,
@@ -451,8 +525,58 @@ err: info->hpdet_active = false; } + +static void arizona_start_hpdet_acc_id (struct arizona_extcon_info *info) +{ +struct arizona *arizona = info->arizona; +int ret; + +dev_dbg (arizona->dev,"Starting identification via HPDET\n" ); + +/* Make sure we keep the device enabled during the measurement */ +pm_runtime_get (info->dev); + + info->hpdet_active = true; + + ret =regmap_update_bits (arizona->regmap,0x225 ,0x4000 ,0x4000 ); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); + + ret =regmap_update_bits (arizona->regmap,0x226 ,0x4000 ,0x4000 ); +if (ret !=0 ) +dev_warn (arizona->dev,"Failed to do magic: %d\n" , ret); + + ret =regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_SRC |ARIZONA_ACCDET_MODE_MASK , + info->micd_modes[0 ].src | +ARIZONA_ACCDET_MODE_HPL ); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to set HPDETL mode: %d\n" , ret); + goto err; } + ret =regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , +ARIZONA_HP_POLL ,ARIZONA_HP_POLL ); +if (ret !=0 ) { +dev_err (arizona->dev,"Can't start HPDETL measurement: %d\n" , + ret); + goto err; + } + +return ; + +err: +regmap_update_bits (arizona->regmap,ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK ,ARIZONA_ACCDET_MODE_MIC ); + +/* Just report headphone */ + ret =extcon_update_state (&info->edev, +1 <<ARIZONA_CABLE_HEADPHONE , +1 <<ARIZONA_CABLE_HEADPHONE ); +if (ret !=0 ) +dev_err (arizona->dev,"Failed to report headphone: %d\n" , ret); + info->hpdet_active = false; }
@@ -612,12 +736,24 @@ static irqreturn_t arizona_jackdet(int irq, void *data)dev_err (arizona->dev,"Mechanical report failed: %d\n" , ret); -arizona_start_mic (info); +if (!arizona->pdata.hpdet_acc_id) { + info->detecting = true; + info->mic = false; + info->jack_flips =0 ; + +arizona_start_mic (info); + }else { +arizona_start_hpdet_acc_id (info); + } }else {dev_dbg (arizona->dev,"Detected jack removal\n" );arizona_stop_mic (info); + info->num_hpdet_res =0 ; +for (i =0 ; i <ARRAY_SIZE (info->hpdet_res); i++) + info->hpdet_res[i] =0 ; + info->mic = false;for (i =0 ; i <ARIZONA_NUM_BUTTONS ; i++) input_report_key(info->input,
@@ -665,7 +801,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)mutex_init (&info->lock); info->arizona = arizona; info->dev = &pdev->dev; - info->detecting = true;platform_set_drvdata (pdev, info);switch (arizona->type) {
include/linux/mfd/arizona/pdata.h +3 -0
@@ -99,6 +99,9 @@ struct arizona_pdata {/** GPIO5 is used for jack detection */ bool jd_gpio5; +/** Use the headphone detect circuit to identify the accessory */ +bool hpdet_acc_id; +/** GPIO for mic detection polarity */ int micd_pol_gpio;
Signature · 1 line
1.7.10.4
Chanwoo Choi
maintainerRe: [PATCH 09/11] extcon: arizona: Support HPDET based accessory identification
drivers/extcon/extcon-arizona.c static int arizona_hpdet_read(struct arizona_extcon_info *info) · line 350
Quoted 3 lines
drivers/extcon/extcon-arizona.c +3
-0+ } + +/* OK, got both. Now, compare... */
Is is correct comment?
drivers/extcon/extcon-arizona.c static int arizona_hpdet_read(struct arizona_extcon_info *info) · line 353
Quoted 3 lines
drivers/extcon/extcon-arizona.c +3
-0+dev_dbg (arizona->dev,"HPDET measured %d %d\n" , + info->hpdet_res[0 ], info->hpdet_res[1 ]); +
Thank you,
Chanwoo Choi
Re: [PATCH 09/11] extcon: arizona: Support HPDET based accessory identification
Quoted 3 lines · Chanwoo Choi
drivers/extcon/extcon-arizona.c static int arizona_hpdet_read(struct arizona_extcon_info *info) · line 350
Quoted 1 line
drivers/extcon/extcon-arizona.c +1
-0+/* OK, got both. Now, compare... */ Is is correct comment?
I think so but that doesn't mean I'm not mistaken or there's nothing that could be improved - why do you ask?
PATCH 10/11 extcon: arizona: Support direct microphone measurement via HPDET
In reply to Mark BrownWith some GPIO control it is possible to detect microphones in a wider range of configurations by directly measuring the microphone impedance when the HPDET method cannot distinguish between the behaviour of the two grounds. Allow a GPIO to be provided in platform data and use it to implement this behaviour.
--- drivers/extcon/extcon-arizona.c | 50 +++++++++++++++++++++++++++++++++---- include/linux/mfd/arizona/pdata.h | 3 +++ 2 files changed, 48 insertions(+), 5 deletions(-)
drivers/extcon/extcon-arizona.c +45 -5
@@ -56,7 +56,7 @@ struct arizona_extcon_info {bool hpdet_active;int num_hpdet_res; -unsigned int hpdet_res[2 ]; +unsigned int hpdet_res[3 ];bool mic;bool detecting;
@@ -313,6 +313,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)static int arizona_hpdet_do_id (struct arizona_extcon_info *info,int *reading) {struct arizona *arizona = info->arizona; +int id_gpio = arizona->pdata.hpdet_id_gpio;int ret;/*
@@ -338,9 +339,27 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)ARIZONA_ACCESSORY_DETECT_MODE_1 ,ARIZONA_ACCDET_SRC , ~info->micd_modes[0].src); +regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 , -ARIZONA_HP_POLL ,0 ); +ARIZONA_HP_POLL ,ARIZONA_HP_POLL ); +return -EAGAIN ; + } + +/* Only check the mic directly if we didn't already ID it */ +if (id_gpio && info->num_hpdet_res ==2 && + !((info->hpdet_res[0 ] > info->hpdet_res[1 ] *2 ))) { +dev_dbg (arizona->dev,"Measuring mic\n" ); + +regmap_update_bits (arizona->regmap, +ARIZONA_ACCESSORY_DETECT_MODE_1 , +ARIZONA_ACCDET_MODE_MASK | +ARIZONA_ACCDET_SRC , +ARIZONA_ACCDET_MODE_HPR | + info->micd_modes[0 ].src); + +gpio_set_value_cansleep (id_gpio,1 ); +regmap_update_bits (arizona->regmap,ARIZONA_HEADPHONE_DETECT_1 ,ARIZONA_HP_POLL ,ARIZONA_HP_POLL );
@@ -348,10 +367,16 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) }/* OK, got both. Now, compare... */ -dev_dbg (arizona->dev,"HPDET measured %d %d\n" , - info->hpdet_res[0 ], info->hpdet_res[1 ]); +dev_dbg (arizona->dev,"HPDET measured %d %d %d\n" , + info->hpdet_res[0 ], info->hpdet_res[1 ], + info->hpdet_res[2 ]); -if (info->hpdet_res[0 ] > info->hpdet_res[1 ] *2 ) { +/* +* Either the two grounds measure differently or we +* measure the mic as high impedance. +*/ +if ((info->hpdet_res[0 ] > info->hpdet_res[1 ] *2 ) || + (id_gpio && info->hpdet_res[2 ] >10 )) {dev_dbg (arizona->dev,"Detected mic\n" ); info->mic = true; ret = extcon_set_cable_state_(&info->edev,
@@ -382,6 +407,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) {struct arizona_extcon_info *info = data;struct arizona *arizona = info->arizona; +int id_gpio = arizona->pdata.hpdet_id_gpio;int report =ARIZONA_CABLE_HEADPHONE ;int ret, reading;
@@ -446,6 +472,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)dev_warn (arizona->dev,"Failed to undo magic: %d\n" , ret); done: +if (id_gpio) +gpio_set_value_cansleep (id_gpio,0 );/* Revert back to MICDET mode */ regmap_update_bits(arizona->regmap,
@@ -854,6 +882,18 @@ static int arizona_extcon_probe(struct platform_device *pdev) } } +if (arizona->pdata.hpdet_id_gpio >0 ) { + ret =devm_gpio_request_one (&pdev->dev, + arizona->pdata.hpdet_id_gpio, +GPIOF_OUT_INIT_LOW , +"HPDET" ); +if (ret !=0 ) { +dev_err (arizona->dev,"Failed to request GPIO%d: %d\n" , + arizona->pdata.hpdet_id_gpio, ret); + goto err_register; + } + } +if (arizona->pdata.micd_bias_start_time) regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, ARIZONA_MICD_BIAS_STARTTIME_MASK,
include/linux/mfd/arizona/pdata.h +3 -0
@@ -102,6 +102,9 @@ struct arizona_pdata {/** Use the headphone detect circuit to identify the accessory */ bool hpdet_acc_id; +/** GPIO used for mic isolation with HPDET */ +int hpdet_id_gpio; +/** GPIO for mic detection polarity */ int micd_pol_gpio;
Signature · 1 line
1.7.10.4
PATCH 11/11 mfd: wm5102: Add microphone clamp control registers
In reply to Mark Brown--- drivers/mfd/wm5102-tables.c | 7 +++++++ include/linux/mfd/arizona/registers.h | 8 ++++++++ 2 files changed, 15 insertions(+)
drivers/mfd/wm5102-tables.c +7 -0
@@ -84,6 +84,12 @@ int wm5102_patch(struct arizona *arizona) }static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ ] = { + [ARIZONA_IRQ_MICD_CLAMP_FALL ] = { + .mask =ARIZONA_MICD_CLAMP_FALL_EINT1 + }, + [ARIZONA_IRQ_MICD_CLAMP_RISE ] = { + .mask =ARIZONA_MICD_CLAMP_RISE_EINT1 + }, [ARIZONA_IRQ_GP5_FALL ] = { .mask =ARIZONA_GP5_FALL_EINT1 }, [ARIZONA_IRQ_GP5_RISE ] = { .mask =ARIZONA_GP5_RISE_EINT1 }, [ARIZONA_IRQ_JD_FALL ] = { .mask =ARIZONA_JD1_FALL_EINT1 },
@@ -312,6 +318,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */ { 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */ { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */ + { 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ { 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */
include/linux/mfd/arizona/registers.h +8 -0
@@ -1196,6 +1196,14 @@/* * R64 (0x40) - Wake control */ +#define ARIZONA_WKUP_MICD_CLAMP_FALL 0x0080/* WKUP_MICD_CLAMP_FALL */ +#define ARIZONA_WKUP_MICD_CLAMP_FALL_MASK 0x0080/* WKUP_MICD_CLAMP_FALL */ +#define ARIZONA_WKUP_MICD_CLAMP_FALL_SHIFT 7/* WKUP_MICD_CLAMP_FALL */ +#define ARIZONA_WKUP_MICD_CLAMP_FALL_WIDTH 1/* WKUP_MICD_CLAMP_FALL */ +#define ARIZONA_WKUP_MICD_CLAMP_RISE 0x0040/* WKUP_MICD_CLAMP_RISE */ +#define ARIZONA_WKUP_MICD_CLAMP_RISE_MASK 0x0040/* WKUP_MICD_CLAMP_RISE */ +#define ARIZONA_WKUP_MICD_CLAMP_RISE_SHIFT 6/* WKUP_MICD_CLAMP_RISE */ +#define ARIZONA_WKUP_MICD_CLAMP_RISE_WIDTH 1/* WKUP_MICD_CLAMP_RISE */ #define ARIZONA_WKUP_GP5_FALL 0x0020/* WKUP_GP5_FALL */ #define ARIZONA_WKUP_GP5_FALL_MASK 0x0020/* WKUP_GP5_FALL */ #define ARIZONA_WKUP_GP5_FALL_SHIFT 5/* WKUP_GP5_FALL */
Signature · 1 line
1.7.10.4
Chanwoo Choi
maintainerQuoted 40 lines · Mark Brown
The following changes since commit
9931faca02c604c22335f5a935a501bb2ace6e20:Linux 3.8-rc3 (2013-01-09 18:59:55 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.gittags/extcon-arizona-3.8rc3for you to fetch changes up to
708f5b582ea16b60701e275fe5233ec4c57859cd:mfd: wm5102: Add microphone clamp control registers (2013-01-10 11:35:42 +0000)
----------------------------------------------------------------
extcon: arizona: Updates to arizona extcon driverThis patch series adds a number of new features to the arizona driver:
- Headphone measurements.
- Alternative detection mechanism for non-default system designs.
- Microphone clamp integration.
- Support for additional detection pin.
- MICBIAS rise time configuration.There's one trivial MFD patch which is here because it depends on register definitions from the new features.
----------------------------------------------------------------
Mark Brown (11):
extcon: arizona: Convert todevm_input_allocate_device()
extcon: arizona: Remove duplicate mic ramp configuration
extcon: arizona: Only set GPIO if it has been requested
extcon: arizona: Allow configuration of MICBIAS rise time
extcon: arizona: Use microphone clamp function if available
extcon: arizona: Support use of GPIO5 as an input to jack detection
extcon: arizona: Enable basic headphone identification
extcon: arizona: Move start and stop mic functions earlier
extcon: arizona: Support HPDET based accessory identification
extcon: arizona: Support direct microphone measurement via HPDET
mfd: wm5102: Add microphone clamp control registers
Quoted 6 lines
drivers/extcon/extcon-arizona.c | 634 ++++++++++++++++++++++++++++++--- drivers/mfd/wm5102-tables.c | 10 + include/linux/mfd/arizona/core.h | 4 +- include/linux/mfd/arizona/pdata.h | 12 + include/linux/mfd/arizona/registers.h | 48 +++ 5 files changed, 658 insertions(+), 50 deletions(-)
Applied this patch set.
You can check this on extcon git repository:
http://git.kernel.org/?p=linux/kernel/git/chanwoo/extcon.git;a=shortlog;h=refs/heads/for-next
Thank you,
Chanwoo Choi
Quoted 4 lines · Chanwoo Choi
Applied this patch set.
You can check this on extcon git repository:
http://git.kernel.org/?p=linux/kernel/git/chanwoo/extcon.git;a=shortlog;h=refs/heads/for-next
Looks good. It does seem this tree isn't in -next, though - if this tree ends up getting sent to Linus (via Greg I guess?) it'd make sense to do that so we get integration testing for it as soon as possible.
Quoted 10 lines · Mark Brown
Quoted 4 lines · Chanwoo Choi
Applied this patch set.
You can check this on extcon git repository:
http://git.kernel.org/?p=linux/kernel/git/chanwoo/extcon.git;a=shortlog;h=refs/heads/for-nextLooks good. It does seem this tree isn't in -next, though - if this tree ends up getting sent to Linus (via Greg I guess?) it'd make sense to do that so we get integration testing for it as soon as possible.
It would be good if Chanwoo sent me pull requests, I thought that was going to happen but I have not seen any yet...
Chanwoo Choi
maintainerQuoted 8 lines · Greg Kroah-Hartman
Quoted 7 lines · Mark Brown
Quoted 4 lines · Chanwoo Choi
Applied this patch set.
You can check this on extcon git repository:
http://git.kernel.org/?p=linux/kernel/git/chanwoo/extcon.git;a=shortlog;h=refs/heads/for-next
Quoted 7 lines
Quoted 3 lines
Looks good. It does seem this tree isn't in -next, though - if this tree ends up getting sent to Linus (via Greg I guess?) it'd make sense to do that so we get integration testing for it as soon as possible.
It would be good if Chanwoo sent me pull requests, I thought that was going to happen but I have not seen any yet...
OK, I will send pull request to GregKH for extcon immediately.
Best Regards,
Chanwoo Choi
Quoted 1 line · Chanwoo Choi
OK, I will send pull request to GregKH for extcon immediately.
Thanks. Like I say if you're doing this it's probably also worth asking to get the tree in -next, the build coverage (especially from Fenguang's awesome build farm!) and merge test coverage are both worth it.
Chanwoo Choi
maintainerQuoted 8 lines · Greg Kroah-Hartman
Quoted 7 lines · Mark Brown
Quoted 4 lines · Chanwoo Choi
Applied this patch set.
You can check this on extcon git repository:
http://git.kernel.org/?p=linux/kernel/git/chanwoo/extcon.git;a=shortlog;h=refs/heads/for-next
Quoted 7 lines
Quoted 3 lines
Looks good. It does seem this tree isn't in -next, though - if this tree ends up getting sent to Linus (via Greg I guess?) it'd make sense to do that so we get integration testing for it as soon as possible.
It would be good if Chanwoo sent me pull requests, I thought that was going to happen but I have not seen any yet...
OK, I will send pull request to GregKH for extcon immediately.
Thank you,
Chanwoo Choi