diff options
author | Chanwoo Choi <cw00.choi@samsung.com> | 2014-05-28 02:35:29 -0400 |
---|---|---|
committer | Chanwoo Choi <cw00.choi@samsung.com> | 2014-07-22 21:22:35 -0400 |
commit | a75fed2ee6c187ab32b1cb01882c1032c4c9e4a8 (patch) | |
tree | 706b108a592f8d109329e44a22fe54cfed1ce9c8 | |
parent | e1954452f500cb21c09ea401f6f431ab55b35ba3 (diff) |
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>
-rw-r--r-- | drivers/extcon/extcon-sm5502.c | 78 | ||||
-rw-r--r-- | include/linux/extcon/sm5502.h | 23 |
2 files changed, 96 insertions, 5 deletions
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index a32d40f97ff0..560d7dccec7b 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c | |||
@@ -228,6 +228,61 @@ static const struct regmap_config sm5502_muic_regmap_config = { | |||
228 | .max_register = SM5502_REG_END, | 228 | .max_register = SM5502_REG_END, |
229 | }; | 229 | }; |
230 | 230 | ||
231 | /* Change DM_CON/DP_CON/VBUSIN switch according to cable type */ | ||
232 | static int sm5502_muic_set_path(struct sm5502_muic_info *info, | ||
233 | unsigned int con_sw, unsigned int vbus_sw, | ||
234 | bool attached) | ||
235 | { | ||
236 | int ret; | ||
237 | |||
238 | if (!attached) { | ||
239 | con_sw = DM_DP_SWITCH_OPEN; | ||
240 | vbus_sw = VBUSIN_SWITCH_OPEN; | ||
241 | } | ||
242 | |||
243 | switch (con_sw) { | ||
244 | case DM_DP_SWITCH_OPEN: | ||
245 | case DM_DP_SWITCH_USB: | ||
246 | case DM_DP_SWITCH_AUDIO: | ||
247 | case DM_DP_SWITCH_UART: | ||
248 | ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1, | ||
249 | SM5502_REG_MANUAL_SW1_DP_MASK | | ||
250 | SM5502_REG_MANUAL_SW1_DM_MASK, | ||
251 | con_sw); | ||
252 | if (ret < 0) { | ||
253 | dev_err(info->dev, | ||
254 | "cannot update DM_CON/DP_CON switch\n"); | ||
255 | return ret; | ||
256 | } | ||
257 | break; | ||
258 | default: | ||
259 | dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n", | ||
260 | con_sw); | ||
261 | return -EINVAL; | ||
262 | }; | ||
263 | |||
264 | switch (vbus_sw) { | ||
265 | case VBUSIN_SWITCH_OPEN: | ||
266 | case VBUSIN_SWITCH_VBUSOUT: | ||
267 | case VBUSIN_SWITCH_MIC: | ||
268 | case VBUSIN_SWITCH_VBUSOUT_WITH_USB: | ||
269 | ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1, | ||
270 | SM5502_REG_MANUAL_SW1_VBUSIN_MASK, | ||
271 | vbus_sw); | ||
272 | if (ret < 0) { | ||
273 | dev_err(info->dev, | ||
274 | "cannot update VBUSIN switch\n"); | ||
275 | return ret; | ||
276 | } | ||
277 | break; | ||
278 | default: | ||
279 | dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw); | ||
280 | return -EINVAL; | ||
281 | }; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
231 | /* Return cable type of attached or detached accessories */ | 286 | /* Return cable type of attached or detached accessories */ |
232 | static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) | 287 | static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) |
233 | { | 288 | { |
@@ -329,7 +384,10 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, | |||
329 | static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; | 384 | static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; |
330 | const char **cable_names = info->edev->supported_cable; | 385 | const char **cable_names = info->edev->supported_cable; |
331 | unsigned int cable_type = SM5502_MUIC_ADC_GROUND; | 386 | unsigned int cable_type = SM5502_MUIC_ADC_GROUND; |
387 | unsigned int con_sw = DM_DP_SWITCH_OPEN; | ||
388 | unsigned int vbus_sw = VBUSIN_SWITCH_OPEN; | ||
332 | unsigned int idx = 0; | 389 | unsigned int idx = 0; |
390 | int ret; | ||
333 | 391 | ||
334 | if (!cable_names) | 392 | if (!cable_names) |
335 | return 0; | 393 | return 0; |
@@ -343,15 +401,19 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, | |||
343 | 401 | ||
344 | switch (cable_type) { | 402 | switch (cable_type) { |
345 | case SM5502_MUIC_ADC_OPEN_USB: | 403 | case SM5502_MUIC_ADC_OPEN_USB: |
346 | idx = EXTCON_CABLE_USB; | 404 | idx = EXTCON_CABLE_USB; |
405 | con_sw = DM_DP_SWITCH_USB; | ||
406 | vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB; | ||
347 | break; | 407 | break; |
348 | case SM5502_MUIC_ADC_OPEN_TA: | 408 | case SM5502_MUIC_ADC_OPEN_TA: |
349 | idx = EXTCON_CABLE_TA; | 409 | idx = EXTCON_CABLE_TA; |
410 | con_sw = DM_DP_SWITCH_OPEN; | ||
411 | vbus_sw = VBUSIN_SWITCH_VBUSOUT; | ||
350 | break; | 412 | break; |
351 | case SM5502_MUIC_ADC_OPEN_USB_OTG: | 413 | case SM5502_MUIC_ADC_OPEN_USB_OTG: |
352 | idx = EXTCON_CABLE_USB_HOST; | 414 | idx = EXTCON_CABLE_USB_HOST; |
353 | break; | 415 | con_sw = DM_DP_SWITCH_USB; |
354 | case SM5502_MUIC_ADC_GROUND: | 416 | vbus_sw = VBUSIN_SWITCH_OPEN; |
355 | break; | 417 | break; |
356 | default: | 418 | default: |
357 | dev_dbg(info->dev, | 419 | dev_dbg(info->dev, |
@@ -359,6 +421,12 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, | |||
359 | return 0; | 421 | return 0; |
360 | }; | 422 | }; |
361 | 423 | ||
424 | /* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */ | ||
425 | ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached); | ||
426 | if (ret < 0) | ||
427 | return ret; | ||
428 | |||
429 | /* Change the state of external accessory */ | ||
362 | extcon_set_cable_state(info->edev, cable_names[idx], attached); | 430 | extcon_set_cable_state(info->edev, cable_names[idx], attached); |
363 | 431 | ||
364 | return 0; | 432 | return 0; |
diff --git a/include/linux/extcon/sm5502.h b/include/linux/extcon/sm5502.h index 17bd6550c485..030526bf8d79 100644 --- a/include/linux/extcon/sm5502.h +++ b/include/linux/extcon/sm5502.h | |||
@@ -223,6 +223,29 @@ enum sm5502_reg { | |||
223 | #define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT) | 223 | #define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT) |
224 | #define SM5502_REG_DEV_TYPE2_AV_CABLE_MASK (0x1 << SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT) | 224 | #define SM5502_REG_DEV_TYPE2_AV_CABLE_MASK (0x1 << SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT) |
225 | 225 | ||
226 | #define SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT 0 | ||
227 | #define SM5502_REG_MANUAL_SW1_DP_SHIFT 2 | ||
228 | #define SM5502_REG_MANUAL_SW1_DM_SHIFT 5 | ||
229 | #define SM5502_REG_MANUAL_SW1_VBUSIN_MASK (0x3 << SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT) | ||
230 | #define SM5502_REG_MANUAL_SW1_DP_MASK (0x7 << SM5502_REG_MANUAL_SW1_DP_SHIFT) | ||
231 | #define SM5502_REG_MANUAL_SW1_DM_MASK (0x7 << SM5502_REG_MANUAL_SW1_DM_SHIFT) | ||
232 | #define VBUSIN_SWITCH_OPEN 0x0 | ||
233 | #define VBUSIN_SWITCH_VBUSOUT 0x1 | ||
234 | #define VBUSIN_SWITCH_MIC 0x2 | ||
235 | #define VBUSIN_SWITCH_VBUSOUT_WITH_USB 0x3 | ||
236 | #define DM_DP_CON_SWITCH_OPEN 0x0 | ||
237 | #define DM_DP_CON_SWITCH_USB 0x1 | ||
238 | #define DM_DP_CON_SWITCH_AUDIO 0x2 | ||
239 | #define DM_DP_CON_SWITCH_UART 0x3 | ||
240 | #define DM_DP_SWITCH_OPEN ((DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ | ||
241 | | (DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) | ||
242 | #define DM_DP_SWITCH_USB ((DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ | ||
243 | | (DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) | ||
244 | #define DM_DP_SWITCH_AUDIO ((DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ | ||
245 | | (DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) | ||
246 | #define DM_DP_SWITCH_UART ((DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ | ||
247 | | (DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) | ||
248 | |||
226 | /* SM5502 Interrupts */ | 249 | /* SM5502 Interrupts */ |
227 | enum sm5502_irq { | 250 | enum sm5502_irq { |
228 | /* INT1 */ | 251 | /* INT1 */ |