static void m5mols_irq_work(struct work_struct *work) { struct m5mols_info *info = container_of(work, struct m5mols_info, work_irq); struct v4l2_subdev *sd = &info->sd; u8 reg; int ret; if (!is_powered(info) || m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) return; switch (info->interrupt & REG_INT_MASK) { case REG_INT_AF: if (!is_available_af(info)) break; ret = m5mols_read_u8(sd, AF_STATUS, ®); v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", reg == REG_AF_FAIL ? "Failed" : reg == REG_AF_SUCCESS ? "Success" : reg == REG_AF_IDLE ? "Idle" : "Busy"); break; case REG_INT_CAPTURE: if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) wake_up_interruptible(&info->irq_waitq); v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); break; default: v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); break; }; }
static int m5mols_sensor_power(struct m5mols_info *info, bool enable) { struct v4l2_subdev *sd = &info->sd; struct i2c_client *client = v4l2_get_subdevdata(sd); const struct m5mols_platform_data *pdata = info->pdata; int ret; if (enable) { if (is_powered(info)) return 0; if (info->set_power) { ret = info->set_power(&client->dev, 1); if (ret) return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); if (ret) { info->set_power(&client->dev, 0); return ret; } gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); usleep_range(1000, 1000); info->power = true; return ret; } if (!is_powered(info)) return 0; ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); if (ret) return ret; if (info->set_power) info->set_power(&client->dev, 0); gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); usleep_range(1000, 1000); info->power = false; return ret; }
static void charger_check_battery_level(struct charger_info *di) { /* check for battery full condition */ if (is_charging(di) && di->gg_capacity == 100) { if (di->gg_status == POWER_SUPPLY_STATUS_FULL) { dev_warn(di->dev, "gas gauge reports full capacity\n"); di->battery_full = 1; } else if (di->gg_current_uA < CHARGER_TAPER_CURRENT) { dev_warn(di->dev, "gas gauge did not report full capacity\n"); di->battery_full = 1; } } if (!is_powered(di)) di->battery_full = 0; if (di->battery_full && di->gg_capacity <= di->recharge_capacity) { if (is_powered(di) && !is_charging(di)) dev_warn(di->dev, "battery drained from full to %d%%, charging again\n", di->gg_capacity); di->battery_full = 0; } }
static void charger_work(struct work_struct *work) { struct charger_info *di = container_of(work, struct charger_info, work); int next_state; bool limiting_active; bool charge_source; if (is_charging(di)) charger_pet_watchdog(di); charger_lock(di); /* update inputs and limit conditions */ charger_gas_gauge_update(di); charger_check_temp_limits(di); charger_check_battery_level(di); /* aggregate limiting factors */ limiting_active = di->battery_full || di->charge_disabled || di->temperature_lockout; /* hardware ready for charging? */ charge_source = di->vbus_online && !di->otg_online; dev_dbg(di->dev, "%s: battery_full=%d charge_disabled=%d temperature_lockout=%d " "invalid_charger=%d vbus_online=%d usb_online=%d otg_online=%d\n", __func__, di->battery_full, di->charge_disabled, di->temperature_lockout, di->invalid_charger, di->vbus_online, di->usb_online, di->otg_online); /* determine the next charger state */ switch (di->state) { case CHARGER_STATE_UNPLUGGED: case CHARGER_STATE_CHARGING: if (charge_source) { if (limiting_active) next_state = CHARGER_STATE_NOT_CHARGING; else next_state = CHARGER_STATE_CHARGING; } else { next_state = CHARGER_STATE_UNPLUGGED; } break; case CHARGER_STATE_NOT_CHARGING: if (charge_source) { if (limiting_active) next_state = CHARGER_STATE_NOT_CHARGING; else next_state = CHARGER_STATE_CHARGING; } else { next_state = CHARGER_STATE_UNPLUGGED; } break; default: next_state = di->state; // silence compiler warning } /* if the state changed, fulfill the required changes */ if (next_state != di->state) { dev_info(di->dev, "transitioning from %s to %s\n", state_to_str(di->state), state_to_str(next_state)); switch (next_state) { case CHARGER_STATE_UNPLUGGED: wake_lock_timeout(&di->wake_lock, HZ / 2); charger_stop_usb_charger(di); break; case CHARGER_STATE_NOT_CHARGING: if (!is_powered(di)) wake_lock(&di->wake_lock); charger_stop_usb_charger(di); break; case CHARGER_STATE_CHARGING: if (!is_powered(di)) wake_lock(&di->wake_lock); charger_start_usb_charger(di); break; } di->state = next_state; power_supply_changed(&di->usb); twl6030_eval_led_state(di->led, is_powered(di), is_charging(di)); } charger_unlock(di); /* update timer */ mod_timer(&di->timer, di->monitor_interval_jiffies + jiffies); }