/* TODO: remove this function later */ static int max8997_enable_charging_x(struct chg_data *chg, int charge_type) { struct i2c_client *i2c = chg->max8997->i2c; int ret; u8 val, mask; /* enable charging */ if (charge_type == POWER_SUPPLY_CHARGE_TYPE_FAST) { /* ac */ dev_info(chg->dev, "%s: TA charging", __func__); /* set fast charging current : 650mA */ ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL4, (9 << MBCICHFC_SHIFT), MBCICHFC_MASK); if (ret) goto err; } else if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TRICKLE) { /* usb */ dev_info(chg->dev, "%s: USB charging", __func__); /* set fast charging current : 450mA */ ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL4, (5 << MBCICHFC_SHIFT), MBCICHFC_MASK); if (ret) goto err; } else { dev_err(chg->dev, "%s: invalid arg\n", __func__); ret = -EINVAL; goto err; } /* set auto stop disable */ ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL6, (0 << AUTOSTOP_SHIFT), AUTOSTOP_MASK); if (ret) goto err; /* set fast charging enable and main battery charging enable */ val = (1 << MBCHOSTEN_SHIFT) | (1 << VCHGR_FC_SHIFT); mask = MBCHOSTEN_MASK | VCHGR_FC_MASK; ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL2, val, mask); if (ret) goto err; return 0; err: dev_err(chg->dev, "%s: max8997 update reg error!(%d)\n", __func__, ret); return ret; }
static int max8997_muic_handle_dock(struct max8997_muic_info *info, int adc, bool attached) { struct max8997_muic_platform_data *mdata = info->muic_pdata; int ret = 0; ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN, SW_MASK); if (ret) { dev_err(info->dev, "failed to update muic register\n"); goto out; } switch (adc) { case MAX8997_ADC_DESKDOCK: if (mdata->deskdock_callback) mdata->deskdock_callback(attached); break; case MAX8997_ADC_CARDOCK: if (mdata->cardock_callback) mdata->cardock_callback(attached); break; default: break; } out: return ret; }
/* * max8997_muic_set_debounce_time - Set the debounce time of ADC * @info: the instance including private data of max8997 MUIC * @time: the debounce time of ADC */ static int max8997_muic_set_debounce_time(struct max8997_muic_info *info, enum max8997_muic_adc_debounce_time time) { int ret; switch (time) { case ADC_DEBOUNCE_TIME_0_5MS: case ADC_DEBOUNCE_TIME_10MS: case ADC_DEBOUNCE_TIME_25MS: case ADC_DEBOUNCE_TIME_38_62MS: ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL3, time << CONTROL3_ADCDBSET_SHIFT, CONTROL3_ADCDBSET_MASK); if (ret) { dev_err(info->dev, "failed to set ADC debounce time\n"); return ret; } break; default: dev_err(info->dev, "invalid ADC debounce time\n"); return -EINVAL; } return 0; };
static ssize_t max8997_muic_set_audio_path(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct max8997_muic_info *info = dev_get_drvdata(dev); struct i2c_client *client = info->muic; u8 cntl1_val, cntl1_msk; u8 val; if (!strncmp(buf, "0", 1)) val = 0; else if (!strncmp(buf, "1", 1)) val = 2; else { dev_warn(info->dev, "%s: Wrong command\n", __func__); return count; } cntl1_val = (val << COMN1SW_SHIFT) | (val << COMP2SW_SHIFT) | (0 << MICEN_SHIFT); cntl1_msk = COMN1SW_MASK | COMP2SW_MASK | MICEN_MASK; max8997_update_reg(client, MAX8997_MUIC_REG_CTRL1, cntl1_val, cntl1_msk); cntl1_val = 0; max8997_read_reg(client, MAX8997_MUIC_REG_CTRL1, &cntl1_val); dev_info(info->dev, "%s: CNTL1(0x%02x)\n", __func__, cntl1_val); return count; }
static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable) { int ret; u8 val, mask; if (!smpl_en) return; if (enable) val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); else val = 0; mask = SMPL_EN_MASK | SMPLT_MASK; dev_info(info->dev, "%s: %s SMPL\n", __func__, enable ? "enable" : "disable"); ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); if (ret < 0) { dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", __func__, ret); return; } max8997_rtc_set_update_reg(info); val = 0; max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val); pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); }
static void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable) { int ret; u8 val, mask; if (!wtsr_en) return; if (enable) val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); else val = 0; mask = WTSR_EN_MASK | WTSRT_MASK; dev_info(info->dev, "%s: %s WTSR\n", __func__, enable ? "enable" : "disable"); ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); if (ret < 0) { dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", __func__, ret); return; } max8997_rtc_set_update_reg(info); }
static void max8997_led_set_current(struct max8997_led *led, enum led_brightness value) { int ret; struct i2c_client *client = led->iodev->i2c; u8 val = 0, mask = 0, reg = 0; switch (led->led_mode) { case MAX8997_FLASH_MODE: case MAX8997_FLASH_PIN_CONTROL_MODE: val = value << MAX8997_LED_FLASH_SHIFT; mask = MAX8997_LED_FLASH_CUR_MASK; reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR; break; case MAX8997_MOVIE_MODE: case MAX8997_MOVIE_PIN_CONTROL_MODE: val = value << MAX8997_LED_MOVIE_SHIFT; mask = MAX8997_LED_MOVIE_CUR_MASK; reg = MAX8997_REG_MOVIE_CUR; break; default: break; } if (mask) { ret = max8997_update_reg(client, reg, val, mask); if (ret) dev_err(led->iodev->dev, "failed to update register(%d)\n", ret); } }
static ssize_t max8997_muic_set_otg_test(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct max8997_muic_info *info = dev_get_drvdata(dev); struct i2c_client *client = info->muic; u8 val; if (!strncmp(buf, "0", 1)) val = 0; else if (!strncmp(buf, "1", 1)) val = 1; else { dev_warn(info->dev, "%s: Wrong command\n", __func__); return count; } max8997_update_reg(client, MAX8997_MUIC_REG_CDETCTRL, val << CHGDETEN_SHIFT, CHGDETEN_MASK); val = 0; max8997_read_reg(client, MAX8997_MUIC_REG_CDETCTRL, &val); dev_info(info->dev, "%s: CDETCTRL(0x%02x)\n", __func__, val); return count; }
static int max8997_disable_charging(struct chg_data *chg) { struct i2c_client *i2c = chg->max8997->i2c; int ret; u8 mask; dev_info(chg->dev, "%s: disable charging\n", __func__); mask = MBCHOSTEN_MASK | VCHGR_FC_MASK; ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL2, 0, mask); if (ret < 0) dev_err(chg->dev, "%s: fail update reg!!!\n", __func__); return ret; }
static int max8997_enable_charging(struct chg_data *chg) { struct i2c_client *i2c = chg->max8997->i2c; int ret; u8 val, mask; /* set auto stop disable */ ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL6, (0 << AUTOSTOP_SHIFT), AUTOSTOP_MASK); if (ret) dev_err(chg->dev, "%s: failt to disable autostop(%d)\n", __func__, ret); /* set fast charging enable and main battery charging enable */ val = (1 << MBCHOSTEN_SHIFT) | (1 << VCHGR_FC_SHIFT); mask = MBCHOSTEN_MASK | VCHGR_FC_MASK; ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL2, val, mask); if (ret) dev_err(chg->dev, "%s: failt to enable charging(%d)\n", __func__, ret); return ret; }
/* * max8997_muic_set_path - Set hardware line according to attached cable * @info: the instance including private data of max8997 MUIC * @value: the path according to attached cable * @attached: the state of cable (true:attached, false:detached) * * The max8997 MUIC device share outside H/W line among a varity of cables, * so this function set internal path of H/W line according to the type of * attached cable. */ static int max8997_muic_set_path(struct max8997_muic_info *info, u8 val, bool attached) { int ret = 0; u8 ctrl1, ctrl2 = 0; if (attached) ctrl1 = val; else ctrl1 = CONTROL1_SW_OPEN; ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK); if (ret < 0) { dev_err(info->dev, "failed to update MUIC register\n"); return ret; } if (attached) ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */ else ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */ ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL2, ctrl2, CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK); if (ret < 0) { dev_err(info->dev, "failed to update MUIC register\n"); return ret; } dev_info(info->dev, "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n", ctrl1, ctrl2, attached ? "attached" : "detached"); return 0; }
static void max8997_led_set_mode(struct max8997_led *led, enum max8997_led_mode mode) { int ret; struct i2c_client *client = led->iodev->i2c; u8 mask = 0, val; switch (mode) { case MAX8997_FLASH_MODE: mask = MAX8997_LED1_FLASH_MASK | MAX8997_LED0_FLASH_MASK; val = led->id ? MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; break; case MAX8997_MOVIE_MODE: mask = MAX8997_LED1_MOVIE_MASK | MAX8997_LED0_MOVIE_MASK; val = led->id ? MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; break; case MAX8997_FLASH_PIN_CONTROL_MODE: mask = MAX8997_LED1_FLASH_PIN_MASK | MAX8997_LED0_FLASH_PIN_MASK; val = led->id ? MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; break; case MAX8997_MOVIE_PIN_CONTROL_MODE: mask = MAX8997_LED1_MOVIE_PIN_MASK | MAX8997_LED0_MOVIE_PIN_MASK; val = led->id ? MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; break; default: led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS; break; } if (mask) { ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val, mask); if (ret) dev_err(led->iodev->dev, "failed to update register(%d)\n", ret); } led->led_mode = mode; }
static int max8997_chg_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { int ret, reg_val; struct chg_data *chg = container_of(psy, struct chg_data, psy_bat); struct i2c_client *i2c = chg->max8997->i2c; switch (psp) { case POWER_SUPPLY_PROP_CHARGE_TYPE: /* TODO: remove this */ if (val->intval == POWER_SUPPLY_CHARGE_TYPE_NONE) ret = max8997_disable_charging(chg); else ret = max8997_enable_charging_x(chg, val->intval); break; case POWER_SUPPLY_PROP_CURRENT_NOW: /* Set charging current */ ret = max8997_set_charging_current(chg, val->intval); break; case POWER_SUPPLY_PROP_STATUS: /* Enable/Disable charging */ if (val->intval == POWER_SUPPLY_STATUS_CHARGING) ret = max8997_enable_charging(chg); else ret = max8997_disable_charging(chg); break; case POWER_SUPPLY_PROP_CHARGE_FULL: /* Set recharging current */ if (val->intval < 50 || val->intval > 200) { dev_err(chg->dev, "%s: invalid topoff current(%d)\n", __func__, val->intval); return -EINVAL; } reg_val = (val->intval - 50) / 10; dev_info(chg->dev, "%s: Set toppoff current to 0x%x\n", __func__, reg_val); ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL5, (reg_val << ITOPOFF_SHIFT), ITOPOFF_MASK); if (ret) { dev_err(chg->dev, "%s: max8997 update reg error(%d)\n", __func__, ret); return ret; } break; default: return -EINVAL; } return ret; }
static void max8997_muic_handle_jig_uart(struct max8997_muic_info *info, u8 vbvolt) { struct max8997_muic_data *mdata = info->muic_data; enum cable_type prev_ct = info->cable_type; bool is_otgtest = false; u8 cntl1_val, cntl1_msk; dev_info(info->dev, "%s: JIG UART/BOOTOFF(0x%x)\n", __func__, vbvolt); #if defined(CONFIG_SEC_MODEM_M0_TD) gpio_set_value(GPIO_AP_CP_INT1, 1); #endif /* UT1, UR2 */ cntl1_val = (3 << COMN1SW_SHIFT) | (3 << COMP2SW_SHIFT); cntl1_msk = COMN1SW_MASK | COMP2SW_MASK; max8997_update_reg(info->muic, MAX8997_MUIC_REG_CTRL1, cntl1_val, cntl1_msk); if (vbvolt & STATUS2_VBVOLT_MASK) { if (mdata->host_notify_cb) { if (mdata->host_notify_cb(1) == NOTIFY_TEST_MODE) { is_otgtest = true; dev_info(info->dev, "%s: OTG TEST\n", __func__); } } info->cable_type = CABLE_TYPE_JIG_UART_OFF_VB; max8997_muic_set_charging_type(info, is_otgtest); } else { info->cable_type = CABLE_TYPE_JIG_UART_OFF; #if 0 if (mdata->uart_path == UART_PATH_CP && mdata->jig_uart_cb) mdata->jig_uart_cb(UART_PATH_CP); #endif if (prev_ct == CABLE_TYPE_JIG_UART_OFF_VB) { max8997_muic_set_charging_type(info, false); if (mdata->host_notify_cb) mdata->host_notify_cb(0); } } }
static void max8997_led_enable(struct max8997_led *led, bool enable) { int ret; struct i2c_client *client = led->iodev->i2c; u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK; if (led->enabled == enable) return; val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0; ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask); if (ret) dev_err(led->iodev->dev, "failed to update register(%d)\n", ret); led->enabled = enable; }
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, bool attached) { struct max8997_muic_platform_data *mdata = info->muic_pdata; int ret = 0; ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, attached ? MAX8997_SW_UART : MAX8997_SW_OPEN, SW_MASK); if (ret) { dev_err(info->dev, "failed to update muic register\n"); goto out; } if (mdata->uart_callback) mdata->uart_callback(attached); out: return ret; }
static int max8997_set_charging_current(struct chg_data *chg, int chg_current) { struct i2c_client *i2c = chg->max8997->i2c; int ret; u8 val; if (chg_current < 200 || chg_current > 950) return -EINVAL; val = ((chg_current - 200) / 50) & 0xf; dev_info(chg->dev, "%s: charging current=%d", __func__, chg_current); ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL4, (val << MBCICHFC_SHIFT), MBCICHFC_MASK); if (ret) dev_err(chg->dev, "%s: fail to write chg current(%d)\n", __func__, ret); return ret; }
void max8997_muic_shutdown(struct device *dev) { struct max8997_muic_info *info = dev_get_drvdata(dev); int ret; u8 val; if (!info->muic) { dev_err(info->dev, "%s: no muic i2c client\n", __func__); return; } dev_info(info->dev, "%s: JIGSet: auto detection\n", __func__); val = (0 << CTRL3_JIGSET_SHIFT) | (0 << CTRL3_BOOTSET_SHIFT); ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CTRL3, val, CTRL3_JIGSET_MASK | CTRL3_BOOTSET_MASK); if (ret < 0) { dev_err(info->dev, "%s: fail to update reg\n", __func__); return; } }
static int max8997_muic_handle_usb(struct max8997_muic_info *info, enum max8997_muic_usb_type usb_type, bool attached) { struct max8997_muic_platform_data *mdata = info->muic_pdata; int ret = 0; if (usb_type == MAX8997_USB_HOST) { ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, attached ? MAX8997_SW_USB : MAX8997_SW_OPEN, SW_MASK); if (ret) { dev_err(info->dev, "failed to update muic register\n"); goto out; } } if (mdata->usb_callback) mdata->usb_callback(usb_type, attached); out: return ret; }
static void max8997_led_clear_mode(struct max8997_led *led, enum max8997_led_mode mode) { struct i2c_client *client = led->iodev->i2c; u8 val = 0, mask = 0; int ret; switch (mode) { case MAX8997_FLASH_MODE: mask = led->id ? MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; break; case MAX8997_MOVIE_MODE: mask = led->id ? MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; break; case MAX8997_FLASH_PIN_CONTROL_MODE: mask = led->id ? MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; break; case MAX8997_MOVIE_PIN_CONTROL_MODE: mask = led->id ? MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; break; default: break; } if (mask) { ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val, mask); if (ret) dev_err(led->iodev->dev, "failed to update register(%d)\n", ret); } }
static void max8997_muic_set_adcdbset(struct max8997_muic_info *info, int value) { int ret; u8 val; if (value > 3) { dev_err(info->dev, "%s: invalid value(%d)\n", __func__, value); return; } if (!info->muic) { dev_err(info->dev, "%s: no muic i2c client\n", __func__); return; } val = value << CTRL3_ADCDBSET_SHIFT; dev_info(info->dev, "%s: ADCDBSET(0x%02x)\n", __func__, val); ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CTRL3, val, CTRL3_ADCDBSET_MASK); if (ret < 0) dev_err(info->dev, "%s: fail to update reg\n", __func__); }
static int max8997_muic_set_usb_path(struct max8997_muic_info *info, int path) { struct i2c_client *client = info->muic; struct max8997_muic_data *mdata = info->muic_data; int ret; int gpio_val; u8 accdet, cntl1_val, cntl1_msk = 0, cntl2_val; if (mdata->set_safeout) { ret = mdata->set_safeout(path); if (ret) { dev_err(info->dev, "%s: fail to set safout!\n", __func__); return ret; } } switch (path) { case AP_USB_MODE: dev_info(info->dev, "%s: AP_USB_MODE\n", __func__); gpio_val = 0; accdet = 1; if (info->cable_type == CABLE_TYPE_OTG) { accdet = 0; /* DN1, DP2 */ cntl1_val = (1 << COMN1SW_SHIFT) | (1 << COMP2SW_SHIFT); cntl1_msk = COMN1SW_MASK | COMP2SW_MASK; } break; case CP_USB_MODE: dev_info(info->dev, "%s: CP_USB_MODE\n", __func__); gpio_val = 1; accdet = 0; /* UT1, UR2 */ cntl1_val = (3 << COMN1SW_SHIFT) | (3 << COMP2SW_SHIFT); cntl1_msk = COMN1SW_MASK | COMP2SW_MASK; break; case AUDIO_MODE: dev_info(info->dev, "%s: AUDIO_MODE\n", __func__); gpio_val = 0; accdet = 0; /* SL1, SR2 */ cntl1_val = (2 << COMN1SW_SHIFT) | (2 << COMP2SW_SHIFT) | (0 << MICEN_SHIFT); cntl1_msk = COMN1SW_MASK | COMP2SW_MASK | MICEN_MASK; break; default: dev_warn(info->dev, "%s: invalid path(%d)\n", __func__, path); return -EINVAL; } #if !defined(CONFIG_TARGET_LOCALE_NA) && !defined(CONFIG_MACH_U1CAMERA_BD) if (gpio_is_valid(info->muic_data->gpio_usb_sel)) gpio_direction_output(mdata->gpio_usb_sel, gpio_val); #endif /* !CONFIG_TARGET_LOCALE_NA && !CONFIG_MACH_U1CAMERA_BD */ /* Enable/Disable Factory Accessory Detection State Machine */ cntl2_val = accdet << CTRL2_ACCDET_SHIFT; max8997_update_reg(client, MAX8997_MUIC_REG_CTRL2, cntl2_val, CTRL2_ACCDET_MASK); if (!accdet) { dev_info(info->dev, "%s: Set manual path\n", __func__); max8997_update_reg(client, MAX8997_MUIC_REG_CTRL1, cntl1_val, cntl1_msk); cntl1_val = 0; max8997_read_reg(client, MAX8997_MUIC_REG_CTRL1, &cntl1_val); dev_info(info->dev, "%s: CNTL1(0x%02x)\n", __func__, cntl1_val); } return 0; }
static int max8997_muic_handle_detach(struct max8997_muic_info *info) { struct i2c_client *client = info->muic; struct max8997_muic_data *mdata = info->muic_data; cable_type_t prev_ct = CABLE_TYPE_NONE; int ret = 0; /* Workaround: irq doesn't occur after detaching mHL cable */ max8997_write_reg(client, MAX8997_MUIC_REG_CTRL1, 0x00); /* Enable Factory Accessory Detection State Machine */ max8997_update_reg(client, MAX8997_MUIC_REG_CTRL2, (1 << CTRL2_ACCDET_SHIFT), CTRL2_ACCDET_MASK); info->previous_key = DOCK_KEY_NONE; if (info->cable_type == CABLE_TYPE_NONE) { dev_info(info->dev, "%s: duplicated(NONE)\n", __func__); return 0; } #if 0 if (mdata->jig_uart_cb) mdata->jig_uart_cb(UART_PATH_AP); #endif if (mdata->is_mhl_attached && mdata->is_mhl_attached() && info->cable_type == CABLE_TYPE_MHL) { dev_info(info->dev, "%s: MHL attached. Do Nothing\n", __func__); return 0; } switch (info->cable_type) { case CABLE_TYPE_OTG: dev_info(info->dev, "%s: OTG\n", __func__); info->cable_type = CABLE_TYPE_NONE; if (mdata->usb_cb && info->is_usb_ready) mdata->usb_cb(USB_OTGHOST_DETACHED); break; case CABLE_TYPE_USB: case CABLE_TYPE_JIG_USB_OFF: case CABLE_TYPE_JIG_USB_ON: dev_info(info->dev, "%s: USB(0x%x)\n", __func__, info->cable_type); prev_ct = info->cable_type; info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) { info->cable_type = prev_ct; break; } if (mdata->sw_path == CP_USB_MODE) return 0; if (mdata->usb_cb && info->is_usb_ready) mdata->usb_cb(USB_CABLE_DETACHED); break; case CABLE_TYPE_DESKDOCK: dev_info(info->dev, "%s: DESKDOCK\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) { info->cable_type = CABLE_TYPE_DESKDOCK; break; } if (mdata->deskdock_cb) mdata->deskdock_cb(MAX8997_MUIC_DETACHED); break; case CABLE_TYPE_CARDOCK: dev_info(info->dev, "%s: CARDOCK\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) { info->cable_type = CABLE_TYPE_CARDOCK; break; } if (mdata->cardock_cb) mdata->cardock_cb(MAX8997_MUIC_DETACHED); break; case CABLE_TYPE_TA: dev_info(info->dev, "%s: TA\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) info->cable_type = CABLE_TYPE_TA; break; case CABLE_TYPE_JIG_UART_ON: dev_info(info->dev, "%s: JIG UART/BOOTON\n", __func__); info->cable_type = CABLE_TYPE_NONE; break; case CABLE_TYPE_JIG_UART_OFF: dev_info(info->dev, "%s: JIG UART/BOOTOFF\n", __func__); info->cable_type = CABLE_TYPE_NONE; break; case CABLE_TYPE_JIG_UART_OFF_VB: dev_info(info->dev, "%s: JIG UART/OFF/VB\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) info->cable_type = CABLE_TYPE_JIG_UART_OFF_VB; break; case CABLE_TYPE_MHL: dev_info(info->dev, "%s: MHL\n", __func__); info->cable_type = CABLE_TYPE_NONE; break; case CABLE_TYPE_MHL_VB: dev_info(info->dev, "%s: MHL VBUS\n", __func__); info->cable_type = CABLE_TYPE_NONE; max8997_muic_set_charging_type(info, false); if (mdata->is_mhl_attached && mdata->is_mhl_attached()) { if (mdata->mhl_cb && info->is_mhl_ready) mdata->mhl_cb(MAX8997_MUIC_DETACHED); } break; case CABLE_TYPE_UNKNOWN: dev_info(info->dev, "%s: UNKNOWN\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) info->cable_type = CABLE_TYPE_UNKNOWN; break; default: dev_info(info->dev, "%s:invalid cable type %d\n", __func__, info->cable_type); break; } return ret; }
static int max8997_muic_handle_detach(struct max8997_muic_info *info) { struct i2c_client *client = info->muic; struct max8997_muic_data *mdata = info->muic_data; enum cable_type prev_ct = CABLE_TYPE_NONE; int ret = 0; #if defined(CONFIG_SEC_MODEM_M0_TD) gpio_set_value(GPIO_AP_CP_INT1, 0); #endif /* * MAX8996/8997-MUIC bug: * * Auto-switching COMN/P is not restored automatically when detached and * remains undetermined state. UART(UT1, UR2) will be short (because TA * D+/D- is short) if charger(TA) insertion is followed right after the * JIG off. Reset CONTROL1 is needed when detaching cable. */ max8997_write_reg(client, MAX8997_MUIC_REG_CTRL1, 0x00); if (info->cable_type == CABLE_TYPE_MHL) { /* Enable Factory Accessory Detection State Machine */ max8997_update_reg(client, MAX8997_MUIC_REG_CTRL2, (1 << CTRL2_ACCDET_SHIFT), CTRL2_ACCDET_MASK); } #ifdef CONFIG_USBHUB_USB3803 /* setting usb hub in default mode (standby) */ usb3803_set_mode(USB_3803_MODE_STANDBY); #endif /* CONFIG_USBHUB_USB3803 */ info->previous_key = DOCK_KEY_NONE; if (info->cable_type == CABLE_TYPE_NONE) { dev_info(info->dev, "%s: duplicated(NONE)\n", __func__); return 0; } #if 0 if (mdata->jig_uart_cb) mdata->jig_uart_cb(UART_PATH_AP); #endif if (mdata->is_mhl_attached && mdata->is_mhl_attached() && info->cable_type == CABLE_TYPE_MHL) { dev_info(info->dev, "%s: MHL attached. Do Nothing\n", __func__); return 0; } switch (info->cable_type) { case CABLE_TYPE_OTG: dev_info(info->dev, "%s: OTG\n", __func__); info->cable_type = CABLE_TYPE_NONE; if (mdata->usb_cb && info->is_usb_ready) mdata->usb_cb(USB_OTGHOST_DETACHED); break; case CABLE_TYPE_USB: case CABLE_TYPE_JIG_USB_OFF: case CABLE_TYPE_JIG_USB_ON: dev_info(info->dev, "%s: USB(0x%x)\n", __func__, info->cable_type); prev_ct = info->cable_type; info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) { info->cable_type = prev_ct; break; } if (mdata->sw_path == CP_USB_MODE) return 0; if (mdata->usb_cb && info->is_usb_ready) mdata->usb_cb(USB_CABLE_DETACHED); break; case CABLE_TYPE_DESKDOCK: dev_info(info->dev, "%s: DESKDOCK\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) { info->cable_type = CABLE_TYPE_DESKDOCK; break; } if (mdata->deskdock_cb) mdata->deskdock_cb(MAX8997_MUIC_DETACHED); break; case CABLE_TYPE_CARDOCK: dev_info(info->dev, "%s: CARDOCK\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) { info->cable_type = CABLE_TYPE_CARDOCK; break; } if (mdata->cardock_cb) mdata->cardock_cb(MAX8997_MUIC_DETACHED); break; case CABLE_TYPE_TA: dev_info(info->dev, "%s: TA\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) info->cable_type = CABLE_TYPE_TA; break; case CABLE_TYPE_JIG_UART_ON: dev_info(info->dev, "%s: JIG UART/BOOTON\n", __func__); info->cable_type = CABLE_TYPE_NONE; break; case CABLE_TYPE_JIG_UART_OFF: dev_info(info->dev, "%s: JIG UART/BOOTOFF\n", __func__); info->cable_type = CABLE_TYPE_NONE; break; case CABLE_TYPE_JIG_UART_OFF_VB: dev_info(info->dev, "%s: JIG UART/OFF/VB\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) info->cable_type = CABLE_TYPE_JIG_UART_OFF_VB; break; case CABLE_TYPE_MHL: dev_info(info->dev, "%s: MHL\n", __func__); info->cable_type = CABLE_TYPE_NONE; break; case CABLE_TYPE_MHL_VB: dev_info(info->dev, "%s: MHL VBUS\n", __func__); info->cable_type = CABLE_TYPE_NONE; max8997_muic_set_charging_type(info, false); if (mdata->is_mhl_attached && mdata->is_mhl_attached()) { if (mdata->mhl_cb && info->is_mhl_ready) mdata->mhl_cb(MAX8997_MUIC_DETACHED); } break; case CABLE_TYPE_UNKNOWN: dev_info(info->dev, "%s: UNKNOWN\n", __func__); info->cable_type = CABLE_TYPE_NONE; ret = max8997_muic_set_charging_type(info, false); if (ret) info->cable_type = CABLE_TYPE_UNKNOWN; break; default: dev_info(info->dev, "%s:invalid cable type %d\n", __func__, info->cable_type); break; } return ret; }
static __devinit int max8997_charger_probe(struct platform_device *pdev) { struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); struct i2c_client *i2c = max8997->i2c; struct chg_data *chg; int ret = 0; dev_info(&pdev->dev, "%s : MAX8997 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->dev = &pdev->dev; chg->max8997 = max8997; chg->power = pdata->power; chg->irq_topoff = max8997->irq_base + MAX8997_IRQ_TOPOFF; chg->irq_chgins = max8997->irq_base + MAX8997_IRQ_CHGINS; chg->irq_chgrm = max8997->irq_base + MAX8997_IRQ_CHGRM; chg->psy_bat.name = "max8997-charger", chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, chg->psy_bat.properties = max8997_battery_props, chg->psy_bat.num_properties = ARRAY_SIZE(max8997_battery_props), chg->psy_bat.get_property = max8997_chg_get_property, chg->psy_bat.set_property = max8997_chg_set_property, platform_set_drvdata(pdev, chg); /* TODO: configure by platform data*/ ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1, /* Disable */ (0x7 << TFCH_SHIFT), TFCH_MASK); if (ret < 0) goto err_kfree; /* TODO: configure by platform data*/ ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL3, /* 4.2V */ (0x0 << MBCCV_SHIFT), MBCCV_MASK); if (ret < 0) goto err_kfree; /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("Failed to register power supply psy_bat\n"); goto err_kfree; } ret = request_threaded_irq(chg->irq_topoff, NULL, max8997_chg_topoff_irq, 0, "chg-topoff", chg); if (ret < 0) dev_err(&pdev->dev, "%s: fail to request topoff IRQ: %d: %d\n", __func__, chg->irq_topoff, ret); ret = request_threaded_irq(chg->irq_chgins, NULL, max8997_chg_charger_irq, 0, "chg-insert", chg); if (ret < 0) dev_err(&pdev->dev, "%s: fail to request chgins IRQ: %d: %d\n", __func__, chg->irq_chgins, ret); ret = request_threaded_irq(chg->irq_chgrm, NULL, max8997_chg_charger_irq, 0, "chg-remove", chg); if (ret < 0) dev_err(&pdev->dev, "%s: fail to request chgrm IRQ: %d: %d\n", __func__, chg->irq_chgrm, ret); return 0; err_kfree: kfree(chg); return ret; }
static int max8997_battery_probe(struct platform_device *pdev) { int ret = 0; struct charger_data *charger; struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); struct power_supply_config psy_cfg = {}; if (!pdata) return -EINVAL; if (pdata->eoc_mA) { int val = (pdata->eoc_mA - 50) / 10; if (val < 0) val = 0; if (val > 0xf) val = 0xf; ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL5, val, 0xf); if (ret < 0) { dev_err(&pdev->dev, "Cannot use i2c bus.\n"); return ret; } } switch (pdata->timeout) { case 5: ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1, 0x2 << 4, 0x7 << 4); break; case 6: ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1, 0x3 << 4, 0x7 << 4); break; case 7: ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1, 0x4 << 4, 0x7 << 4); break; case 0: ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1, 0x7 << 4, 0x7 << 4); break; default: dev_err(&pdev->dev, "incorrect timeout value (%d)\n", pdata->timeout); return -EINVAL; } if (ret < 0) { dev_err(&pdev->dev, "Cannot use i2c bus.\n"); return ret; } charger = devm_kzalloc(&pdev->dev, sizeof(struct charger_data), GFP_KERNEL); if (charger == NULL) { dev_err(&pdev->dev, "Cannot allocate memory.\n"); return -ENOMEM; } platform_set_drvdata(pdev, charger); charger->dev = &pdev->dev; charger->iodev = iodev; psy_cfg.drv_data = charger; charger->battery = power_supply_register(&pdev->dev, &max8997_battery_desc, &psy_cfg); if (IS_ERR(charger->battery)) { dev_err(&pdev->dev, "failed: power supply register\n"); return PTR_ERR(charger->battery); } return 0; }