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