Esempio n. 1
0
/*
 * Do I2C/PMU writes to bring up SD card bus power
 *
 */
void board_sdmmc_voltage_init(void)
{
	struct udevice *dev;
	uchar reg, data_buffer[1];
	int ret;
	int i;

	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
	if (ret) {
		debug("%s: Cannot find PMIC I2C chip\n", __func__);
		return;
	}

	/* TPS659110: LDO5_REG = 3.3v, ACTIVE to SDMMC1 */
	data_buffer[0] = 0x65;
	reg = 0x32;

	for (i = 0; i < MAX_I2C_RETRY; ++i) {
		if (dm_i2c_write(dev, reg, data_buffer, 1))
			udelay(100);
	}

	/* TPS659110: GPIO7_REG = PDEN, output a 1 to EN_3V3_SYS */
	data_buffer[0] = 0x09;
	reg = 0x67;

	for (i = 0; i < MAX_I2C_RETRY; ++i) {
		if (dm_i2c_write(dev, reg, data_buffer, 1))
			udelay(100);
	}
}
Esempio n. 2
0
/*
 * Set USB VBUS signals (via I2C IO expander/GPIO) as output and set
 * output value as disabled
 *
 * Set USB Current Limit signals (via I2C IO expander/GPIO) as output
 * and set output value as enabled
 */
int board_xhci_config(void)
{
	struct udevice *dev;
	int ret;
	u8 buf[8];

	if (of_machine_is_compatible("marvell,armada7040-db")) {
		/* Configure IO exander PCA9555: 7bit address 0x21 */
		ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
		if (ret) {
			printf("Cannot find PCA9555: %d\n", ret);
			return 0;
		}

		/*
		 * Read configuration (direction) and set VBUS pin as output
		 * (reset pin = output)
		 */
		ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
		if (ret) {
			printf("Failed to read IO expander value via I2C\n");
			return -EIO;
		}
		buf[0] &= ~I2C_IO_REG_VBUS;
		buf[0] &= ~I2C_IO_REG_CL;
		ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
		if (ret) {
			printf("Failed to set IO expander via I2C\n");
			return -EIO;
		}

		/* Read output value and configure it */
		ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
		if (ret) {
			printf("Failed to read IO expander value via I2C\n");
			return -EIO;
		}
		buf[0] &= ~I2C_IO_REG_VBUS;
		buf[0] |= I2C_IO_REG_CL;
		ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
		if (ret) {
			printf("Failed to set IO expander via I2C\n");
			return -EIO;
		}

		mdelay(500); /* required delay to let output value settle */
	}

	return 0;
}
Esempio n. 3
0
static int pcf2127_rtc_set(struct udevice *dev, const struct rtc_time *tm)
{
	uchar buf[8];
	int i = 0, ret;

	/* start register address */
	buf[i++] = PCF2127_REG_SC;

	/* hours, minutes and seconds */
	buf[i++] = bin2bcd(tm->tm_sec);
	buf[i++] = bin2bcd(tm->tm_min);
	buf[i++] = bin2bcd(tm->tm_hour);
	buf[i++] = bin2bcd(tm->tm_mday);
	buf[i++] = tm->tm_wday & 0x07;

	/* month, 1 - 12 */
	buf[i++] = bin2bcd(tm->tm_mon + 1);

	/* year */
	buf[i++] = bin2bcd(tm->tm_year % 100);

	/* write register's data */
	ret = dm_i2c_write(dev, PCF2127_REG_CTRL1, buf, sizeof(buf));

	return ret;
}
Esempio n. 4
0
static int pcf2127_rtc_get(struct udevice *dev, struct rtc_time *tm)
{
	int ret = 0;
	uchar buf[10] = { PCF2127_REG_CTRL1 };

	ret = dm_i2c_write(dev, PCF2127_REG_CTRL1, buf, 1);
	if (ret < 0)
		return ret;
	ret = dm_i2c_read(dev, PCF2127_REG_CTRL1, buf, sizeof(buf));
	if (ret < 0)
		return ret;

	if (buf[PCF2127_REG_CTRL3] & 0x04)
		puts("### Warning: RTC Low Voltage - date/time not reliable\n");

	tm->tm_sec  = bcd2bin(buf[PCF2127_REG_SC] & 0x7F);
	tm->tm_min  = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
	tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F);
	tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F);
	tm->tm_mon  = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1;
	tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]) + 1900;
	if (tm->tm_year < 1970)
		tm->tm_year += 100;	/* assume we are in 1970...2069 */
	tm->tm_wday = buf[PCF2127_REG_DW] & 0x07;
	tm->tm_yday = 0;
	tm->tm_isdst = 0;

	debug("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
	      tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
	      tm->tm_hour, tm->tm_min, tm->tm_sec);

	return ret;
}
Esempio n. 5
0
static bool disable_mcu_watchdog(void)
{
	struct udevice *bus, *dev;
	int ret, retry = 3;
	uchar buf[1] = {0x0};

	if (uclass_get_device_by_name(UCLASS_I2C, OMNIA_I2C_MCU_DM_NAME, &bus)) {
		puts("Cannot find MCU bus! Can not disable MCU WDT.\n");
		return false;
	}

	ret = i2c_get_chip(bus, OMNIA_I2C_MCU, 1, &dev);
	if (ret) {
		puts("Cannot get MCU chip! Can not disable MCU WDT.\n");
		return false;
	}

	for (; retry > 0; --retry)
		if (!dm_i2c_write(dev, OMNIA_I2C_MCU_WDT_ADDR, (uchar *) buf, 1))
			break;

	if (retry <= 0) {
		puts("I2C MCU watchdog failed to disable!\n");
		return false;
	}

	return true;
}
Esempio n. 6
0
static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr,
				     const u8 *buffer, size_t len,
				     unsigned int sleep_time_us, u8 max_count)
{
	struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
	struct tpm_chip *chip = dev_get_priv(dev);
	int rc = 0;
	int count;

	if (chip->chip_type == SLB9635) {
		/* Prepare send buffer to include the address */
		priv->buf[0] = addr;
		memcpy(&(priv->buf[1]), buffer, len);
		buffer = priv->buf;
		len++;
		addr = 0;
	}

	for (count = 0; count < max_count; count++) {
		rc = dm_i2c_write(dev, addr, buffer, len);
		if (rc == 0)
			break;  /* Success, break to skip sleep */
		udelay(sleep_time_us);
	}

	/* take care of 'guard time' */
	udelay(sleep_time_us);
	if (rc)
		return rc;

	return 0;
}
Esempio n. 7
0
/*
 * Do I2C/PMU writes to bring up SD card bus power
 *
 */
