0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/err.h>
0010 #include <linux/i2c.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regmap.h>
0017 #include <linux/slab.h>
0018 #include <linux/extcon-provider.h>
0019
0020 #include "extcon-sm5502.h"
0021
0022 #define DELAY_MS_DEFAULT 17000
0023
0024 struct muic_irq {
0025 unsigned int irq;
0026 const char *name;
0027 unsigned int virq;
0028 };
0029
0030 struct reg_data {
0031 u8 reg;
0032 unsigned int val;
0033 bool invert;
0034 };
0035
0036 struct sm5502_muic_info {
0037 struct device *dev;
0038 struct extcon_dev *edev;
0039
0040 struct i2c_client *i2c;
0041 struct regmap *regmap;
0042
0043 const struct sm5502_type *type;
0044 struct regmap_irq_chip_data *irq_data;
0045 int irq;
0046 bool irq_attach;
0047 bool irq_detach;
0048 struct work_struct irq_work;
0049
0050 struct mutex mutex;
0051
0052
0053
0054
0055
0056
0057
0058 struct delayed_work wq_detcable;
0059 };
0060
0061 struct sm5502_type {
0062 struct muic_irq *muic_irqs;
0063 unsigned int num_muic_irqs;
0064 const struct regmap_irq_chip *irq_chip;
0065
0066 struct reg_data *reg_data;
0067 unsigned int num_reg_data;
0068
0069 unsigned int otg_dev_type1;
0070 int (*parse_irq)(struct sm5502_muic_info *info, int irq_type);
0071 };
0072
0073
0074 static struct reg_data sm5502_reg_data[] = {
0075 {
0076 .reg = SM5502_REG_RESET,
0077 .val = SM5502_REG_RESET_MASK,
0078 .invert = true,
0079 }, {
0080 .reg = SM5502_REG_CONTROL,
0081 .val = SM5502_REG_CONTROL_MASK_INT_MASK,
0082 .invert = false,
0083 }, {
0084 .reg = SM5502_REG_INTMASK1,
0085 .val = SM5502_REG_INTM1_KP_MASK
0086 | SM5502_REG_INTM1_LKP_MASK
0087 | SM5502_REG_INTM1_LKR_MASK,
0088 .invert = true,
0089 }, {
0090 .reg = SM5502_REG_INTMASK2,
0091 .val = SM5502_REG_INTM2_VBUS_DET_MASK
0092 | SM5502_REG_INTM2_REV_ACCE_MASK
0093 | SM5502_REG_INTM2_ADC_CHG_MASK
0094 | SM5502_REG_INTM2_STUCK_KEY_MASK
0095 | SM5502_REG_INTM2_STUCK_KEY_RCV_MASK
0096 | SM5502_REG_INTM2_MHL_MASK,
0097 .invert = true,
0098 },
0099 };
0100
0101
0102 static struct reg_data sm5504_reg_data[] = {
0103 {
0104 .reg = SM5502_REG_RESET,
0105 .val = SM5502_REG_RESET_MASK,
0106 .invert = true,
0107 }, {
0108 .reg = SM5502_REG_INTMASK1,
0109 .val = SM5504_REG_INTM1_ATTACH_MASK
0110 | SM5504_REG_INTM1_DETACH_MASK,
0111 .invert = false,
0112 }, {
0113 .reg = SM5502_REG_INTMASK2,
0114 .val = SM5504_REG_INTM2_RID_CHG_MASK
0115 | SM5504_REG_INTM2_UVLO_MASK
0116 | SM5504_REG_INTM2_POR_MASK,
0117 .invert = true,
0118 }, {
0119 .reg = SM5502_REG_CONTROL,
0120 .val = SM5502_REG_CONTROL_MANUAL_SW_MASK
0121 | SM5504_REG_CONTROL_CHGTYP_MASK
0122 | SM5504_REG_CONTROL_USBCHDEN_MASK
0123 | SM5504_REG_CONTROL_ADC_EN_MASK,
0124 .invert = true,
0125 },
0126 };
0127
0128
0129 static const unsigned int sm5502_extcon_cable[] = {
0130 EXTCON_USB,
0131 EXTCON_USB_HOST,
0132 EXTCON_CHG_USB_SDP,
0133 EXTCON_CHG_USB_DCP,
0134 EXTCON_NONE,
0135 };
0136
0137
0138 enum sm5502_muic_acc_type {
0139 SM5502_MUIC_ADC_GROUND = 0x0,
0140 SM5502_MUIC_ADC_SEND_END_BUTTON,
0141 SM5502_MUIC_ADC_REMOTE_S1_BUTTON,
0142 SM5502_MUIC_ADC_REMOTE_S2_BUTTON,
0143 SM5502_MUIC_ADC_REMOTE_S3_BUTTON,
0144 SM5502_MUIC_ADC_REMOTE_S4_BUTTON,
0145 SM5502_MUIC_ADC_REMOTE_S5_BUTTON,
0146 SM5502_MUIC_ADC_REMOTE_S6_BUTTON,
0147 SM5502_MUIC_ADC_REMOTE_S7_BUTTON,
0148 SM5502_MUIC_ADC_REMOTE_S8_BUTTON,
0149 SM5502_MUIC_ADC_REMOTE_S9_BUTTON,
0150 SM5502_MUIC_ADC_REMOTE_S10_BUTTON,
0151 SM5502_MUIC_ADC_REMOTE_S11_BUTTON,
0152 SM5502_MUIC_ADC_REMOTE_S12_BUTTON,
0153 SM5502_MUIC_ADC_RESERVED_ACC_1,
0154 SM5502_MUIC_ADC_RESERVED_ACC_2,
0155 SM5502_MUIC_ADC_RESERVED_ACC_3,
0156 SM5502_MUIC_ADC_RESERVED_ACC_4,
0157 SM5502_MUIC_ADC_RESERVED_ACC_5,
0158 SM5502_MUIC_ADC_AUDIO_TYPE2,
0159 SM5502_MUIC_ADC_PHONE_POWERED_DEV,
0160 SM5502_MUIC_ADC_TTY_CONVERTER,
0161 SM5502_MUIC_ADC_UART_CABLE,
0162 SM5502_MUIC_ADC_TYPE1_CHARGER,
0163 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB,
0164 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB,
0165 SM5502_MUIC_ADC_AUDIO_VIDEO_CABLE,
0166 SM5502_MUIC_ADC_TYPE2_CHARGER,
0167 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART,
0168 SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART,
0169 SM5502_MUIC_ADC_AUDIO_TYPE1,
0170 SM5502_MUIC_ADC_OPEN = 0x1f,
0171
0172
0173
0174
0175
0176
0177
0178 SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e,
0179 SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END = 0x5e,
0180
0181 SM5502_MUIC_ADC_GROUND_USB_OTG = 0x80,
0182 SM5502_MUIC_ADC_OPEN_USB = 0x5f,
0183 SM5502_MUIC_ADC_OPEN_TA = 0xdf,
0184 SM5502_MUIC_ADC_OPEN_USB_OTG = 0xff,
0185 };
0186
0187
0188 static struct muic_irq sm5502_muic_irqs[] = {
0189 { SM5502_IRQ_INT1_ATTACH, "muic-attach" },
0190 { SM5502_IRQ_INT1_DETACH, "muic-detach" },
0191 { SM5502_IRQ_INT1_KP, "muic-kp" },
0192 { SM5502_IRQ_INT1_LKP, "muic-lkp" },
0193 { SM5502_IRQ_INT1_LKR, "muic-lkr" },
0194 { SM5502_IRQ_INT1_OVP_EVENT, "muic-ovp-event" },
0195 { SM5502_IRQ_INT1_OCP_EVENT, "muic-ocp-event" },
0196 { SM5502_IRQ_INT1_OVP_OCP_DIS, "muic-ovp-ocp-dis" },
0197 { SM5502_IRQ_INT2_VBUS_DET, "muic-vbus-det" },
0198 { SM5502_IRQ_INT2_REV_ACCE, "muic-rev-acce" },
0199 { SM5502_IRQ_INT2_ADC_CHG, "muic-adc-chg" },
0200 { SM5502_IRQ_INT2_STUCK_KEY, "muic-stuck-key" },
0201 { SM5502_IRQ_INT2_STUCK_KEY_RCV, "muic-stuck-key-rcv" },
0202 { SM5502_IRQ_INT2_MHL, "muic-mhl" },
0203 };
0204
0205
0206 static const struct regmap_irq sm5502_irqs[] = {
0207
0208 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_ATTACH_MASK, },
0209 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_DETACH_MASK, },
0210 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_KP_MASK, },
0211 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_LKP_MASK, },
0212 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_LKR_MASK, },
0213 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OVP_EVENT_MASK, },
0214 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OCP_EVENT_MASK, },
0215 { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OVP_OCP_DIS_MASK, },
0216
0217
0218 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_VBUS_DET_MASK,},
0219 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_REV_ACCE_MASK, },
0220 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_ADC_CHG_MASK, },
0221 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_STUCK_KEY_MASK, },
0222 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_STUCK_KEY_RCV_MASK, },
0223 { .reg_offset = 1, .mask = SM5502_IRQ_INT2_MHL_MASK, },
0224 };
0225
0226 static const struct regmap_irq_chip sm5502_muic_irq_chip = {
0227 .name = "sm5502",
0228 .status_base = SM5502_REG_INT1,
0229 .mask_base = SM5502_REG_INTMASK1,
0230 .num_regs = 2,
0231 .irqs = sm5502_irqs,
0232 .num_irqs = ARRAY_SIZE(sm5502_irqs),
0233 };
0234
0235
0236 static struct muic_irq sm5504_muic_irqs[] = {
0237 { SM5504_IRQ_INT1_ATTACH, "muic-attach" },
0238 { SM5504_IRQ_INT1_DETACH, "muic-detach" },
0239 { SM5504_IRQ_INT1_CHG_DET, "muic-chg-det" },
0240 { SM5504_IRQ_INT1_DCD_OUT, "muic-dcd-out" },
0241 { SM5504_IRQ_INT1_OVP_EVENT, "muic-ovp-event" },
0242 { SM5504_IRQ_INT1_CONNECT, "muic-connect" },
0243 { SM5504_IRQ_INT1_ADC_CHG, "muic-adc-chg" },
0244 { SM5504_IRQ_INT2_RID_CHG, "muic-rid-chg" },
0245 { SM5504_IRQ_INT2_UVLO, "muic-uvlo" },
0246 { SM5504_IRQ_INT2_POR, "muic-por" },
0247 { SM5504_IRQ_INT2_OVP_FET, "muic-ovp-fet" },
0248 { SM5504_IRQ_INT2_OCP_LATCH, "muic-ocp-latch" },
0249 { SM5504_IRQ_INT2_OCP_EVENT, "muic-ocp-event" },
0250 { SM5504_IRQ_INT2_OVP_OCP_EVENT, "muic-ovp-ocp-event" },
0251 };
0252
0253
0254 static const struct regmap_irq sm5504_irqs[] = {
0255
0256 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ATTACH_MASK, },
0257 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DETACH_MASK, },
0258 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CHG_DET_MASK, },
0259 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DCD_OUT_MASK, },
0260 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_OVP_MASK, },
0261 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CONNECT_MASK, },
0262 { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ADC_CHG_MASK, },
0263
0264
0265 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_RID_CHG_MASK,},
0266 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_UVLO_MASK, },
0267 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_POR_MASK, },
0268 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_FET_MASK, },
0269 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_LATCH_MASK, },
0270 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_EVENT_MASK, },
0271 { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK, },
0272 };
0273
0274 static const struct regmap_irq_chip sm5504_muic_irq_chip = {
0275 .name = "sm5504",
0276 .status_base = SM5502_REG_INT1,
0277 .mask_base = SM5502_REG_INTMASK1,
0278 .num_regs = 2,
0279 .irqs = sm5504_irqs,
0280 .num_irqs = ARRAY_SIZE(sm5504_irqs),
0281 };
0282
0283
0284 static bool sm5502_muic_volatile_reg(struct device *dev, unsigned int reg)
0285 {
0286 switch (reg) {
0287 case SM5502_REG_INTMASK1:
0288 case SM5502_REG_INTMASK2:
0289 return true;
0290 default:
0291 break;
0292 }
0293 return false;
0294 }
0295
0296 static const struct regmap_config sm5502_muic_regmap_config = {
0297 .reg_bits = 8,
0298 .val_bits = 8,
0299 .volatile_reg = sm5502_muic_volatile_reg,
0300 .max_register = SM5502_REG_END,
0301 };
0302
0303
0304 static int sm5502_muic_set_path(struct sm5502_muic_info *info,
0305 unsigned int con_sw, unsigned int vbus_sw,
0306 bool attached)
0307 {
0308 int ret;
0309
0310 if (!attached) {
0311 con_sw = DM_DP_SWITCH_OPEN;
0312 vbus_sw = VBUSIN_SWITCH_OPEN;
0313 }
0314
0315 switch (con_sw) {
0316 case DM_DP_SWITCH_OPEN:
0317 case DM_DP_SWITCH_USB:
0318 case DM_DP_SWITCH_AUDIO:
0319 case DM_DP_SWITCH_UART:
0320 ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1,
0321 SM5502_REG_MANUAL_SW1_DP_MASK |
0322 SM5502_REG_MANUAL_SW1_DM_MASK,
0323 con_sw);
0324 if (ret < 0) {
0325 dev_err(info->dev,
0326 "cannot update DM_CON/DP_CON switch\n");
0327 return ret;
0328 }
0329 break;
0330 default:
0331 dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
0332 con_sw);
0333 return -EINVAL;
0334 }
0335
0336 switch (vbus_sw) {
0337 case VBUSIN_SWITCH_OPEN:
0338 case VBUSIN_SWITCH_VBUSOUT:
0339 case VBUSIN_SWITCH_MIC:
0340 case VBUSIN_SWITCH_VBUSOUT_WITH_USB:
0341 ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1,
0342 SM5502_REG_MANUAL_SW1_VBUSIN_MASK,
0343 vbus_sw);
0344 if (ret < 0) {
0345 dev_err(info->dev,
0346 "cannot update VBUSIN switch\n");
0347 return ret;
0348 }
0349 break;
0350 default:
0351 dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw);
0352 return -EINVAL;
0353 }
0354
0355 return 0;
0356 }
0357
0358
0359 static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
0360 {
0361 unsigned int cable_type, adc, dev_type1;
0362 int ret;
0363
0364
0365 ret = regmap_read(info->regmap, SM5502_REG_ADC, &adc);
0366 if (ret) {
0367 dev_err(info->dev, "failed to read ADC register\n");
0368 return ret;
0369 }
0370
0371
0372
0373
0374
0375 cable_type = adc & SM5502_REG_ADC_MASK;
0376
0377 switch (cable_type) {
0378 case SM5502_MUIC_ADC_GROUND:
0379 ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1,
0380 &dev_type1);
0381 if (ret) {
0382 dev_err(info->dev, "failed to read DEV_TYPE1 reg\n");
0383 return ret;
0384 }
0385
0386 if (dev_type1 == info->type->otg_dev_type1) {
0387 cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG;
0388 } else {
0389 dev_dbg(info->dev,
0390 "cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n",
0391 adc, dev_type1);
0392 return -EINVAL;
0393 }
0394 break;
0395 case SM5502_MUIC_ADC_SEND_END_BUTTON:
0396 case SM5502_MUIC_ADC_REMOTE_S1_BUTTON:
0397 case SM5502_MUIC_ADC_REMOTE_S2_BUTTON:
0398 case SM5502_MUIC_ADC_REMOTE_S3_BUTTON:
0399 case SM5502_MUIC_ADC_REMOTE_S4_BUTTON:
0400 case SM5502_MUIC_ADC_REMOTE_S5_BUTTON:
0401 case SM5502_MUIC_ADC_REMOTE_S6_BUTTON:
0402 case SM5502_MUIC_ADC_REMOTE_S7_BUTTON:
0403 case SM5502_MUIC_ADC_REMOTE_S8_BUTTON:
0404 case SM5502_MUIC_ADC_REMOTE_S9_BUTTON:
0405 case SM5502_MUIC_ADC_REMOTE_S10_BUTTON:
0406 case SM5502_MUIC_ADC_REMOTE_S11_BUTTON:
0407 case SM5502_MUIC_ADC_REMOTE_S12_BUTTON:
0408 case SM5502_MUIC_ADC_RESERVED_ACC_1:
0409 case SM5502_MUIC_ADC_RESERVED_ACC_2:
0410 case SM5502_MUIC_ADC_RESERVED_ACC_3:
0411 case SM5502_MUIC_ADC_RESERVED_ACC_4:
0412 case SM5502_MUIC_ADC_RESERVED_ACC_5:
0413 case SM5502_MUIC_ADC_AUDIO_TYPE2:
0414 case SM5502_MUIC_ADC_PHONE_POWERED_DEV:
0415 case SM5502_MUIC_ADC_TTY_CONVERTER:
0416 case SM5502_MUIC_ADC_UART_CABLE:
0417 case SM5502_MUIC_ADC_TYPE1_CHARGER:
0418 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB:
0419 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB:
0420 case SM5502_MUIC_ADC_AUDIO_VIDEO_CABLE:
0421 case SM5502_MUIC_ADC_TYPE2_CHARGER:
0422 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART:
0423 case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART:
0424 break;
0425 case SM5502_MUIC_ADC_AUDIO_TYPE1:
0426
0427
0428
0429
0430
0431
0432 break;
0433 case SM5502_MUIC_ADC_OPEN:
0434 ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1,
0435 &dev_type1);
0436 if (ret) {
0437 dev_err(info->dev, "failed to read DEV_TYPE1 reg\n");
0438 return ret;
0439 }
0440
0441 if (dev_type1 == info->type->otg_dev_type1) {
0442 cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG;
0443 break;
0444 }
0445
0446 switch (dev_type1) {
0447 case SM5502_REG_DEV_TYPE1_USB_SDP_MASK:
0448 cable_type = SM5502_MUIC_ADC_OPEN_USB;
0449 break;
0450 case SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK:
0451 cable_type = SM5502_MUIC_ADC_OPEN_TA;
0452 break;
0453 default:
0454 dev_dbg(info->dev,
0455 "cannot identify the cable type: adc(0x%x)\n",
0456 adc);
0457 return -EINVAL;
0458 }
0459 break;
0460 default:
0461 dev_err(info->dev,
0462 "failed to identify the cable type: adc(0x%x)\n", adc);
0463 return -EINVAL;
0464 }
0465
0466 return cable_type;
0467 }
0468
0469 static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
0470 bool attached)
0471 {
0472 static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND;
0473 unsigned int cable_type = SM5502_MUIC_ADC_GROUND;
0474 unsigned int con_sw = DM_DP_SWITCH_OPEN;
0475 unsigned int vbus_sw = VBUSIN_SWITCH_OPEN;
0476 unsigned int id;
0477 int ret;
0478
0479
0480 if (attached)
0481 cable_type = sm5502_muic_get_cable_type(info);
0482 else
0483 cable_type = prev_cable_type;
0484 prev_cable_type = cable_type;
0485
0486 switch (cable_type) {
0487 case SM5502_MUIC_ADC_OPEN_USB:
0488 id = EXTCON_USB;
0489 con_sw = DM_DP_SWITCH_USB;
0490 vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB;
0491 break;
0492 case SM5502_MUIC_ADC_OPEN_TA:
0493 id = EXTCON_CHG_USB_DCP;
0494 con_sw = DM_DP_SWITCH_OPEN;
0495 vbus_sw = VBUSIN_SWITCH_VBUSOUT;
0496 break;
0497 case SM5502_MUIC_ADC_GROUND_USB_OTG:
0498 case SM5502_MUIC_ADC_OPEN_USB_OTG:
0499 id = EXTCON_USB_HOST;
0500 con_sw = DM_DP_SWITCH_USB;
0501 vbus_sw = VBUSIN_SWITCH_OPEN;
0502 break;
0503 default:
0504 dev_dbg(info->dev,
0505 "cannot handle this cable_type (0x%x)\n", cable_type);
0506 return 0;
0507 }
0508
0509
0510 ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached);
0511 if (ret < 0)
0512 return ret;
0513
0514
0515 extcon_set_state_sync(info->edev, id, attached);
0516 if (id == EXTCON_USB)
0517 extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
0518 attached);
0519
0520 return 0;
0521 }
0522
0523 static void sm5502_muic_irq_work(struct work_struct *work)
0524 {
0525 struct sm5502_muic_info *info = container_of(work,
0526 struct sm5502_muic_info, irq_work);
0527 int ret = 0;
0528
0529 if (!info->edev)
0530 return;
0531
0532 mutex_lock(&info->mutex);
0533
0534
0535 if (info->irq_attach) {
0536 ret = sm5502_muic_cable_handler(info, true);
0537 info->irq_attach = false;
0538 }
0539 if (info->irq_detach) {
0540 ret = sm5502_muic_cable_handler(info, false);
0541 info->irq_detach = false;
0542 }
0543
0544 if (ret < 0)
0545 dev_err(info->dev, "failed to handle MUIC interrupt\n");
0546
0547 mutex_unlock(&info->mutex);
0548 }
0549
0550
0551
0552
0553
0554 static int sm5502_parse_irq(struct sm5502_muic_info *info, int irq_type)
0555 {
0556 switch (irq_type) {
0557 case SM5502_IRQ_INT1_ATTACH:
0558 info->irq_attach = true;
0559 break;
0560 case SM5502_IRQ_INT1_DETACH:
0561 info->irq_detach = true;
0562 break;
0563 case SM5502_IRQ_INT1_KP:
0564 case SM5502_IRQ_INT1_LKP:
0565 case SM5502_IRQ_INT1_LKR:
0566 case SM5502_IRQ_INT1_OVP_EVENT:
0567 case SM5502_IRQ_INT1_OCP_EVENT:
0568 case SM5502_IRQ_INT1_OVP_OCP_DIS:
0569 case SM5502_IRQ_INT2_VBUS_DET:
0570 case SM5502_IRQ_INT2_REV_ACCE:
0571 case SM5502_IRQ_INT2_ADC_CHG:
0572 case SM5502_IRQ_INT2_STUCK_KEY:
0573 case SM5502_IRQ_INT2_STUCK_KEY_RCV:
0574 case SM5502_IRQ_INT2_MHL:
0575 default:
0576 break;
0577 }
0578
0579 return 0;
0580 }
0581
0582 static int sm5504_parse_irq(struct sm5502_muic_info *info, int irq_type)
0583 {
0584 switch (irq_type) {
0585 case SM5504_IRQ_INT1_ATTACH:
0586 info->irq_attach = true;
0587 break;
0588 case SM5504_IRQ_INT1_DETACH:
0589 info->irq_detach = true;
0590 break;
0591 case SM5504_IRQ_INT1_CHG_DET:
0592 case SM5504_IRQ_INT1_DCD_OUT:
0593 case SM5504_IRQ_INT1_OVP_EVENT:
0594 case SM5504_IRQ_INT1_CONNECT:
0595 case SM5504_IRQ_INT1_ADC_CHG:
0596 case SM5504_IRQ_INT2_RID_CHG:
0597 case SM5504_IRQ_INT2_UVLO:
0598 case SM5504_IRQ_INT2_POR:
0599 case SM5504_IRQ_INT2_OVP_FET:
0600 case SM5504_IRQ_INT2_OCP_LATCH:
0601 case SM5504_IRQ_INT2_OCP_EVENT:
0602 case SM5504_IRQ_INT2_OVP_OCP_EVENT:
0603 default:
0604 break;
0605 }
0606
0607 return 0;
0608 }
0609
0610 static irqreturn_t sm5502_muic_irq_handler(int irq, void *data)
0611 {
0612 struct sm5502_muic_info *info = data;
0613 int i, irq_type = -1, ret;
0614
0615 for (i = 0; i < info->type->num_muic_irqs; i++)
0616 if (irq == info->type->muic_irqs[i].virq)
0617 irq_type = info->type->muic_irqs[i].irq;
0618
0619 ret = info->type->parse_irq(info, irq_type);
0620 if (ret < 0) {
0621 dev_warn(info->dev, "cannot handle is interrupt:%d\n",
0622 irq_type);
0623 return IRQ_HANDLED;
0624 }
0625 schedule_work(&info->irq_work);
0626
0627 return IRQ_HANDLED;
0628 }
0629
0630 static void sm5502_muic_detect_cable_wq(struct work_struct *work)
0631 {
0632 struct sm5502_muic_info *info = container_of(to_delayed_work(work),
0633 struct sm5502_muic_info, wq_detcable);
0634 int ret;
0635
0636
0637 ret = sm5502_muic_cable_handler(info, true);
0638 if (ret < 0)
0639 dev_warn(info->dev, "failed to detect cable state\n");
0640 }
0641
0642 static void sm5502_init_dev_type(struct sm5502_muic_info *info)
0643 {
0644 unsigned int reg_data, vendor_id, version_id;
0645 int i, ret;
0646
0647
0648 ret = regmap_read(info->regmap, SM5502_REG_DEVICE_ID, ®_data);
0649 if (ret) {
0650 dev_err(info->dev,
0651 "failed to read DEVICE_ID register: %d\n", ret);
0652 return;
0653 }
0654
0655 vendor_id = ((reg_data & SM5502_REG_DEVICE_ID_VENDOR_MASK) >>
0656 SM5502_REG_DEVICE_ID_VENDOR_SHIFT);
0657 version_id = ((reg_data & SM5502_REG_DEVICE_ID_VERSION_MASK) >>
0658 SM5502_REG_DEVICE_ID_VERSION_SHIFT);
0659
0660 dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n",
0661 version_id, vendor_id);
0662
0663
0664 for (i = 0; i < info->type->num_reg_data; i++) {
0665 unsigned int val = 0;
0666
0667 if (!info->type->reg_data[i].invert)
0668 val |= ~info->type->reg_data[i].val;
0669 else
0670 val = info->type->reg_data[i].val;
0671 regmap_write(info->regmap, info->type->reg_data[i].reg, val);
0672 }
0673 }
0674
0675 static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
0676 {
0677 struct device_node *np = i2c->dev.of_node;
0678 struct sm5502_muic_info *info;
0679 int i, ret, irq_flags;
0680
0681 if (!np)
0682 return -EINVAL;
0683
0684 info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
0685 if (!info)
0686 return -ENOMEM;
0687 i2c_set_clientdata(i2c, info);
0688
0689 info->dev = &i2c->dev;
0690 info->i2c = i2c;
0691 info->irq = i2c->irq;
0692 info->type = device_get_match_data(info->dev);
0693 if (!info->type)
0694 return -EINVAL;
0695 if (!info->type->parse_irq) {
0696 dev_err(info->dev, "parse_irq missing in struct sm5502_type\n");
0697 return -EINVAL;
0698 }
0699
0700 mutex_init(&info->mutex);
0701
0702 INIT_WORK(&info->irq_work, sm5502_muic_irq_work);
0703
0704 info->regmap = devm_regmap_init_i2c(i2c, &sm5502_muic_regmap_config);
0705 if (IS_ERR(info->regmap)) {
0706 ret = PTR_ERR(info->regmap);
0707 dev_err(info->dev, "failed to allocate register map: %d\n",
0708 ret);
0709 return ret;
0710 }
0711
0712
0713 irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
0714 ret = devm_regmap_add_irq_chip(info->dev, info->regmap, info->irq,
0715 irq_flags, 0, info->type->irq_chip,
0716 &info->irq_data);
0717 if (ret != 0) {
0718 dev_err(info->dev, "failed to request IRQ %d: %d\n",
0719 info->irq, ret);
0720 return ret;
0721 }
0722
0723 for (i = 0; i < info->type->num_muic_irqs; i++) {
0724 struct muic_irq *muic_irq = &info->type->muic_irqs[i];
0725 int virq = 0;
0726
0727 virq = regmap_irq_get_virq(info->irq_data, muic_irq->irq);
0728 if (virq <= 0)
0729 return -EINVAL;
0730 muic_irq->virq = virq;
0731
0732 ret = devm_request_threaded_irq(info->dev, virq, NULL,
0733 sm5502_muic_irq_handler,
0734 IRQF_NO_SUSPEND | IRQF_ONESHOT,
0735 muic_irq->name, info);
0736 if (ret) {
0737 dev_err(info->dev,
0738 "failed: irq request (IRQ: %d, error :%d)\n",
0739 muic_irq->irq, ret);
0740 return ret;
0741 }
0742 }
0743
0744
0745 info->edev = devm_extcon_dev_allocate(info->dev, sm5502_extcon_cable);
0746 if (IS_ERR(info->edev)) {
0747 dev_err(info->dev, "failed to allocate memory for extcon\n");
0748 return -ENOMEM;
0749 }
0750
0751
0752 ret = devm_extcon_dev_register(info->dev, info->edev);
0753 if (ret) {
0754 dev_err(info->dev, "failed to register extcon device\n");
0755 return ret;
0756 }
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766 INIT_DELAYED_WORK(&info->wq_detcable, sm5502_muic_detect_cable_wq);
0767 queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
0768 msecs_to_jiffies(DELAY_MS_DEFAULT));
0769
0770
0771 sm5502_init_dev_type(info);
0772
0773 return 0;
0774 }
0775
0776 static const struct sm5502_type sm5502_data = {
0777 .muic_irqs = sm5502_muic_irqs,
0778 .num_muic_irqs = ARRAY_SIZE(sm5502_muic_irqs),
0779 .irq_chip = &sm5502_muic_irq_chip,
0780 .reg_data = sm5502_reg_data,
0781 .num_reg_data = ARRAY_SIZE(sm5502_reg_data),
0782 .otg_dev_type1 = SM5502_REG_DEV_TYPE1_USB_OTG_MASK,
0783 .parse_irq = sm5502_parse_irq,
0784 };
0785
0786 static const struct sm5502_type sm5504_data = {
0787 .muic_irqs = sm5504_muic_irqs,
0788 .num_muic_irqs = ARRAY_SIZE(sm5504_muic_irqs),
0789 .irq_chip = &sm5504_muic_irq_chip,
0790 .reg_data = sm5504_reg_data,
0791 .num_reg_data = ARRAY_SIZE(sm5504_reg_data),
0792 .otg_dev_type1 = SM5504_REG_DEV_TYPE1_USB_OTG_MASK,
0793 .parse_irq = sm5504_parse_irq,
0794 };
0795
0796 static const struct of_device_id sm5502_dt_match[] = {
0797 { .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data },
0798 { .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data },
0799 { .compatible = "siliconmitus,sm5703-muic", .data = &sm5502_data },
0800 { },
0801 };
0802 MODULE_DEVICE_TABLE(of, sm5502_dt_match);
0803
0804 #ifdef CONFIG_PM_SLEEP
0805 static int sm5502_muic_suspend(struct device *dev)
0806 {
0807 struct i2c_client *i2c = to_i2c_client(dev);
0808 struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
0809
0810 enable_irq_wake(info->irq);
0811
0812 return 0;
0813 }
0814
0815 static int sm5502_muic_resume(struct device *dev)
0816 {
0817 struct i2c_client *i2c = to_i2c_client(dev);
0818 struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
0819
0820 disable_irq_wake(info->irq);
0821
0822 return 0;
0823 }
0824 #endif
0825
0826 static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops,
0827 sm5502_muic_suspend, sm5502_muic_resume);
0828
0829 static const struct i2c_device_id sm5502_i2c_id[] = {
0830 { "sm5502", (kernel_ulong_t)&sm5502_data },
0831 { "sm5504", (kernel_ulong_t)&sm5504_data },
0832 { "sm5703-muic", (kernel_ulong_t)&sm5502_data },
0833 { }
0834 };
0835 MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id);
0836
0837 static struct i2c_driver sm5502_muic_i2c_driver = {
0838 .driver = {
0839 .name = "sm5502",
0840 .pm = &sm5502_muic_pm_ops,
0841 .of_match_table = sm5502_dt_match,
0842 },
0843 .probe_new = sm5022_muic_i2c_probe,
0844 .id_table = sm5502_i2c_id,
0845 };
0846
0847 static int __init sm5502_muic_i2c_init(void)
0848 {
0849 return i2c_add_driver(&sm5502_muic_i2c_driver);
0850 }
0851 subsys_initcall(sm5502_muic_i2c_init);
0852
0853 MODULE_DESCRIPTION("Silicon Mitus SM5502 Extcon driver");
0854 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
0855 MODULE_LICENSE("GPL");