172132Ssemenu// SPDX-License-Identifier: GPL-2.0
272132Ssemenu/*
372132Ssemenu * Driver for Amlogic A1 SPI flash controller (SPIFC)
472132Ssemenu *
572132Ssemenu * Copyright (c) 2023, SberDevices. All Rights Reserved.
672132Ssemenu *
772132Ssemenu * Author: Martin Kurbanov <mmkurbanov@sberdevices.ru>
872132Ssemenu */
972132Ssemenu
1072132Ssemenu#include <linux/bitfield.h>
1172132Ssemenu#include <linux/clk.h>
1272132Ssemenu#include <linux/device.h>
1372132Ssemenu#include <linux/io.h>
1472132Ssemenu#include <linux/iopoll.h>
1572132Ssemenu#include <linux/kernel.h>
1672132Ssemenu#include <linux/module.h>
1772132Ssemenu#include <linux/of.h>
1872132Ssemenu#include <linux/platform_device.h>
1972132Ssemenu#include <linux/pm_runtime.h>
2072132Ssemenu#include <linux/spi/spi.h>
2172132Ssemenu#include <linux/spi/spi-mem.h>
2272132Ssemenu#include <linux/types.h>
2372132Ssemenu
2472132Ssemenu#define SPIFC_A1_AHB_CTRL_REG		0x0
2572132Ssemenu#define SPIFC_A1_AHB_BUS_EN		BIT(31)
2672132Ssemenu
2772132Ssemenu#define SPIFC_A1_USER_CTRL0_REG		0x200
2872132Ssemenu#define SPIFC_A1_USER_REQUEST_ENABLE	BIT(31)
2972132Ssemenu#define SPIFC_A1_USER_REQUEST_FINISH	BIT(30)
3072132Ssemenu#define SPIFC_A1_USER_DATA_UPDATED	BIT(0)
3172132Ssemenu
3272132Ssemenu#define SPIFC_A1_USER_CTRL1_REG		0x204
3372132Ssemenu#define SPIFC_A1_USER_CMD_ENABLE	BIT(30)
3472132Ssemenu#define SPIFC_A1_USER_CMD_MODE		GENMASK(29, 28)
3572132Ssemenu#define SPIFC_A1_USER_CMD_CODE		GENMASK(27, 20)
3672132Ssemenu#define SPIFC_A1_USER_ADDR_ENABLE	BIT(19)
3772132Ssemenu#define SPIFC_A1_USER_ADDR_MODE		GENMASK(18, 17)
3872132Ssemenu#define SPIFC_A1_USER_ADDR_BYTES	GENMASK(16, 15)
3972132Ssemenu#define SPIFC_A1_USER_DOUT_ENABLE	BIT(14)
4072132Ssemenu#define SPIFC_A1_USER_DOUT_MODE		GENMASK(11, 10)
4172132Ssemenu#define SPIFC_A1_USER_DOUT_BYTES	GENMASK(9, 0)
4272132Ssemenu
4372132Ssemenu#define SPIFC_A1_USER_CTRL2_REG		0x208
4472132Ssemenu#define SPIFC_A1_USER_DUMMY_ENABLE	BIT(31)
4572132Ssemenu#define SPIFC_A1_USER_DUMMY_MODE	GENMASK(30, 29)
4672132Ssemenu#define SPIFC_A1_USER_DUMMY_CLK_SYCLES	GENMASK(28, 23)
4772132Ssemenu
4872132Ssemenu#define SPIFC_A1_USER_CTRL3_REG		0x20c
4972132Ssemenu#define SPIFC_A1_USER_DIN_ENABLE	BIT(31)
5072132Ssemenu#define SPIFC_A1_USER_DIN_MODE		GENMASK(28, 27)
5172132Ssemenu#define SPIFC_A1_USER_DIN_BYTES		GENMASK(25, 16)
5272132Ssemenu
5372132Ssemenu#define SPIFC_A1_USER_ADDR_REG		0x210
5472132Ssemenu
5572132Ssemenu#define SPIFC_A1_AHB_REQ_CTRL_REG	0x214
5672132Ssemenu#define SPIFC_A1_AHB_REQ_ENABLE		BIT(31)
5772132Ssemenu
5872132Ssemenu#define SPIFC_A1_ACTIMING0_REG		(0x0088 << 2)
5972132Ssemenu#define SPIFC_A1_TSLCH			GENMASK(31, 30)
6072132Ssemenu#define SPIFC_A1_TCLSH			GENMASK(29, 28)
6172132Ssemenu#define SPIFC_A1_TSHWL			GENMASK(20, 16)
6272132Ssemenu#define SPIFC_A1_TSHSL2			GENMASK(15, 12)
6372132Ssemenu#define SPIFC_A1_TSHSL1			GENMASK(11, 8)
6472132Ssemenu#define SPIFC_A1_TWHSL			GENMASK(7, 0)
6572132Ssemenu
6672132Ssemenu#define SPIFC_A1_DBUF_CTRL_REG		0x240
6772132Ssemenu#define SPIFC_A1_DBUF_DIR		BIT(31)
6872132Ssemenu#define SPIFC_A1_DBUF_AUTO_UPDATE_ADDR	BIT(30)
6972132Ssemenu#define SPIFC_A1_DBUF_ADDR		GENMASK(7, 0)
7072132Ssemenu
7172132Ssemenu#define SPIFC_A1_DBUF_DATA_REG		0x244
7272132Ssemenu
7372132Ssemenu#define SPIFC_A1_USER_DBUF_ADDR_REG	0x248
7472132Ssemenu
7572132Ssemenu#define SPIFC_A1_BUFFER_SIZE		512U
7672132Ssemenu
7772132Ssemenu#define SPIFC_A1_MAX_HZ			200000000
7872132Ssemenu#define SPIFC_A1_MIN_HZ			1000000
7972132Ssemenu
8072132Ssemenu#define SPIFC_A1_USER_CMD(op) ( \
8172132Ssemenu	SPIFC_A1_USER_CMD_ENABLE | \
8272132Ssemenu	FIELD_PREP(SPIFC_A1_USER_CMD_CODE, (op)->cmd.opcode) | \
8372132Ssemenu	FIELD_PREP(SPIFC_A1_USER_CMD_MODE, ilog2((op)->cmd.buswidth)))
84109514Sobrien
8572132Ssemenu#define SPIFC_A1_USER_ADDR(op) ( \
8672132Ssemenu	SPIFC_A1_USER_ADDR_ENABLE | \
8772132Ssemenu	FIELD_PREP(SPIFC_A1_USER_ADDR_MODE, ilog2((op)->addr.buswidth)) | \
8872132Ssemenu	FIELD_PREP(SPIFC_A1_USER_ADDR_BYTES, (op)->addr.nbytes - 1))
8972132Ssemenu
9072132Ssemenu#define SPIFC_A1_USER_DUMMY(op) ( \
9172132Ssemenu	SPIFC_A1_USER_DUMMY_ENABLE | \
9272132Ssemenu	FIELD_PREP(SPIFC_A1_USER_DUMMY_MODE, ilog2((op)->dummy.buswidth)) | \
9372132Ssemenu	FIELD_PREP(SPIFC_A1_USER_DUMMY_CLK_SYCLES, (op)->dummy.nbytes << 3))
9472132Ssemenu
95105135Salfred#define SPIFC_A1_TSLCH_VAL	FIELD_PREP(SPIFC_A1_TSLCH, 1)
96105135Salfred#define SPIFC_A1_TCLSH_VAL	FIELD_PREP(SPIFC_A1_TCLSH, 1)
9772132Ssemenu#define SPIFC_A1_TSHWL_VAL	FIELD_PREP(SPIFC_A1_TSHWL, 7)
9872132Ssemenu#define SPIFC_A1_TSHSL2_VAL	FIELD_PREP(SPIFC_A1_TSHSL2, 7)
9972132Ssemenu#define SPIFC_A1_TSHSL1_VAL	FIELD_PREP(SPIFC_A1_TSHSL1, 7)
10072132Ssemenu#define SPIFC_A1_TWHSL_VAL	FIELD_PREP(SPIFC_A1_TWHSL, 2)
10172132Ssemenu#define SPIFC_A1_ACTIMING0_VAL	(SPIFC_A1_TSLCH_VAL | SPIFC_A1_TCLSH_VAL | \
10295722Sphk				 SPIFC_A1_TSHWL_VAL | SPIFC_A1_TSHSL2_VAL | \
10372132Ssemenu				 SPIFC_A1_TSHSL1_VAL | SPIFC_A1_TWHSL_VAL)
10472132Ssemenu
10572132Ssemenustruct amlogic_spifc_a1 {
10672132Ssemenu	struct spi_controller *ctrl;
10772132Ssemenu	struct clk *clk;
10872132Ssemenu	struct device *dev;
10972132Ssemenu	void __iomem *base;
11072132Ssemenu	u32 curr_speed_hz;
11172132Ssemenu};
11272132Ssemenu
11372132Ssemenustatic int amlogic_spifc_a1_request(struct amlogic_spifc_a1 *spifc, bool read)
11472132Ssemenu{
11572132Ssemenu	u32 mask = SPIFC_A1_USER_REQUEST_FINISH |
11672132Ssemenu		   (read ? SPIFC_A1_USER_DATA_UPDATED : 0);
11792739Salfred	u32 val;
11892739Salfred
11992739Salfred	writel(SPIFC_A1_USER_REQUEST_ENABLE,
12072132Ssemenu	       spifc->base + SPIFC_A1_USER_CTRL0_REG);
121105135Salfred
122105135Salfred	return readl_poll_timeout(spifc->base + SPIFC_A1_USER_CTRL0_REG,
12372132Ssemenu				  val, (val & mask) == mask, 0,
12472132Ssemenu				  200 * USEC_PER_MSEC);
12572132Ssemenu}
12672132Ssemenu
12772132Ssemenustatic void amlogic_spifc_a1_drain_buffer(struct amlogic_spifc_a1 *spifc,
12872132Ssemenu					  char *buf, u32 len)
12972132Ssemenu{
13072132Ssemenu	u32 data;
13172132Ssemenu	const u32 count = len / sizeof(data);
132109147Sobrien	const u32 pad = len % sizeof(data);
133109147Sobrien
134109147Sobrien	writel(SPIFC_A1_DBUF_AUTO_UPDATE_ADDR,
13572132Ssemenu	       spifc->base + SPIFC_A1_DBUF_CTRL_REG);
13672132Ssemenu	ioread32_rep(spifc->base + SPIFC_A1_DBUF_DATA_REG, buf, count);
13772132Ssemenu
13872132Ssemenu	if (pad) {
13972132Ssemenu		data = readl(spifc->base + SPIFC_A1_DBUF_DATA_REG);
14072132Ssemenu		memcpy(buf + len - pad, &data, pad);
141105135Salfred	}
142105135Salfred}
14372132Ssemenu
14472132Ssemenustatic void amlogic_spifc_a1_fill_buffer(struct amlogic_spifc_a1 *spifc,
14572132Ssemenu					 const char *buf, u32 len)
14672132Ssemenu{
14772132Ssemenu	u32 data;
14872132Ssemenu	const u32 count = len / sizeof(data);
14972132Ssemenu	const u32 pad = len % sizeof(data);
15072132Ssemenu
15172132Ssemenu	writel(SPIFC_A1_DBUF_DIR | SPIFC_A1_DBUF_AUTO_UPDATE_ADDR,
15272132Ssemenu	       spifc->base + SPIFC_A1_DBUF_CTRL_REG);
15372132Ssemenu	iowrite32_rep(spifc->base + SPIFC_A1_DBUF_DATA_REG, buf, count);
15472132Ssemenu
15572132Ssemenu	if (pad) {
15672132Ssemenu		memcpy(&data, buf + len - pad, pad);
15772132Ssemenu		writel(data, spifc->base + SPIFC_A1_DBUF_DATA_REG);
15872132Ssemenu	}
15972132Ssemenu}
16072132Ssemenu
16172132Ssemenustatic void amlogic_spifc_a1_user_init(struct amlogic_spifc_a1 *spifc)
16272132Ssemenu{
16372132Ssemenu	writel(0, spifc->base + SPIFC_A1_USER_CTRL0_REG);
16472132Ssemenu	writel(0, spifc->base + SPIFC_A1_USER_CTRL1_REG);
16572132Ssemenu	writel(0, spifc->base + SPIFC_A1_USER_CTRL2_REG);
16672132Ssemenu	writel(0, spifc->base + SPIFC_A1_USER_CTRL3_REG);
16772132Ssemenu}
16895667Sphk
16972132Ssemenustatic void amlogic_spifc_a1_set_cmd(struct amlogic_spifc_a1 *spifc,
17072132Ssemenu				     u32 cmd_cfg)
17172132Ssemenu{
17272132Ssemenu	u32 val;
17372132Ssemenu
17472132Ssemenu	val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
17584145Sjlemon	val &= ~(SPIFC_A1_USER_CMD_MODE | SPIFC_A1_USER_CMD_CODE);
17672132Ssemenu	val |= cmd_cfg;
17772132Ssemenu	writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
17872132Ssemenu}
17972132Ssemenu
18072132Ssemenustatic void amlogic_spifc_a1_set_addr(struct amlogic_spifc_a1 *spifc, u32 addr,
18172132Ssemenu				      u32 addr_cfg)
18272132Ssemenu{
18372132Ssemenu	u32 val;
18495877Ssemenu
18595877Ssemenu	writel(addr, spifc->base + SPIFC_A1_USER_ADDR_REG);
18695877Ssemenu
18795877Ssemenu	val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
18895877Ssemenu	val &= ~(SPIFC_A1_USER_ADDR_MODE | SPIFC_A1_USER_ADDR_BYTES);
18995877Ssemenu	val |= addr_cfg;
19095877Ssemenu	writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
19195877Ssemenu}
19295877Ssemenu
19395877Ssemenustatic void amlogic_spifc_a1_set_dummy(struct amlogic_spifc_a1 *spifc,
19495877Ssemenu				       u32 dummy_cfg)
19595877Ssemenu{
19695877Ssemenu	u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL2_REG);
19772132Ssemenu
19872132Ssemenu	val &= ~(SPIFC_A1_USER_DUMMY_MODE | SPIFC_A1_USER_DUMMY_CLK_SYCLES);
19972132Ssemenu	val |= dummy_cfg;
20072132Ssemenu	writel(val, spifc->base + SPIFC_A1_USER_CTRL2_REG);
20172132Ssemenu}
20272132Ssemenu
20372132Ssemenustatic int amlogic_spifc_a1_read(struct amlogic_spifc_a1 *spifc, void *buf,
20472132Ssemenu				 u32 size, u32 mode)
20572132Ssemenu{
20672132Ssemenu	u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL3_REG);
20772132Ssemenu	int ret;
20895877Ssemenu
20972132Ssemenu	val &= ~(SPIFC_A1_USER_DIN_MODE | SPIFC_A1_USER_DIN_BYTES);
21072132Ssemenu	val |= SPIFC_A1_USER_DIN_ENABLE;
21172132Ssemenu	val |= FIELD_PREP(SPIFC_A1_USER_DIN_MODE, mode);
21272132Ssemenu	val |= FIELD_PREP(SPIFC_A1_USER_DIN_BYTES, size);
21372132Ssemenu	writel(val, spifc->base + SPIFC_A1_USER_CTRL3_REG);
21472132Ssemenu
21572132Ssemenu	ret = amlogic_spifc_a1_request(spifc, true);
21672132Ssemenu	if (!ret)
21772132Ssemenu		amlogic_spifc_a1_drain_buffer(spifc, buf, size);
21872132Ssemenu
21972132Ssemenu	return ret;
22072132Ssemenu}
22196026Sphk
22272132Ssemenustatic int amlogic_spifc_a1_write(struct amlogic_spifc_a1 *spifc,
22372132Ssemenu				  const void *buf, u32 size, u32 mode)
22472132Ssemenu{
22572132Ssemenu	u32 val;
22672132Ssemenu
22772132Ssemenu	amlogic_spifc_a1_fill_buffer(spifc, buf, size);
22872132Ssemenu
22972132Ssemenu	val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
23072132Ssemenu	val &= ~(SPIFC_A1_USER_DOUT_MODE | SPIFC_A1_USER_DOUT_BYTES);
23172132Ssemenu	val |= FIELD_PREP(SPIFC_A1_USER_DOUT_MODE, mode);
23272132Ssemenu	val |= FIELD_PREP(SPIFC_A1_USER_DOUT_BYTES, size);
23372132Ssemenu	val |= SPIFC_A1_USER_DOUT_ENABLE;
23472132Ssemenu	writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
23572132Ssemenu
23684145Sjlemon	return amlogic_spifc_a1_request(spifc, false);
23772132Ssemenu}
23884145Sjlemon
23972132Ssemenustatic int amlogic_spifc_a1_set_freq(struct amlogic_spifc_a1 *spifc, u32 freq)
24072132Ssemenu{
24172132Ssemenu	int ret;
24284145Sjlemon
24372132Ssemenu	if (freq == spifc->curr_speed_hz)
24484145Sjlemon		return 0;
24584145Sjlemon
24672132Ssemenu	ret = clk_set_rate(spifc->clk, freq);
24772132Ssemenu	if (ret)
24895877Ssemenu		return ret;
24972132Ssemenu
25072132Ssemenu	spifc->curr_speed_hz = freq;
25172132Ssemenu	return 0;
25272132Ssemenu}
25372132Ssemenu
25472132Ssemenustatic int amlogic_spifc_a1_exec_op(struct spi_mem *mem,
25572132Ssemenu				    const struct spi_mem_op *op)
25672132Ssemenu{
25784145Sjlemon	struct amlogic_spifc_a1 *spifc =
25872132Ssemenu		spi_controller_get_devdata(mem->spi->controller);
25972132Ssemenu	size_t data_size = op->data.nbytes;
26072132Ssemenu	int ret;
26184145Sjlemon
26272132Ssemenu	ret = amlogic_spifc_a1_set_freq(spifc, mem->spi->max_speed_hz);
26372132Ssemenu	if (ret)
26472132Ssemenu		return ret;
26572132Ssemenu
26672132Ssemenu	amlogic_spifc_a1_user_init(spifc);
26772132Ssemenu	amlogic_spifc_a1_set_cmd(spifc, SPIFC_A1_USER_CMD(op));
26872132Ssemenu
26972132Ssemenu	if (op->addr.nbytes)
27072132Ssemenu		amlogic_spifc_a1_set_addr(spifc, op->addr.val,
27172132Ssemenu					  SPIFC_A1_USER_ADDR(op));
27272132Ssemenu
27372132Ssemenu	if (op->dummy.nbytes)
27472132Ssemenu		amlogic_spifc_a1_set_dummy(spifc, SPIFC_A1_USER_DUMMY(op));
27572132Ssemenu
27672132Ssemenu	if (data_size) {
27772132Ssemenu		u32 mode = ilog2(op->data.buswidth);
27872132Ssemenu
27972132Ssemenu		writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
28072132Ssemenu
28172132Ssemenu		if (op->data.dir == SPI_MEM_DATA_IN)
28272132Ssemenu			ret = amlogic_spifc_a1_read(spifc, op->data.buf.in,
28372132Ssemenu						    data_size, mode);
28472132Ssemenu		else
28572132Ssemenu			ret = amlogic_spifc_a1_write(spifc, op->data.buf.out,
28672132Ssemenu						     data_size, mode);
28772132Ssemenu	} else {
28872132Ssemenu		ret = amlogic_spifc_a1_request(spifc, false);
28972132Ssemenu	}
29072132Ssemenu
29172132Ssemenu	return ret;
29272132Ssemenu}
29395877Ssemenu
29472132Ssemenustatic int amlogic_spifc_a1_adjust_op_size(struct spi_mem *mem,
29572132Ssemenu					   struct spi_mem_op *op)
29672132Ssemenu{
29772132Ssemenu	op->data.nbytes = min(op->data.nbytes, SPIFC_A1_BUFFER_SIZE);
29872132Ssemenu	return 0;
29972132Ssemenu}
30072132Ssemenu
30172132Ssemenustatic void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
30272132Ssemenu{
30372132Ssemenu	u32 regv;
30472132Ssemenu
30584145Sjlemon	regv = readl(spifc->base + SPIFC_A1_AHB_REQ_CTRL_REG);
30672132Ssemenu	regv &= ~(SPIFC_A1_AHB_REQ_ENABLE);
30772132Ssemenu	writel(regv, spifc->base + SPIFC_A1_AHB_REQ_CTRL_REG);
30872132Ssemenu
30972132Ssemenu	regv = readl(spifc->base + SPIFC_A1_AHB_CTRL_REG);
31072132Ssemenu	regv &= ~(SPIFC_A1_AHB_BUS_EN);
31172132Ssemenu	writel(regv, spifc->base + SPIFC_A1_AHB_CTRL_REG);
31272132Ssemenu
313	writel(SPIFC_A1_ACTIMING0_VAL, spifc->base + SPIFC_A1_ACTIMING0_REG);
314
315	writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
316}
317
318static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = {
319	.exec_op = amlogic_spifc_a1_exec_op,
320	.adjust_op_size = amlogic_spifc_a1_adjust_op_size,
321};
322
323static int amlogic_spifc_a1_probe(struct platform_device *pdev)
324{
325	struct spi_controller *ctrl;
326	struct amlogic_spifc_a1 *spifc;
327	int ret;
328
329	ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*spifc));
330	if (!ctrl)
331		return -ENOMEM;
332
333	spifc = spi_controller_get_devdata(ctrl);
334	platform_set_drvdata(pdev, spifc);
335
336	spifc->dev = &pdev->dev;
337	spifc->ctrl = ctrl;
338
339	spifc->base = devm_platform_ioremap_resource(pdev, 0);
340	if (IS_ERR(spifc->base))
341		return PTR_ERR(spifc->base);
342
343	spifc->clk = devm_clk_get_enabled(spifc->dev, NULL);
344	if (IS_ERR(spifc->clk))
345		return dev_err_probe(spifc->dev, PTR_ERR(spifc->clk),
346				     "unable to get clock\n");
347
348	amlogic_spifc_a1_hw_init(spifc);
349
350	pm_runtime_set_autosuspend_delay(spifc->dev, 500);
351	pm_runtime_use_autosuspend(spifc->dev);
352	devm_pm_runtime_enable(spifc->dev);
353
354	ctrl->num_chipselect = 1;
355	ctrl->dev.of_node = pdev->dev.of_node;
356	ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
357	ctrl->auto_runtime_pm = true;
358	ctrl->mem_ops = &amlogic_spifc_a1_mem_ops;
359	ctrl->min_speed_hz = SPIFC_A1_MIN_HZ;
360	ctrl->max_speed_hz = SPIFC_A1_MAX_HZ;
361	ctrl->mode_bits = (SPI_RX_DUAL | SPI_TX_DUAL |
362			   SPI_RX_QUAD | SPI_TX_QUAD);
363
364	ret = devm_spi_register_controller(spifc->dev, ctrl);
365	if (ret)
366		return dev_err_probe(spifc->dev, ret,
367				     "failed to register spi controller\n");
368
369	return 0;
370}
371
372#ifdef CONFIG_PM_SLEEP
373static int amlogic_spifc_a1_suspend(struct device *dev)
374{
375	struct amlogic_spifc_a1 *spifc = dev_get_drvdata(dev);
376	int ret;
377
378	ret = spi_controller_suspend(spifc->ctrl);
379	if (ret)
380		return ret;
381
382	if (!pm_runtime_suspended(dev))
383		clk_disable_unprepare(spifc->clk);
384
385	return 0;
386}
387
388static int amlogic_spifc_a1_resume(struct device *dev)
389{
390	struct amlogic_spifc_a1 *spifc = dev_get_drvdata(dev);
391	int ret = 0;
392
393	if (!pm_runtime_suspended(dev)) {
394		ret = clk_prepare_enable(spifc->clk);
395		if (ret)
396			return ret;
397	}
398
399	amlogic_spifc_a1_hw_init(spifc);
400
401	ret = spi_controller_resume(spifc->ctrl);
402	if (ret)
403		clk_disable_unprepare(spifc->clk);
404
405	return ret;
406}
407#endif /* CONFIG_PM_SLEEP */
408
409#ifdef CONFIG_PM
410static int amlogic_spifc_a1_runtime_suspend(struct device *dev)
411{
412	struct amlogic_spifc_a1 *spifc = dev_get_drvdata(dev);
413
414	clk_disable_unprepare(spifc->clk);
415
416	return 0;
417}
418
419static int amlogic_spifc_a1_runtime_resume(struct device *dev)
420{
421	struct amlogic_spifc_a1 *spifc = dev_get_drvdata(dev);
422	int ret;
423
424	ret = clk_prepare_enable(spifc->clk);
425	if (!ret)
426		amlogic_spifc_a1_hw_init(spifc);
427
428	return ret;
429}
430#endif /* CONFIG_PM */
431
432static const struct dev_pm_ops amlogic_spifc_a1_pm_ops = {
433	SET_SYSTEM_SLEEP_PM_OPS(amlogic_spifc_a1_suspend,
434				amlogic_spifc_a1_resume)
435	SET_RUNTIME_PM_OPS(amlogic_spifc_a1_runtime_suspend,
436			   amlogic_spifc_a1_runtime_resume,
437			   NULL)
438};
439
440#ifdef CONFIG_OF
441static const struct of_device_id amlogic_spifc_a1_dt_match[] = {
442	{ .compatible = "amlogic,a1-spifc", },
443	{ },
444};
445MODULE_DEVICE_TABLE(of, amlogic_spifc_a1_dt_match);
446#endif /* CONFIG_OF */
447
448static struct platform_driver amlogic_spifc_a1_driver = {
449	.probe	= amlogic_spifc_a1_probe,
450	.driver	= {
451		.name		= "amlogic-spifc-a1",
452		.of_match_table	= of_match_ptr(amlogic_spifc_a1_dt_match),
453		.pm		= &amlogic_spifc_a1_pm_ops,
454	},
455};
456module_platform_driver(amlogic_spifc_a1_driver);
457
458MODULE_AUTHOR("Martin Kurbanov <mmkurbanov@sberdevices.ru>");
459MODULE_DESCRIPTION("Amlogic A1 SPIFC driver");
460MODULE_LICENSE("GPL");
461