extcon: sm5502: Change internal hardware switch according to cable type

This patch changes internal hardware DP_CON/DM_CON switch according to
cable type. The SM5502 MUIC device can set hardware switch as following:
- OPEN (not connected state) / USB / UART / AUDIO
Also, this patch set VBUSIN switch according to cable type.

Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
This commit is contained in:
Chanwoo Choi 2014-05-28 15:35:29 +09:00
Родитель e1954452f5
Коммит a75fed2ee6
2 изменённых файлов: 96 добавлений и 5 удалений

Просмотреть файл

@ -228,6 +228,61 @@ static const struct regmap_config sm5502_muic_regmap_config = {
.max_register = SM5502_REG_END,
};
/* Change DM_CON/DP_CON/VBUSIN switch according to cable type */
static int sm5502_muic_set_path(struct sm5502_muic_info *info,
unsigned int con_sw, unsigned int vbus_sw,
bool attached)
{
int ret;
if (!attached) {
con_sw = DM_DP_SWITCH_OPEN;
vbus_sw = VBUSIN_SWITCH_OPEN;
}
switch (con_sw) {
case DM_DP_SWITCH_OPEN:
case DM_DP_SWITCH_USB:
case DM_DP_SWITCH_AUDIO:
case DM_DP_SWITCH_UART:
ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1,
SM5502_REG_MANUAL_SW1_DP_MASK |
SM5502_REG_MANUAL_SW1_DM_MASK,
con_sw);
if (ret < 0) {
dev_err(info->dev,
"cannot update DM_CON/DP_CON switch\n");
return ret;
}
break;
default:
dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
con_sw);
return -EINVAL;
};
switch (vbus_sw) {
case VBUSIN_SWITCH_OPEN:
case VBUSIN_SWITCH_VBUSOUT:
case VBUSIN_SWITCH_MIC:
case VBUSIN_SWITCH_VBUSOUT_WITH_USB:
ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1,
SM5502_REG_MANUAL_SW1_VBUSIN_MASK,
vbus_sw);
if (ret < 0) {
dev_err(info->dev,
"cannot update VBUSIN switch\n");
return ret;
}
break;
default:
dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw);
return -EINVAL;
};
return 0;
}
/* Return cable type of attached or detached accessories */
static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
{
@ -329,7 +384,10 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND;
const char **cable_names = info->edev->supported_cable;
unsigned int cable_type = SM5502_MUIC_ADC_GROUND;
unsigned int con_sw = DM_DP_SWITCH_OPEN;
unsigned int vbus_sw = VBUSIN_SWITCH_OPEN;
unsigned int idx = 0;
int ret;
if (!cable_names)
return 0;
@ -343,15 +401,19 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
switch (cable_type) {
case SM5502_MUIC_ADC_OPEN_USB:
idx = EXTCON_CABLE_USB;
idx = EXTCON_CABLE_USB;
con_sw = DM_DP_SWITCH_USB;
vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB;
break;
case SM5502_MUIC_ADC_OPEN_TA:
idx = EXTCON_CABLE_TA;
idx = EXTCON_CABLE_TA;
con_sw = DM_DP_SWITCH_OPEN;
vbus_sw = VBUSIN_SWITCH_VBUSOUT;
break;
case SM5502_MUIC_ADC_OPEN_USB_OTG:
idx = EXTCON_CABLE_USB_HOST;
break;
case SM5502_MUIC_ADC_GROUND:
idx = EXTCON_CABLE_USB_HOST;
con_sw = DM_DP_SWITCH_USB;
vbus_sw = VBUSIN_SWITCH_OPEN;
break;
default:
dev_dbg(info->dev,
@ -359,6 +421,12 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
return 0;
};
/* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */
ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached);
if (ret < 0)
return ret;
/* Change the state of external accessory */
extcon_set_cable_state(info->edev, cable_names[idx], attached);
return 0;

Просмотреть файл

@ -223,6 +223,29 @@ enum sm5502_reg {
#define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT)
#define SM5502_REG_DEV_TYPE2_AV_CABLE_MASK (0x1 << SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT)
#define SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT 0
#define SM5502_REG_MANUAL_SW1_DP_SHIFT 2
#define SM5502_REG_MANUAL_SW1_DM_SHIFT 5
#define SM5502_REG_MANUAL_SW1_VBUSIN_MASK (0x3 << SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT)
#define SM5502_REG_MANUAL_SW1_DP_MASK (0x7 << SM5502_REG_MANUAL_SW1_DP_SHIFT)
#define SM5502_REG_MANUAL_SW1_DM_MASK (0x7 << SM5502_REG_MANUAL_SW1_DM_SHIFT)
#define VBUSIN_SWITCH_OPEN 0x0
#define VBUSIN_SWITCH_VBUSOUT 0x1
#define VBUSIN_SWITCH_MIC 0x2
#define VBUSIN_SWITCH_VBUSOUT_WITH_USB 0x3
#define DM_DP_CON_SWITCH_OPEN 0x0
#define DM_DP_CON_SWITCH_USB 0x1
#define DM_DP_CON_SWITCH_AUDIO 0x2
#define DM_DP_CON_SWITCH_UART 0x3
#define DM_DP_SWITCH_OPEN ((DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
#define DM_DP_SWITCH_USB ((DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
#define DM_DP_SWITCH_AUDIO ((DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
#define DM_DP_SWITCH_UART ((DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
/* SM5502 Interrupts */
enum sm5502_irq {
/* INT1 */