static int pic32_spi_probe(struct udevice *bus) { struct pic32_spi_priv *priv = dev_get_priv(bus); struct dm_spi_bus *dm_spi = dev_get_uclass_priv(bus); struct udevice *clkdev; fdt_addr_t addr; fdt_size_t size; int ret; debug("%s: %d, bus: %i\n", __func__, __LINE__, bus->seq); addr = fdtdec_get_addr_size(gd->fdt_blob, bus->of_offset, "reg", &size); if (addr == FDT_ADDR_T_NONE) return -EINVAL; priv->regs = ioremap(addr, size); if (!priv->regs) return -EINVAL; dm_spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset, "spi-max-frequency", 250000000); /* get clock rate */ ret = clk_get_by_index(bus, 0, &clkdev); if (ret < 0) { printf("pic32-spi: error, clk not found\n"); return ret; } priv->clk_rate = clk_get_periph_rate(clkdev, ret); /* initialize HW */ pic32_spi_hw_init(priv); /* set word len */ pic32_spi_set_word_size(priv, SPI_DEFAULT_WORDLEN); /* PIC32 SPI controller can automatically drive /CS during transfer * depending on fifo fill-level. /CS will stay asserted as long as * TX fifo is non-empty, else will be deasserted confirming completion * of the ongoing transfer. To avoid this sort of error we will drive * /CS manually by toggling cs-gpio pins. */ ret = gpio_request_by_name_nodev(gd->fdt_blob, bus->of_offset, "cs-gpios", 0, &priv->cs_gpio, GPIOD_IS_OUT); if (ret) { printf("pic32-spi: error, cs-gpios not found\n"); return ret; } return 0; }
static int pic32_spi_prepare_message(struct spi_master *master, struct spi_message *msg) { struct pic32_spi *pic32s = spi_master_get_devdata(master); struct spi_device *spi = msg->spi; u32 val; /* set device specific bits_per_word */ if (pic32s->bits_per_word != spi->bits_per_word) { pic32_spi_set_word_size(pic32s, spi->bits_per_word); pic32s->bits_per_word = spi->bits_per_word; } /* device specific speed change */ if (pic32s->speed_hz != spi->max_speed_hz) { pic32_spi_set_clk_rate(pic32s, spi->max_speed_hz); pic32s->speed_hz = spi->max_speed_hz; } /* device specific mode change */ if (pic32s->mode != spi->mode) { val = readl(&pic32s->regs->ctrl); /* active low */ if (spi->mode & SPI_CPOL) val |= CTRL_CKP; else val &= ~CTRL_CKP; /* tx on rising edge */ if (spi->mode & SPI_CPHA) val &= ~CTRL_CKE; else val |= CTRL_CKE; /* rx at end of tx */ val |= CTRL_SMP; writel(val, &pic32s->regs->ctrl); pic32s->mode = spi->mode; } return 0; }
static int pic32_spi_one_transfer(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer) { struct pic32_spi *pic32s; bool dma_issued = false; unsigned long timeout; int ret; pic32s = spi_master_get_devdata(master); /* handle transfer specific word size change */ if (transfer->bits_per_word && (transfer->bits_per_word != pic32s->bits_per_word)) { ret = pic32_spi_set_word_size(pic32s, transfer->bits_per_word); if (ret) return ret; pic32s->bits_per_word = transfer->bits_per_word; } /* handle transfer specific speed change */ if (transfer->speed_hz && (transfer->speed_hz != pic32s->speed_hz)) { pic32_spi_set_clk_rate(pic32s, transfer->speed_hz); pic32s->speed_hz = transfer->speed_hz; } reinit_completion(&pic32s->xfer_done); /* transact by DMA mode */ if (transfer->rx_sg.nents && transfer->tx_sg.nents) { ret = pic32_spi_dma_transfer(pic32s, transfer); if (ret) { dev_err(&spi->dev, "dma submit error\n"); return ret; } /* DMA issued */ dma_issued = true; } else { /* set current transfer information */ pic32s->tx = (const void *)transfer->tx_buf; pic32s->rx = (const void *)transfer->rx_buf; pic32s->tx_end = pic32s->tx + transfer->len; pic32s->rx_end = pic32s->rx + transfer->len; pic32s->len = transfer->len; /* transact by interrupt driven PIO */ enable_irq(pic32s->fault_irq); enable_irq(pic32s->rx_irq); enable_irq(pic32s->tx_irq); } /* wait for completion */ timeout = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ); if (timeout == 0) { dev_err(&spi->dev, "wait error/timedout\n"); if (dma_issued) { dmaengine_terminate_all(master->dma_rx); dmaengine_terminate_all(master->dma_rx); } ret = -ETIMEDOUT; } else { ret = 0; } return ret; }
static int pic32_spi_set_wordlen(struct udevice *slave, unsigned int wordlen) { struct pic32_spi_priv *priv = dev_get_priv(slave->parent); return pic32_spi_set_word_size(priv, wordlen); }