diff options
| -rw-r--r-- | drivers/extcon/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/extcon/extcon-sm5502.c | 132 | ||||
| -rw-r--r-- | drivers/extcon/extcon-sm5502.h | 78 | 
3 files changed, 204 insertions, 8 deletions
| diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index e3db936becfd..c69d40ae5619 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -154,7 +154,7 @@ config EXTCON_RT8973A  	  from abnormal high input voltage (up to 28V).  config EXTCON_SM5502 -	tristate "Silicon Mitus SM5502 EXTCON support" +	tristate "Silicon Mitus SM5502/SM5504 EXTCON support"  	depends on I2C  	select IRQ_DOMAIN  	select REGMAP_I2C diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index 60e2d12e81a2..93da2d8379b1 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -66,6 +66,7 @@ struct sm5502_type {  	struct reg_data *reg_data;  	unsigned int num_reg_data; +	unsigned int otg_dev_type1;  	int (*parse_irq)(struct sm5502_muic_info *info, int irq_type);  }; @@ -97,6 +98,33 @@ static struct reg_data sm5502_reg_data[] = {  	},  }; +/* Default value of SM5504 register to bring up MUIC device. */ +static struct reg_data sm5504_reg_data[] = { +	{ +		.reg = SM5502_REG_RESET, +		.val = SM5502_REG_RESET_MASK, +		.invert = true, +	}, { +		.reg = SM5502_REG_INTMASK1, +		.val = SM5504_REG_INTM1_ATTACH_MASK +			| SM5504_REG_INTM1_DETACH_MASK, +		.invert = false, +	}, { +		.reg = SM5502_REG_INTMASK2, +		.val = SM5504_REG_INTM2_RID_CHG_MASK +			| SM5504_REG_INTM2_UVLO_MASK +			| SM5504_REG_INTM2_POR_MASK, +		.invert = true, +	}, { +		.reg = SM5502_REG_CONTROL, +		.val = SM5502_REG_CONTROL_MANUAL_SW_MASK +			| SM5504_REG_CONTROL_CHGTYP_MASK +			| SM5504_REG_CONTROL_USBCHDEN_MASK +			| SM5504_REG_CONTROL_ADC_EN_MASK, +		.invert = true, +	}, +}; +  /* List of detectable cables */  static const unsigned int sm5502_extcon_cable[] = {  	EXTCON_USB, @@ -205,6 +233,55 @@ static const struct regmap_irq_chip sm5502_muic_irq_chip = {  	.num_irqs		= ARRAY_SIZE(sm5502_irqs),  }; +/* List of supported interrupt for SM5504 */ +static struct muic_irq sm5504_muic_irqs[] = { +	{ SM5504_IRQ_INT1_ATTACH,	"muic-attach" }, +	{ SM5504_IRQ_INT1_DETACH,	"muic-detach" }, +	{ SM5504_IRQ_INT1_CHG_DET,	"muic-chg-det" }, +	{ SM5504_IRQ_INT1_DCD_OUT,	"muic-dcd-out" }, +	{ SM5504_IRQ_INT1_OVP_EVENT,	"muic-ovp-event" }, +	{ SM5504_IRQ_INT1_CONNECT,	"muic-connect" }, +	{ SM5504_IRQ_INT1_ADC_CHG,	"muic-adc-chg" }, +	{ SM5504_IRQ_INT2_RID_CHG,	"muic-rid-chg" }, +	{ SM5504_IRQ_INT2_UVLO,		"muic-uvlo" }, +	{ SM5504_IRQ_INT2_POR,		"muic-por" }, +	{ SM5504_IRQ_INT2_OVP_FET,	"muic-ovp-fet" }, +	{ SM5504_IRQ_INT2_OCP_LATCH,	"muic-ocp-latch" }, +	{ SM5504_IRQ_INT2_OCP_EVENT,	"muic-ocp-event" }, +	{ SM5504_IRQ_INT2_OVP_OCP_EVENT, "muic-ovp-ocp-event" }, +}; + +/* Define interrupt list of SM5504 to register regmap_irq */ +static const struct regmap_irq sm5504_irqs[] = { +	/* INT1 interrupts */ +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_ATTACH_MASK, }, +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_DETACH_MASK, }, +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_CHG_DET_MASK, }, +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_DCD_OUT_MASK, }, +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_OVP_MASK, }, +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_CONNECT_MASK, }, +	{ .reg_offset = 0, .mask = SM5504_IRQ_INT1_ADC_CHG_MASK, }, + +	/* INT2 interrupts */ +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_RID_CHG_MASK,}, +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_UVLO_MASK, }, +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_POR_MASK, }, +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_FET_MASK, }, +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_LATCH_MASK, }, +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_EVENT_MASK, }, +	{ .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK, }, +}; + +static const struct regmap_irq_chip sm5504_muic_irq_chip = { +	.name			= "sm5504", +	.status_base		= SM5502_REG_INT1, +	.mask_base		= SM5502_REG_INTMASK1, +	.mask_invert		= false, +	.num_regs		= 2, +	.irqs			= sm5504_irqs, +	.num_irqs		= ARRAY_SIZE(sm5504_irqs), +}; +  /* Define regmap configuration of SM5502 for I2C communication  */  static bool sm5502_muic_volatile_reg(struct device *dev, unsigned int reg)  { @@ -308,11 +385,9 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)  			return ret;  		} -		switch (dev_type1) { -		case SM5502_REG_DEV_TYPE1_USB_OTG_MASK: +		if (dev_type1 == info->type->otg_dev_type1) {  			cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG; -			break; -		default: +		} else {  			dev_dbg(info->dev,  				"cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n",  				adc, dev_type1); @@ -365,6 +440,11 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)  			return ret;  		} +		if (dev_type1 == info->type->otg_dev_type1) { +			cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG; +			break; +		} +  		switch (dev_type1) {  		case SM5502_REG_DEV_TYPE1_USB_SDP_MASK:  			cable_type = SM5502_MUIC_ADC_OPEN_USB; @@ -372,9 +452,6 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)  		case SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK:  			cable_type = SM5502_MUIC_ADC_OPEN_TA;  			break; -		case SM5502_REG_DEV_TYPE1_USB_OTG_MASK: -			cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG; -			break;  		default:  			dev_dbg(info->dev,  				"cannot identify the cable type: adc(0x%x)\n", @@ -504,6 +581,34 @@ static int sm5502_parse_irq(struct sm5502_muic_info *info, int irq_type)  	return 0;  } +static int sm5504_parse_irq(struct sm5502_muic_info *info, int irq_type) +{ +	switch (irq_type) { +	case SM5504_IRQ_INT1_ATTACH: +		info->irq_attach = true; +		break; +	case SM5504_IRQ_INT1_DETACH: +		info->irq_detach = true; +		break; +	case SM5504_IRQ_INT1_CHG_DET: +	case SM5504_IRQ_INT1_DCD_OUT: +	case SM5504_IRQ_INT1_OVP_EVENT: +	case SM5504_IRQ_INT1_CONNECT: +	case SM5504_IRQ_INT1_ADC_CHG: +	case SM5504_IRQ_INT2_RID_CHG: +	case SM5504_IRQ_INT2_UVLO: +	case SM5504_IRQ_INT2_POR: +	case SM5504_IRQ_INT2_OVP_FET: +	case SM5504_IRQ_INT2_OCP_LATCH: +	case SM5504_IRQ_INT2_OCP_EVENT: +	case SM5504_IRQ_INT2_OVP_OCP_EVENT: +	default: +		break; +	} + +	return 0; +} +  static irqreturn_t sm5502_muic_irq_handler(int irq, void *data)  {  	struct sm5502_muic_info *info = data; @@ -676,11 +781,23 @@ static const struct sm5502_type sm5502_data = {  	.irq_chip = &sm5502_muic_irq_chip,  	.reg_data = sm5502_reg_data,  	.num_reg_data = ARRAY_SIZE(sm5502_reg_data), +	.otg_dev_type1 = SM5502_REG_DEV_TYPE1_USB_OTG_MASK,  	.parse_irq = sm5502_parse_irq,  }; +static const struct sm5502_type sm5504_data = { +	.muic_irqs = sm5504_muic_irqs, +	.num_muic_irqs = ARRAY_SIZE(sm5504_muic_irqs), +	.irq_chip = &sm5504_muic_irq_chip, +	.reg_data = sm5504_reg_data, +	.num_reg_data = ARRAY_SIZE(sm5504_reg_data), +	.otg_dev_type1 = SM5504_REG_DEV_TYPE1_USB_OTG_MASK, +	.parse_irq = sm5504_parse_irq, +}; +  static const struct of_device_id sm5502_dt_match[] = {  	{ .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data }, +	{ .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data },  	{ },  };  MODULE_DEVICE_TABLE(of, sm5502_dt_match); @@ -712,6 +829,7 @@ static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops,  static const struct i2c_device_id sm5502_i2c_id[] = {  	{ "sm5502", (kernel_ulong_t)&sm5502_data }, +	{ "sm5504", (kernel_ulong_t)&sm5504_data },  	{ }  };  MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id); diff --git a/drivers/extcon/extcon-sm5502.h b/drivers/extcon/extcon-sm5502.h index d187205df7b3..9c04315d48e2 100644 --- a/drivers/extcon/extcon-sm5502.h +++ b/drivers/extcon/extcon-sm5502.h @@ -89,6 +89,13 @@ enum sm5502_reg {  #define SM5502_REG_CONTROL_RAW_DATA_MASK	(0x1 << SM5502_REG_CONTROL_RAW_DATA_SHIFT)  #define SM5502_REG_CONTROL_SW_OPEN_MASK		(0x1 << SM5502_REG_CONTROL_SW_OPEN_SHIFT) +#define SM5504_REG_CONTROL_CHGTYP_SHIFT		5 +#define SM5504_REG_CONTROL_USBCHDEN_SHIFT	6 +#define SM5504_REG_CONTROL_ADC_EN_SHIFT		7 +#define SM5504_REG_CONTROL_CHGTYP_MASK		(0x1 << SM5504_REG_CONTROL_CHGTYP_SHIFT) +#define SM5504_REG_CONTROL_USBCHDEN_MASK	(0x1 << SM5504_REG_CONTROL_USBCHDEN_SHIFT) +#define SM5504_REG_CONTROL_ADC_EN_MASK		(0x1 << SM5504_REG_CONTROL_ADC_EN_SHIFT) +  #define SM5502_REG_INTM1_ATTACH_SHIFT		0  #define SM5502_REG_INTM1_DETACH_SHIFT		1  #define SM5502_REG_INTM1_KP_SHIFT		2 @@ -119,6 +126,36 @@ enum sm5502_reg {  #define SM5502_REG_INTM2_STUCK_KEY_RCV_MASK	(0x1 << SM5502_REG_INTM2_STUCK_KEY_RCV_SHIFT)  #define SM5502_REG_INTM2_MHL_MASK		(0x1 << SM5502_REG_INTM2_MHL_SHIFT) +#define SM5504_REG_INTM1_ATTACH_SHIFT		0 +#define SM5504_REG_INTM1_DETACH_SHIFT		1 +#define SM5504_REG_INTM1_CHG_DET_SHIFT		2 +#define SM5504_REG_INTM1_DCD_OUT_SHIFT		3 +#define SM5504_REG_INTM1_OVP_EVENT_SHIFT	4 +#define SM5504_REG_INTM1_CONNECT_SHIFT		5 +#define SM5504_REG_INTM1_ADC_CHG_SHIFT		6 +#define SM5504_REG_INTM1_ATTACH_MASK		(0x1 << SM5504_REG_INTM1_ATTACH_SHIFT) +#define SM5504_REG_INTM1_DETACH_MASK		(0x1 << SM5504_REG_INTM1_DETACH_SHIFT) +#define SM5504_REG_INTM1_CHG_DET_MASK		(0x1 << SM5504_REG_INTM1_CHG_DET_SHIFT) +#define SM5504_REG_INTM1_DCD_OUT_MASK		(0x1 << SM5504_REG_INTM1_DCD_OUT_SHIFT) +#define SM5504_REG_INTM1_OVP_EVENT_MASK		(0x1 << SM5504_REG_INTM1_OVP_EVENT_SHIFT) +#define SM5504_REG_INTM1_CONNECT_MASK		(0x1 << SM5504_REG_INTM1_CONNECT_SHIFT) +#define SM5504_REG_INTM1_ADC_CHG_MASK		(0x1 << SM5504_REG_INTM1_ADC_CHG_SHIFT) + +#define SM5504_REG_INTM2_RID_CHG_SHIFT		0 +#define SM5504_REG_INTM2_UVLO_SHIFT		1 +#define SM5504_REG_INTM2_POR_SHIFT		2 +#define SM5504_REG_INTM2_OVP_FET_SHIFT		4 +#define SM5504_REG_INTM2_OCP_LATCH_SHIFT	5 +#define SM5504_REG_INTM2_OCP_EVENT_SHIFT	6 +#define SM5504_REG_INTM2_OVP_OCP_EVENT_SHIFT	7 +#define SM5504_REG_INTM2_RID_CHG_MASK		(0x1 << SM5504_REG_INTM2_RID_CHG_SHIFT) +#define SM5504_REG_INTM2_UVLO_MASK		(0x1 << SM5504_REG_INTM2_UVLO_SHIFT) +#define SM5504_REG_INTM2_POR_MASK		(0x1 << SM5504_REG_INTM2_POR_SHIFT) +#define SM5504_REG_INTM2_OVP_FET_MASK		(0x1 << SM5504_REG_INTM2_OVP_FET_SHIFT) +#define SM5504_REG_INTM2_OCP_LATCH_MASK		(0x1 << SM5504_REG_INTM2_OCP_LATCH_SHIFT) +#define SM5504_REG_INTM2_OCP_EVENT_MASK		(0x1 << SM5504_REG_INTM2_OCP_EVENT_SHIFT) +#define SM5504_REG_INTM2_OVP_OCP_EVENT_MASK	(0x1 << SM5504_REG_INTM2_OVP_OCP_EVENT_SHIFT) +  #define SM5502_REG_ADC_SHIFT			0  #define SM5502_REG_ADC_MASK			(0x1f << SM5502_REG_ADC_SHIFT) @@ -195,6 +232,9 @@ enum sm5502_reg {  #define SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK		(0x1 << SM5502_REG_DEV_TYPE1_DEDICATED_CHG_SHIFT)  #define SM5502_REG_DEV_TYPE1_USB_OTG_MASK		(0x1 << SM5502_REG_DEV_TYPE1_USB_OTG_SHIFT) +#define SM5504_REG_DEV_TYPE1_USB_OTG_SHIFT		0 +#define SM5504_REG_DEV_TYPE1_USB_OTG_MASK		(0x1 << SM5504_REG_DEV_TYPE1_USB_OTG_SHIFT) +  #define SM5502_REG_DEV_TYPE2_JIG_USB_ON_SHIFT		0  #define SM5502_REG_DEV_TYPE2_JIG_USB_OFF_SHIFT		1  #define SM5502_REG_DEV_TYPE2_JIG_UART_ON_SHIFT		2 @@ -273,4 +313,42 @@ enum sm5502_irq {  #define SM5502_IRQ_INT2_STUCK_KEY_RCV_MASK	BIT(4)  #define SM5502_IRQ_INT2_MHL_MASK		BIT(5) +/* SM5504 Interrupts */ +enum sm5504_irq { +	/* INT1 */ +	SM5504_IRQ_INT1_ATTACH, +	SM5504_IRQ_INT1_DETACH, +	SM5504_IRQ_INT1_CHG_DET, +	SM5504_IRQ_INT1_DCD_OUT, +	SM5504_IRQ_INT1_OVP_EVENT, +	SM5504_IRQ_INT1_CONNECT, +	SM5504_IRQ_INT1_ADC_CHG, + +	/* INT2 */ +	SM5504_IRQ_INT2_RID_CHG, +	SM5504_IRQ_INT2_UVLO, +	SM5504_IRQ_INT2_POR, +	SM5504_IRQ_INT2_OVP_FET, +	SM5504_IRQ_INT2_OCP_LATCH, +	SM5504_IRQ_INT2_OCP_EVENT, +	SM5504_IRQ_INT2_OVP_OCP_EVENT, + +	SM5504_IRQ_NUM, +}; + +#define SM5504_IRQ_INT1_ATTACH_MASK		BIT(0) +#define SM5504_IRQ_INT1_DETACH_MASK		BIT(1) +#define SM5504_IRQ_INT1_CHG_DET_MASK		BIT(2) +#define SM5504_IRQ_INT1_DCD_OUT_MASK		BIT(3) +#define SM5504_IRQ_INT1_OVP_MASK		BIT(4) +#define SM5504_IRQ_INT1_CONNECT_MASK		BIT(5) +#define SM5504_IRQ_INT1_ADC_CHG_MASK		BIT(6) +#define SM5504_IRQ_INT2_RID_CHG_MASK		BIT(0) +#define SM5504_IRQ_INT2_UVLO_MASK		BIT(1) +#define SM5504_IRQ_INT2_POR_MASK		BIT(2) +#define SM5504_IRQ_INT2_OVP_FET_MASK		BIT(4) +#define SM5504_IRQ_INT2_OCP_LATCH_MASK		BIT(5) +#define SM5504_IRQ_INT2_OCP_EVENT_MASK		BIT(6) +#define SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK	BIT(7) +  #endif /*  __LINUX_EXTCON_SM5502_H */ | 
