#define pr_fmt(fmt) "[ath79_spi_fifo]" fmt #include #include #include #include #include #include #include #define REG_FS 0x00 #define REG_CLOCK 0x04 #define REG_DATA_OUT 0x10 #define REG_CTRL 0x14 #define REG_DATA_IN 0x18 #define REG_FS_GPIO_MODE 1 #define REG_FS_MEM_MODE 0 #define REG_CLOCK_TSHSL_CNT(x) ((x & 0x3F) << 8) #define REG_CLOCK_SPI_RELOCATE (1 << 7) #define REG_CLOCK_REMAP_DISABLE (1 << 6) #define REG_CLOCK_DIV(x) ((x) & 0x1F) #define REG_CTRL_EN (1 << 31) #define REG_CTRL_CS(x) (1 << (28 + (x))) #define REG_CTRL_TERM (1 << 26) #define REG_CTRL_BITS(x) (x) struct ath79_driver { void __iomem *base; /* Currently unused but kept around */ struct clk *clk; }; static inline struct ath79_driver *ath79_spidev_to_drv(struct spi_device *spi) { return spi_master_get_devdata(spi->master); } static inline u32 read_reg(struct ath79_driver *drv, unsigned int reg) { return ioread32(drv->base + reg); } static inline void write_reg(struct ath79_driver *drv, unsigned int reg, u32 val) { iowrite32(val, drv->base + reg); } static inline u32 pack_data(u8 count, const u8 *src) { /* * We need to pack the data for the register. * * The register is lsb aligned an we need to fill the lower * 8*count bits of the register. * * There is probabbly some clever way, but be clear and write it * out as easy as possible for now. */ unsigned int i; u32 data = 0; for (i = 0; i < count; i++, src++) { data <<= 8; data |= *src; } return data; } static inline void unpack_data(u8 count, u32 data, u8 *dst) { /* * We need to unpack the data from the register. * * The data is lsb aligned and we need to extract the lower * 8*count bits of the register. */ unsigned int i; for (i = count; i > 0; i--, dst++) *dst = (data >> (i - 1) * 8) & 0xFF; } static int ath79_spi_transfer_one(struct spi_message *msg, struct spi_transfer *t, bool deassert) { struct ath79_driver *drv = ath79_spidev_to_drv(msg->spi); unsigned int count = t->len; const u8 *tx = t->tx_buf; u8 *rx = t->rx_buf; /* * We can transmit up to 32bit in one operation. The loop tries to use * as many of the available fifo as possible. Therefore we always try to * take 4 bytes unless the source buffer is smaller. */ while (count > 0) { const unsigned int take = min_t(unsigned int, count, 4); u32 data = 0; u32 ctrl = REG_CTRL_CS(msg->spi->chip_select) | REG_CTRL_BITS(take * 8); /* * This is the last fifo operation we make for this transfer and * we've been asked to deassert the CS afterwards. */ if (take == count && deassert) ctrl |= REG_CTRL_TERM; if (tx) { data = pack_data(take, tx); tx += take; } /* * Set the output data **then** write the control word. * * We can write the control word in one sweep to both configure * it and start the whole process this way. */ write_reg(drv, REG_DATA_OUT, data); write_reg(drv, REG_CTRL, REG_CTRL_EN | ctrl); /* * The EN bit we set will stay until the fifo is processed. */ while (read_reg(drv, REG_CTRL) & REG_CTRL_EN) ; if (rx) { data = read_reg(drv, REG_DATA_IN); unpack_data(take, data, rx); rx += take; } count -= take; } return 0; } static int ath79_spi_transfer(struct spi_master *master, struct spi_message *msg) { struct ath79_driver *drv = ath79_spidev_to_drv(msg->spi); struct spi_transfer *xfer; int ret = 0; list_for_each_entry(xfer, &msg->transfers, transfer_list) { bool deassert = false; /* * We need to deassert the CS on the last transfer, unless * cs_change is set, which indicates the CS should be keep * asserted for future messages */ if (list_is_last(&xfer->transfer_list, &msg->transfers) && !xfer->cs_change) deassert = true; /* * We need to toggle the cs between transfers. * * TODO: we probably need to delay after this messages a bit. * Currently not used. */ else if (xfer->cs_change) deassert = true; ret = ath79_spi_transfer_one(msg, xfer, deassert); if (ret != 0) goto out; msg->actual_length += xfer->len; } out: msg->status = ret; write_reg(drv, REG_CTRL, 0); spi_finalize_current_message(master); return ret; } static int ath79_spi_probe(struct platform_device *pdev) { struct spi_master *master; struct ath79_driver *drv; struct resource *r; int ret; u32 num_cs; master = spi_alloc_master(&pdev->dev, sizeof(*drv)); if (master == NULL) { dev_err(&pdev->dev, "failed to allocate spi master\n"); return -ENOMEM; } drv = spi_master_get_devdata(master); master->dev.of_node = pdev->dev.of_node; platform_set_drvdata(pdev, drv); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->transfer_one_message = ath79_spi_transfer; if (!master->dev.of_node) { dev_err(&pdev->dev, "missing of_node\n"); ret = -EINVAL; goto err_put_master; } if (of_property_read_u32(master->dev.of_node, "num-cs", &num_cs)) num_cs = 1; master->num_chipselect = num_cs; master->bus_num = of_alias_get_id(master->dev.of_node, "spi"); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); drv->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(drv->base)) { ret = PTR_ERR(drv->base); goto err_put_master; } drv->clk = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(drv->clk)) { ret = PTR_ERR(drv->clk); goto err_put_master; } ret = clk_prepare_enable(drv->clk); if (ret) goto err_put_master; write_reg(drv, REG_FS, REG_FS_GPIO_MODE); // TODO: we should probably make the div configurable. write_reg(drv, REG_CLOCK, REG_CLOCK_REMAP_DISABLE | REG_CLOCK_DIV(3)); ret = devm_spi_register_master(&pdev->dev, master); if (ret) goto err_disable; return 0; err_disable: clk_disable_unprepare(drv->clk); err_put_master: spi_master_put(master); return ret; } static int ath79_spi_remove(struct platform_device *pdev) { struct ath79_driver *drv = platform_get_drvdata(pdev); write_reg(drv, REG_FS, REG_FS_MEM_MODE); clk_disable_unprepare(drv->clk); // spi_master_put(sp->bitbang.master); return 0; } static const struct of_device_id ath79_fifo_spi_of_match[] = { { .compatible = "qca,ath79-spi-fifo", }, {}, }; static struct platform_driver ath79_fifo_spi_driver = { .probe = ath79_spi_probe, .remove = ath79_spi_remove, .driver = { .name = "ath79-spi-fifo", .of_match_table = ath79_fifo_spi_of_match, }, }; module_platform_driver(ath79_fifo_spi_driver);