brintos

brintos / linux-shallow public Read only

0
0
Text · 21.6 KiB · 5476f48 Raw
804 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC4//5// Copyright (C) 2013,2014 Samsung Electronics6// Chanwoo Choi <cw00.choi@samsung.com>7// Krzysztof Kozlowski <krzk@kernel.org>8 9#include <linux/devm-helpers.h>10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/i2c.h>13#include <linux/interrupt.h>14#include <linux/platform_device.h>15#include <linux/mfd/max14577.h>16#include <linux/mfd/max14577-private.h>17#include <linux/extcon-provider.h>18 19#define	DELAY_MS_DEFAULT		17000		/* unit: millisecond */20 21enum max14577_muic_adc_debounce_time {22	ADC_DEBOUNCE_TIME_5MS = 0,23	ADC_DEBOUNCE_TIME_10MS,24	ADC_DEBOUNCE_TIME_25MS,25	ADC_DEBOUNCE_TIME_38_62MS,26};27 28enum max14577_muic_status {29	MAX14577_MUIC_STATUS1 = 0,30	MAX14577_MUIC_STATUS2 = 1,31	MAX14577_MUIC_STATUS_END,32};33 34/**35 * struct max14577_muic_irq36 * @irq: the index of irq list of MUIC device.37 * @name: the name of irq.38 * @virq: the virtual irq to use irq domain39 */40struct max14577_muic_irq {41	unsigned int irq;42	const char *name;43	unsigned int virq;44};45 46static struct max14577_muic_irq max14577_muic_irqs[] = {47	{ MAX14577_IRQ_INT1_ADC,	"muic-ADC" },48	{ MAX14577_IRQ_INT1_ADCLOW,	"muic-ADCLOW" },49	{ MAX14577_IRQ_INT1_ADCERR,	"muic-ADCError" },50	{ MAX14577_IRQ_INT2_CHGTYP,	"muic-CHGTYP" },51	{ MAX14577_IRQ_INT2_CHGDETRUN,	"muic-CHGDETRUN" },52	{ MAX14577_IRQ_INT2_DCDTMR,	"muic-DCDTMR" },53	{ MAX14577_IRQ_INT2_DBCHG,	"muic-DBCHG" },54	{ MAX14577_IRQ_INT2_VBVOLT,	"muic-VBVOLT" },55};56 57static struct max14577_muic_irq max77836_muic_irqs[] = {58	{ MAX14577_IRQ_INT1_ADC,	"muic-ADC" },59	{ MAX14577_IRQ_INT1_ADCLOW,	"muic-ADCLOW" },60	{ MAX14577_IRQ_INT1_ADCERR,	"muic-ADCError" },61	{ MAX77836_IRQ_INT1_ADC1K,	"muic-ADC1K" },62	{ MAX14577_IRQ_INT2_CHGTYP,	"muic-CHGTYP" },63	{ MAX14577_IRQ_INT2_CHGDETRUN,	"muic-CHGDETRUN" },64	{ MAX14577_IRQ_INT2_DCDTMR,	"muic-DCDTMR" },65	{ MAX14577_IRQ_INT2_DBCHG,	"muic-DBCHG" },66	{ MAX14577_IRQ_INT2_VBVOLT,	"muic-VBVOLT" },67	{ MAX77836_IRQ_INT2_VIDRM,	"muic-VIDRM" },68};69 70struct max14577_muic_info {71	struct device *dev;72	struct max14577 *max14577;73	struct extcon_dev *edev;74	int prev_cable_type;75	int prev_chg_type;76	u8 status[MAX14577_MUIC_STATUS_END];77 78	struct max14577_muic_irq *muic_irqs;79	unsigned int muic_irqs_num;80	bool irq_adc;81	bool irq_chg;82	struct work_struct irq_work;83	struct mutex mutex;84 85	/*86	 * Use delayed workqueue to detect cable state and then87	 * notify cable state to notifiee/platform through uevent.88	 * After completing the booting of platform, the extcon provider89	 * driver should notify cable state to upper layer.90	 */91	struct delayed_work wq_detcable;92 93	/*94	 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB95	 * h/w path of COMP2/COMN1 on CONTROL1 register.96	 */97	int path_usb;98	int path_uart;99};100 101enum max14577_muic_cable_group {102	MAX14577_CABLE_GROUP_ADC = 0,103	MAX14577_CABLE_GROUP_CHG,104};105 106/* Define supported accessory type */107enum max14577_muic_acc_type {108	MAX14577_MUIC_ADC_GROUND = 0x0,109	MAX14577_MUIC_ADC_SEND_END_BUTTON,110	MAX14577_MUIC_ADC_REMOTE_S1_BUTTON,111	MAX14577_MUIC_ADC_REMOTE_S2_BUTTON,112	MAX14577_MUIC_ADC_REMOTE_S3_BUTTON,113	MAX14577_MUIC_ADC_REMOTE_S4_BUTTON,114	MAX14577_MUIC_ADC_REMOTE_S5_BUTTON,115	MAX14577_MUIC_ADC_REMOTE_S6_BUTTON,116	MAX14577_MUIC_ADC_REMOTE_S7_BUTTON,117	MAX14577_MUIC_ADC_REMOTE_S8_BUTTON,118	MAX14577_MUIC_ADC_REMOTE_S9_BUTTON,119	MAX14577_MUIC_ADC_REMOTE_S10_BUTTON,120	MAX14577_MUIC_ADC_REMOTE_S11_BUTTON,121	MAX14577_MUIC_ADC_REMOTE_S12_BUTTON,122	MAX14577_MUIC_ADC_RESERVED_ACC_1,123	MAX14577_MUIC_ADC_RESERVED_ACC_2,124	MAX14577_MUIC_ADC_RESERVED_ACC_3,125	MAX14577_MUIC_ADC_RESERVED_ACC_4,126	MAX14577_MUIC_ADC_RESERVED_ACC_5,127	MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE2,128	MAX14577_MUIC_ADC_PHONE_POWERED_DEV,129	MAX14577_MUIC_ADC_TTY_CONVERTER,130	MAX14577_MUIC_ADC_UART_CABLE,131	MAX14577_MUIC_ADC_CEA936A_TYPE1_CHG,132	MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF,133	MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON,134	MAX14577_MUIC_ADC_AV_CABLE_NOLOAD,135	MAX14577_MUIC_ADC_CEA936A_TYPE2_CHG,136	MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF,137	MAX14577_MUIC_ADC_FACTORY_MODE_UART_ON,138	MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE1, /* with Remote and Simple Ctrl */139	MAX14577_MUIC_ADC_OPEN,140};141 142static const unsigned int max14577_extcon_cable[] = {143	EXTCON_USB,144	EXTCON_CHG_USB_SDP,145	EXTCON_CHG_USB_DCP,146	EXTCON_CHG_USB_FAST,147	EXTCON_CHG_USB_SLOW,148	EXTCON_CHG_USB_CDP,149	EXTCON_JIG,150	EXTCON_NONE,151};152 153/*154 * max14577_muic_set_debounce_time - Set the debounce time of ADC155 * @info: the instance including private data of max14577 MUIC156 * @time: the debounce time of ADC157 */158static int max14577_muic_set_debounce_time(struct max14577_muic_info *info,159		enum max14577_muic_adc_debounce_time time)160{161	u8 ret;162 163	switch (time) {164	case ADC_DEBOUNCE_TIME_5MS:165	case ADC_DEBOUNCE_TIME_10MS:166	case ADC_DEBOUNCE_TIME_25MS:167	case ADC_DEBOUNCE_TIME_38_62MS:168		ret = max14577_update_reg(info->max14577->regmap,169					  MAX14577_MUIC_REG_CONTROL3,170					  CTRL3_ADCDBSET_MASK,171					  time << CTRL3_ADCDBSET_SHIFT);172		if (ret) {173			dev_err(info->dev, "failed to set ADC debounce time\n");174			return ret;175		}176		break;177	default:178		dev_err(info->dev, "invalid ADC debounce time\n");179		return -EINVAL;180	}181 182	return 0;183};184 185/*186 * max14577_muic_set_path - Set hardware line according to attached cable187 * @info: the instance including private data of max14577 MUIC188 * @value: the path according to attached cable189 * @attached: the state of cable (true:attached, false:detached)190 *191 * The max14577 MUIC device share outside H/W line among a varity of cables192 * so, this function set internal path of H/W line according to the type of193 * attached cable.194 */195static int max14577_muic_set_path(struct max14577_muic_info *info,196		u8 val, bool attached)197{198	u8 ctrl1, ctrl2 = 0;199	int ret;200 201	/* Set open state to path before changing hw path */202	ret = max14577_update_reg(info->max14577->regmap,203				MAX14577_MUIC_REG_CONTROL1,204				CLEAR_IDBEN_MICEN_MASK, CTRL1_SW_OPEN);205	if (ret < 0) {206		dev_err(info->dev, "failed to update MUIC register\n");207		return ret;208	}209 210	if (attached)211		ctrl1 = val;212	else213		ctrl1 = CTRL1_SW_OPEN;214 215	ret = max14577_update_reg(info->max14577->regmap,216				MAX14577_MUIC_REG_CONTROL1,217				CLEAR_IDBEN_MICEN_MASK, ctrl1);218	if (ret < 0) {219		dev_err(info->dev, "failed to update MUIC register\n");220		return ret;221	}222 223	if (attached)224		ctrl2 |= CTRL2_CPEN_MASK;	/* LowPwr=0, CPEn=1 */225	else226		ctrl2 |= CTRL2_LOWPWR_MASK;	/* LowPwr=1, CPEn=0 */227 228	ret = max14577_update_reg(info->max14577->regmap,229			MAX14577_REG_CONTROL2,230			CTRL2_LOWPWR_MASK | CTRL2_CPEN_MASK, ctrl2);231	if (ret < 0) {232		dev_err(info->dev, "failed to update MUIC register\n");233		return ret;234	}235 236	dev_dbg(info->dev,237		"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",238		ctrl1, ctrl2, attached ? "attached" : "detached");239 240	return 0;241}242 243/*244 * max14577_muic_get_cable_type - Return cable type and check cable state245 * @info: the instance including private data of max14577 MUIC246 * @group: the path according to attached cable247 * @attached: store cable state and return248 *249 * This function check the cable state either attached or detached,250 * and then divide precise type of cable according to cable group.251 *	- max14577_CABLE_GROUP_ADC252 *	- max14577_CABLE_GROUP_CHG253 */254static int max14577_muic_get_cable_type(struct max14577_muic_info *info,255		enum max14577_muic_cable_group group, bool *attached)256{257	int cable_type = 0;258	int adc;259	int chg_type;260 261	switch (group) {262	case MAX14577_CABLE_GROUP_ADC:263		/*264		 * Read ADC value to check cable type and decide cable state265		 * according to cable type266		 */267		adc = info->status[MAX14577_MUIC_STATUS1] & STATUS1_ADC_MASK;268		adc >>= STATUS1_ADC_SHIFT;269 270		/*271		 * Check current cable state/cable type and store cable type272		 * (info->prev_cable_type) for handling cable when cable is273		 * detached.274		 */275		if (adc == MAX14577_MUIC_ADC_OPEN) {276			*attached = false;277 278			cable_type = info->prev_cable_type;279			info->prev_cable_type = MAX14577_MUIC_ADC_OPEN;280		} else {281			*attached = true;282 283			cable_type = info->prev_cable_type = adc;284		}285		break;286	case MAX14577_CABLE_GROUP_CHG:287		/*288		 * Read charger type to check cable type and decide cable state289		 * according to type of charger cable.290		 */291		chg_type = info->status[MAX14577_MUIC_STATUS2] &292			STATUS2_CHGTYP_MASK;293		chg_type >>= STATUS2_CHGTYP_SHIFT;294 295		if (chg_type == MAX14577_CHARGER_TYPE_NONE) {296			*attached = false;297 298			cable_type = info->prev_chg_type;299			info->prev_chg_type = MAX14577_CHARGER_TYPE_NONE;300		} else {301			*attached = true;302 303			/*304			 * Check current cable state/cable type and store cable305			 * type(info->prev_chg_type) for handling cable when306			 * charger cable is detached.307			 */308			cable_type = info->prev_chg_type = chg_type;309		}310 311		break;312	default:313		dev_err(info->dev, "Unknown cable group (%d)\n", group);314		cable_type = -EINVAL;315		break;316	}317 318	return cable_type;319}320 321static int max14577_muic_jig_handler(struct max14577_muic_info *info,322		int cable_type, bool attached)323{324	int ret = 0;325	u8 path = CTRL1_SW_OPEN;326 327	dev_dbg(info->dev,328		"external connector is %s (adc:0x%02x)\n",329		attached ? "attached" : "detached", cable_type);330 331	switch (cable_type) {332	case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF:	/* ADC_JIG_USB_OFF */333	case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON:	/* ADC_JIG_USB_ON */334		/* PATH:AP_USB */335		path = CTRL1_SW_USB;336		break;337	case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF:	/* ADC_JIG_UART_OFF */338		/* PATH:AP_UART */339		path = CTRL1_SW_UART;340		break;341	default:342		dev_err(info->dev, "failed to detect %s jig cable\n",343			attached ? "attached" : "detached");344		return -EINVAL;345	}346 347	ret = max14577_muic_set_path(info, path, attached);348	if (ret < 0)349		return ret;350 351	extcon_set_state_sync(info->edev, EXTCON_JIG, attached);352 353	return 0;354}355 356static int max14577_muic_adc_handler(struct max14577_muic_info *info)357{358	int cable_type;359	bool attached;360	int ret = 0;361 362	/* Check accessory state which is either detached or attached */363	cable_type = max14577_muic_get_cable_type(info,364				MAX14577_CABLE_GROUP_ADC, &attached);365 366	dev_dbg(info->dev,367		"external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",368		attached ? "attached" : "detached", cable_type,369		info->prev_cable_type);370 371	switch (cable_type) {372	case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF:373	case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON:374	case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF:375		/* JIG */376		ret = max14577_muic_jig_handler(info, cable_type, attached);377		if (ret < 0)378			return ret;379		break;380	case MAX14577_MUIC_ADC_GROUND:381	case MAX14577_MUIC_ADC_SEND_END_BUTTON:382	case MAX14577_MUIC_ADC_REMOTE_S1_BUTTON:383	case MAX14577_MUIC_ADC_REMOTE_S2_BUTTON:384	case MAX14577_MUIC_ADC_REMOTE_S3_BUTTON:385	case MAX14577_MUIC_ADC_REMOTE_S4_BUTTON:386	case MAX14577_MUIC_ADC_REMOTE_S5_BUTTON:387	case MAX14577_MUIC_ADC_REMOTE_S6_BUTTON:388	case MAX14577_MUIC_ADC_REMOTE_S7_BUTTON:389	case MAX14577_MUIC_ADC_REMOTE_S8_BUTTON:390	case MAX14577_MUIC_ADC_REMOTE_S9_BUTTON:391	case MAX14577_MUIC_ADC_REMOTE_S10_BUTTON:392	case MAX14577_MUIC_ADC_REMOTE_S11_BUTTON:393	case MAX14577_MUIC_ADC_REMOTE_S12_BUTTON:394	case MAX14577_MUIC_ADC_RESERVED_ACC_1:395	case MAX14577_MUIC_ADC_RESERVED_ACC_2:396	case MAX14577_MUIC_ADC_RESERVED_ACC_3:397	case MAX14577_MUIC_ADC_RESERVED_ACC_4:398	case MAX14577_MUIC_ADC_RESERVED_ACC_5:399	case MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE2:400	case MAX14577_MUIC_ADC_PHONE_POWERED_DEV:401	case MAX14577_MUIC_ADC_TTY_CONVERTER:402	case MAX14577_MUIC_ADC_UART_CABLE:403	case MAX14577_MUIC_ADC_CEA936A_TYPE1_CHG:404	case MAX14577_MUIC_ADC_AV_CABLE_NOLOAD:405	case MAX14577_MUIC_ADC_CEA936A_TYPE2_CHG:406	case MAX14577_MUIC_ADC_FACTORY_MODE_UART_ON:407	case MAX14577_MUIC_ADC_AUDIO_DEVICE_TYPE1:408		/*409		 * This accessory isn't used in general case if it is specially410		 * needed to detect additional accessory, should implement411		 * proper operation when this accessory is attached/detached.412		 */413		dev_info(info->dev,414			"accessory is %s but it isn't used (adc:0x%x)\n",415			attached ? "attached" : "detached", cable_type);416		return -EAGAIN;417	default:418		dev_err(info->dev,419			"failed to detect %s accessory (adc:0x%x)\n",420			attached ? "attached" : "detached", cable_type);421		return -EINVAL;422	}423 424	return 0;425}426 427static int max14577_muic_chg_handler(struct max14577_muic_info *info)428{429	int chg_type;430	bool attached;431	int ret = 0;432 433	chg_type = max14577_muic_get_cable_type(info,434				MAX14577_CABLE_GROUP_CHG, &attached);435 436	dev_dbg(info->dev,437		"external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",438			attached ? "attached" : "detached",439			chg_type, info->prev_chg_type);440 441	switch (chg_type) {442	case MAX14577_CHARGER_TYPE_USB:443		/* PATH:AP_USB */444		ret = max14577_muic_set_path(info, info->path_usb, attached);445		if (ret < 0)446			return ret;447 448		extcon_set_state_sync(info->edev, EXTCON_USB, attached);449		extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,450					attached);451		break;452	case MAX14577_CHARGER_TYPE_DEDICATED_CHG:453		extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,454					attached);455		break;456	case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:457		extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP,458					attached);459		break;460	case MAX14577_CHARGER_TYPE_SPECIAL_500MA:461		extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW,462					attached);463		break;464	case MAX14577_CHARGER_TYPE_SPECIAL_1A:465		extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST,466					attached);467		break;468	case MAX14577_CHARGER_TYPE_NONE:469	case MAX14577_CHARGER_TYPE_DEAD_BATTERY:470		break;471	default:472		dev_err(info->dev,473			"failed to detect %s accessory (chg_type:0x%x)\n",474			attached ? "attached" : "detached", chg_type);475		return -EINVAL;476	}477 478	return 0;479}480 481static void max14577_muic_irq_work(struct work_struct *work)482{483	struct max14577_muic_info *info = container_of(work,484			struct max14577_muic_info, irq_work);485	int ret = 0;486 487	if (!info->edev)488		return;489 490	mutex_lock(&info->mutex);491 492	ret = max14577_bulk_read(info->max14577->regmap,493			MAX14577_MUIC_REG_STATUS1, info->status, 2);494	if (ret) {495		dev_err(info->dev, "failed to read MUIC register\n");496		mutex_unlock(&info->mutex);497		return;498	}499 500	if (info->irq_adc) {501		ret = max14577_muic_adc_handler(info);502		info->irq_adc = false;503	}504	if (info->irq_chg) {505		ret = max14577_muic_chg_handler(info);506		info->irq_chg = false;507	}508 509	if (ret < 0)510		dev_err(info->dev, "failed to handle MUIC interrupt\n");511 512	mutex_unlock(&info->mutex);513}514 515/*516 * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.517 * Returns 0 if irq_type does not match registered IRQ for this device type.518 */519static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)520{521	switch (irq_type) {522	case MAX14577_IRQ_INT1_ADC:523	case MAX14577_IRQ_INT1_ADCLOW:524	case MAX14577_IRQ_INT1_ADCERR:525		/*526		 * Handle all of accessory except for527		 * type of charger accessory.528		 */529		info->irq_adc = true;530		return 1;531	case MAX14577_IRQ_INT2_CHGTYP:532	case MAX14577_IRQ_INT2_CHGDETRUN:533	case MAX14577_IRQ_INT2_DCDTMR:534	case MAX14577_IRQ_INT2_DBCHG:535	case MAX14577_IRQ_INT2_VBVOLT:536		/* Handle charger accessory */537		info->irq_chg = true;538		return 1;539	default:540		return 0;541	}542}543 544/*545 * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.546 * Returns 0 if irq_type does not match registered IRQ for this device type.547 */548static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)549{550	/* First check common max14577 interrupts */551	if (max14577_parse_irq(info, irq_type))552		return 1;553 554	switch (irq_type) {555	case MAX77836_IRQ_INT1_ADC1K:556		info->irq_adc = true;557		return 1;558	case MAX77836_IRQ_INT2_VIDRM:559		/* Handle charger accessory */560		info->irq_chg = true;561		return 1;562	default:563		return 0;564	}565}566 567static irqreturn_t max14577_muic_irq_handler(int irq, void *data)568{569	struct max14577_muic_info *info = data;570	int i, irq_type = -1;571	bool irq_parsed;572 573	/*574	 * We may be called multiple times for different nested IRQ-s.575	 * Including changes in INT1_ADC and INT2_CGHTYP at once.576	 * However we only need to know whether it was ADC, charger577	 * or both interrupts so decode IRQ and turn on proper flags.578	 */579	for (i = 0; i < info->muic_irqs_num; i++)580		if (irq == info->muic_irqs[i].virq)581			irq_type = info->muic_irqs[i].irq;582 583	switch (info->max14577->dev_type) {584	case MAXIM_DEVICE_TYPE_MAX77836:585		irq_parsed = max77836_parse_irq(info, irq_type);586		break;587	case MAXIM_DEVICE_TYPE_MAX14577:588	default:589		irq_parsed = max14577_parse_irq(info, irq_type);590		break;591	}592 593	if (!irq_parsed) {594		dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",595				irq_type);596		return IRQ_HANDLED;597	}598	schedule_work(&info->irq_work);599 600	return IRQ_HANDLED;601}602 603static int max14577_muic_detect_accessory(struct max14577_muic_info *info)604{605	int ret = 0;606	int adc;607	int chg_type;608	bool attached;609 610	mutex_lock(&info->mutex);611 612	/* Read STATUSx register to detect accessory */613	ret = max14577_bulk_read(info->max14577->regmap,614			MAX14577_MUIC_REG_STATUS1, info->status, 2);615	if (ret) {616		dev_err(info->dev, "failed to read MUIC register\n");617		mutex_unlock(&info->mutex);618		return ret;619	}620 621	adc = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_ADC,622					&attached);623	if (attached && adc != MAX14577_MUIC_ADC_OPEN) {624		ret = max14577_muic_adc_handler(info);625		if (ret < 0) {626			dev_err(info->dev, "Cannot detect accessory\n");627			mutex_unlock(&info->mutex);628			return ret;629		}630	}631 632	chg_type = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_CHG,633					&attached);634	if (attached && chg_type != MAX14577_CHARGER_TYPE_NONE) {635		ret = max14577_muic_chg_handler(info);636		if (ret < 0) {637			dev_err(info->dev, "Cannot detect charger accessory\n");638			mutex_unlock(&info->mutex);639			return ret;640		}641	}642 643	mutex_unlock(&info->mutex);644 645	return 0;646}647 648static void max14577_muic_detect_cable_wq(struct work_struct *work)649{650	struct max14577_muic_info *info = container_of(to_delayed_work(work),651				struct max14577_muic_info, wq_detcable);652 653	max14577_muic_detect_accessory(info);654}655 656static int max14577_muic_probe(struct platform_device *pdev)657{658	struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);659	struct max14577_muic_info *info;660	int delay_jiffies;661	int cable_type;662	bool attached;663	int ret;664	int i;665	u8 id;666 667	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);668	if (!info)669		return -ENOMEM;670 671	info->dev = &pdev->dev;672	info->max14577 = max14577;673 674	platform_set_drvdata(pdev, info);675	mutex_init(&info->mutex);676 677	ret = devm_work_autocancel(&pdev->dev, &info->irq_work,678				   max14577_muic_irq_work);679	if (ret)680		return ret;681 682	switch (max14577->dev_type) {683	case MAXIM_DEVICE_TYPE_MAX77836:684		info->muic_irqs = max77836_muic_irqs;685		info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);686		break;687	case MAXIM_DEVICE_TYPE_MAX14577:688	default:689		info->muic_irqs = max14577_muic_irqs;690		info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs);691	}692 693	/* Support irq domain for max14577 MUIC device */694	for (i = 0; i < info->muic_irqs_num; i++) {695		struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];696		int virq = 0;697 698		virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);699		if (virq <= 0)700			return -EINVAL;701		muic_irq->virq = virq;702 703		ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,704				max14577_muic_irq_handler,705				IRQF_NO_SUSPEND,706				muic_irq->name, info);707		if (ret) {708			dev_err(&pdev->dev,709				"failed: irq request (IRQ: %d, error :%d)\n",710				muic_irq->irq, ret);711			return ret;712		}713	}714 715	/* Initialize extcon device */716	info->edev = devm_extcon_dev_allocate(&pdev->dev,717					      max14577_extcon_cable);718	if (IS_ERR(info->edev)) {719		dev_err(&pdev->dev, "failed to allocate memory for extcon\n");720		return PTR_ERR(info->edev);721	}722 723	ret = devm_extcon_dev_register(&pdev->dev, info->edev);724	if (ret) {725		dev_err(&pdev->dev, "failed to register extcon device\n");726		return ret;727	}728 729	/* Default h/w line path */730	info->path_usb = CTRL1_SW_USB;731	info->path_uart = CTRL1_SW_UART;732	delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);733 734	/* Set initial path for UART when JIG is connected to get serial logs */735	ret = max14577_bulk_read(info->max14577->regmap,736			MAX14577_MUIC_REG_STATUS1, info->status, 2);737	if (ret) {738		dev_err(info->dev, "Cannot read STATUS registers\n");739		return ret;740	}741	cable_type = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_ADC,742					 &attached);743	if (attached && cable_type == MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF)744		max14577_muic_set_path(info, info->path_uart, true);745 746	/* Check revision number of MUIC device*/747	ret = max14577_read_reg(info->max14577->regmap,748			MAX14577_REG_DEVICEID, &id);749	if (ret < 0) {750		dev_err(&pdev->dev, "failed to read revision number\n");751		return ret;752	}753	dev_info(info->dev, "device ID : 0x%x\n", id);754 755	/* Set ADC debounce time */756	max14577_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);757 758	/*759	 * Detect accessory after completing the initialization of platform760	 *761	 * - Use delayed workqueue to detect cable state and then762	 * notify cable state to notifiee/platform through uevent.763	 * After completing the booting of platform, the extcon provider764	 * driver should notify cable state to upper layer.765	 */766	INIT_DELAYED_WORK(&info->wq_detcable, max14577_muic_detect_cable_wq);767	queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,768			delay_jiffies);769 770	return ret;771}772 773static const struct platform_device_id max14577_muic_id[] = {774	{ "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },775	{ "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },776	{ }777};778MODULE_DEVICE_TABLE(platform, max14577_muic_id);779 780static const struct of_device_id of_max14577_muic_dt_match[] = {781	{ .compatible = "maxim,max14577-muic",782	  .data = (void *)MAXIM_DEVICE_TYPE_MAX14577, },783	{ .compatible = "maxim,max77836-muic",784	  .data = (void *)MAXIM_DEVICE_TYPE_MAX77836, },785	{ },786};787MODULE_DEVICE_TABLE(of, of_max14577_muic_dt_match);788 789static struct platform_driver max14577_muic_driver = {790	.driver		= {791		.name	= "max14577-muic",792		.of_match_table = of_max14577_muic_dt_match,793	},794	.probe		= max14577_muic_probe,795	.id_table	= max14577_muic_id,796};797 798module_platform_driver(max14577_muic_driver);799 800MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");801MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <krzk@kernel.org>");802MODULE_LICENSE("GPL");803MODULE_ALIAS("platform:extcon-max14577");804