static int bq2419x_resume(struct device *dev)
{
	int ret = 0;
	struct bq2419x_chip *bq2419x = dev_get_drvdata(dev);
	unsigned int val;

	ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, &val);
	if (ret < 0) {
		dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret);
		return ret;
	}

	if (val & BQ2419x_FAULT_WATCHDOG_FAULT) {
		dev_err(bq2419x->dev,
			"Charging Fault: Watchdog Timer Expired\n");

		ret = bq2419x_watchdog_init(bq2419x, bq2419x->wdt_time_sec,
						"RESUME");
		if (ret < 0) {
			dev_err(bq2419x->dev, "BQWDT init failed %d\n", ret);
			return ret;
		}
	}

	ret = bq2419x_fault_clear_sts(bq2419x);
	if (ret < 0) {
		dev_err(bq2419x->dev, "fault clear status failed %d\n", ret);
		return ret;
	}

	ret = bq2419x_charger_init(bq2419x);
	if (ret < 0) {
		dev_err(bq2419x->dev, "Charger init failed: %d\n", ret);
		return ret;
	}

	ret = bq2419x_init(bq2419x);
	if (ret < 0) {
		dev_err(bq2419x->dev, "bq2419x init failed: %d\n", ret);
		return ret;
	}

	mutex_lock(&bq2419x->mutex);
	bq2419x->suspended = 0;
	mutex_unlock(&bq2419x->mutex);
	if (gpio_is_valid(bq2419x->gpio_otg_iusb))
		gpio_set_value(bq2419x->gpio_otg_iusb, 1);

	enable_irq(bq2419x->irq);
	return 0;
};
static int bq2419x_set_charging_current(struct regulator_dev *rdev,
					int min_uA, int max_uA)
{
	struct bq2419x_chip *bq_charger = rdev_get_drvdata(rdev);
	int ret = 0;
	int val;

	dev_info(bq_charger->dev, "Setting charging current %d\n", max_uA/1000);
	msleep(200);
	bq_charger->status = 0;

	ret = bq2419x_charger_enable(bq_charger);
	if (ret < 0) {
		dev_err(bq_charger->dev, "Charger enable failed %d", ret);
		return ret;
	}

	ret = regmap_read(bq_charger->regmap, BQ2419X_SYS_STAT_REG, &val);
	if (ret < 0)
		dev_err(bq_charger->dev, "error reading reg: 0x%x\n",
				BQ2419X_SYS_STAT_REG);

	if (max_uA == 0 && val != 0)
		return ret;

	bq_charger->in_current_limit = max_uA/1000;
	if ((val & BQ2419x_VBUS_STAT) == BQ2419x_VBUS_UNKNOWN) {
		bq_charger->in_current_limit = 500;
		bq_charger->status = 0;
	} else {
		bq_charger->status = 1;
	}
	ret = bq2419x_init(bq_charger);
	if (ret < 0)
		goto error;
	if (bq_charger->update_status)
		bq_charger->update_status(bq_charger->status, 0);
	return 0;
error:
	dev_err(bq_charger->dev, "Charger enable failed, err = %d\n", ret);
	return ret;
}
static irqreturn_t bq2419x_irq(int irq, void *data)
{
	struct bq2419x_chip *bq2419x = data;
	int ret;
	unsigned int val;
	int check_chg_state = 0;

	ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, &val);
	if (ret < 0) {
		dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret);
		return ret;
	}

	dev_info(bq2419x->dev, "%s() Irq %d status 0x%02x\n",
		__func__, irq, val);

	if (val & BQ2419x_FAULT_WATCHDOG_FAULT) {
		dev_err(bq2419x->dev,
			"Charging Fault: Watchdog Timer Expired\n");
		ret = bq2419x_watchdog_init(bq2419x, bq2419x->wdt_time_sec,
						"ISR");
		if (ret < 0) {
			dev_err(bq2419x->dev, "BQWDT init failed %d\n", ret);
			return ret;
		}

		ret = bq2419x_charger_init(bq2419x);
		if (ret < 0) {
			dev_err(bq2419x->dev, "Charger init failed: %d\n", ret);
			return ret;
		}

		ret = bq2419x_init(bq2419x);
		if (ret < 0) {
			dev_err(bq2419x->dev, "bq2419x init failed: %d\n", ret);
			return ret;
		}
	}

	if (val & BQ2419x_FAULT_BOOST_FAULT)
		dev_err(bq2419x->dev, "Charging Fault: VBUS Overloaded\n");

	switch (val & BQ2419x_FAULT_CHRG_FAULT_MASK) {
	case BQ2419x_FAULT_CHRG_INPUT:
		dev_err(bq2419x->dev, "Charging Fault: "
				"Input Fault (VBUS OVP or VBAT<VBUS<3.8V)\n");
		break;
	case BQ2419x_FAULT_CHRG_THERMAL:
		dev_err(bq2419x->dev, "Charging Fault: Thermal shutdown\n");
		check_chg_state = 1;
		break;
	case BQ2419x_FAULT_CHRG_SAFTY:
		dev_err(bq2419x->dev,
			"Charging Fault: Safety timer expiration\n");
		bq2419x->chg_restart_timeout = bq2419x->chg_restart_time /
						bq2419x->wdt_refresh_timeout;
		ret = bq2419x_reset_safety_timer(bq2419x);
		if (ret < 0) {
			dev_err(bq2419x->dev, "Reset safety timer failed %d\n",
							ret);
			return ret;
		}

		check_chg_state = 1;
		break;
	default:
		break;
	}

	if (val & BQ2419x_FAULT_NTC_FAULT) {
		dev_err(bq2419x->dev, "Charging Fault: NTC fault %d\n",
				val & BQ2419x_FAULT_NTC_FAULT);
		check_chg_state = 1;
	}

	ret = bq2419x_fault_clear_sts(bq2419x);
	if (ret < 0) {
		dev_err(bq2419x->dev, "fault clear status failed %d\n", ret);
		return ret;
	}

	ret = regmap_read(bq2419x->regmap, BQ2419X_SYS_STAT_REG, &val);
	if (ret < 0) {
		dev_err(bq2419x->dev, "SYS_STAT_REG read failed %d\n", ret);
		return ret;
	}

	if ((val & BQ2419x_CHRG_STATE_MASK) ==
				BQ2419x_CHRG_STATE_CHARGE_DONE) {
		bq2419x->chg_restart_timeout = bq2419x->chg_restart_time /
						bq2419x->wdt_refresh_timeout;
		dev_info(bq2419x->dev, "Charging completed\n");
		bq2419x->status = 4;
		if (bq2419x->update_status)
			bq2419x->update_status(bq2419x->status, 0);
	}

	/*
	* Update Charging status based on STAT register
	*/
	if (check_chg_state) {
		if ((val & BQ2419x_CHRG_STATE_MASK) ==
				BQ2419x_CHRG_STATE_NOTCHARGING) {
			bq2419x->status = 0;
			if (bq2419x->update_status)
				bq2419x->update_status(bq2419x->status, 0);
		}
	}

	return IRQ_HANDLED;
}
static int bq2419x_set_charging_current(struct regulator_dev *rdev,
					int min_uA, int max_uA)
{
	struct bq2419x_chip *bq_charger = rdev_get_drvdata(rdev);
	int ret = 0;
	int val;

	dev_info(bq_charger->dev, "Setting charging current %d\n", max_uA/1000);
	msleep(200);
	bq_charger->usb_online = 0;
	bq_charger->ac_online = 0;
	bq_charger->status = 0;

	ret = bq2419x_charger_enable(bq_charger);
	if (ret < 0) {
		dev_err(bq_charger->dev, "Charger enable failed %d", ret);
		return ret;
	}

	ret = regmap_read(bq_charger->regmap, BQ2419X_SYS_STAT_REG, &val);
	if (ret < 0)
		dev_err(bq_charger->dev, "error reading reg: 0x%x\n",
				BQ2419X_SYS_STAT_REG);

	if (max_uA == 0 && val != 0)
		return ret;

	bq_charger->in_current_limit = max_uA/1000;
	if ((val & BQ2419x_VBUS_STAT) == BQ2419x_VBUS_UNKNOWN) {
		bq_charger->status = 0;
		bq_charger->usb_online = 0;
		bq_charger->in_current_limit = 500;
		ret = bq2419x_init(bq_charger);
		if (ret < 0)
			goto error;
		if (bq_charger->update_status)
			bq_charger->update_status
				(bq_charger->status, 0);
	} else if (bq_charger->in_current_limit == 500) {
		bq_charger->status = 1;
		bq_charger->usb_online = 1;
		ret = bq2419x_init(bq_charger);
		if (ret < 0)
			goto error;
		if (bq_charger->update_status)
			bq_charger->update_status
				(bq_charger->status, 2);
	} else if (bq_charger->in_current_limit > 500) {
		bq_charger->status = 1;
		bq_charger->ac_online = 1;
		ret = bq2419x_init(bq_charger);
		if (ret < 0)
			goto error;
		if (bq_charger->update_status)
			bq_charger->update_status
				(bq_charger->status, 1);
	}

	if (bq_charger->ac_online) {
		if ((bq_charger->in_current_limit == 1500))
			bq_charger->ac.type = POWER_SUPPLY_TYPE_USB_CDP;
		else
			bq_charger->ac.type = POWER_SUPPLY_TYPE_MAINS;
	}

	if (ret == 0) {
		if (bq_charger->use_mains)
			power_supply_changed(&bq_charger->ac);
		if (bq_charger->use_usb)
			power_supply_changed(&bq_charger->usb);
	}
	return 0;
error:
	dev_err(bq_charger->dev, "Charger enable failed, err = %d\n", ret);
	return ret;
}
Exemple #5
0
int8_t pmu_init(void)
{
	int8_t ret;
	bool battery_present;

	state = OFF;

	/* make panic button an input */
	io_input_pin(PANICn);
	panic_last = io_test_pin(PANICn);

	/* make the LED outputs */
	io_output_pin(CHARGE);
	io_output_pin(POWER_LED);

	/* initialize the ADC, so we can sense the battery */
	adc_init();

	/* initialize TPS54478 for core power */
	tps54478_init(true);

	/* wiggle USB and FTDI pins */
	io_input_pin(USB_RESETn);
	io_output_pin(FTDI_RESETn);
	io_output_pin(USB_CLK_EN);
	io_input_pin(FTDI_CBUS3);

	/* make OVERTEMP input pin */
	io_input_pin(OVERTEMP);

	/* initialize the charger */
	ret = bq2419x_init();
	if (ret)
		goto fail_bq2419x;

	/* wait a sec */
	_delay_ms(1000);

	/* wdt setup */
	cli();
	WDTCSR |= BIT(WDCE) | BIT(WDE);
	WDTCSR = BIT(WDIE);
	sei();

	/* see if we got a battery */
	battery_present = pmu_battery_present();
	battery_present_last = battery_present;

	if (battery_present) {
		last_full_charge = eeprom_get_last_full();
		ret = ltc294x_init(LTC294X_MODEL_2942);
	}
	if (ret)
		return ret;

	ret = ltc3675_init();
	if (ret)
		goto fail_ltc3675;


	/* need to hold them low until power is stable */
	io_output_pin(PS_POR);
	io_output_pin(PS_SRST);
	io_clear_pin(PS_POR);
	io_clear_pin(PS_SRST);

	/* TODO: Not sure if needed */
	io_input_pin(AVR_RESET);

	/* TODO: This will probably need to change */
	io_input_pin(AVR_IRQ);
	io_set_pin(AVR_IRQ); // enable pull-up ?

	/* configure and enable interrupts */
	interrupt_init();

	/* initialize the timers */
	timer0_init();
	timer1_init();

	state = OFF;

	return 0;

fail_ltc3675:
fail_bq2419x:
	return -1;
}