예제 #1
0
/* Test that the bus ops are called when a child is probed/removed */
static int dm_test_bus_parent_ops(struct dm_test_state *dms)
{
	struct dm_test_parent_data *parent_data;
	struct udevice *bus, *dev;
	struct uclass *uc;

	test_state = dms;
	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));

	uclass_foreach_dev(dev, uc) {
		/* Ignore these if they are not on this bus */
		if (dev->parent != bus)
			continue;
		ut_asserteq_ptr(NULL, dev_get_parentdata(dev));

		ut_assertok(device_probe(dev));
		parent_data = dev_get_parentdata(dev);
		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
	}

	uclass_foreach_dev(dev, uc) {
		/* Ignore these if they are not on this bus */
		if (dev->parent != bus)
			continue;
		parent_data = dev_get_parentdata(dev);
		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
		ut_assertok(device_remove(dev));
		ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
		ut_asserteq_ptr(dms->removed, dev);
	}
	test_state = NULL;

	return 0;
}
예제 #2
0
static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
					  struct QH *qh)
{
	struct usb_device *ttdev;
	int parent_devnum;

	if (udev->speed != USB_SPEED_LOW && udev->speed != USB_SPEED_FULL)
		return;

	/*
	 * For full / low speed devices we need to get the devnum and portnr of
	 * the tt, so of the first upstream usb-2 hub, there may be usb-1 hubs
	 * in the tree before that one!
	 */
#ifdef CONFIG_DM_USB
	/*
	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
	 * to the parent udevice, not the actual udevice belonging to the
	 * udev as the device is not instantiated yet. So when searching
	 * for the first usb-2 parent start with udev->dev not
	 * udev->dev->parent .
	 */
	struct udevice *parent;
	struct usb_device *uparent;

	ttdev = udev;
	parent = udev->dev;
	uparent = dev_get_parentdata(parent);

	while (uparent->speed != USB_SPEED_HIGH) {
		struct udevice *dev = parent;

		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
			printf("ehci: Error cannot find high-speed parent of usb-1 device\n");
			return;
		}

		ttdev = dev_get_parentdata(dev);
		parent = dev->parent;
		uparent = dev_get_parentdata(parent);
	}
	parent_devnum = uparent->devnum;
#else
	ttdev = udev;
	while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH)
		ttdev = ttdev->parent;
	if (!ttdev->parent)
		return;
	parent_devnum = ttdev->parent->devnum;
