• Home
  • Raw
  • Download

Lines Matching +full:f +full:- +full:ospi

1 // SPDX-License-Identifier: GPL-2.0-only
16 #include <linux/spi/spi-mem.h>
119 if (!op->dummy.nbytes) in f_ospi_get_dummy_cycle()
122 return (op->dummy.nbytes * 8) / op->dummy.buswidth; in f_ospi_get_dummy_cycle()
125 static void f_ospi_clear_irq(struct f_ospi *ospi) in f_ospi_clear_irq() argument
128 ospi->base + OSPI_IRQ); in f_ospi_clear_irq()
131 static void f_ospi_enable_irq_status(struct f_ospi *ospi, u32 irq_bits) in f_ospi_enable_irq_status() argument
135 val = readl(ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_enable_irq_status()
137 writel(val, ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_enable_irq_status()
140 static void f_ospi_disable_irq_status(struct f_ospi *ospi, u32 irq_bits) in f_ospi_disable_irq_status() argument
144 val = readl(ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_disable_irq_status()
146 writel(val, ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_disable_irq_status()
149 static void f_ospi_disable_irq_output(struct f_ospi *ospi, u32 irq_bits) in f_ospi_disable_irq_output() argument
153 val = readl(ospi->base + OSPI_IRQ_SIG_EN); in f_ospi_disable_irq_output()
155 writel(val, ospi->base + OSPI_IRQ_SIG_EN); in f_ospi_disable_irq_output()
158 static int f_ospi_prepare_config(struct f_ospi *ospi) in f_ospi_prepare_config() argument
163 val = readl(ospi->base + OSPI_CLK_CTL); in f_ospi_prepare_config()
165 writel(val, ospi->base + OSPI_CLK_CTL); in f_ospi_prepare_config()
171 return readl_poll_timeout(ospi->base + OSPI_STAT, in f_ospi_prepare_config()
176 static int f_ospi_unprepare_config(struct f_ospi *ospi) in f_ospi_unprepare_config() argument
181 val = readl(ospi->base + OSPI_CLK_CTL); in f_ospi_unprepare_config()
183 writel(val, ospi->base + OSPI_CLK_CTL); in f_ospi_unprepare_config()
186 return readl_poll_timeout(ospi->base + OSPI_STAT, in f_ospi_unprepare_config()
191 static void f_ospi_config_clk(struct f_ospi *ospi, u32 device_hz) in f_ospi_config_clk() argument
193 long rate_hz = clk_get_rate(ospi->clk); in f_ospi_config_clk()
199 dev_warn(ospi->dev, "Device frequency too large: %d\n", in f_ospi_config_clk()
212 dev_warn(ospi->dev, "Device frequency too small: %d\n", in f_ospi_config_clk()
223 val = readl(ospi->base + OSPI_CLK_CTL); in f_ospi_config_clk()
229 writel(val, ospi->base + OSPI_CLK_CTL); in f_ospi_config_clk()
232 static void f_ospi_config_dll(struct f_ospi *ospi) in f_ospi_config_dll() argument
237 static u8 f_ospi_get_mode(struct f_ospi *ospi, int width, int data_size) in f_ospi_get_mode() argument
256 dev_err(ospi->dev, "Invalid buswidth: %d\n", width); in f_ospi_get_mode()
263 static void f_ospi_config_indir_protocol(struct f_ospi *ospi, in f_ospi_config_indir_protocol() argument
267 struct spi_device *spi = mem->spi; in f_ospi_config_indir_protocol()
273 writel(BIT(spi_get_chipselect(spi, 0)), ospi->base + OSPI_SSEL); in f_ospi_config_indir_protocol()
275 mode = f_ospi_get_mode(ospi, op->cmd.buswidth, 1); in f_ospi_config_indir_protocol()
278 mode = f_ospi_get_mode(ospi, op->addr.buswidth, op->addr.nbytes); in f_ospi_config_indir_protocol()
281 mode = f_ospi_get_mode(ospi, op->data.buswidth, op->data.nbytes); in f_ospi_config_indir_protocol()
289 if (spi->mode & SPI_LSB_FIRST) in f_ospi_config_indir_protocol()
293 if (spi->mode & SPI_CPHA) in f_ospi_config_indir_protocol()
297 switch (op->data.nbytes & 0x3) { in f_ospi_config_indir_protocol()
304 val = OSPI_DAT_SIZE_EN | (op->data.nbytes - 1); in f_ospi_config_indir_protocol()
308 val = OSPI_DAT_SIZE_EN | (op->data.nbytes - 1); in f_ospi_config_indir_protocol()
313 switch (op->data.dir) { in f_ospi_config_indir_protocol()
327 dev_warn(ospi->dev, "Unsupported direction"); in f_ospi_config_indir_protocol()
331 prot |= FIELD_PREP(OSPI_PROT_ADDR_SIZE_MASK, op->addr.nbytes); in f_ospi_config_indir_protocol()
334 writel(prot, ospi->base + OSPI_PROT_CTL_INDIR); in f_ospi_config_indir_protocol()
335 writel(val, ospi->base + OSPI_DAT_SIZE_INDIR); in f_ospi_config_indir_protocol()
338 static int f_ospi_indir_prepare_op(struct f_ospi *ospi, struct spi_mem *mem, in f_ospi_indir_prepare_op() argument
341 struct spi_device *spi = mem->spi; in f_ospi_indir_prepare_op()
345 ret = f_ospi_prepare_config(ospi); in f_ospi_indir_prepare_op()
349 f_ospi_config_clk(ospi, spi->max_speed_hz); in f_ospi_indir_prepare_op()
351 f_ospi_config_indir_protocol(ospi, mem, op); in f_ospi_indir_prepare_op()
353 writel(f_ospi_get_dummy_cycle(op), ospi->base + OSPI_DMY_INDIR); in f_ospi_indir_prepare_op()
354 writel(op->addr.val, ospi->base + OSPI_ADDR); in f_ospi_indir_prepare_op()
355 writel(op->cmd.opcode, ospi->base + OSPI_CMD_IDX_INDIR); in f_ospi_indir_prepare_op()
357 f_ospi_clear_irq(ospi); in f_ospi_indir_prepare_op()
359 switch (op->data.dir) { in f_ospi_indir_prepare_op()
373 dev_warn(ospi->dev, "Unsupported direction"); in f_ospi_indir_prepare_op()
377 f_ospi_disable_irq_status(ospi, ~irq_stat_en); in f_ospi_indir_prepare_op()
378 f_ospi_enable_irq_status(ospi, irq_stat_en); in f_ospi_indir_prepare_op()
380 return f_ospi_unprepare_config(ospi); in f_ospi_indir_prepare_op()
383 static void f_ospi_indir_start_xfer(struct f_ospi *ospi) in f_ospi_indir_start_xfer() argument
386 writel(OSPI_TRANS_CTL_START_REQ, ospi->base + OSPI_TRANS_CTL); in f_ospi_indir_start_xfer()
389 static void f_ospi_indir_stop_xfer(struct f_ospi *ospi) in f_ospi_indir_stop_xfer() argument
392 writel(OSPI_TRANS_CTL_STOP_REQ, ospi->base + OSPI_TRANS_CTL); in f_ospi_indir_stop_xfer()
395 static int f_ospi_indir_wait_xfer_complete(struct f_ospi *ospi) in f_ospi_indir_wait_xfer_complete() argument
399 return readl_poll_timeout(ospi->base + OSPI_IRQ, val, in f_ospi_indir_wait_xfer_complete()
404 static int f_ospi_indir_read(struct f_ospi *ospi, struct spi_mem *mem, in f_ospi_indir_read() argument
407 u8 *buf = op->data.buf.in; in f_ospi_indir_read()
411 mutex_lock(&ospi->mlock); in f_ospi_indir_read()
413 /* E1-2: Prepare transfer operation */ in f_ospi_indir_read()
414 ret = f_ospi_indir_prepare_op(ospi, mem, op); in f_ospi_indir_read()
418 f_ospi_indir_start_xfer(ospi); in f_ospi_indir_read()
420 /* E3-4: Wait for ready and read data */ in f_ospi_indir_read()
421 for (i = 0; i < op->data.nbytes; i++) { in f_ospi_indir_read()
422 ret = readl_poll_timeout(ospi->base + OSPI_IRQ, val, in f_ospi_indir_read()
428 buf[i] = readl(ospi->base + OSPI_DAT) & 0xFF; in f_ospi_indir_read()
431 /* E5-6: Stop transfer if data size is nothing */ in f_ospi_indir_read()
432 if (!(readl(ospi->base + OSPI_DAT_SIZE_INDIR) & OSPI_DAT_SIZE_EN)) in f_ospi_indir_read()
433 f_ospi_indir_stop_xfer(ospi); in f_ospi_indir_read()
435 /* E7-8: Wait for completion and clear */ in f_ospi_indir_read()
436 ret = f_ospi_indir_wait_xfer_complete(ospi); in f_ospi_indir_read()
440 writel(OSPI_IRQ_CS_TRANS_COMP, ospi->base + OSPI_IRQ); in f_ospi_indir_read()
443 if (readl(ospi->base + OSPI_DAT_SIZE_INDIR) & OSPI_DAT_SIZE_EN) in f_ospi_indir_read()
446 /* E10-11: Reset and check read fifo */ in f_ospi_indir_read()
447 writel(OSPI_SWRST_INDIR_READ_FIFO, ospi->base + OSPI_SWRST); in f_ospi_indir_read()
449 ret = readl_poll_timeout(ospi->base + OSPI_SWRST, val, in f_ospi_indir_read()
453 mutex_unlock(&ospi->mlock); in f_ospi_indir_read()
458 static int f_ospi_indir_write(struct f_ospi *ospi, struct spi_mem *mem, in f_ospi_indir_write() argument
461 u8 *buf = (u8 *)op->data.buf.out; in f_ospi_indir_write()
465 mutex_lock(&ospi->mlock); in f_ospi_indir_write()
467 /* F1-3: Prepare transfer operation */ in f_ospi_indir_write()
468 ret = f_ospi_indir_prepare_op(ospi, mem, op); in f_ospi_indir_write()
472 f_ospi_indir_start_xfer(ospi); in f_ospi_indir_write()
474 if (!(readl(ospi->base + OSPI_PROT_CTL_INDIR) & OSPI_PROT_DATA_EN)) in f_ospi_indir_write()
477 /* F4-5: Wait for buffer ready and write data */ in f_ospi_indir_write()
478 for (i = 0; i < op->data.nbytes; i++) { in f_ospi_indir_write()
479 ret = readl_poll_timeout(ospi->base + OSPI_IRQ, val, in f_ospi_indir_write()
485 writel(buf[i], ospi->base + OSPI_DAT); in f_ospi_indir_write()
488 /* F6-7: Stop transfer if data size is nothing */ in f_ospi_indir_write()
489 if (!(readl(ospi->base + OSPI_DAT_SIZE_INDIR) & OSPI_DAT_SIZE_EN)) in f_ospi_indir_write()
490 f_ospi_indir_stop_xfer(ospi); in f_ospi_indir_write()
493 /* F8-9: Wait for completion and clear */ in f_ospi_indir_write()
494 ret = f_ospi_indir_wait_xfer_complete(ospi); in f_ospi_indir_write()
498 writel(OSPI_IRQ_CS_TRANS_COMP, ospi->base + OSPI_IRQ); in f_ospi_indir_write()
500 mutex_unlock(&ospi->mlock); in f_ospi_indir_write()
507 struct f_ospi *ospi = spi_controller_get_devdata(mem->spi->controller); in f_ospi_exec_op() local
510 switch (op->data.dir) { in f_ospi_exec_op()
512 err = f_ospi_indir_read(ospi, mem, op); in f_ospi_exec_op()
518 err = f_ospi_indir_write(ospi, mem, op); in f_ospi_exec_op()
522 dev_warn(ospi->dev, "Unsupported direction"); in f_ospi_exec_op()
523 err = -EOPNOTSUPP; in f_ospi_exec_op()
533 u8 width_op[] = { op->cmd.buswidth, op->addr.buswidth, in f_ospi_supports_op_width()
534 op->dummy.buswidth, op->data.buswidth }; in f_ospi_supports_op_width()
561 if (op->addr.nbytes > 4) in f_ospi_supports_op()
572 op->data.nbytes = min_t(int, op->data.nbytes, OSPI_DAT_SIZE_MAX); in f_ospi_adjust_op_size()
583 static int f_ospi_init(struct f_ospi *ospi) in f_ospi_init() argument
587 ret = f_ospi_prepare_config(ospi); in f_ospi_init()
592 writel(OSPI_ACC_MODE_BOOT_DISABLE, ospi->base + OSPI_ACC_MODE); in f_ospi_init()
594 f_ospi_config_dll(ospi); in f_ospi_init()
597 f_ospi_clear_irq(ospi); in f_ospi_init()
598 f_ospi_disable_irq_status(ospi, OSPI_IRQ_ALL); in f_ospi_init()
599 f_ospi_disable_irq_output(ospi, OSPI_IRQ_ALL); in f_ospi_init()
601 return f_ospi_unprepare_config(ospi); in f_ospi_init()
607 struct device *dev = &pdev->dev; in f_ospi_probe()
608 struct f_ospi *ospi; in f_ospi_probe() local
612 ctlr = spi_alloc_host(dev, sizeof(*ospi)); in f_ospi_probe()
614 return -ENOMEM; in f_ospi_probe()
616 ctlr->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL in f_ospi_probe()
619 ctlr->mem_ops = &f_ospi_mem_ops; in f_ospi_probe()
620 ctlr->bus_num = -1; in f_ospi_probe()
621 of_property_read_u32(dev->of_node, "num-cs", &num_cs); in f_ospi_probe()
623 dev_err(dev, "num-cs too large: %d\n", num_cs); in f_ospi_probe()
624 return -ENOMEM; in f_ospi_probe()
626 ctlr->num_chipselect = num_cs; in f_ospi_probe()
627 ctlr->dev.of_node = dev->of_node; in f_ospi_probe()
629 ospi = spi_controller_get_devdata(ctlr); in f_ospi_probe()
630 ospi->dev = dev; in f_ospi_probe()
632 platform_set_drvdata(pdev, ospi); in f_ospi_probe()
634 ospi->base = devm_platform_ioremap_resource(pdev, 0); in f_ospi_probe()
635 if (IS_ERR(ospi->base)) { in f_ospi_probe()
636 ret = PTR_ERR(ospi->base); in f_ospi_probe()
640 ospi->clk = devm_clk_get_enabled(dev, NULL); in f_ospi_probe()
641 if (IS_ERR(ospi->clk)) { in f_ospi_probe()
642 ret = PTR_ERR(ospi->clk); in f_ospi_probe()
646 mutex_init(&ospi->mlock); in f_ospi_probe()
648 ret = f_ospi_init(ospi); in f_ospi_probe()
659 mutex_destroy(&ospi->mlock); in f_ospi_probe()
669 struct f_ospi *ospi = platform_get_drvdata(pdev); in f_ospi_remove() local
671 mutex_destroy(&ospi->mlock); in f_ospi_remove()
675 { .compatible = "socionext,f-ospi" },
682 .name = "socionext,f-ospi",