void board_sdmmc_voltage_init(void)
{
	struct udevice *dev;
	uchar reg, data_buffer[1];
	int ret;

	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
	if (ret) {
		debug("%s: Cannot find PMIC I2C chip\n", __func__);
		return;
	}

	/* TPS65913: LDO9_VOLTAGE = 3.3V */
	data_buffer[0] = 0x31;
	reg = 0x61;

	ret = dm_i2c_write(dev, reg, data_buffer, 1);
	if (ret)
		printf("%s: PMU i2c_write %02X<-%02X returned %d\n",
			__func__, reg, data_buffer[0], ret);

	/* TPS65913: LDO9_CTRL = Active */
	data_buffer[0] = 0x01;
	reg = 0x60;

	ret = dm_i2c_write(dev, reg, data_buffer, 1);
	if (ret)
		printf("%s: PMU i2c_write %02X<-%02X returned %d\n",
			__func__, reg, data_buffer[0], ret);

	/* TPS65090: FET6_CTRL = enable output auto discharge, enable FET6 */
	data_buffer[0] = 0x03;
	reg = 0x14;

	ret = i2c_get_chip_for_busnum(0, BAT_I2C_ADDRESS, 1, &dev);
	if (ret) {
		debug("%s: Cannot find charger I2C chip\n", __func__);
		return;
	}
	ret = dm_i2c_write(dev, reg, data_buffer, 1);
	if (ret)
		printf("%s: BAT i2c_write %02X<-%02X returned %d\n",
			__func__, reg, data_buffer[0], ret);
}
int tegra_pcie_board_init(void)
{
	struct udevice *dev;
	u8 addr, data[1];
	int err;

	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
	if (err) {
		debug("%s: Cannot find PMIC I2C chip\n", __func__);
		return err;
	}

	/* TPS659110: VDD2_OP_REG = 1.05V */
	data[0] = 0x27;
	addr = 0x25;

	err = dm_i2c_write(dev, addr, data, 1);
	if (err) {
		debug("failed to set VDD supply\n");
		return err;
	}

	/* TPS659110: VDD2_REG 7.5 mV/us, ACTIVE */
	data[0] = 0x0D;
	addr = 0x24;

	err = dm_i2c_write(dev, addr, data, 1);
	if (err) {
		debug("failed to enable VDD supply\n");
		return err;
	}

	/* TPS659110: LDO6_REG = 1.1V, ACTIVE */
	data[0] = 0x0D;
	addr = 0x35;

	err = dm_i2c_write(dev, addr, data, 1);
	if (err) {
		debug("failed to set AVDD supply\n");
		return err;
	}

	return 0;
}
Esempio n. 9
0
static int act8846_write(struct udevice *dev, uint reg, const uint8_t *buff,
			  int len)
{
	if (dm_i2c_write(dev, reg, buff, len)) {
		debug("write error to device: %p register: %#x!\n", dev, reg);
		return -EIO;
	}

	return 0;
}
Esempio n. 10
0
static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff,
			  int len)
{
	if (dm_i2c_write(dev, reg, buff, len)) {
		error("write error to device: %p register: %#x!", dev, reg);
		return -EIO;
	}

	return 0;
}
Esempio n. 11
0
/*
 * st33zp24_i2c_write8_reg
 * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
 * @param: tpm_register, the tpm tis register where the data should be written
 * @param: tpm_data, the tpm_data to write inside the tpm_register
 * @param: tpm_size, The length of the data
 * @return: Number of byte written successfully else an error code.
 */