#endif

	qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(ttdev->portnr) |
				     QH_ENDPT2_HUBADDR(parent_devnum));
}
예제 #3
0
int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
{
	struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
	struct spi_slave *slave = dev_get_parentdata(dev->dev);
	int rv;

	/* Do the transfer */
	if (spi_claim_bus(slave)) {
		debug("%s: Cannot claim SPI bus\n", __func__);
		return -1;
	}

	rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8,
		      dev->dout, dev->din,
		      SPI_XFER_BEGIN | SPI_XFER_END);

	spi_release_bus(slave);

	if (rv) {
		debug("%s: Cannot complete SPI transfer\n", __func__);
		return -1;
	}

	return in_bytes;
}
예제 #4
0
int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
{
	struct udevice *dev;

	debug("%s: Searching bus '%s' for address %02x: ", __func__,
	      bus->name, chip_addr);
	for (device_find_first_child(bus, &dev); dev;
			device_find_next_child(&dev)) {
		struct dm_i2c_chip store;
		struct dm_i2c_chip *chip = dev_get_parentdata(dev);
		int ret;

		if (!chip) {
			chip = &store;
			i2c_chip_ofdata_to_platdata(gd->fdt_blob,
						    dev->of_offset, chip);
		}
		if (chip->chip_addr == chip_addr) {
			ret = device_probe(dev);
			debug("found, ret=%d\n", ret);
			if (ret)
				return ret;
			*devp = dev;
			return 0;
		}
	}
	debug("not found\n");
	return i2c_bind_driver(bus, chip_addr, devp);
}
예제 #5
0
int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
{
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
	struct udevice *bus = dev_get_parent(dev);
	struct dm_i2c_ops *ops = i2c_get_ops(bus);
	struct i2c_msg msg[2], *ptr;
	uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
	int msg_count;

	if (!ops->xfer)
		return -ENOSYS;
	if (chip->flags & DM_I2C_CHIP_RD_ADDRESS)
		return i2c_read_bytewise(dev, offset, buffer, len);
	ptr = msg;
	if (!i2c_setup_offset(chip, offset, offset_buf, ptr))
		ptr++;

	if (len) {
		ptr->addr = chip->chip_addr;
		ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
		ptr->flags |= I2C_M_RD;
		ptr->len = len;
		ptr->buf = buffer;
		ptr++;
	}
	msg_count = ptr - msg;

	return ops->xfer(bus, msg, msg_count);
}
예제 #6
0
static int i2c_read_bytewise(struct udevice *dev, uint offset,
			     uint8_t *buffer, int len)
{
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
	struct udevice *bus = dev_get_parent(dev);
	struct dm_i2c_ops *ops = i2c_get_ops(bus);
	struct i2c_msg msg[2], *ptr;
	uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
	int ret;
	int i;

	for (i = 0; i < len; i++) {
		if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
			return -EINVAL;
		ptr = msg + 1;
		ptr->addr = chip->chip_addr;
		ptr->flags = msg->flags | I2C_M_RD;
		ptr->len = 1;
		ptr->buf = &buffer[i];
		ptr++;

		ret = ops->xfer(bus, msg, ptr - msg);
		if (ret)
			return ret;
	}

	return 0;
}
예제 #7
0
static int testbus_child_pre_probe(struct udevice *dev)
{
	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);

	parent_data->flag += FLAG_CHILD_PROBED;

	return 0;
}
예제 #8
0
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
{
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);

	*flagsp = chip->flags;

	return 0;
}
예제 #9
0
/* Test that the bus can store data about each child */
static int dm_test_bus_parent_data(struct dm_test_state *dms)
{
	struct dm_test_parent_data *parent_data;
	struct udevice *bus, *dev;
	struct uclass *uc;
	int value;

	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));

	/* Check that parent data is allocated */
	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
	ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
	parent_data = dev_get_parentdata(dev);
	ut_assert(NULL != parent_data);

	/* Check that it starts at 0 and goes away when device is removed */
	parent_data->sum += 5;
	ut_asserteq(5, parent_data->sum);
	device_remove(dev);
	ut_asserteq_ptr(NULL, dev_get_parentdata(dev));

	/* Check that we can do this twice */
	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
	parent_data = dev_get_parentdata(dev);
	ut_assert(NULL != parent_data);
	parent_data->sum += 5;
	ut_asserteq(5, parent_data->sum);

	/* Add parent data to all children */
	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
	value = 5;
	uclass_foreach_dev(dev, uc) {
		/* Ignore these if they are not on this bus */
		if (dev->parent != bus) {
			ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
			continue;
		}
		ut_assertok(device_probe(dev));
		parent_data = dev_get_parentdata(dev);

		parent_data->sum = value;
		value += 5;
	}

	/* Check it is still there */
	value = 5;
	uclass_foreach_dev(dev, uc) {
		/* Ignore these if they are not on this bus */
		if (dev->parent != bus)
			continue;
		parent_data = dev_get_parentdata(dev);

		ut_asserteq(value, parent_data->sum);
		value += 5;
	}

	return 0;
}
예제 #10
0
int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
{
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);

	if (offset_len > I2C_MAX_OFFSET_LEN)
		return -EINVAL;
	chip->offset_len = offset_len;

	return 0;
}
예제 #11
0
int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
{
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
	struct udevice *bus = dev_get_parent(dev);
	struct dm_i2c_ops *ops = i2c_get_ops(bus);
	struct i2c_msg msg[1];

	if (!ops->xfer)
		return -ENOSYS;

	if (chip->flags & DM_I2C_CHIP_WR_ADDRESS)
		return i2c_write_bytewise(dev, offset, buffer, len);
	/*
	 * The simple approach would be to send two messages here: one to
	 * set the offset and one to write the bytes. However some drivers
	 * will not be expecting this, and some chips won't like how the
	 * driver presents this on the I2C bus.
	 *
	 * The API does not support separate offset and data. We could extend
	 * it with a flag indicating that there is data in the next message
	 * that needs to be processed in the same transaction. We could
	 * instead add an additional buffer to each message. For now, handle
	 * this in the uclass since it isn't clear what the impact on drivers
	 * would be with this extra complication. Unfortunately this means
	 * copying the message.
	 *
	 * Use the stack for small messages, malloc() for larger ones. We
	 * need to allow space for the offset (up to 4 bytes) and the message
	 * itself.
	 */
	if (len < 64) {
		uint8_t buf[I2C_MAX_OFFSET_LEN + len];

		i2c_setup_offset(chip, offset, buf, msg);
		msg->len += len;
		memcpy(buf + chip->offset_len, buffer, len);

		return ops->xfer(bus, msg, 1);
	} else {
		uint8_t *buf;
		int ret;

		buf = malloc(I2C_MAX_OFFSET_LEN + len);
		if (!buf)
			return -ENOMEM;
		i2c_setup_offset(chip, offset, buf, msg);
		msg->len += len;
		memcpy(buf + chip->offset_len, buffer, len);

		ret = ops->xfer(bus, msg, 1);
		free(buf);
		return ret;
	}
}
예제 #12
0
static int testbus_child_post_remove(struct udevice *dev)
{
	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
	struct dm_test_state *dms = test_state;

	parent_data->flag += FLAG_CHILD_REMOVED;
	if (dms)
		dms->removed = dev;

	return 0;
}
예제 #13
0
static int zynq_qspi_child_pre_probe(struct udevice *bus)
{
	struct spi_slave *slave = dev_get_parentdata(bus);
	struct zynq_qspi_priv *priv = dev_get_priv(bus->parent);

	slave->option = priv->is_dual;
	slave->dio = priv->is_dio;
	slave->op_mode_rx = SPI_OPM_RX_QOF;
	slave->op_mode_tx = SPI_OPM_TX_QPP;

	return 0;
}
예제 #14
0
static int zynqmp_qspi_child_pre_probe(struct udevice *bus)
{
	struct spi_slave *slave = dev_get_parentdata(bus);
	struct zynqmp_qspi_priv *priv = dev_get_priv(bus->parent);
	u8 bootmode;
	u32 reg;

	slave->option = priv->is_dual;
	slave->op_mode_rx = SPI_OPM_RX_QOF;
	slave->op_mode_tx = SPI_OPM_TX_QPP;
	slave->bytemode = SPI_4BYTE_MODE;

	return 0;
}
예제 #15
0
/* Compatibility function - to be removed */
struct spi_slave *spi_setup_slave_fdt(const void *blob, int node,
				      int bus_node)
{
	struct udevice *bus, *dev;
	int ret;

	ret = uclass_get_device_by_of_offset(UCLASS_SPI, bus_node, &bus);
	if (ret)
		return NULL;
	ret = device_get_child_by_of_offset(bus, node, &dev);
	if (ret)
		return NULL;
	return dev_get_parentdata(dev);
}
예제 #16
0
int i2c_set_chip_flags(struct udevice *dev, uint flags)
{
	struct udevice *bus = dev->parent;
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
	struct dm_i2c_ops *ops = i2c_get_ops(bus);
	int ret;

	if (ops->set_flags) {
		ret = ops->set_flags(dev, flags);
		if (ret)
			return ret;
	}
	chip->flags = flags;

	return 0;
}
예제 #17
0
int spi_child_pre_probe(struct udevice *dev)
{
	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
	struct spi_slave *slave = dev_get_parentdata(dev);

	/*
	 * This is needed because we pass struct spi_slave around the place
	 * instead slave->dev (a struct udevice). So we have to have some
	 * way to access the slave udevice given struct spi_slave. Once we
	 * change the SPI API to use udevice instead of spi_slave, we can
	 * drop this.
	 */
	slave->dev = dev;

	slave->max_hz = plat->max_hz;
	slave->mode = plat->mode;

	return 0;
}
예제 #18
0
static int i2c_write_bytewise(struct udevice *dev, uint offset,
			     const uint8_t *buffer, int len)
{
	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
	struct udevice *bus = dev_get_parent(dev);
	struct dm_i2c_ops *ops = i2c_get_ops(bus);
	struct i2c_msg msg[1];
	uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
	int ret;
	int i;

	for (i = 0; i < len; i++) {
		if (i2c_setup_offset(chip, offset + i, buf, msg))
			return -EINVAL;
		buf[msg->len++] = buffer[i];

		ret = ops->xfer(bus, msg, 1);
		if (ret)
			return ret;
	}

	return 0;
}
예제 #19
0
int usb_hub_scan(struct udevice *hub)
{
	struct usb_device *udev = dev_get_parentdata(hub);

	return usb_hub_configure(udev);
}
예제 #20
0
int hub_port_reset(struct udevice *dev, int port, unsigned short *portstat)
{
	struct usb_device *udev = dev_get_parentdata(dev);

	return legacy_hub_port_reset(udev, port, portstat);
}
예제 #21
0
/**
 * Send a command to a LPC CROS_EC device and return the reply.
 *
 * The device's internal input/output buffers are used.
 *
 * @param dev		CROS_EC device
 * @param cmd		Command to send (EC_CMD_...)
 * @param cmd_version	Version of command to send (EC_VER_...)
 * @param dout		Output data (may be NULL If dout_len=0)
 * @param dout_len      Size of output data in bytes
 * @param dinp		Returns pointer to response data. This will be
 *			untouched unless we return a value > 0.
 * @param din_len	Maximum size of response in bytes
 * @return number of bytes in response, or -1 on error
 */
