Beispiel #1
0
static irqreturn_t pm860x_temp_handler(int irq, void *data)
{
    struct power_supply *psy;
    struct pm860x_charger_info *info = data;
    union power_supply_propval temp;
    int value;
    int ret;

    psy = power_supply_get_by_name(pm860x_supplied_to[0]);
    if (!psy)
        return IRQ_HANDLED;
    ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &temp);
    if (ret)
        goto out;
    value = temp.intval / 10;

    mutex_lock(&info->lock);
    /* Temperature < -10 C or >40 C, Will not allow charge */
    if (value < -10 || value > 40)
        info->allowed = 0;
    else
        info->allowed = 1;
    dev_dbg(info->dev, "%s, Allowed: %d\n", __func__, info->allowed);
    mutex_unlock(&info->lock);

    set_charging_fsm(info);
out:
    power_supply_put(psy);
    return IRQ_HANDLED;
}
Beispiel #2
0
static irqreturn_t pm860x_done_handler(int irq, void *data)
{
    struct pm860x_charger_info *info = data;
    struct power_supply *psy;
    union power_supply_propval val;
    int ret;
    int vbatt;

    mutex_lock(&info->lock);
    /* pre-charge done, will transimit to fast-charge stage */
    if (info->state == FSM_PRECHARGE) {
        info->allowed = 1;
        goto out;
    }
    /*
     * Fast charge done, delay to read
     * the correct status of CHG_DET.
     */
    mdelay(5);
    info->allowed = 0;
    psy = power_supply_get_by_name(pm860x_supplied_to[0]);
    if (!psy)
        goto out;
    ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,
                                    &val);
    if (ret)
        goto out_psy_put;
    vbatt = val.intval / 1000;
    /*
     * CHG_DONE interrupt is faster than CHG_DET interrupt when
     * plug in/out usb, So we can not rely on info->online, we
     * need check pm8607 status register to check usb is online
     * or not, then we can decide it is real charge done
     * automatically or it is triggered by usb plug out;
     */
    ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2);
    if (ret < 0)
        goto out_psy_put;
    if (vbatt > CHARGE_THRESHOLD && ret & STATUS2_CHG)
        power_supply_set_property(psy, POWER_SUPPLY_PROP_CHARGE_FULL,
                                  &val);

out_psy_put:
    power_supply_put(psy);