static int st33zp24_i2c_write8_reg(struct udevice *dev, u8 tpm_register,
				   const u8 *tpm_data, size_t tpm_size)
{
	struct tpm_chip_priv *chip_priv = dev_get_uclass_priv(dev);

	chip_priv->buf[0] = tpm_register;
	memcpy(chip_priv->buf + 1, tpm_data, tpm_size);

	return dm_i2c_write(dev, 0, chip_priv->buf, tpm_size + 1);
}
Esempio n. 12
0
static int max8997_write(struct udevice *dev, uint reg, const uint8_t *buff,
		int len)
{
	int ret;

	ret = dm_i2c_write(dev, reg, buff, len);
	if (ret)
		pr_err("write error to device: %p register: %#x!", dev, reg);

	return ret;
}
Esempio n. 13
0
static int pmic_tps65910_write(struct udevice *dev, uint reg, const u8 *buffer,
			       int len)
{
	int ret;

	ret = dm_i2c_write(dev, reg, buffer, len);
	if (ret)
		pr_err("%s write error on register %02x\n", dev->name, reg);

	return ret;
}
Esempio n. 14
0
int tegra_pcie_board_init(void)
{
	struct udevice *dev;
	u8 addr, data[1];
	int err;

	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
	if (err) {
		debug("failed to find PMU bus\n");
		return err;
	}

	/* TPS659110: LDO1_REG = 1.05V, ACTIVE */
	data[0] = 0x15;
	addr = 0x30;

	err = dm_i2c_write(dev, addr, data, 1);
	if (err) {
		debug("failed to set VDD supply\n");
		return err;
	}

	/* GPIO: PEX = 3.3V */
	err = gpio_request(TEGRA_GPIO(L, 7), "PEX");
	if (err < 0)
		return err;

	gpio_direction_output(TEGRA_GPIO(L, 7), 1);

	/* TPS659110: LDO2_REG = 1.05V, ACTIVE */
	data[0] = 0x15;
	addr = 0x31;

	err = dm_i2c_write(dev, addr, data, 1);
	if (err) {
		debug("failed to set AVDD supply\n");
		return err;
	}

	return 0;
}
Esempio n. 15
0
int i2c_write(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
	      int len)
{
	struct udevice *dev;
	int ret;

	ret = i2c_compat_get_device(chip_addr, alen, &dev);
	if (ret)
		return ret;

	return dm_i2c_write(dev, addr, buffer, len);
}
Esempio n. 16
0
void pmu_write(uchar reg, uchar data)
{
	struct udevice *dev;
	int ret;

	ret = i2c_get_chip_for_busnum(4, PMU_I2C_ADDRESS, 1, &dev);
	if (ret) {
		debug("%s: Cannot find PMIC I2C chip\n", __func__);
		return;
	}
	dm_i2c_write(dev, reg, &data, 1);
}
Esempio n. 17
0
static int stpmu1_write(struct udevice *dev, uint reg, const uint8_t *buff,
			int len)
{
	int ret;

	ret = dm_i2c_write(dev, reg, buff, len);
	if (ret)
		dev_err(dev, "%s: failed to write register %#x :%d",
			__func__, reg, ret);

	return ret;
}
Esempio n. 18
0
/*
 * tpm_tis_i2c_read() - read from TPM register
 * @addr: register address to read from
 * @buffer: provided by caller
 * @len: number of bytes to read
 *
 * Read len bytes from TPM register and put them into
 * buffer (little-endian format, i.e. first byte is put into buffer[0]).
 *
 * NOTE: TPM is big-endian for multi-byte values. Multi-byte
 * values have to be swapped.
 *
 * Return -EIO on error, 0 on success.
 */
