Ejemplo n.º 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;
}
Ejemplo n.º 2
0
static void ac_status_changed(void)
{
	struct power_supply *psy = power_supply_get_by_name("olpc-ac");

	if (psy) {
		power_supply_changed(psy);
		power_supply_put(psy);
	}
}
Ejemplo n.º 3
0
static void raumfeld_power_signal_charged(void)
{
	struct power_supply *psy =
		power_supply_get_by_name(raumfeld_power_supplicants[0]);

	if (psy) {
		power_supply_set_battery_charged(psy);
		power_supply_put(psy);
	}
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
static void olpc_xo175_ec_complete(void *arg)
{
	struct olpc_xo175_ec *priv = arg;
	struct device *dev = &priv->spi->dev;
	struct power_supply *psy;
	unsigned long flags;
	u8 channel;
	u8 byte;
	int ret;

	ret = priv->msg.status;
	if (ret) {
		dev_err(dev, "SPI transfer failed: %d\n", ret);

		spin_lock_irqsave(&priv->cmd_state_lock, flags);
		if (priv->cmd_running) {
			priv->resp_len = 0;
			priv->cmd_state = CMD_STATE_ERROR_RECEIVED;
			complete(&priv->cmd_done);
		}
		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);

		if (ret != -EINTR)
			olpc_xo175_ec_read_packet(priv);

		return;
	}

	channel = priv->rx_buf.resp.channel;
	byte = priv->rx_buf.resp.byte;

	switch (channel) {
	case CHAN_NONE:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			/* We can safely ignore these */
			dev_err(dev, "spurious FIFO read packet\n");
			spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
			return;
		}

		priv->cmd_state = CMD_STATE_CMD_SENT;
		if (!priv->expected_resp_len)
			complete(&priv->cmd_done);
		olpc_xo175_ec_read_packet(priv);

		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		return;

	case CHAN_SWITCH:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			/* Just go with the flow */
			dev_err(dev, "spurious SWITCH packet\n");
			memset(&priv->cmd, 0, sizeof(priv->cmd));
			priv->cmd.command = CMD_ECHO;
		}

		priv->cmd_state = CMD_STATE_CMD_IN_TX_FIFO;

		/* Throw command into TxFIFO */
		gpiod_set_value_cansleep(priv->gpio_cmd, 0);
		olpc_xo175_ec_send_command(priv, &priv->cmd, sizeof(priv->cmd));

		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		return;

	case CHAN_CMD_RESP:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			dev_err(dev, "spurious response packet\n");
		} else if (priv->resp_len >= priv->expected_resp_len) {
			dev_err(dev, "too many response packets\n");
		} else {
			priv->resp_data[priv->resp_len++] = byte;
			if (priv->resp_len == priv->expected_resp_len) {
				priv->cmd_state = CMD_STATE_RESP_RECEIVED;
				complete(&priv->cmd_done);
			}
		}

		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		break;

	case CHAN_CMD_ERROR:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			dev_err(dev, "spurious cmd error packet\n");
		} else {
			priv->resp_data[0] = byte;
			priv->resp_len = 1;
			priv->cmd_state = CMD_STATE_ERROR_RECEIVED;
			complete(&priv->cmd_done);
		}
		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		break;

	case CHAN_KEYBOARD:
		dev_warn(dev, "keyboard is not supported\n");
		break;

	case CHAN_TOUCHPAD:
		dev_warn(dev, "touchpad is not supported\n");
		break;

	case CHAN_EVENT:
		dev_dbg(dev, "got event %.2x\n", byte);
		switch (byte) {
		case EVENT_AC_CHANGE:
			psy = power_supply_get_by_name("olpc-ac");
			if (psy) {
				power_supply_changed(psy);
				power_supply_put(psy);
			}
			break;
		case EVENT_BATTERY_STATUS:
		case EVENT_BATTERY_CRITICAL:
		case EVENT_BATTERY_SOC_CHANGE:
		case EVENT_BATTERY_ERROR:
			psy = power_supply_get_by_name("olpc-battery");
			if (psy) {
				power_supply_changed(psy);
				power_supply_put(psy);
			}
			break;
		case EVENT_POWER_PRESSED:
			input_report_key(priv->pwrbtn, KEY_POWER, 1);
			input_sync(priv->pwrbtn);
			input_report_key(priv->pwrbtn, KEY_POWER, 0);
			input_sync(priv->pwrbtn);
			/* fall through */
		case EVENT_POWER_PRESS_WAKE:
		case EVENT_TIMED_HOST_WAKE:
			pm_wakeup_event(priv->pwrbtn->dev.parent,
						PM_WAKEUP_TIME);
			break;
		default:
			dev_dbg(dev, "ignored unknown event %.2x\n", byte);
			break;
		}
		break;

	case CHAN_DEBUG:
		if (byte == '\n') {
			olpc_xo175_ec_flush_logbuf(priv);
		} else if (isprint(byte)) {
			priv->logbuf[priv->logbuf_len++] = byte;
			if (priv->logbuf_len == LOG_BUF_SIZE)
				olpc_xo175_ec_flush_logbuf(priv);
		}
		break;

	default:
		dev_warn(dev, "unknown channel: %d, %.2x\n", channel, byte);
		break;
	}

	/* Most non-command packets get the TxFIFO refilled and an ACK. */
	olpc_xo175_ec_read_packet(priv);
}
Ejemplo n.º 6
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;
}