out:
    mutex_unlock(&info->lock);
    dev_dbg(info->dev, "%s, Allowed: %d\n", __func__, info->allowed);
    set_charging_fsm(info);

    return IRQ_HANDLED;
}
Beispiel #3
0
static ssize_t power_supply_show_property(struct device *dev,
					  struct device_attribute *attr,
					  char *buf) {
	static char *type_text[] = {
		"Unknown", "Battery", "UPS", "Mains", "USB",
		"USB_DCP", "USB_CDP", "USB_ACA"
	};
	static char *status_text[] = {
		"Unknown", "Charging", "Discharging", "Not charging", "Full"
	};
	static char *charge_type[] = {
		"Unknown", "N/A", "Trickle", "Fast"
	};
	static char *health_text[] = {
		"Unknown", "Good", "Overheat", "Dead", "Over voltage",
		"Unspecified failure", "Cold", "Watchdog timer expire",
		"Safety timer expire"
	};
	static char *technology_text[] = {
		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
		"LiMn"
	};
	static char *capacity_level_text[] = {
		"Unknown", "Critical", "Low", "Normal", "High", "Full"
	};
	static char *scope_text[] = {
		"Unknown", "System", "Device"
	};
	ssize_t ret = 0;
	struct power_supply *psy = dev_get_drvdata(dev);
	const ptrdiff_t off = attr - power_supply_attrs;
	union power_supply_propval value;

	if (off == POWER_SUPPLY_PROP_TYPE) {
		value.intval = psy->desc->type;
	} else {
		ret = power_supply_get_property(psy, off, &value);

		if (ret < 0) {
			if (ret == -ENODATA)
				dev_dbg(dev, "driver has no data for `%s' property\n",
					attr->attr.name);
			else if (ret != -ENODEV)
				dev_err(dev, "driver failed to report `%s' property: %zd\n",
					attr->attr.name, ret);
			return ret;
		}
	}

	if (off == POWER_SUPPLY_PROP_STATUS)
		return sprintf(buf, "%s\n", status_text[value.intval]);
	else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
		return sprintf(buf, "%s\n", charge_type[value.intval]);
	else if (off == POWER_SUPPLY_PROP_HEALTH)
		return sprintf(buf, "%s\n", health_text[value.intval]);
	else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
		return sprintf(buf, "%s\n", technology_text[value.intval]);
	else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
		return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
	else if (off == POWER_SUPPLY_PROP_TYPE)
		return sprintf(buf, "%s\n", type_text[value.intval]);
	else if (off == POWER_SUPPLY_PROP_SCOPE)
		return sprintf(buf, "%s\n", scope_text[value.intval]);
	else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
		return sprintf(buf, "%s\n", value.strval);

	return sprintf(buf, "%d\n", value.intval);
}
Beispiel #4
0
static int set_charging_fsm(struct pm860x_charger_info *info)
{
    struct power_supply *psy;
    union power_supply_propval data;
    unsigned char fsm_state[][16] = { "init", "discharge", "precharge",
                                      "fastcharge",
                                    };
    int ret;
    int vbatt;

    psy = power_supply_get_by_name(pm860x_supplied_to[0]);
    if (!psy)
        return -EINVAL;
    ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,
                                    &data);
    if (ret) {
        power_supply_put(psy);
        return ret;
    }
    vbatt = data.intval / 1000;

    ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, &data);
    if (ret) {
        power_supply_put(psy);
        return ret;
    }
    power_supply_put(psy);

    mutex_lock(&info->lock);
    info->present = data.intval;

    dev_dbg(info->dev, "Entering FSM:%s, Charger:%s, Battery:%s, "
            "Allowed:%d\n",
            &fsm_state[info->state][0],
            (info->online) ? "online" : "N/A",
            (info->present) ? "present" : "N/A", info->allowed);
    dev_dbg(info->dev, "set_charging_fsm:vbatt:%d(mV)\n", vbatt);

    switch (info->state) {
    case FSM_INIT:
        if (info->online && info->present && info->allowed) {
            if (vbatt < PRECHARGE_THRESHOLD) {
                info->state = FSM_PRECHARGE;
                start_precharge(info);
            } else if (vbatt > DISCHARGE_THRESHOLD) {
                info->state = FSM_DISCHARGE;
                stop_charge(info, vbatt);
            } else if (vbatt < DISCHARGE_THRESHOLD) {
                info->state = FSM_FASTCHARGE;
                start_fastcharge(info);
            }
        } else {
            if (vbatt < POWEROFF_THRESHOLD) {
                power_off_notification(info);
            } else {
                info->state = FSM_DISCHARGE;
                stop_charge(info, vbatt);
            }
        }
        break;
    case FSM_PRECHARGE:
        if (info->online && info->present && info->allowed) {
            if (vbatt > PRECHARGE_THRESHOLD) {
                info->state = FSM_FASTCHARGE;
                start_fastcharge(info);
            }
        } else {
            info->state = FSM_DISCHARGE;
            stop_charge(info, vbatt);
        }
        break;
    case FSM_FASTCHARGE:
        if (info->online && info->present && info->allowed) {
            if (vbatt < PRECHARGE_THRESHOLD) {
                info->state = FSM_PRECHARGE;
                start_precharge(info);
            }
        } else {
            info->state = FSM_DISCHARGE;
            stop_charge(info, vbatt);
        }
        break;
    case FSM_DISCHARGE:
        if (info->online && info->present && info->allowed) {
            if (vbatt < PRECHARGE_THRESHOLD) {
                info->state = FSM_PRECHARGE;
                start_precharge(info);
            } else if (vbatt < DISCHARGE_THRESHOLD) {
                info->state = FSM_FASTCHARGE;
                start_fastcharge(info);
            }
        } else {
            if (vbatt < POWEROFF_THRESHOLD)
                power_off_notification(info);
            else if (vbatt > CHARGE_THRESHOLD && info->online)
                set_vbatt_threshold(info, CHARGE_THRESHOLD, 0);
        }
        break;
    default:
        dev_warn(info->dev, "FSM meets wrong state:%d\n",
                 info->state);
        break;
    }
    dev_dbg(info->dev,
            "Out FSM:%s, Charger:%s, Battery:%s, Allowed:%d\n",
            &fsm_state[info->state][0],
            (info->online) ? "online" : "N/A",
            (info->present) ? "present" : "N/A", info->allowed);
    mutex_unlock(&info->lock);

    return 0;
}