summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-mtk-snfi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-mtk-snfi.c')
-rw-r--r--drivers/spi/spi-mtk-snfi.c96
1 files changed, 43 insertions, 53 deletions
diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c
index fa8412ba20e2..ae38c244e258 100644
--- a/drivers/spi/spi-mtk-snfi.c
+++ b/drivers/spi/spi-mtk-snfi.c
@@ -76,7 +76,8 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/mtd/nand-ecc-mtk.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -195,6 +196,8 @@
#define DATA_READ_MODE_X4 2
#define DATA_READ_MODE_DUAL 5
#define DATA_READ_MODE_QUAD 6
+#define DATA_READ_LATCH_LAT GENMASK(9, 8)
+#define DATA_READ_LATCH_LAT_S 8
#define PG_LOAD_CUSTOM_EN BIT(7)
#define DATARD_CUSTOM_EN BIT(6)
#define CS_DESELECT_CYC_S 0
@@ -205,6 +208,9 @@
#define SNF_DLY_CTL3 0x548
#define SFCK_SAM_DLY_S 0
+#define SFCK_SAM_DLY GENMASK(5, 0)
+#define SFCK_SAM_DLY_TOTAL 9
+#define SFCK_SAM_DLY_RANGE 47
#define SNF_STA_CTL1 0x550
#define CUS_PG_DONE BIT(28)
@@ -297,6 +303,7 @@ struct mtk_snand {
struct device *dev;
struct clk *nfi_clk;
struct clk *pad_clk;
+ struct clk *nfi_hclk;
void __iomem *nfi_base;
int irq;
struct completion op_done;
@@ -769,7 +776,7 @@ static int mtk_snand_ecc_finish_io_req(struct nand_device *nand,
return snf->ecc_stats.failed ? -EBADMSG : snf->ecc_stats.bitflips;
}
-static struct nand_ecc_engine_ops mtk_snfi_ecc_engine_ops = {
+static const struct nand_ecc_engine_ops mtk_snfi_ecc_engine_ops = {
.init_ctx = mtk_snand_ecc_init_ctx,
.cleanup_ctx = mtk_snand_ecc_cleanup_ctx,
.prepare_io_req = mtk_snand_ecc_prepare_io_req,
@@ -1132,7 +1139,6 @@ static int mtk_snand_write_page_cache(struct mtk_snand *snf,
// Prepare for custom write interrupt
nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG);
reinit_completion(&snf->op_done);
- ;
// Trigger NFI into custom mode
nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE);
@@ -1180,7 +1186,7 @@ cleanup:
/**
* mtk_snand_is_page_ops() - check if the op is a controller supported page op.
- * @op spi-mem op to check
+ * @op: spi-mem op to check
*
* Check whether op can be executed with read_from_cache or program_load
* mode in the controller.
@@ -1248,7 +1254,7 @@ static bool mtk_snand_supports_op(struct spi_mem *mem,
static int mtk_snand_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->master);
+ struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->controller);
// page ops transfer size must be exactly ((sector_size + spare_size) *
// nsectors). Limit the op size if the caller requests more than that.
// exec_op will read more than needed and discard the leftover if the
@@ -1275,11 +1281,8 @@ static int mtk_snand_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
static int mtk_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->master);
+ struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->controller);
- dev_dbg(ms->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
- op->addr.val, op->addr.buswidth, op->addr.nbytes,
- op->data.buswidth, op->data.nbytes);
if (mtk_snand_is_page_ops(op)) {
if (op->data.dir == SPI_MEM_DATA_IN)
return mtk_snand_read_page_cache(ms, op);
@@ -1325,45 +1328,21 @@ static const struct of_device_id mtk_snand_ids[] = {
MODULE_DEVICE_TABLE(of, mtk_snand_ids);
-static int mtk_snand_enable_clk(struct mtk_snand *ms)
-{
- int ret;
-
- ret = clk_prepare_enable(ms->nfi_clk);
- if (ret) {
- dev_err(ms->dev, "unable to enable nfi clk\n");
- return ret;
- }
- ret = clk_prepare_enable(ms->pad_clk);
- if (ret) {
- dev_err(ms->dev, "unable to enable pad clk\n");
- goto err1;
- }
- return 0;
-err1:
- clk_disable_unprepare(ms->nfi_clk);
- return ret;
-}
-
-static void mtk_snand_disable_clk(struct mtk_snand *ms)
-{
- clk_disable_unprepare(ms->pad_clk);
- clk_disable_unprepare(ms->nfi_clk);
-}
-
static int mtk_snand_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *dev_id;
struct spi_controller *ctlr;
struct mtk_snand *ms;
+ unsigned long spi_freq;
+ u32 val = 0;
int ret;
dev_id = of_match_node(mtk_snand_ids, np);
if (!dev_id)
return -EINVAL;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*ms));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*ms));
if (!ctlr)
return -ENOMEM;
platform_set_drvdata(pdev, ctlr);
@@ -1387,54 +1366,69 @@ static int mtk_snand_probe(struct platform_device *pdev)
ms->dev = &pdev->dev;
- ms->nfi_clk = devm_clk_get(&pdev->dev, "nfi_clk");
+ ms->nfi_clk = devm_clk_get_enabled(&pdev->dev, "nfi_clk");
if (IS_ERR(ms->nfi_clk)) {
ret = PTR_ERR(ms->nfi_clk);
dev_err(&pdev->dev, "unable to get nfi_clk, err = %d\n", ret);
goto release_ecc;
}
- ms->pad_clk = devm_clk_get(&pdev->dev, "pad_clk");
+ ms->pad_clk = devm_clk_get_enabled(&pdev->dev, "pad_clk");
if (IS_ERR(ms->pad_clk)) {
ret = PTR_ERR(ms->pad_clk);
dev_err(&pdev->dev, "unable to get pad_clk, err = %d\n", ret);
goto release_ecc;
}
- ret = mtk_snand_enable_clk(ms);
- if (ret)
+ ms->nfi_hclk = devm_clk_get_optional_enabled(&pdev->dev, "nfi_hclk");
+ if (IS_ERR(ms->nfi_hclk)) {
+ ret = PTR_ERR(ms->nfi_hclk);
+ dev_err(&pdev->dev, "unable to get nfi_hclk, err = %d\n", ret);
goto release_ecc;
+ }
init_completion(&ms->op_done);
ms->irq = platform_get_irq(pdev, 0);
if (ms->irq < 0) {
ret = ms->irq;
- goto disable_clk;
+ goto release_ecc;
}
ret = devm_request_irq(ms->dev, ms->irq, mtk_snand_irq, 0x0,
"mtk-snand", ms);
if (ret) {
dev_err(ms->dev, "failed to request snfi irq\n");
- goto disable_clk;
+ goto release_ecc;
}
ret = dma_set_mask(ms->dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(ms->dev, "failed to set dma mask\n");
- goto disable_clk;
+ goto release_ecc;
}
// switch to SNFI mode
nfi_write32(ms, SNF_CFG, SPI_MODE);
+ ret = of_property_read_u32(np, "rx-sample-delay-ns", &val);
+ if (!ret)
+ nfi_rmw32(ms, SNF_DLY_CTL3, SFCK_SAM_DLY,
+ val * SFCK_SAM_DLY_RANGE / SFCK_SAM_DLY_TOTAL);
+
+ ret = of_property_read_u32(np, "mediatek,rx-latch-latency-ns", &val);
+ if (!ret) {
+ spi_freq = clk_get_rate(ms->pad_clk);
+ val = DIV_ROUND_CLOSEST(val, NSEC_PER_SEC / spi_freq);
+ nfi_rmw32(ms, SNF_MISC_CTL, DATA_READ_LATCH_LAT,
+ val << DATA_READ_LATCH_LAT_S);
+ }
+
// setup an initial page format for ops matching page_cache_op template
// before ECC is called.
- ret = mtk_snand_setup_pagefmt(ms, ms->caps->sector_size,
- ms->caps->spare_sizes[0]);
+ ret = mtk_snand_setup_pagefmt(ms, SZ_2K, SZ_64);
if (ret) {
dev_err(ms->dev, "failed to set initial page format\n");
- goto disable_clk;
+ goto release_ecc;
}
// setup ECC engine
@@ -1446,7 +1440,7 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = nand_ecc_register_on_host_hw_engine(&ms->ecc_eng);
if (ret) {
dev_err(&pdev->dev, "failed to register ecc engine.\n");
- goto disable_clk;
+ goto release_ecc;
}
ctlr->num_chipselect = 1;
@@ -1458,27 +1452,23 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = spi_register_controller(ctlr);
if (ret) {
dev_err(&pdev->dev, "spi_register_controller failed.\n");
- goto disable_clk;
+ goto release_ecc;
}
return 0;
-disable_clk:
- mtk_snand_disable_clk(ms);
release_ecc:
mtk_ecc_release(ms->ecc);
return ret;
}
-static int mtk_snand_remove(struct platform_device *pdev)
+static void mtk_snand_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct mtk_snand *ms = spi_controller_get_devdata(ctlr);
spi_unregister_controller(ctlr);
- mtk_snand_disable_clk(ms);
mtk_ecc_release(ms->ecc);
kfree(ms->buf);
- return 0;
}
static struct platform_driver mtk_snand_driver = {