static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer,
			    size_t len)
{
	struct tpm_chip *chip = dev_get_priv(dev);
	int rc;
	int count;
	uint32_t addrbuf = addr;

	if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) {
		/* slb9635 protocol should work in both cases */
		for (count = 0; count < MAX_COUNT; count++) {
			rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1);
			if (rc == 0)
				break;  /* Success, break to skip sleep */
			udelay(SLEEP_DURATION_US);
		}
		if (rc)
			return rc;

		/* After the TPM has successfully received the register address
		 * it needs some time, thus we're sleeping here again, before
		 * retrieving the data
		 */
		for (count = 0; count < MAX_COUNT; count++) {
			udelay(SLEEP_DURATION_US);
			rc = dm_i2c_read(dev, 0, buffer, len);
			if (rc == 0)
				break;  /* success, break to skip sleep */
		}
	} else {
		/*
		 * Use a combined read for newer chips.
		 * Unfortunately the smbus functions are not suitable due to
		 * the 32 byte limit of the smbus.
		 * Retries should usually not be needed, but are kept just to
		 * be safe on the safe side.
		 */
		for (count = 0; count < MAX_COUNT; count++) {
			rc = dm_i2c_read(dev, addr, buffer, len);
			if (rc == 0)
				break;  /* break here to skip sleep */
			udelay(SLEEP_DURATION_US);
		}
	}

	/* Take care of 'guard time' */
	udelay(SLEEP_DURATION_US);
	if (rc)
		return rc;

	return 0;
}
Esempio n. 19
0
int board_late_init(void)
{
	struct udevice *dev;
	u8 buf[8];
	int ret;

	/* Configure SMSC USB2513 USB Hub: 7bit address 0x2c */
	ret = i2c_get_chip_for_busnum(0, 0x2c, 1, &dev);
	if (ret) {
		printf("Cannot find USB2513: %d\n", ret);
		return 0;
	}

	/*
	 * The first access to the USB Hub fails sometimes, so lets read
	 * a dummy byte to be sure here
	 */
	dm_i2c_read(dev, 0x00, buf, 1);

	/*
	 * The SMSC hub is not visible on the I2C bus after the first
	 * configuration at power-up. The following code deliberately
	 * does not report upon failure of these I2C write calls.
	 */
	buf[0] = 0x93;
	dm_i2c_write(dev, 0x06, buf, 1);

	buf[0] = 0xaa;
	dm_i2c_write(dev, 0xf8, buf, 1);

	buf[0] = 0x0f;
	dm_i2c_write(dev, 0xfa, buf, 1);

	buf[0] = 0x01;
	dm_i2c_write(dev, 0xff, buf, 1);

	return 0;
}
Esempio n. 20
0
static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
				int offset)
{
	struct pca953x_info *info = dev_get_platdata(dev);
	int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
	int off = offset / BANK_SZ;
	int ret = 0;

	ret = dm_i2c_write(dev, (reg << bank_shift) + off, &val, 1);
	if (ret) {
		dev_err(dev, "%s error\n", __func__);
		return ret;
	}

	return 0;
}
Esempio n. 21
0
void pin_mux_mmc(void)
{
	struct udevice *dev;
	uchar val;
	int ret;

	/* Turn on MAX77620 LDO2 to 3.3V for SD card power */
	debug("%s: Set LDO2 for VDDIO_SDMMC_AP power to 3.3V\n", __func__);
	ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev);
	if (ret) {
		printf("%s: Cannot find MAX77620 I2C chip\n", __func__);
		return;
	}
	/* 0xF2 for 3.3v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */
	val = 0xF2;
	ret = dm_i2c_write(dev, MAX77620_CNFG1_L2_REG, &val, 1);
	if (ret)
		printf("i2c_write 0 0x3c 0x27 failed: %d\n", ret);
}
Esempio n. 22
0
int board_xhci_enable(void)
{
	struct udevice *dev;
	int ret;
	u8 buf[8];

	if (of_machine_is_compatible("marvell,armada7040-db")) {
		/*
		 * This function enables all USB ports simultaniously,
		 * it only needs to get called once
		 */
		if (usb_enabled)
			return 0;

		/* Configure IO exander PCA9555: 7bit address 0x21 */
		ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
		if (ret) {
			printf("Cannot find PCA9555: %d\n", ret);
			return 0;
		}

		/* Read VBUS output value */
		ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
		if (ret) {
			printf("Failed to read IO expander value via I2C\n");
			return -EIO;
		}

		/* Enable VBUS power: Set output value of VBUS pin as enabled */
		buf[0] |= I2C_IO_REG_VBUS;
		ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
		if (ret) {
			printf("Failed to set IO expander via I2C\n");
			return -EIO;
		}

		mdelay(500); /* required delay to let output value settle */
		usb_enabled = 1;
	}

	return 0;
}
Esempio n. 23
0
void reset_cpu(ulong addr)
{
	struct udevice *dev;
	const u8 pmic_bus = 6;
	const u8 pmic_addr = 0x5a;
	u8 data;
	int ret;

	ret = i2c_get_chip_for_busnum(pmic_bus, pmic_addr, 1, &dev);
	if (ret)
		hang();

	ret = dm_i2c_read(dev, 0x13, &data, 1);
	if (ret)
		hang();

	data |= BIT(1);

	ret = dm_i2c_write(dev, 0x13, &data, 1);
	if (ret)
		hang();
}
Esempio n. 24
0
int arch_misc_init(void)
{
	/* Disable PMIC sleep mode on low supply voltage */
	struct udevice *dev;
	u8 addr, data[1];
	int err;

	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
	if (err) {
		debug("%s: Cannot find PMIC I2C chip\n", __func__);
		return err;
	}

	addr = PMU_SUPPLYENE;

	err = dm_i2c_read(dev, addr, data, 1);
	if (err) {
		debug("failed to get PMU_SUPPLYENE\n");
		return err;
	}

	data[0] &= ~PMU_SUPPLYENE_SYSINEN;
	data[0] |= PMU_SUPPLYENE_EXITSLREQ;

	err = dm_i2c_write(dev, addr, data, 1);
	if (err) {
		debug("failed to set PMU_SUPPLYENE\n");
		return err;
	}

	/* make sure SODIMM pin 87 nRESET_OUT is released properly */
	pinmux_set_func(PMUX_PINGRP_ATA, PMUX_FUNC_GMI);

	if (readl(NV_PA_BASE_SRAM + NVBOOTINFOTABLE_BOOTTYPE) ==
	    NVBOOTTYPE_RECOVERY)
		printf("USB recovery mode\n");

	return 0;
}
Esempio n. 25
0
int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
{
	uint8_t val = value;

	return dm_i2c_write(dev, offset, &val, 1);
}
Esempio n. 26
0
static int cros_ec_i2c_command(struct udevice *udev, uint8_t cmd,
			       int cmd_version, const uint8_t *dout,
			       int dout_len, uint8_t **dinp, int din_len)
{
	struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
	/* version8, cmd8, arglen8, out8[dout_len], csum8 */
	int out_bytes = dout_len + 4;
	/* response8, arglen8, in8[din_len], checksum8 */
	int in_bytes = din_len + 3;
	uint8_t *ptr;
	/* Receive input data, so that args will be dword aligned */
	uint8_t *in_ptr;
	int len, csum, ret;

	/*
	 * Sanity-check I/O sizes given transaction overhead in internal
	 * buffers.
	 */
	if (out_bytes > sizeof(dev->dout)) {
		debug("%s: Cannot send %d bytes\n", __func__, dout_len);
		return -1;
	}
	if (in_bytes > sizeof(dev->din)) {
		debug("%s: Cannot receive %d bytes\n", __func__, din_len);
		return -1;
	}
	assert(dout_len >= 0);
	assert(dinp);

	/*
	 * Copy command and data into output buffer so we can do a single I2C
	 * burst transaction.
	 */
	ptr = dev->dout;

	/*
	 * in_ptr starts of pointing to a dword-aligned input data buffer.
	 * We decrement it back by the number of header bytes we expect to
	 * receive, so that the first parameter of the resulting input data
	 * will be dword aligned.
	 */
	in_ptr = dev->din + sizeof(int64_t);

	if (dev->protocol_version != 2) {
		/* Something we don't support */
		debug("%s: Protocol version %d unsupported\n",
		      __func__, dev->protocol_version);
		return -1;
	}

	*ptr++ = EC_CMD_VERSION0 + cmd_version;
	*ptr++ = cmd;
	*ptr++ = dout_len;
	in_ptr -= 2;	/* Expect status, length bytes */

	memcpy(ptr, dout, dout_len);
	ptr += dout_len;

	*ptr++ = (uint8_t)
		cros_ec_calc_checksum(dev->dout, dout_len + 3);

	/* Send output data */
	cros_ec_dump_data("out", -1, dev->dout, out_bytes);
	ret = dm_i2c_write(udev, 0, dev->dout, out_bytes);
	if (ret) {
		debug("%s: Cannot complete I2C write to %s\n", __func__,
		      udev->name);
		ret = -1;
	}

	if (!ret) {
		ret = dm_i2c_read(udev, 0, in_ptr, in_bytes);
		if (ret) {
			debug("%s: Cannot complete I2C read from %s\n",
			      __func__, udev->name);
			ret = -1;
		}
	}

	if (*in_ptr != EC_RES_SUCCESS) {
		debug("%s: Received bad result code %d\n", __func__, *in_ptr);
		return -(int)*in_ptr;
	}

	len = in_ptr[1];
	if (len + 3 > sizeof(dev->din)) {
		debug("%s: Received length %#02x too large\n",
		      __func__, len);
		return -1;
	}
	csum = cros_ec_calc_checksum(in_ptr, 2 + len);
	if (csum != in_ptr[2 + len]) {
		debug("%s: Invalid checksum rx %#02x, calced %#02x\n",
		      __func__, in_ptr[2 + din_len], csum);
		return -1;
	}
	din_len = min(din_len, len);
	cros_ec_dump_data("in", -1, in_ptr, din_len + 3);

	/* Return pointer to dword-aligned input data, if any */
	*dinp = dev->din + sizeof(int64_t);

	return din_len;
}