static void max14577_muic_irq_work(struct work_struct *work) { struct max14577_muic_info *info = container_of(work, struct max14577_muic_info, irq_work); int ret = 0; if (!info->edev) return; mutex_lock(&info->mutex); ret = max14577_bulk_read(info->max14577->regmap, MAX14577_MUIC_REG_STATUS1, info->status, 2); if (ret) { dev_err(info->dev, "failed to read MUIC register\n"); mutex_unlock(&info->mutex); return; } if (info->irq_adc) { ret = max14577_muic_adc_handler(info); info->irq_adc = false; } if (info->irq_chg) { ret = max14577_muic_chg_handler(info); info->irq_chg = false; } if (ret < 0) dev_err(info->dev, "failed to handle MUIC interrupt\n"); mutex_unlock(&info->mutex); }
static ssize_t max14577_muic_show_dump_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct max14577_muic_data *muic_data = dev_get_drvdata(dev); u8 stat[3] = {0}; u8 ctrl[3] = {0}; u8 cdet[2] = {0}; max14577_bulk_read(muic_data->i2c, MAX14577_MUIC_REG_STATUS1, 3, stat); max14577_bulk_read(muic_data->i2c, MAX14577_MUIC_REG_CONTROL1, 3, ctrl); max14577_bulk_read(muic_data->i2c, MAX14577_REG_CDETCTRL1, 2, cdet); return sprintf(buf, "reg : 1 / 2 / 3 \n" "stat: 0x%02x / 0x%02x / 0x%02x\n" "ctrl: 0x%02x / 0x%02x / 0x%02x\n" "cdet: 0x%02x / 0x%02x /\n", stat[0], stat[1], stat[2], ctrl[0], ctrl[1], ctrl[2], cdet[0], cdet[1]); }
static irqreturn_t max14577_irq_thread(int irq, void *data) { struct max14577_dev *max14577 = data; struct max14577_platform_data *pdata = max14577->pdata; u8 irq_reg[MAX14577_IRQ_REGS_NUM] = {0}; u8 tmp_irq_reg[MAX14577_IRQ_REGS_NUM] = {}; int gpio_val; int i; pr_debug("%s: irq gpio pre-state(0x%02x)\n", __func__, gpio_get_value(pdata->irq_gpio)); do { /* MAX14577 INT1 ~ INT3 */ max14577_bulk_read(max14577->i2c, MAX14577_REG_INT1, MAX14577_IRQ_REGS_NUM, &tmp_irq_reg[MAX14577_IRQ_INT1]); /* Or temp irq register to irq register for if it retries */ for (i = MAX14577_IRQ_INT1; i < MAX14577_IRQ_REGS_NUM; i++) irq_reg[i] |= tmp_irq_reg[i]; pr_info("%s: interrupt[1:0x%02x, 2:0x%02x, 3:0x%02x]\n", __func__, irq_reg[MAX14577_IRQ_INT1], irq_reg[MAX14577_IRQ_INT2], irq_reg[MAX14577_IRQ_INT3]); gpio_val = gpio_get_value(pdata->irq_gpio); pr_debug("%s: irq gpio post-state(0x%02x)\n", __func__, gpio_val); if (gpio_get_value(pdata->irq_gpio) == 0) pr_warn("%s: irq_gpio is not High, retry read int reg\n", __func__); } while (gpio_val == 0); /* Apply masking */ for (i = 0; i < MAX14577_IRQ_REGS_NUM; i++) irq_reg[i] &= max14577->irq_masks_cur[i]; /* Report */ for (i = 0; i < MAX14577_IRQ_NUM; i++) { if (irq_reg[max14577_irqs[i].group] & max14577_irqs[i].mask) handle_nested_irq(pdata->irq_base + i); } return IRQ_HANDLED; }
static int max14577_muic_detect_accessory(struct max14577_muic_info *info) { int ret = 0; int adc; int chg_type; bool attached; mutex_lock(&info->mutex); /* Read STATUSx register to detect accessory */ ret = max14577_bulk_read(info->max14577->regmap, MAX14577_MUIC_REG_STATUS1, info->status, 2); if (ret) { dev_err(info->dev, "failed to read MUIC register\n"); mutex_unlock(&info->mutex); return ret; } adc = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_ADC, &attached); if (attached && adc != MAX14577_MUIC_ADC_OPEN) { ret = max14577_muic_adc_handler(info); if (ret < 0) { dev_err(info->dev, "Cannot detect accessory\n"); mutex_unlock(&info->mutex); return ret; } } chg_type = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_CHG, &attached); if (attached && chg_type != MAX14577_CHARGER_TYPE_NONE) { ret = max14577_muic_chg_handler(info); if (ret < 0) { dev_err(info->dev, "Cannot detect charger accessory\n"); mutex_unlock(&info->mutex); return ret; } } mutex_unlock(&info->mutex); return 0; }
static void max14577_muic_detect_dev(struct max14577_muic_data *muic_data, int irq) { struct i2c_client *i2c = muic_data->i2c; const struct max14577_muic_vps_data *tmp_vps; muic_attached_dev_t new_dev = ATTACHED_DEV_UNKNOWN_MUIC; int intr = MUIC_INTR_DETACH; u8 status[2]; u8 adcerr, adclow, adc, vbvolt, chgdetrun, chgtyp; int ret; int i; ret = max14577_bulk_read(i2c, MAX14577_MUIC_REG_STATUS1, 2, status); if (ret) { pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_DEV_NAME, __func__, ret); return; } pr_info("%s:%s STATUS1:0x%02x, 2:0x%02x\n", MUIC_DEV_NAME, __func__, status[0], status[1]); adcerr = status[0] & STATUS1_ADCERR_MASK; adclow = status[0] & STATUS1_ADCLOW_MASK; adc = status[0] & STATUS1_ADC_MASK; vbvolt = status[1] & STATUS2_VBVOLT_MASK; chgdetrun = status[1] & STATUS2_CHGDETRUN_MASK; chgtyp = status[1] & STATUS2_CHGTYP_MASK; pr_info("%s:%s adcerr:0x%x adclow:0x%x adc:0x%x vb:0x%x chgdetrun:0x%x" " chgtyp:0x%x\n", MUIC_DEV_NAME, __func__, adcerr, adclow, adc, vbvolt, chgdetrun, chgtyp); /* Workaround for Factory mode. * Abandon adc interrupt of approximately +-100K range * if previous cable status was JIG UART BOOT OFF. */ if (muic_data->attached_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC) { if ((adc == (ADC_JIG_UART_OFF + 1)) || (adc == (ADC_JIG_UART_OFF - 1))) { pr_warn("%s:%s abandon ADC\n", MUIC_DEV_NAME, __func__); return; } } for (i = 0; i < ARRAY_SIZE(muic_vps_table); i++) { tmp_vps = &(muic_vps_table[i]); if (tmp_vps->adcerr != adcerr) continue; if (tmp_vps->adclow != adclow) continue; if (tmp_vps->adc != adc) continue; if (tmp_vps->vbvolt != vbvolt) continue; if (tmp_vps->chgdetrun != chgdetrun) continue; if (tmp_vps->chgtyp != chgtyp) continue; pr_info("%s:%s vps table match found at i(%d), %s\n", MUIC_DEV_NAME, __func__, i, tmp_vps->vps_name); new_dev = tmp_vps->attached_dev; intr = MUIC_INTR_ATTACH; break; } if (intr == MUIC_INTR_ATTACH) { pr_info("%s:%s ATTACHED\n", MUIC_DEV_NAME, __func__); max14577_muic_handle_attach(muic_data, new_dev); } else { pr_info("%s:%s DETACHED\n", MUIC_DEV_NAME, __func__); max14577_muic_handle_detach(muic_data); } return; }