int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info) { struct spi_cs_info local_info; struct dm_spi_ops *ops; int ret; if (!info) info = &local_info; /* If there is a device attached, return it */ info->dev = NULL; ret = spi_find_chip_select(bus, cs, &info->dev); if (!ret) return 0; /* * Otherwise ask the driver. For the moment we don't have CS info. * When we do we could provide the driver with a helper function * to figure out what chip selects are valid, or just handle the * request. */ ops = spi_get_ops(bus); if (ops->cs_info) return ops->cs_info(bus, cs, info); /* * We could assume there is at least one valid chip select, but best * to be sure and return an error in this case. The driver didn't * care enough to tell us. */ return -ENODEV; }
int dm_spi_claim_bus(struct udevice *dev) { struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); struct dm_spi_bus *spi = dev_get_uclass_priv(bus); struct spi_slave *slave = dev_get_parent_priv(dev); int speed; int ret; speed = slave->max_hz; if (spi->max_hz) { if (speed) speed = min(speed, (int)spi->max_hz); else speed = spi->max_hz; } if (!speed) speed = 100000; if (speed != slave->speed) { ret = spi_set_speed_mode(bus, speed, slave->mode); if (ret) return ret; slave->speed = speed; } return ops->claim_bus ? ops->claim_bus(dev) : 0; }
static int spi_post_probe(struct udevice *bus) { #if !CONFIG_IS_ENABLED(OF_PLATDATA) struct dm_spi_bus *spi = dev_get_uclass_priv(bus); spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset, "spi-max-frequency", 0); #endif #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->claim_bus) ops->claim_bus += gd->reloc_off; if (ops->release_bus) ops->release_bus += gd->reloc_off; if (ops->set_wordlen) ops->set_wordlen += gd->reloc_off; if (ops->xfer) ops->xfer += gd->reloc_off; if (ops->set_speed) ops->set_speed += gd->reloc_off; if (ops->set_mode) ops->set_mode += gd->reloc_off; if (ops->cs_info) ops->cs_info += gd->reloc_off; #endif return 0; }
static int spi_set_speed_mode(struct udevice *bus, int speed, int mode) { struct dm_spi_ops *ops; int ret; ops = spi_get_ops(bus); if (ops->set_speed) ret = ops->set_speed(bus, speed); else ret = -EINVAL; if (ret) { printf("Cannot set speed (err=%d)\n", ret); return ret; } if (ops->set_mode) ret = ops->set_mode(bus, mode); else ret = -EINVAL; if (ret) { printf("Cannot set mode (err=%d)\n", ret); return ret; } return 0; }
static int spi_post_probe(struct udevice *bus) { #if !CONFIG_IS_ENABLED(OF_PLATDATA) struct dm_spi_bus *spi = dev_get_uclass_priv(bus); spi->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0); #endif #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->claim_bus) ops->claim_bus += gd->reloc_off; if (ops->release_bus) ops->release_bus += gd->reloc_off; if (ops->set_wordlen) ops->set_wordlen += gd->reloc_off; if (ops->xfer) ops->xfer += gd->reloc_off; if (ops->set_speed) ops->set_speed += gd->reloc_off; if (ops->set_mode) ops->set_mode += gd->reloc_off; if (ops->cs_info) ops->cs_info += gd->reloc_off; if (ops->is_flash_command_supported) ops->is_flash_command_supported += gd->reloc_off; if (ops->exec_flash_command) ops->exec_flash_command += gd->reloc_off; #endif return 0; }
void dm_spi_release_bus(struct udevice *dev) { struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->release_bus) ops->release_bus(dev); }
void spi_release_bus(struct spi_slave *slave) { struct udevice *dev = slave->dev; struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->release_bus) ops->release_bus(bus); }
int dm_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev->parent; if (bus->uclass->uc_drv->id != UCLASS_SPI) return -EOPNOTSUPP; return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags); }
/** * spi_mem_supports_op() - Check if a memory device and the controller it is * connected to support a specific memory operation * @slave: the SPI device * @op: the memory operation to check * * Some controllers are only supporting Single or Dual IOs, others might only * support specific opcodes, or it can even be that the controller and device * both support Quad IOs but the hardware prevents you from using it because * only 2 IO lines are connected. * * This function checks whether a specific operation is supported. * * Return: true if @op is supported, false otherwise. */ bool spi_mem_supports_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct udevice *bus = slave->dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->mem_ops && ops->mem_ops->supports_op) return ops->mem_ops->supports_op(slave, op); return spi_mem_default_supports_op(slave, op); }
bool dm_spi_is_flash_command_supported(struct udevice *dev, const struct spi_flash_command *cmd) { struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->is_flash_command_supported) return ops->is_flash_command_supported(dev, cmd); return false; }
int dm_spi_exec_flash_command(struct udevice *dev, const struct spi_flash_command *cmd) { struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->exec_flash_command) return ops->exec_flash_command(dev, cmd); return -EINVAL; }
int spi_claim_bus(struct spi_slave *slave) { struct udevice *dev = slave->dev; struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); struct dm_spi_bus *spi = bus->uclass_priv; int speed; int ret; speed = slave->max_hz; if (spi->max_hz) { if (speed) speed = min(speed, (int)spi->max_hz); else speed = spi->max_hz; } if (!speed) speed = 100000; ret = spi_set_speed_mode(bus, speed, slave->mode); if (ret) return ret; return ops->claim_bus ? ops->claim_bus(bus) : 0; }
/** * spi_mem_exec_op() - Execute a memory operation * @slave: the SPI device * @op: the memory operation to execute * * Executes a memory operation. * * This function first checks that @op is supported and then tries to execute * it. * * Return: 0 in case of success, a negative error code otherwise. */ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct udevice *bus = slave->dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); unsigned int pos = 0; const u8 *tx_buf = NULL; u8 *rx_buf = NULL; u8 *op_buf; int op_len; u32 flag; int ret; int i; if (!spi_mem_supports_op(slave, op)) return -ENOTSUPP; if (ops->mem_ops) { #ifndef __UBOOT__ /* * Flush the message queue before executing our SPI memory * operation to prevent preemption of regular SPI transfers. */ spi_flush_queue(ctlr); if (ctlr->auto_runtime_pm) { ret = pm_runtime_get_sync(ctlr->dev.parent); if (ret < 0) { dev_err(&ctlr->dev, "Failed to power device: %d\n", ret); return ret; } } mutex_lock(&ctlr->bus_lock_mutex); mutex_lock(&ctlr->io_mutex); #endif ret = ops->mem_ops->exec_op(slave, op); #ifndef __UBOOT__ mutex_unlock(&ctlr->io_mutex); mutex_unlock(&ctlr->bus_lock_mutex); if (ctlr->auto_runtime_pm) pm_runtime_put(ctlr->dev.parent); #endif /* * Some controllers only optimize specific paths (typically the * read path) and expect the core to use the regular SPI * interface in other cases. */ if (!ret || ret != -ENOTSUPP) return ret; } #ifndef __UBOOT__ tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; /* * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so * we're guaranteed that this buffer is DMA-able, as required by the * SPI layer. */ tmpbuf = kzalloc(tmpbufsize, GFP_KERNEL | GFP_DMA); if (!tmpbuf) return -ENOMEM; spi_message_init(&msg); tmpbuf[0] = op->cmd.opcode; xfers[xferpos].tx_buf = tmpbuf; xfers[xferpos].len = sizeof(op->cmd.opcode); xfers[xferpos].tx_nbits = op->cmd.buswidth; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; totalxferlen++; if (op->addr.nbytes) { int i; for (i = 0; i < op->addr.nbytes; i++) tmpbuf[i + 1] = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); xfers[xferpos].tx_buf = tmpbuf + 1; xfers[xferpos].len = op->addr.nbytes; xfers[xferpos].tx_nbits = op->addr.buswidth; spi_message_add_tail(&xfers[xferpos], &msg); xferpos++; totalxferlen += op->addr.nbytes; }