extcon-sm5502.c (24214B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * extcon-sm5502.c - Silicon Mitus SM5502 extcon drvier to support USB switches 4 * 5 * Copyright (c) 2014 Samsung Electronics Co., Ltd 6 * Author: Chanwoo Choi <cw00.choi@samsung.com> 7 */ 8 9#include <linux/err.h> 10#include <linux/i2c.h> 11#include <linux/interrupt.h> 12#include <linux/irqdomain.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/platform_device.h> 16#include <linux/regmap.h> 17#include <linux/slab.h> 18#include <linux/extcon-provider.h> 19 20#include "extcon-sm5502.h" 21 22#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */ 23 24struct muic_irq { 25 unsigned int irq; 26 const char *name; 27 unsigned int virq; 28}; 29 30struct reg_data { 31 u8 reg; 32 unsigned int val; 33 bool invert; 34}; 35 36struct sm5502_muic_info { 37 struct device *dev; 38 struct extcon_dev *edev; 39 40 struct i2c_client *i2c; 41 struct regmap *regmap; 42 43 const struct sm5502_type *type; 44 struct regmap_irq_chip_data *irq_data; 45 int irq; 46 bool irq_attach; 47 bool irq_detach; 48 struct work_struct irq_work; 49 50 struct mutex mutex; 51 52 /* 53 * Use delayed workqueue to detect cable state and then 54 * notify cable state to notifiee/platform through uevent. 55 * After completing the booting of platform, the extcon provider 56 * driver should notify cable state to upper layer. 57 */ 58 struct delayed_work wq_detcable; 59}; 60 61struct sm5502_type { 62 struct muic_irq *muic_irqs; 63 unsigned int num_muic_irqs; 64 const struct regmap_irq_chip *irq_chip; 65 66 struct reg_data *reg_data; 67 unsigned int num_reg_data; 68 69 unsigned int otg_dev_type1; 70 int (*parse_irq)(struct sm5502_muic_info *info, int irq_type); 71}; 72 73/* Default value of SM5502 register to bring up MUIC device. */ 74static struct reg_data sm5502_reg_data[] = { 75 { 76 .reg = SM5502_REG_RESET, 77 .val = SM5502_REG_RESET_MASK, 78 .invert = true, 79 }, { 80 .reg = SM5502_REG_CONTROL, 81 .val = SM5502_REG_CONTROL_MASK_INT_MASK, 82 .invert = false, 83 }, { 84 .reg = SM5502_REG_INTMASK1, 85 .val = SM5502_REG_INTM1_KP_MASK 86 | SM5502_REG_INTM1_LKP_MASK 87 | SM5502_REG_INTM1_LKR_MASK, 88 .invert = true, 89 }, { 90 .reg = SM5502_REG_INTMASK2, 91 .val = SM5502_REG_INTM2_VBUS_DET_MASK 92 | SM5502_REG_INTM2_REV_ACCE_MASK 93 | SM5502_REG_INTM2_ADC_CHG_MASK 94 | SM5502_REG_INTM2_STUCK_KEY_MASK 95 | SM5502_REG_INTM2_STUCK_KEY_RCV_MASK 96 | SM5502_REG_INTM2_MHL_MASK, 97 .invert = true, 98 }, 99}; 100 101/* Default value of SM5504 register to bring up MUIC device. */ 102static struct reg_data sm5504_reg_data[] = { 103 { 104 .reg = SM5502_REG_RESET, 105 .val = SM5502_REG_RESET_MASK, 106 .invert = true, 107 }, { 108 .reg = SM5502_REG_INTMASK1, 109 .val = SM5504_REG_INTM1_ATTACH_MASK 110 | SM5504_REG_INTM1_DETACH_MASK, 111 .invert = false, 112 }, { 113 .reg = SM5502_REG_INTMASK2, 114 .val = SM5504_REG_INTM2_RID_CHG_MASK 115 | SM5504_REG_INTM2_UVLO_MASK 116 | SM5504_REG_INTM2_POR_MASK, 117 .invert = true, 118 }, { 119 .reg = SM5502_REG_CONTROL, 120 .val = SM5502_REG_CONTROL_MANUAL_SW_MASK 121 | SM5504_REG_CONTROL_CHGTYP_MASK 122 | SM5504_REG_CONTROL_USBCHDEN_MASK 123 | SM5504_REG_CONTROL_ADC_EN_MASK, 124 .invert = true, 125 }, 126}; 127 128/* List of detectable cables */ 129static const unsigned int sm5502_extcon_cable[] = { 130 EXTCON_USB, 131 EXTCON_USB_HOST, 132 EXTCON_CHG_USB_SDP, 133 EXTCON_CHG_USB_DCP, 134 EXTCON_NONE, 135}; 136 137/* Define supported accessory type */ 138enum sm5502_muic_acc_type { 139 SM5502_MUIC_ADC_GROUND = 0x0, 140 SM5502_MUIC_ADC_SEND_END_BUTTON, 141 SM5502_MUIC_ADC_REMOTE_S1_BUTTON, 142 SM5502_MUIC_ADC_REMOTE_S2_BUTTON, 143 SM5502_MUIC_ADC_REMOTE_S3_BUTTON, 144 SM5502_MUIC_ADC_REMOTE_S4_BUTTON, 145 SM5502_MUIC_ADC_REMOTE_S5_BUTTON, 146 SM5502_MUIC_ADC_REMOTE_S6_BUTTON, 147 SM5502_MUIC_ADC_REMOTE_S7_BUTTON, 148 SM5502_MUIC_ADC_REMOTE_S8_BUTTON, 149 SM5502_MUIC_ADC_REMOTE_S9_BUTTON, 150 SM5502_MUIC_ADC_REMOTE_S10_BUTTON, 151 SM5502_MUIC_ADC_REMOTE_S11_BUTTON, 152 SM5502_MUIC_ADC_REMOTE_S12_BUTTON, 153 SM5502_MUIC_ADC_RESERVED_ACC_1, 154 SM5502_MUIC_ADC_RESERVED_ACC_2, 155 SM5502_MUIC_ADC_RESERVED_ACC_3, 156 SM5502_MUIC_ADC_RESERVED_ACC_4, 157 SM5502_MUIC_ADC_RESERVED_ACC_5, 158 SM5502_MUIC_ADC_AUDIO_TYPE2, 159 SM5502_MUIC_ADC_PHONE_POWERED_DEV, 160 SM5502_MUIC_ADC_TTY_CONVERTER, 161 SM5502_MUIC_ADC_UART_CABLE, 162 SM5502_MUIC_ADC_TYPE1_CHARGER, 163 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB, 164 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB, 165 SM5502_MUIC_ADC_AUDIO_VIDEO_CABLE, 166 SM5502_MUIC_ADC_TYPE2_CHARGER, 167 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART, 168 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART, 169 SM5502_MUIC_ADC_AUDIO_TYPE1, 170 SM5502_MUIC_ADC_OPEN = 0x1f, 171 172 /* 173 * The below accessories have same ADC value (0x1f or 0x1e). 174 * So, Device type1 is used to separate specific accessory. 175 */ 176 /* |---------|--ADC| */ 177 /* | [7:5]|[4:0]| */ 178 SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* | 001|11110| */ 179 SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END = 0x5e, /* | 010|11110| */ 180 /* |Dev Type1|--ADC| */ 181 SM5502_MUIC_ADC_GROUND_USB_OTG = 0x80, /* | 100|00000| */ 182 SM5502_MUIC_ADC_OPEN_USB = 0x5f, /* | 010|11111| */ 183 SM5502_MUIC_ADC_OPEN_TA = 0xdf, /* | 110|11111| */ 184 SM5502_MUIC_ADC_OPEN_USB_OTG = 0xff, /* | 111|11111| */ 185}; 186 187/* List of supported interrupt for SM5502 */ 188static struct muic_irq sm5502_muic_irqs[] = { 189 { SM5502_IRQ_INT1_ATTACH, "muic-attach" }, 190 { SM5502_IRQ_INT1_DETACH, "muic-detach" }, 191 { SM5502_IRQ_INT1_KP, "muic-kp" }, 192 { SM5502_IRQ_INT1_LKP, "muic-lkp" }, 193 { SM5502_IRQ_INT1_LKR, "muic-lkr" }, 194 { SM5502_IRQ_INT1_OVP_EVENT, "muic-ovp-event" }, 195 { SM5502_IRQ_INT1_OCP_EVENT, "muic-ocp-event" }, 196 { SM5502_IRQ_INT1_OVP_OCP_DIS, "muic-ovp-ocp-dis" }, 197 { SM5502_IRQ_INT2_VBUS_DET, "muic-vbus-det" }, 198 { SM5502_IRQ_INT2_REV_ACCE, "muic-rev-acce" }, 199 { SM5502_IRQ_INT2_ADC_CHG, "muic-adc-chg" }, 200 { SM5502_IRQ_INT2_STUCK_KEY, "muic-stuck-key" }, 201 { SM5502_IRQ_INT2_STUCK_KEY_RCV, "muic-stuck-key-rcv" }, 202 { SM5502_IRQ_INT2_MHL, "muic-mhl" }, 203}; 204 205/* Define interrupt list of SM5502 to register regmap_irq */ 206static const struct regmap_irq sm5502_irqs[] = { 207 /* INT1 interrupts */ 208 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_ATTACH_MASK, }, 209 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_DETACH_MASK, }, 210 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_KP_MASK, }, 211 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_LKP_MASK, }, 212 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_LKR_MASK, }, 213 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OVP_EVENT_MASK, }, 214 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OCP_EVENT_MASK, }, 215 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OVP_OCP_DIS_MASK, }, 216 217 /* INT2 interrupts */ 218 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_VBUS_DET_MASK,}, 219 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_REV_ACCE_MASK, }, 220 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_ADC_CHG_MASK, }, 221 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_STUCK_KEY_MASK, }, 222 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_STUCK_KEY_RCV_MASK, }, 223 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_MHL_MASK, }, 224}; 225 226static const struct regmap_irq_chip sm5502_muic_irq_chip = { 227 .name = "sm5502", 228 .status_base = SM5502_REG_INT1, 229 .mask_base = SM5502_REG_INTMASK1, 230 .mask_invert = false, 231 .num_regs = 2, 232 .irqs = sm5502_irqs, 233 .num_irqs = ARRAY_SIZE(sm5502_irqs), 234}; 235 236/* List of supported interrupt for SM5504 */ 237static struct muic_irq sm5504_muic_irqs[] = { 238 { SM5504_IRQ_INT1_ATTACH, "muic-attach" }, 239 { SM5504_IRQ_INT1_DETACH, "muic-detach" }, 240 { SM5504_IRQ_INT1_CHG_DET, "muic-chg-det" }, 241 { SM5504_IRQ_INT1_DCD_OUT, "muic-dcd-out" }, 242 { SM5504_IRQ_INT1_OVP_EVENT, "muic-ovp-event" }, 243 { SM5504_IRQ_INT1_CONNECT, "muic-connect" }, 244 { SM5504_IRQ_INT1_ADC_CHG, "muic-adc-chg" }, 245 { SM5504_IRQ_INT2_RID_CHG, "muic-rid-chg" }, 246 { SM5504_IRQ_INT2_UVLO, "muic-uvlo" }, 247 { SM5504_IRQ_INT2_POR, "muic-por" }, 248 { SM5504_IRQ_INT2_OVP_FET, "muic-ovp-fet" }, 249 { SM5504_IRQ_INT2_OCP_LATCH, "muic-ocp-latch" }, 250 { SM5504_IRQ_INT2_OCP_EVENT, "muic-ocp-event" }, 251 { SM5504_IRQ_INT2_OVP_OCP_EVENT, "muic-ovp-ocp-event" }, 252}; 253 254/* Define interrupt list of SM5504 to register regmap_irq */ 255static const struct regmap_irq sm5504_irqs[] = { 256 /* INT1 interrupts */ 257 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ATTACH_MASK, }, 258 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DETACH_MASK, }, 259 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CHG_DET_MASK, }, 260 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DCD_OUT_MASK, }, 261 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_OVP_MASK, }, 262 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CONNECT_MASK, }, 263 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ADC_CHG_MASK, }, 264 265 /* INT2 interrupts */ 266 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_RID_CHG_MASK,}, 267 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_UVLO_MASK, }, 268 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_POR_MASK, }, 269 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_FET_MASK, }, 270 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_LATCH_MASK, }, 271 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_EVENT_MASK, }, 272 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK, }, 273}; 274 275static const struct regmap_irq_chip sm5504_muic_irq_chip = { 276 .name = "sm5504", 277 .status_base = SM5502_REG_INT1, 278 .mask_base = SM5502_REG_INTMASK1, 279 .mask_invert = false, 280 .num_regs = 2, 281 .irqs = sm5504_irqs, 282 .num_irqs = ARRAY_SIZE(sm5504_irqs), 283}; 284 285/* Define regmap configuration of SM5502 for I2C communication */ 286static bool sm5502_muic_volatile_reg(struct device *dev, unsigned int reg) 287{ 288 switch (reg) { 289 case SM5502_REG_INTMASK1: 290 case SM5502_REG_INTMASK2: 291 return true; 292 default: 293 break; 294 } 295 return false; 296} 297 298static const struct regmap_config sm5502_muic_regmap_config = { 299 .reg_bits = 8, 300 .val_bits = 8, 301 .volatile_reg = sm5502_muic_volatile_reg, 302 .max_register = SM5502_REG_END, 303}; 304 305/* Change DM_CON/DP_CON/VBUSIN switch according to cable type */ 306static int sm5502_muic_set_path(struct sm5502_muic_info *info, 307 unsigned int con_sw, unsigned int vbus_sw, 308 bool attached) 309{ 310 int ret; 311 312 if (!attached) { 313 con_sw = DM_DP_SWITCH_OPEN; 314 vbus_sw = VBUSIN_SWITCH_OPEN; 315 } 316 317 switch (con_sw) { 318 case DM_DP_SWITCH_OPEN: 319 case DM_DP_SWITCH_USB: 320 case DM_DP_SWITCH_AUDIO: 321 case DM_DP_SWITCH_UART: 322 ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1, 323 SM5502_REG_MANUAL_SW1_DP_MASK | 324 SM5502_REG_MANUAL_SW1_DM_MASK, 325 con_sw); 326 if (ret < 0) { 327 dev_err(info->dev, 328 "cannot update DM_CON/DP_CON switch\n"); 329 return ret; 330 } 331 break; 332 default: 333 dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n", 334 con_sw); 335 return -EINVAL; 336 } 337 338 switch (vbus_sw) { 339 case VBUSIN_SWITCH_OPEN: 340 case VBUSIN_SWITCH_VBUSOUT: 341 case VBUSIN_SWITCH_MIC: 342 case VBUSIN_SWITCH_VBUSOUT_WITH_USB: 343 ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1, 344 SM5502_REG_MANUAL_SW1_VBUSIN_MASK, 345 vbus_sw); 346 if (ret < 0) { 347 dev_err(info->dev, 348 "cannot update VBUSIN switch\n"); 349 return ret; 350 } 351 break; 352 default: 353 dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw); 354 return -EINVAL; 355 } 356 357 return 0; 358} 359 360/* Return cable type of attached or detached accessories */ 361static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) 362{ 363 unsigned int cable_type, adc, dev_type1; 364 int ret; 365 366 /* Read ADC value according to external cable or button */ 367 ret = regmap_read(info->regmap, SM5502_REG_ADC, &adc); 368 if (ret) { 369 dev_err(info->dev, "failed to read ADC register\n"); 370 return ret; 371 } 372 373 /* 374 * If ADC is SM5502_MUIC_ADC_GROUND(0x0), external cable hasn't 375 * connected with to MUIC device. 376 */ 377 cable_type = adc & SM5502_REG_ADC_MASK; 378 379 switch (cable_type) { 380 case SM5502_MUIC_ADC_GROUND: 381 ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1, 382 &dev_type1); 383 if (ret) { 384 dev_err(info->dev, "failed to read DEV_TYPE1 reg\n"); 385 return ret; 386 } 387 388 if (dev_type1 == info->type->otg_dev_type1) { 389 cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG; 390 } else { 391 dev_dbg(info->dev, 392 "cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n", 393 adc, dev_type1); 394 return -EINVAL; 395 } 396 break; 397 case SM5502_MUIC_ADC_SEND_END_BUTTON: 398 case SM5502_MUIC_ADC_REMOTE_S1_BUTTON: 399 case SM5502_MUIC_ADC_REMOTE_S2_BUTTON: 400 case SM5502_MUIC_ADC_REMOTE_S3_BUTTON: 401 case SM5502_MUIC_ADC_REMOTE_S4_BUTTON: 402 case SM5502_MUIC_ADC_REMOTE_S5_BUTTON: 403 case SM5502_MUIC_ADC_REMOTE_S6_BUTTON: 404 case SM5502_MUIC_ADC_REMOTE_S7_BUTTON: 405 case SM5502_MUIC_ADC_REMOTE_S8_BUTTON: 406 case SM5502_MUIC_ADC_REMOTE_S9_BUTTON: 407 case SM5502_MUIC_ADC_REMOTE_S10_BUTTON: 408 case SM5502_MUIC_ADC_REMOTE_S11_BUTTON: 409 case SM5502_MUIC_ADC_REMOTE_S12_BUTTON: 410 case SM5502_MUIC_ADC_RESERVED_ACC_1: 411 case SM5502_MUIC_ADC_RESERVED_ACC_2: 412 case SM5502_MUIC_ADC_RESERVED_ACC_3: 413 case SM5502_MUIC_ADC_RESERVED_ACC_4: 414 case SM5502_MUIC_ADC_RESERVED_ACC_5: 415 case SM5502_MUIC_ADC_AUDIO_TYPE2: 416 case SM5502_MUIC_ADC_PHONE_POWERED_DEV: 417 case SM5502_MUIC_ADC_TTY_CONVERTER: 418 case SM5502_MUIC_ADC_UART_CABLE: 419 case SM5502_MUIC_ADC_TYPE1_CHARGER: 420 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB: 421 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB: 422 case SM5502_MUIC_ADC_AUDIO_VIDEO_CABLE: 423 case SM5502_MUIC_ADC_TYPE2_CHARGER: 424 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART: 425 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART: 426 break; 427 case SM5502_MUIC_ADC_AUDIO_TYPE1: 428 /* 429 * Check whether cable type is 430 * SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE 431 * or SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END 432 * by using Button event. 433 */ 434 break; 435 case SM5502_MUIC_ADC_OPEN: 436 ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1, 437 &dev_type1); 438 if (ret) { 439 dev_err(info->dev, "failed to read DEV_TYPE1 reg\n"); 440 return ret; 441 } 442 443 if (dev_type1 == info->type->otg_dev_type1) { 444 cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG; 445 break; 446 } 447 448 switch (dev_type1) { 449 case SM5502_REG_DEV_TYPE1_USB_SDP_MASK: 450 cable_type = SM5502_MUIC_ADC_OPEN_USB; 451 break; 452 case SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK: 453 cable_type = SM5502_MUIC_ADC_OPEN_TA; 454 break; 455 default: 456 dev_dbg(info->dev, 457 "cannot identify the cable type: adc(0x%x)\n", 458 adc); 459 return -EINVAL; 460 } 461 break; 462 default: 463 dev_err(info->dev, 464 "failed to identify the cable type: adc(0x%x)\n", adc); 465 return -EINVAL; 466 } 467 468 return cable_type; 469} 470 471static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, 472 bool attached) 473{ 474 static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; 475 unsigned int cable_type = SM5502_MUIC_ADC_GROUND; 476 unsigned int con_sw = DM_DP_SWITCH_OPEN; 477 unsigned int vbus_sw = VBUSIN_SWITCH_OPEN; 478 unsigned int id; 479 int ret; 480 481 /* Get the type of attached or detached cable */ 482 if (attached) 483 cable_type = sm5502_muic_get_cable_type(info); 484 else 485 cable_type = prev_cable_type; 486 prev_cable_type = cable_type; 487 488 switch (cable_type) { 489 case SM5502_MUIC_ADC_OPEN_USB: 490 id = EXTCON_USB; 491 con_sw = DM_DP_SWITCH_USB; 492 vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB; 493 break; 494 case SM5502_MUIC_ADC_OPEN_TA: 495 id = EXTCON_CHG_USB_DCP; 496 con_sw = DM_DP_SWITCH_OPEN; 497 vbus_sw = VBUSIN_SWITCH_VBUSOUT; 498 break; 499 case SM5502_MUIC_ADC_GROUND_USB_OTG: 500 case SM5502_MUIC_ADC_OPEN_USB_OTG: 501 id = EXTCON_USB_HOST; 502 con_sw = DM_DP_SWITCH_USB; 503 vbus_sw = VBUSIN_SWITCH_OPEN; 504 break; 505 default: 506 dev_dbg(info->dev, 507 "cannot handle this cable_type (0x%x)\n", cable_type); 508 return 0; 509 } 510 511 /* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */ 512 ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached); 513 if (ret < 0) 514 return ret; 515 516 /* Change the state of external accessory */ 517 extcon_set_state_sync(info->edev, id, attached); 518 if (id == EXTCON_USB) 519 extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, 520 attached); 521 522 return 0; 523} 524 525static void sm5502_muic_irq_work(struct work_struct *work) 526{ 527 struct sm5502_muic_info *info = container_of(work, 528 struct sm5502_muic_info, irq_work); 529 int ret = 0; 530 531 if (!info->edev) 532 return; 533 534 mutex_lock(&info->mutex); 535 536 /* Detect attached or detached cables */ 537 if (info->irq_attach) { 538 ret = sm5502_muic_cable_handler(info, true); 539 info->irq_attach = false; 540 } 541 if (info->irq_detach) { 542 ret = sm5502_muic_cable_handler(info, false); 543 info->irq_detach = false; 544 } 545 546 if (ret < 0) 547 dev_err(info->dev, "failed to handle MUIC interrupt\n"); 548 549 mutex_unlock(&info->mutex); 550} 551 552/* 553 * Sets irq_attach or irq_detach in sm5502_muic_info and returns 0. 554 * Returns -ESRCH if irq_type does not match registered IRQ for this dev type. 555 */ 556static int sm5502_parse_irq(struct sm5502_muic_info *info, int irq_type) 557{ 558 switch (irq_type) { 559 case SM5502_IRQ_INT1_ATTACH: 560 info->irq_attach = true; 561 break; 562 case SM5502_IRQ_INT1_DETACH: 563 info->irq_detach = true; 564 break; 565 case SM5502_IRQ_INT1_KP: 566 case SM5502_IRQ_INT1_LKP: 567 case SM5502_IRQ_INT1_LKR: 568 case SM5502_IRQ_INT1_OVP_EVENT: 569 case SM5502_IRQ_INT1_OCP_EVENT: 570 case SM5502_IRQ_INT1_OVP_OCP_DIS: 571 case SM5502_IRQ_INT2_VBUS_DET: 572 case SM5502_IRQ_INT2_REV_ACCE: 573 case SM5502_IRQ_INT2_ADC_CHG: 574 case SM5502_IRQ_INT2_STUCK_KEY: 575 case SM5502_IRQ_INT2_STUCK_KEY_RCV: 576 case SM5502_IRQ_INT2_MHL: 577 default: 578 break; 579 } 580 581 return 0; 582} 583 584static int sm5504_parse_irq(struct sm5502_muic_info *info, int irq_type) 585{ 586 switch (irq_type) { 587 case SM5504_IRQ_INT1_ATTACH: 588 info->irq_attach = true; 589 break; 590 case SM5504_IRQ_INT1_DETACH: 591 info->irq_detach = true; 592 break; 593 case SM5504_IRQ_INT1_CHG_DET: 594 case SM5504_IRQ_INT1_DCD_OUT: 595 case SM5504_IRQ_INT1_OVP_EVENT: 596 case SM5504_IRQ_INT1_CONNECT: 597 case SM5504_IRQ_INT1_ADC_CHG: 598 case SM5504_IRQ_INT2_RID_CHG: 599 case SM5504_IRQ_INT2_UVLO: 600 case SM5504_IRQ_INT2_POR: 601 case SM5504_IRQ_INT2_OVP_FET: 602 case SM5504_IRQ_INT2_OCP_LATCH: 603 case SM5504_IRQ_INT2_OCP_EVENT: 604 case SM5504_IRQ_INT2_OVP_OCP_EVENT: 605 default: 606 break; 607 } 608 609 return 0; 610} 611 612static irqreturn_t sm5502_muic_irq_handler(int irq, void *data) 613{ 614 struct sm5502_muic_info *info = data; 615 int i, irq_type = -1, ret; 616 617 for (i = 0; i < info->type->num_muic_irqs; i++) 618 if (irq == info->type->muic_irqs[i].virq) 619 irq_type = info->type->muic_irqs[i].irq; 620 621 ret = info->type->parse_irq(info, irq_type); 622 if (ret < 0) { 623 dev_warn(info->dev, "cannot handle is interrupt:%d\n", 624 irq_type); 625 return IRQ_HANDLED; 626 } 627 schedule_work(&info->irq_work); 628 629 return IRQ_HANDLED; 630} 631 632static void sm5502_muic_detect_cable_wq(struct work_struct *work) 633{ 634 struct sm5502_muic_info *info = container_of(to_delayed_work(work), 635 struct sm5502_muic_info, wq_detcable); 636 int ret; 637 638 /* Notify the state of connector cable or not */ 639 ret = sm5502_muic_cable_handler(info, true); 640 if (ret < 0) 641 dev_warn(info->dev, "failed to detect cable state\n"); 642} 643 644static void sm5502_init_dev_type(struct sm5502_muic_info *info) 645{ 646 unsigned int reg_data, vendor_id, version_id; 647 int i, ret; 648 649 /* To test I2C, Print version_id and vendor_id of SM5502 */ 650 ret = regmap_read(info->regmap, SM5502_REG_DEVICE_ID, ®_data); 651 if (ret) { 652 dev_err(info->dev, 653 "failed to read DEVICE_ID register: %d\n", ret); 654 return; 655 } 656 657 vendor_id = ((reg_data & SM5502_REG_DEVICE_ID_VENDOR_MASK) >> 658 SM5502_REG_DEVICE_ID_VENDOR_SHIFT); 659 version_id = ((reg_data & SM5502_REG_DEVICE_ID_VERSION_MASK) >> 660 SM5502_REG_DEVICE_ID_VERSION_SHIFT); 661 662 dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n", 663 version_id, vendor_id); 664 665 /* Initiazle the register of SM5502 device to bring-up */ 666 for (i = 0; i < info->type->num_reg_data; i++) { 667 unsigned int val = 0; 668 669 if (!info->type->reg_data[i].invert) 670 val |= ~info->type->reg_data[i].val; 671 else 672 val = info->type->reg_data[i].val; 673 regmap_write(info->regmap, info->type->reg_data[i].reg, val); 674 } 675} 676 677static int sm5022_muic_i2c_probe(struct i2c_client *i2c) 678{ 679 struct device_node *np = i2c->dev.of_node; 680 struct sm5502_muic_info *info; 681 int i, ret, irq_flags; 682 683 if (!np) 684 return -EINVAL; 685 686 info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL); 687 if (!info) 688 return -ENOMEM; 689 i2c_set_clientdata(i2c, info); 690 691 info->dev = &i2c->dev; 692 info->i2c = i2c; 693 info->irq = i2c->irq; 694 info->type = device_get_match_data(info->dev); 695 if (!info->type) 696 return -EINVAL; 697 if (!info->type->parse_irq) { 698 dev_err(info->dev, "parse_irq missing in struct sm5502_type\n"); 699 return -EINVAL; 700 } 701 702 mutex_init(&info->mutex); 703 704 INIT_WORK(&info->irq_work, sm5502_muic_irq_work); 705 706 info->regmap = devm_regmap_init_i2c(i2c, &sm5502_muic_regmap_config); 707 if (IS_ERR(info->regmap)) { 708 ret = PTR_ERR(info->regmap); 709 dev_err(info->dev, "failed to allocate register map: %d\n", 710 ret); 711 return ret; 712 } 713 714 /* Support irq domain for SM5502 MUIC device */ 715 irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED; 716 ret = devm_regmap_add_irq_chip(info->dev, info->regmap, info->irq, 717 irq_flags, 0, info->type->irq_chip, 718 &info->irq_data); 719 if (ret != 0) { 720 dev_err(info->dev, "failed to request IRQ %d: %d\n", 721 info->irq, ret); 722 return ret; 723 } 724 725 for (i = 0; i < info->type->num_muic_irqs; i++) { 726 struct muic_irq *muic_irq = &info->type->muic_irqs[i]; 727 int virq = 0; 728 729 virq = regmap_irq_get_virq(info->irq_data, muic_irq->irq); 730 if (virq <= 0) 731 return -EINVAL; 732 muic_irq->virq = virq; 733 734 ret = devm_request_threaded_irq(info->dev, virq, NULL, 735 sm5502_muic_irq_handler, 736 IRQF_NO_SUSPEND | IRQF_ONESHOT, 737 muic_irq->name, info); 738 if (ret) { 739 dev_err(info->dev, 740 "failed: irq request (IRQ: %d, error :%d)\n", 741 muic_irq->irq, ret); 742 return ret; 743 } 744 } 745 746 /* Allocate extcon device */ 747 info->edev = devm_extcon_dev_allocate(info->dev, sm5502_extcon_cable); 748 if (IS_ERR(info->edev)) { 749 dev_err(info->dev, "failed to allocate memory for extcon\n"); 750 return -ENOMEM; 751 } 752 753 /* Register extcon device */ 754 ret = devm_extcon_dev_register(info->dev, info->edev); 755 if (ret) { 756 dev_err(info->dev, "failed to register extcon device\n"); 757 return ret; 758 } 759 760 /* 761 * Detect accessory after completing the initialization of platform 762 * 763 * - Use delayed workqueue to detect cable state and then 764 * notify cable state to notifiee/platform through uevent. 765 * After completing the booting of platform, the extcon provider 766 * driver should notify cable state to upper layer. 767 */ 768 INIT_DELAYED_WORK(&info->wq_detcable, sm5502_muic_detect_cable_wq); 769 queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, 770 msecs_to_jiffies(DELAY_MS_DEFAULT)); 771 772 /* Initialize SM5502 device and print vendor id and version id */ 773 sm5502_init_dev_type(info); 774 775 return 0; 776} 777 778static const struct sm5502_type sm5502_data = { 779 .muic_irqs = sm5502_muic_irqs, 780 .num_muic_irqs = ARRAY_SIZE(sm5502_muic_irqs), 781 .irq_chip = &sm5502_muic_irq_chip, 782 .reg_data = sm5502_reg_data, 783 .num_reg_data = ARRAY_SIZE(sm5502_reg_data), 784 .otg_dev_type1 = SM5502_REG_DEV_TYPE1_USB_OTG_MASK, 785 .parse_irq = sm5502_parse_irq, 786}; 787 788static const struct sm5502_type sm5504_data = { 789 .muic_irqs = sm5504_muic_irqs, 790 .num_muic_irqs = ARRAY_SIZE(sm5504_muic_irqs), 791 .irq_chip = &sm5504_muic_irq_chip, 792 .reg_data = sm5504_reg_data, 793 .num_reg_data = ARRAY_SIZE(sm5504_reg_data), 794 .otg_dev_type1 = SM5504_REG_DEV_TYPE1_USB_OTG_MASK, 795 .parse_irq = sm5504_parse_irq, 796}; 797 798static const struct of_device_id sm5502_dt_match[] = { 799 { .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data }, 800 { .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data }, 801 { .compatible = "siliconmitus,sm5703-muic", .data = &sm5502_data }, 802 { }, 803}; 804MODULE_DEVICE_TABLE(of, sm5502_dt_match); 805 806#ifdef CONFIG_PM_SLEEP 807static int sm5502_muic_suspend(struct device *dev) 808{ 809 struct i2c_client *i2c = to_i2c_client(dev); 810 struct sm5502_muic_info *info = i2c_get_clientdata(i2c); 811 812 enable_irq_wake(info->irq); 813 814 return 0; 815} 816 817static int sm5502_muic_resume(struct device *dev) 818{ 819 struct i2c_client *i2c = to_i2c_client(dev); 820 struct sm5502_muic_info *info = i2c_get_clientdata(i2c); 821 822 disable_irq_wake(info->irq); 823 824 return 0; 825} 826#endif 827 828static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops, 829 sm5502_muic_suspend, sm5502_muic_resume); 830 831static const struct i2c_device_id sm5502_i2c_id[] = { 832 { "sm5502", (kernel_ulong_t)&sm5502_data }, 833 { "sm5504", (kernel_ulong_t)&sm5504_data }, 834 { "sm5703-muic", (kernel_ulong_t)&sm5502_data }, 835 { } 836}; 837MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id); 838 839static struct i2c_driver sm5502_muic_i2c_driver = { 840 .driver = { 841 .name = "sm5502", 842 .pm = &sm5502_muic_pm_ops, 843 .of_match_table = sm5502_dt_match, 844 }, 845 .probe_new = sm5022_muic_i2c_probe, 846 .id_table = sm5502_i2c_id, 847}; 848 849static int __init sm5502_muic_i2c_init(void) 850{ 851 return i2c_add_driver(&sm5502_muic_i2c_driver); 852} 853subsys_initcall(sm5502_muic_i2c_init); 854 855MODULE_DESCRIPTION("Silicon Mitus SM5502 Extcon driver"); 856MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); 857MODULE_LICENSE("GPL");