int cros_ec_spi_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);
	struct spi_slave *slave = dev_get_parentdata(dev->dev);
	int in_bytes = din_len + 4;	/* status, length, checksum, trailer */
	uint8_t *out;
	uint8_t *p;
	int csum, len;
	int rv;

	if (dev->protocol_version != 2) {
		debug("%s: Unsupported EC protcol version %d\n",
		      __func__, dev->protocol_version);
		return -1;
	}

	/*
	 * Sanity-check input size to make sure it plus transaction overhead
	 * fits in the internal device buffer.
	 */
	if (in_bytes > sizeof(dev->din)) {
		debug("%s: Cannot receive %d bytes\n", __func__, din_len);
		return -1;
	}

	/* We represent message length as a byte */
	if (dout_len > 0xff) {
		debug("%s: Cannot send %d bytes\n", __func__, dout_len);
		return -1;
	}

	/*
	 * Clear input buffer so we don't get false hits for MSG_HEADER
	 */
	memset(dev->din, '\0', in_bytes);

	if (spi_claim_bus(slave)) {
		debug("%s: Cannot claim SPI bus\n", __func__);
		return -1;
	}

	out = dev->dout;
	out[0] = EC_CMD_VERSION0 + cmd_version;
	out[1] = cmd;
	out[2] = (uint8_t)dout_len;
	memcpy(out + 3, dout, dout_len);
	csum = cros_ec_calc_checksum(out, 3)
	       + cros_ec_calc_checksum(dout, dout_len);
	out[3 + dout_len] = (uint8_t)csum;

	/*
	 * Send output data and receive input data starting such that the
	 * message body will be dword aligned.
	 */
	p = dev->din + sizeof(int64_t) - 2;
	len = dout_len + 4;
	cros_ec_dump_data("out", cmd, out, len);
	rv = spi_xfer(slave, max(len, in_bytes) * 8, out, p,
		      SPI_XFER_BEGIN | SPI_XFER_END);

	spi_release_bus(slave);

	if (rv) {
		debug("%s: Cannot complete SPI transfer\n", __func__);
		return -1;
	}

	len = min((int)p[1], din_len);
	cros_ec_dump_data("in", -1, p, len + 3);

	/* Response code is first byte of message */
	if (p[0] != EC_RES_SUCCESS) {
		printf("%s: Returned status %d\n", __func__, p[0]);
		return -(int)(p[0]);
	}

	/* Check checksum */
	csum = cros_ec_calc_checksum(p, len + 2);
	if (csum != p[len + 2]) {
		debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__,
		      p[2 + len], csum);
		return -1;
	}

	/* Anything else is the response data */
	*dinp = p + 2;

	return len;
}
예제 #22
0
int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize)
{
	struct usb_device *udev = dev_get_parentdata(dev);
	struct usb_interface_descriptor *iface_desc;
	bool ep_in_found = false, ep_out_found = false;
	struct usb_interface *iface;
	const int ifnum = 0; /* Always use interface 0 */
	int ret, i;

	iface = &udev->config.if_desc[ifnum];
	iface_desc = &udev->config.if_desc[ifnum].desc;

	/* Initialize the ueth_data structure with some useful info */
	ueth->ifnum = ifnum;
	ueth->subclass = iface_desc->bInterfaceSubClass;
	ueth->protocol = iface_desc->bInterfaceProtocol;

	/*
	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
	 * We will ignore any others.
	 */
	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
		int ep_addr = iface->ep_desc[i].bEndpointAddress;

		/* is it an BULK endpoint? */
		if ((iface->ep_desc[i].bmAttributes &
		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
			if (ep_addr & USB_DIR_IN && !ep_in_found) {
				ueth->ep_in = ep_addr &
					USB_ENDPOINT_NUMBER_MASK;
				ep_in_found = true;
			} else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
				ueth->ep_out = ep_addr &
					USB_ENDPOINT_NUMBER_MASK;
				ep_out_found = true;
			}
		}

		/* is it an interrupt endpoint? */
		if ((iface->ep_desc[i].bmAttributes &
		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
			ueth->ep_int = iface->ep_desc[i].bEndpointAddress &
				USB_ENDPOINT_NUMBER_MASK;
			ueth->irqinterval = iface->ep_desc[i].bInterval;
		}
	}
	debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out,
	      ueth->ep_int);

	/* Do some basic sanity checks, and bail if we find a problem */
	if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) {
		debug("%s: %s: Cannot find endpoints\n", __func__, dev->name);
		return -ENXIO;
	}

	ueth->rxsize = rxsize;
	ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN);
	if (!ueth->rxbuf)
		return -ENOMEM;

	ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum);
	if (ret) {
		debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name,
		      ret);
		return ret;
	}
	ueth->pusb_dev = udev;

	return 0;
}
예제 #23
0
int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
		       const char *drv_name, const char *dev_name,
		       struct udevice **busp, struct spi_slave **devp)
{
	struct udevice *bus, *dev;
	bool created = false;
	int ret;

	ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
	if (ret) {
		printf("Invalid bus %d (err=%d)\n", busnum, ret);
		return ret;
	}
	ret = spi_find_chip_select(bus, cs, &dev);

