diff options
Diffstat (limited to 'drivers/extcon')
| -rw-r--r-- | drivers/extcon/extcon-arizona.c | 498 | ||||
| -rw-r--r-- | drivers/extcon/extcon-max77693.c | 111 | ||||
| -rw-r--r-- | drivers/extcon/extcon-max8997.c | 66 | 
3 files changed, 462 insertions, 213 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index dc357a4051f..7a1b4a7791b 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -33,12 +33,17 @@  #include <linux/mfd/arizona/pdata.h>  #include <linux/mfd/arizona/registers.h> -#define ARIZONA_NUM_BUTTONS 6 +#define ARIZONA_MAX_MICD_RANGE 8  #define ARIZONA_ACCDET_MODE_MIC 0  #define ARIZONA_ACCDET_MODE_HPL 1  #define ARIZONA_ACCDET_MODE_HPR 2 +#define ARIZONA_HPDET_MAX 10000 + +#define HPDET_DEBOUNCE 500 +#define DEFAULT_MICD_TIMEOUT 2000 +  struct arizona_extcon_info {  	struct device *dev;  	struct arizona *arizona; @@ -46,17 +51,27 @@ struct arizona_extcon_info {  	struct regulator *micvdd;  	struct input_dev *input; +	u16 last_jackdet; +  	int micd_mode;  	const struct arizona_micd_config *micd_modes;  	int micd_num_modes; +	const struct arizona_micd_range *micd_ranges; +	int num_micd_ranges; + +	int micd_timeout; +  	bool micd_reva;  	bool micd_clamp;  	struct delayed_work hpdet_work; +	struct delayed_work micd_detect_work; +	struct delayed_work micd_timeout_work;  	bool hpdet_active;  	bool hpdet_done; +	bool hpdet_retried;  	int num_hpdet_res;  	unsigned int hpdet_res[3]; @@ -71,20 +86,25 @@ struct arizona_extcon_info {  };  static const struct arizona_micd_config micd_default_modes[] = { -	{ 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },  	{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, +	{ 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },  }; -static struct { -	u16 status; -	int report; -} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = { -	{  0x1, BTN_0 }, -	{  0x2, BTN_1 }, -	{  0x4, BTN_2 }, -	{  0x8, BTN_3 }, -	{ 0x10, BTN_4 }, -	{ 0x20, BTN_5 }, +static const struct arizona_micd_range micd_default_ranges[] = { +	{ .max =  11, .key = BTN_0 }, +	{ .max =  28, .key = BTN_1 }, +	{ .max =  54, .key = BTN_2 }, +	{ .max = 100, .key = BTN_3 }, +	{ .max = 186, .key = BTN_4 }, +	{ .max = 430, .key = BTN_5 }, +}; + +static const int arizona_micd_levels[] = { +	3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46, +	49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100, +	105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245, +	270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071, +	1257,  };  #define ARIZONA_CABLE_MECHANICAL 0 @@ -100,10 +120,63 @@ static const char *arizona_cable[] = {  	NULL,  }; +static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); + +static void arizona_extcon_do_magic(struct arizona_extcon_info *info, +				    unsigned int magic) +{ +	struct arizona *arizona = info->arizona; +	int ret; + +	mutex_lock(&arizona->dapm->card->dapm_mutex); + +	arizona->hpdet_magic = magic; + +	/* Keep the HP output stages disabled while doing the magic */ +	if (magic) { +		ret = regmap_update_bits(arizona->regmap, +					 ARIZONA_OUTPUT_ENABLES_1, +					 ARIZONA_OUT1L_ENA | +					 ARIZONA_OUT1R_ENA, 0); +		if (ret != 0) +			dev_warn(arizona->dev, +				"Failed to disable headphone outputs: %d\n", +				 ret); +	} + +	ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, +				 magic); +	if (ret != 0) +		dev_warn(arizona->dev, "Failed to do magic: %d\n", +				 ret); + +	ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, +				 magic); +	if (ret != 0) +		dev_warn(arizona->dev, "Failed to do magic: %d\n", +			 ret); + +	/* Restore the desired state while not doing the magic */ +	if (!magic) { +		ret = regmap_update_bits(arizona->regmap, +					 ARIZONA_OUTPUT_ENABLES_1, +					 ARIZONA_OUT1L_ENA | +					 ARIZONA_OUT1R_ENA, arizona->hp_ena); +		if (ret != 0) +			dev_warn(arizona->dev, +				 "Failed to restore headphone outputs: %d\n", +				 ret); +	} + +	mutex_unlock(&arizona->dapm->card->dapm_mutex); +} +  static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)  {  	struct arizona *arizona = info->arizona; +	mode %= info->micd_num_modes; +  	if (arizona->pdata.micd_pol_gpio > 0)  		gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,  					info->micd_modes[mode].gpio); @@ -330,7 +403,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)  		/* 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; +			return ARIZONA_HPDET_MAX;  		}  		dev_dbg(arizona->dev, "HPDET read %d in range %d\n", @@ -391,7 +464,8 @@ 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) +static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, +			       bool *mic)  {  	struct arizona *arizona = info->arizona;  	int id_gpio = arizona->pdata.hpdet_id_gpio; @@ -403,32 +477,8 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)  	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, 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))) { +		if (id_gpio && info->num_hpdet_res == 1) {  			dev_dbg(arizona->dev, "Measuring mic\n");  			regmap_update_bits(arizona->regmap, @@ -447,22 +497,28 @@ 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 %d\n", -			info->hpdet_res[0], info->hpdet_res[1], -			info->hpdet_res[2]); - +		dev_dbg(arizona->dev, "HPDET measured %d %d\n", +			info->hpdet_res[0], info->hpdet_res[1]);  		/* Take the headphone impedance for the main report */  		*reading = info->hpdet_res[0]; +		/* Sometimes we get false readings due to slow insert */ +		if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) { +			dev_dbg(arizona->dev, "Retrying high impedance\n"); +			info->num_hpdet_res = 0; +			info->hpdet_retried = true; +			arizona_start_hpdet_acc_id(info); +			pm_runtime_put(info->dev); +			return -EAGAIN; +		} +  		/* -		 * Either the two grounds measure differently or we -		 * measure the mic as high impedance. +		 * If we measure the mic as   		 */ -		if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) || -		    (id_gpio && info->hpdet_res[2] > 10)) { +		if (!id_gpio || info->hpdet_res[1] > 50) {  			dev_dbg(arizona->dev, "Detected mic\n"); -			info->mic = true; +			*mic = true;  			info->detecting = true;  		} else {  			dev_dbg(arizona->dev, "Detected headphone\n"); @@ -484,8 +540,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)  	struct arizona *arizona = info->arizona;  	int id_gpio = arizona->pdata.hpdet_id_gpio;  	int report = ARIZONA_CABLE_HEADPHONE; -	unsigned int val;  	int ret, reading; +	bool mic = false;  	mutex_lock(&info->lock); @@ -521,7 +577,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)  			   ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,  			   0); -	ret = arizona_hpdet_do_id(info, &reading); +	ret = arizona_hpdet_do_id(info, &reading, &mic);  	if (ret == -EAGAIN) {  		goto out;  	} else if (ret < 0) { @@ -539,28 +595,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)  		dev_err(arizona->dev, "Failed to report HP/line: %d\n",  			ret); -	mutex_lock(&arizona->dapm->card->dapm_mutex); - -	ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); -	if (ret != 0) { -		dev_err(arizona->dev, "Failed to read output enables: %d\n", -			ret); -		val = 0; -	} - -	if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { -		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); -	} - -	mutex_unlock(&arizona->dapm->card->dapm_mutex); +	arizona_extcon_do_magic(info, 0);  done:  	if (id_gpio) @@ -572,7 +607,7 @@ done:  			   ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);  	/* If we have a mic then reenable MICDET */ -	if (info->mic) +	if (mic || info->mic)  		arizona_start_mic(info);  	if (info->hpdet_active) { @@ -606,13 +641,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)  	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); +	arizona_extcon_do_magic(info, 0x4000);  	ret = regmap_update_bits(arizona->regmap,  				 ARIZONA_ACCESSORY_DETECT_MODE_1, @@ -653,7 +682,8 @@ err:  static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)  {  	struct arizona *arizona = info->arizona; -	unsigned int val; +	int hp_reading = 32; +	bool mic;  	int ret;  	dev_dbg(arizona->dev, "Starting identification via HPDET\n"); @@ -663,32 +693,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)  	info->hpdet_active = true; -	arizona_extcon_pulse_micbias(info); - -	mutex_lock(&arizona->dapm->card->dapm_mutex); - -	ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); -	if (ret != 0) { -		dev_err(arizona->dev, "Failed to read output enables: %d\n", -			ret); -		val = 0; -	} - -	if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { -		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); -	} - -	mutex_unlock(&arizona->dapm->card->dapm_mutex); +	arizona_extcon_do_magic(info, 0x4000);  	ret = regmap_update_bits(arizona->regmap,  				 ARIZONA_ACCESSORY_DETECT_MODE_1, @@ -700,12 +705,18 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)  		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; +	if (arizona->pdata.hpdet_acc_id_line) { +		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; +		} +	} else { +		arizona_hpdet_do_id(info, &hp_reading, &mic);  	}  	return; @@ -724,28 +735,58 @@ err:  	info->hpdet_active = false;  } -static irqreturn_t arizona_micdet(int irq, void *data) +static void arizona_micd_timeout_work(struct work_struct *work)  { -	struct arizona_extcon_info *info = data; +	struct arizona_extcon_info *info = container_of(work, +							struct arizona_extcon_info, +							micd_timeout_work.work); + +	mutex_lock(&info->lock); + +	dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n"); +	arizona_identify_headphone(info); + +	info->detecting = false; + +	arizona_stop_mic(info); + +	mutex_unlock(&info->lock); +} + +static void arizona_micd_detect(struct work_struct *work) +{ +	struct arizona_extcon_info *info = container_of(work, +							struct arizona_extcon_info, +							micd_detect_work.work);  	struct arizona *arizona = info->arizona; -	unsigned int val, lvl; -	int ret, i; +	unsigned int val = 0, lvl; +	int ret, i, key; + +	cancel_delayed_work_sync(&info->micd_timeout_work);  	mutex_lock(&info->lock); -	ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); -	if (ret != 0) { -		dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); -		mutex_unlock(&info->lock); -		return IRQ_NONE; -	} +	for (i = 0; i < 10 && !(val & 0x7fc); i++) { +		ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); +		if (ret != 0) { +			dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); +			mutex_unlock(&info->lock); +			return; +		} + +		dev_dbg(arizona->dev, "MICDET: %x\n", val); -	dev_dbg(arizona->dev, "MICDET: %x\n", val); +		if (!(val & ARIZONA_MICD_VALID)) { +			dev_warn(arizona->dev, "Microphone detection state invalid\n"); +			mutex_unlock(&info->lock); +			return; +		} +	} -	if (!(val & ARIZONA_MICD_VALID)) { -		dev_warn(arizona->dev, "Microphone detection state invalid\n"); +	if (i == 10 && !(val & 0x7fc)) { +		dev_err(arizona->dev, "Failed to get valid MICDET value\n");  		mutex_unlock(&info->lock); -		return IRQ_NONE; +		return;  	}  	/* Due to jack detect this should never happen */ @@ -786,7 +827,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)  	 * impedence then give up and report headphones.  	 */  	if (info->detecting && (val & 0x3f8)) { -		if (info->jack_flips >= info->micd_num_modes) { +		if (info->jack_flips >= info->micd_num_modes * 10) {  			dev_dbg(arizona->dev, "Detected HP/line\n");  			arizona_identify_headphone(info); @@ -816,12 +857,17 @@ static irqreturn_t arizona_micdet(int irq, void *data)  			lvl = val & ARIZONA_MICD_LVL_MASK;  			lvl >>= ARIZONA_MICD_LVL_SHIFT; -			for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) -				if (lvl & arizona_lvl_to_key[i].status) -					input_report_key(info->input, -							 arizona_lvl_to_key[i].report, -							 1); -			input_sync(info->input); +			for (i = 0; i < info->num_micd_ranges; i++) +				input_report_key(info->input, +						 info->micd_ranges[i].key, 0); + +			WARN_ON(!lvl); +			WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges); +			if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) { +				key = info->micd_ranges[ffs(lvl) - 1].key; +				input_report_key(info->input, key, 1); +				input_sync(info->input); +			}  		} else if (info->detecting) {  			dev_dbg(arizona->dev, "Headphone detected\n"); @@ -835,16 +881,41 @@ static irqreturn_t arizona_micdet(int irq, void *data)  		}  	} else {  		dev_dbg(arizona->dev, "Mic button released\n"); -		for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) +		for (i = 0; i < info->num_micd_ranges; i++)  			input_report_key(info->input, -					 arizona_lvl_to_key[i].report, 0); +					 info->micd_ranges[i].key, 0);  		input_sync(info->input);  		arizona_extcon_pulse_micbias(info);  	}  handled: +	if (info->detecting) +		schedule_delayed_work(&info->micd_timeout_work, +				      msecs_to_jiffies(info->micd_timeout)); +  	pm_runtime_mark_last_busy(info->dev);  	mutex_unlock(&info->lock); +} + +static irqreturn_t arizona_micdet(int irq, void *data) +{ +	struct arizona_extcon_info *info = data; +	struct arizona *arizona = info->arizona; +	int debounce = arizona->pdata.micd_detect_debounce; + +	cancel_delayed_work_sync(&info->micd_detect_work); +	cancel_delayed_work_sync(&info->micd_timeout_work); + +	mutex_lock(&info->lock); +	if (!info->detecting) +		debounce = 0; +	mutex_unlock(&info->lock); + +	if (debounce) +		schedule_delayed_work(&info->micd_detect_work, +				      msecs_to_jiffies(debounce)); +	else +		arizona_micd_detect(&info->micd_detect_work.work);  	return IRQ_HANDLED;  } @@ -865,11 +936,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  	struct arizona_extcon_info *info = data;  	struct arizona *arizona = info->arizona;  	unsigned int val, present, mask; +	bool cancelled_hp, cancelled_mic;  	int ret, i; -	pm_runtime_get_sync(info->dev); +	cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); +	cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); -	cancel_delayed_work_sync(&info->hpdet_work); +	pm_runtime_get_sync(info->dev);  	mutex_lock(&info->lock); @@ -890,7 +963,22 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  		return IRQ_NONE;  	} -	if ((val & mask) == present) { +	val &= mask; +	if (val == info->last_jackdet) { +		dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n"); +		if (cancelled_hp) +			schedule_delayed_work(&info->hpdet_work, +					      msecs_to_jiffies(HPDET_DEBOUNCE)); + +		if (cancelled_mic) +			schedule_delayed_work(&info->micd_timeout_work, +					      msecs_to_jiffies(info->micd_timeout)); + +		goto out; +	} +	info->last_jackdet = val; + +	if (info->last_jackdet == present) {  		dev_dbg(arizona->dev, "Detected jack\n");  		ret = extcon_set_cable_state_(&info->edev,  					      ARIZONA_CABLE_MECHANICAL, true); @@ -907,7 +995,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  			arizona_start_mic(info);  		} else {  			schedule_delayed_work(&info->hpdet_work, -					      msecs_to_jiffies(250)); +					      msecs_to_jiffies(HPDET_DEBOUNCE));  		}  		regmap_update_bits(arizona->regmap, @@ -923,10 +1011,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  			info->hpdet_res[i] = 0;  		info->mic = false;  		info->hpdet_done = false; +		info->hpdet_retried = false; -		for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) +		for (i = 0; i < info->num_micd_ranges; i++)  			input_report_key(info->input, -					 arizona_lvl_to_key[i].report, 0); +					 info->micd_ranges[i].key, 0);  		input_sync(info->input);  		ret = extcon_update_state(&info->edev, 0xffffffff, 0); @@ -940,6 +1029,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  				   ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);  	} +	if (arizona->pdata.micd_timeout) +		info->micd_timeout = arizona->pdata.micd_timeout; +	else +		info->micd_timeout = DEFAULT_MICD_TIMEOUT; +  	/* Clear trig_sts to make sure DCVDD is not forced up */  	regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,  		     ARIZONA_MICD_CLAMP_FALL_TRIG_STS | @@ -947,6 +1041,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  		     ARIZONA_JD1_FALL_TRIG_STS |  		     ARIZONA_JD1_RISE_TRIG_STS); +out:  	mutex_unlock(&info->lock);  	pm_runtime_mark_last_busy(info->dev); @@ -955,13 +1050,34 @@ static irqreturn_t arizona_jackdet(int irq, void *data)  	return IRQ_HANDLED;  } +/* Map a level onto a slot in the register bank */ +static void arizona_micd_set_level(struct arizona *arizona, int index, +				   unsigned int level) +{ +	int reg; +	unsigned int mask; + +	reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2); + +	if (!(index % 2)) { +		mask = 0x3f00; +		level <<= 8; +	} else { +		mask = 0x3f; +	} + +	/* Program the level itself */ +	regmap_update_bits(arizona->regmap, reg, mask, level); +} +  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; +	unsigned int val;  	int jack_irq_fall, jack_irq_rise; -	int ret, mode, i; +	int ret, mode, i, j;  	if (!arizona->dapm || !arizona->dapm->card)  		return -EPROBE_DEFER; @@ -985,7 +1101,10 @@ static int arizona_extcon_probe(struct platform_device *pdev)  	mutex_init(&info->lock);  	info->arizona = arizona;  	info->dev = &pdev->dev; +	info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);  	INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); +	INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect); +	INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);  	platform_set_drvdata(pdev, info);  	switch (arizona->type) { @@ -1014,6 +1133,17 @@ static int arizona_extcon_probe(struct platform_device *pdev)  		goto err;  	} +	info->input = devm_input_allocate_device(&pdev->dev); +	if (!info->input) { +		dev_err(arizona->dev, "Can't allocate input dev\n"); +		ret = -ENOMEM; +		goto err_register; +	} + +	info->input->name = "Headset"; +	info->input->phys = "arizona/extcon"; +	info->input->dev.parent = &pdev->dev; +  	if (pdata->num_micd_configs) {  		info->micd_modes = pdata->micd_configs;  		info->micd_num_modes = pdata->num_micd_configs; @@ -1069,15 +1199,79 @@ static int arizona_extcon_probe(struct platform_device *pdev)  				   arizona->pdata.micd_dbtime  				   << ARIZONA_MICD_DBTIME_SHIFT); +	BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40); + +	if (arizona->pdata.num_micd_ranges) { +		info->micd_ranges = pdata->micd_ranges; +		info->num_micd_ranges = pdata->num_micd_ranges; +	} else { +		info->micd_ranges = micd_default_ranges; +		info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges); +	} + +	if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) { +		dev_err(arizona->dev, "Too many MICD ranges: %d\n", +			arizona->pdata.num_micd_ranges); +	} + +	if (info->num_micd_ranges > 1) { +		for (i = 1; i < info->num_micd_ranges; i++) { +			if (info->micd_ranges[i - 1].max > +			    info->micd_ranges[i].max) { +				dev_err(arizona->dev, +					"MICD ranges must be sorted\n"); +				ret = -EINVAL; +				goto err_input; +			} +		} +	} + +	/* Disable all buttons by default */ +	regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, +			   ARIZONA_MICD_LVL_SEL_MASK, 0x81); + +	/* Set up all the buttons the user specified */ +	for (i = 0; i < info->num_micd_ranges; i++) { +		for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++) +			if (arizona_micd_levels[j] >= info->micd_ranges[i].max) +				break; + +		if (j == ARRAY_SIZE(arizona_micd_levels)) { +			dev_err(arizona->dev, "Unsupported MICD level %d\n", +				info->micd_ranges[i].max); +			ret = -EINVAL; +			goto err_input; +		} + +		dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n", +			arizona_micd_levels[j], i); + +		arizona_micd_set_level(arizona, i, j); +		input_set_capability(info->input, EV_KEY, +				     info->micd_ranges[i].key); + +		/* Enable reporting of that range */ +		regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, +				   1 << i, 1 << i); +	} + +	/* Set all the remaining keys to a maximum */ +	for (; i < ARIZONA_MAX_MICD_RANGE; i++) +		arizona_micd_set_level(arizona, i, 0x3f); +  	/*  	 * If we have a clamp use it, activating in conjunction with  	 * GPIO5 if that is connected for jack detect operation.  	 */  	if (info->micd_clamp) {  		if (arizona->pdata.jd_gpio5) { -			/* Put the GPIO into input mode */ +			/* Put the GPIO into input mode with optional pull */ +			val = 0xc101; +			if (arizona->pdata.jd_gpio5_nopull) +				val &= ~ARIZONA_GPN_PU; +  			regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, -				     0xc101); +				     val);  			regmap_update_bits(arizona->regmap,  					   ARIZONA_MICD_CLAMP_CONTROL, @@ -1096,20 +1290,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)  	arizona_extcon_set_mode(info, 0); -	info->input = devm_input_allocate_device(&pdev->dev); -	if (!info->input) { -		dev_err(arizona->dev, "Can't allocate input dev\n"); -		ret = -ENOMEM; -		goto err_register; -	} - -	for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) -		input_set_capability(info->input, EV_KEY, -				     arizona_lvl_to_key[i].report); -	info->input->name = "Headset"; -	info->input->phys = "arizona/extcon"; -	info->input->dev.parent = &pdev->dev; -  	pm_runtime_enable(&pdev->dev);  	pm_runtime_idle(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev); diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index b70e3815c45..b56bdaa27d4 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -32,6 +32,38 @@  #define	DEV_NAME			"max77693-muic"  #define	DELAY_MS_DEFAULT		20000		/* unit: millisecond */ +/* + * Default value of MAX77693 register to bring up MUIC device. + * If user don't set some initial value for MUIC device through platform data, + * extcon-max77693 driver use 'default_init_data' to bring up base operation + * of MAX77693 MUIC device. + */ +static struct max77693_reg_data default_init_data[] = { +	{ +		/* STATUS2 - [3]ChgDetRun */ +		.addr = MAX77693_MUIC_REG_STATUS2, +		.data = STATUS2_CHGDETRUN_MASK, +	}, { +		/* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */ +		.addr = MAX77693_MUIC_REG_INTMASK1, +		.data = INTMASK1_ADC1K_MASK +			| INTMASK1_ADC_MASK, +	}, { +		/* INTMASK2 - Unmask [0]ChgTypM */ +		.addr = MAX77693_MUIC_REG_INTMASK2, +		.data = INTMASK2_CHGTYP_MASK, +	}, { +		/* INTMASK3 - Mask all of interrupts */ +		.addr = MAX77693_MUIC_REG_INTMASK3, +		.data = 0x0, +	}, { +		/* CDETCTRL2 */ +		.addr = MAX77693_MUIC_REG_CDETCTRL2, +		.data = CDETCTRL2_VIDRMEN_MASK +			| CDETCTRL2_DXOVPEN_MASK, +	}, +}; +  enum max77693_muic_adc_debounce_time {  	ADC_DEBOUNCE_TIME_5MS = 0,  	ADC_DEBOUNCE_TIME_10MS, @@ -226,7 +258,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,  					  CONTROL3_ADCDBSET_MASK);  		if (ret) {  			dev_err(info->dev, "failed to set ADC debounce time\n"); -			return -EAGAIN; +			return ret;  		}  		break;  	default: @@ -262,7 +294,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,  			MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK);  	if (ret < 0) {  		dev_err(info->dev, "failed to update MUIC register\n"); -		return -EAGAIN; +		return ret;  	}  	if (attached) @@ -275,7 +307,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,  			CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);  	if (ret < 0) {  		dev_err(info->dev, "failed to update MUIC register\n"); -		return -EAGAIN; +		return ret;  	}  	dev_info(info->dev, @@ -1003,7 +1035,7 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info)  	if (ret) {  		dev_err(info->dev, "failed to read MUIC register\n");  		mutex_unlock(&info->mutex); -		return -EINVAL; +		return ret;  	}  	adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC, @@ -1045,8 +1077,9 @@ static int max77693_muic_probe(struct platform_device *pdev)  {  	struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);  	struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); -	struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;  	struct max77693_muic_info *info; +	struct max77693_reg_data *init_data; +	int num_init_data;  	int delay_jiffies;  	int ret;  	int i; @@ -1145,15 +1178,25 @@ static int max77693_muic_probe(struct platform_device *pdev)  		goto err_irq;  	} -	/* Initialize MUIC register by using platform data */ -	for (i = 0 ; i < muic_pdata->num_init_data ; i++) { -		enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR; + +	/* Initialize MUIC register by using platform data or default data */ +	if (pdata->muic_data) { +		init_data = pdata->muic_data->init_data; +		num_init_data = pdata->muic_data->num_init_data; +	} else { +		init_data = default_init_data; +		num_init_data = ARRAY_SIZE(default_init_data); +	} + +	for (i = 0 ; i < num_init_data ; i++) { +		enum max77693_irq_source irq_src +				= MAX77693_IRQ_GROUP_NR;  		max77693_write_reg(info->max77693->regmap_muic, -				muic_pdata->init_data[i].addr, -				muic_pdata->init_data[i].data); +				init_data[i].addr, +				init_data[i].data); -		switch (muic_pdata->init_data[i].addr) { +		switch (init_data[i].addr) {  		case MAX77693_MUIC_REG_INTMASK1:  			irq_src = MUIC_INT1;  			break; @@ -1167,22 +1210,40 @@ static int max77693_muic_probe(struct platform_device *pdev)  		if (irq_src < MAX77693_IRQ_GROUP_NR)  			info->max77693->irq_masks_cur[irq_src] -				= muic_pdata->init_data[i].data; +				= init_data[i].data;  	} -	/* -	 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB -	 * h/w path of COMP2/COMN1 on CONTROL1 register. -	 */ -	if (muic_pdata->path_uart) -		info->path_uart = muic_pdata->path_uart; -	else -		info->path_uart = CONTROL1_SW_UART; +	if (pdata->muic_data) { +		struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; -	if (muic_pdata->path_usb) -		info->path_usb = muic_pdata->path_usb; -	else +		/* +		 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB +		 * h/w path of COMP2/COMN1 on CONTROL1 register. +		 */ +		if (muic_pdata->path_uart) +			info->path_uart = muic_pdata->path_uart; +		else +			info->path_uart = CONTROL1_SW_UART; + +		if (muic_pdata->path_usb) +			info->path_usb = muic_pdata->path_usb; +		else +			info->path_usb = CONTROL1_SW_USB; + +		/* +		 * Default delay time for detecting cable state +		 * after certain time. +		 */ +		if (muic_pdata->detcable_delay_ms) +			delay_jiffies = +				msecs_to_jiffies(muic_pdata->detcable_delay_ms); +		else +			delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); +	} else {  		info->path_usb = CONTROL1_SW_USB; +		info->path_uart = CONTROL1_SW_UART; +		delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); +	}  	/* Set initial path for UART */  	 max77693_muic_set_path(info, info->path_uart, true); @@ -1208,10 +1269,6 @@ static int max77693_muic_probe(struct platform_device *pdev)  	 * driver should notify cable state to upper layer.  	 */  	INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq); -	if (muic_pdata->detcable_delay_ms) -		delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms); -	else -		delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);  	schedule_delayed_work(&info->wq_detcable, delay_jiffies);  	return ret; diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index e636d950ad6..67d6738d85a 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -196,7 +196,7 @@ static int max8997_muic_set_debounce_time(struct max8997_muic_info *info,  					  CONTROL3_ADCDBSET_MASK);  		if (ret) {  			dev_err(info->dev, "failed to set ADC debounce time\n"); -			return -EAGAIN; +			return ret;  		}  		break;  	default: @@ -232,7 +232,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,  			MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK);  	if (ret < 0) {  		dev_err(info->dev, "failed to update MUIC register\n"); -		return -EAGAIN; +		return ret;  	}  	if (attached) @@ -245,7 +245,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,  			CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);  	if (ret < 0) {  		dev_err(info->dev, "failed to update MUIC register\n"); -		return -EAGAIN; +		return ret;  	}  	dev_info(info->dev, @@ -397,7 +397,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,  	ret = max8997_muic_set_path(info, info->path_uart, attached);  	if (ret) {  		dev_err(info->dev, "failed to update muic register\n"); -		return -EINVAL; +		return ret;  	}  	extcon_set_cable_state(info->edev, "JIG", attached); @@ -608,7 +608,7 @@ static int max8997_muic_detect_dev(struct max8997_muic_info *info)  	if (ret) {  		dev_err(info->dev, "failed to read MUIC register\n");  		mutex_unlock(&info->mutex); -		return -EINVAL; +		return ret;  	}  	adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC, @@ -646,7 +646,7 @@ static void max8997_muic_detect_cable_wq(struct work_struct *work)  	ret = max8997_muic_detect_dev(info);  	if (ret < 0) -		pr_err("failed to detect cable type\n"); +		dev_err(info->dev, "failed to detect cable type\n");  }  static int max8997_muic_probe(struct platform_device *pdev) @@ -712,29 +712,45 @@ static int max8997_muic_probe(struct platform_device *pdev)  		goto err_irq;  	} -	/* Initialize registers according to platform data */  	if (pdata->muic_pdata) { -		struct max8997_muic_platform_data *mdata = info->muic_pdata; +		struct max8997_muic_platform_data *muic_pdata +			= pdata->muic_pdata; -		for (i = 0; i < mdata->num_init_data; i++) { -			max8997_write_reg(info->muic, mdata->init_data[i].addr, -					mdata->init_data[i].data); +		/* Initialize registers according to platform data */ +		for (i = 0; i < muic_pdata->num_init_data; i++) { +			max8997_write_reg(info->muic, +					muic_pdata->init_data[i].addr, +					muic_pdata->init_data[i].data);  		} -	} -	/* -	 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB -	 * h/w path of COMP2/COMN1 on CONTROL1 register. -	 */ -	if (pdata->muic_pdata->path_uart) -		info->path_uart = pdata->muic_pdata->path_uart; -	else -		info->path_uart = CONTROL1_SW_UART; +		/* +		 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB +		 * h/w path of COMP2/COMN1 on CONTROL1 register. +		 */ +		if (muic_pdata->path_uart) +			info->path_uart = muic_pdata->path_uart; +		else +			info->path_uart = CONTROL1_SW_UART; -	if (pdata->muic_pdata->path_usb) -		info->path_usb = pdata->muic_pdata->path_usb; -	else +		if (muic_pdata->path_usb) +			info->path_usb = muic_pdata->path_usb; +		else +			info->path_usb = CONTROL1_SW_USB; + +		/* +		 * Default delay time for detecting cable state +		 * after certain time. +		 */ +		if (muic_pdata->detcable_delay_ms) +			delay_jiffies = +				msecs_to_jiffies(muic_pdata->detcable_delay_ms); +		else +			delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); +	} else { +		info->path_uart = CONTROL1_SW_UART;  		info->path_usb = CONTROL1_SW_USB; +		delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); +	}  	/* Set initial path for UART */  	 max8997_muic_set_path(info, info->path_uart, true); @@ -751,10 +767,6 @@ static int max8997_muic_probe(struct platform_device *pdev)  	 * driver should notify cable state to upper layer.  	 */  	INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq); -	if (pdata->muic_pdata->detcable_delay_ms) -		delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms); -	else -		delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);  	schedule_delayed_work(&info->wq_detcable, delay_jiffies);  	return 0;  |