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