	/*
	 * If there is no such device, create one automatically. This means
	 * that we don't need a device tree node or platform data for the
	 * SPI flash chip - we will bind to the correct driver.
	 */
	if (ret == -ENODEV && drv_name) {
		struct dm_spi_slave_platdata *plat;

		debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
		      __func__, dev_name, busnum, cs, drv_name);
		ret = device_bind_driver(bus, drv_name, dev_name, &dev);
		if (ret)
			return ret;
		plat = dev_get_parent_platdata(dev);
		plat->cs = cs;
		plat->max_hz = speed;
		plat->mode = mode;
		created = true;
	} else if (ret) {
		printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
		       ret);
		return ret;
	}

	if (!device_active(dev)) {
		struct spi_slave *slave;

		ret = device_probe(dev);
		if (ret)
			goto err;
		slave = dev_get_parentdata(dev);
		slave->dev = dev;
	}

	ret = spi_set_speed_mode(bus, speed, mode);
	if (ret)
		goto err;

	*busp = bus;
	*devp = dev_get_parentdata(dev);
	debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp);

	return 0;

err:
	debug("%s: Error path, credted=%d, device '%s'\n", __func__,
	      created, dev->name);
	if (created) {
		device_remove(dev);
		device_unbind(dev);
	}

	return ret;
}