/* 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; }
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)); }
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; }
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); }
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); }
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; }
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; }
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp) { struct dm_i2c_chip *chip = dev_get_parentdata(dev); *flagsp = chip->flags; return 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; }
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; }
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; } }
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; }
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; }
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; }
/* 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); }
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; }
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; }
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; }
int usb_hub_scan(struct udevice *hub) { struct usb_device *udev = dev_get_parentdata(hub); return usb_hub_configure(udev); }
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); }
/** * 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; }
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; }
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; }