Skip to content

Commit 8011709

Browse files
Jon Linbroonie
authored andcommitted
spi: rockchip-sfc: Support pm ops
Support system_sleep and runtime_pm ops. Signed-off-by: Jon Lin <jon.lin@rock-chips.com> Link: https://patch.msgid.link/20241208130311.1324024-1-jon.lin@rock-chips.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 3f3b063 commit 8011709

File tree

1 file changed

+128
-20
lines changed

1 file changed

+128
-20
lines changed

drivers/spi/spi-rockchip-sfc.c

Lines changed: 128 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
#include <linux/completion.h>
1414
#include <linux/dma-mapping.h>
1515
#include <linux/iopoll.h>
16+
#include <linux/interrupt.h>
1617
#include <linux/mm.h>
1718
#include <linux/module.h>
1819
#include <linux/of.h>
20+
#include <linux/pinctrl/consumer.h>
1921
#include <linux/platform_device.h>
22+
#include <linux/pm_runtime.h>
2023
#include <linux/slab.h>
21-
#include <linux/interrupt.h>
2224
#include <linux/spi/spi-mem.h>
2325

2426
/* System control */
@@ -150,11 +152,9 @@
150152
/* Data */
151153
#define SFC_DATA 0x108
152154

153-
/* The controller and documentation reports that it supports up to 4 CS
154-
* devices (0-3), however I have only been able to test a single CS (CS 0)
155-
* due to the configuration of my device.
156-
*/
157-
#define SFC_MAX_CHIPSELECT_NUM 4
155+
#define SFC_CS1_REG_OFFSET 0x200
156+
157+
#define SFC_MAX_CHIPSELECT_NUM 2
158158

159159
/* The SFC can transfer max 16KB - 1 at one time
160160
* we set it to 15.5KB here for alignment.
@@ -169,12 +169,14 @@
169169
*/
170170
#define SFC_MAX_SPEED (150 * 1000 * 1000)
171171

172+
#define ROCKCHIP_AUTOSUSPEND_DELAY 2000
173+
172174
struct rockchip_sfc {
173175
struct device *dev;
174176
void __iomem *regbase;
175177
struct clk *hclk;
176178
struct clk *clk;
177-
u32 frequency;
179+
u32 speed[SFC_MAX_CHIPSELECT_NUM];
178180
/* virtual mapped addr for dma_buffer */
179181
void *buffer;
180182
dma_addr_t dma_buffer;
@@ -301,6 +303,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
301303
u32 len)
302304
{
303305
u32 ctrl = 0, cmd = 0;
306+
u8 cs = spi_get_chipselect(mem->spi, 0);
304307

305308
/* set CMD */
306309
cmd = op->cmd.opcode;
@@ -314,7 +317,8 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
314317
cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT;
315318
} else {
316319
cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT;
317-
writel(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT);
320+
writel(op->addr.nbytes * 8 - 1,
321+
sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_ABIT);
318322
}
319323

320324
ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT);
@@ -346,15 +350,15 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
346350

347351
/* set the Controller */
348352
ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE;
349-
cmd |= spi_get_chipselect(mem->spi, 0) << SFC_CMD_CS_SHIFT;
353+
cmd |= cs << SFC_CMD_CS_SHIFT;
350354

351355
dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n",
352356
op->addr.nbytes, op->addr.buswidth,
353357
op->dummy.nbytes, op->dummy.buswidth);
354358
dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n",
355359
ctrl, cmd, op->addr.val, len);
356360

357-
writel(ctrl, sfc->regbase + SFC_CTRL);
361+
writel(ctrl, sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_CTRL);
358362
writel(cmd, sfc->regbase + SFC_CMD);
359363
if (op->addr.nbytes)
360364
writel(op->addr.val, sfc->regbase + SFC_ADDR);
@@ -500,14 +504,22 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op
500504
struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller);
501505
u32 len = op->data.nbytes;
502506
int ret;
507+
u8 cs = spi_get_chipselect(mem->spi, 0);
508+
509+
ret = pm_runtime_get_sync(sfc->dev);
510+
if (ret < 0) {
511+
pm_runtime_put_noidle(sfc->dev);
512+
return ret;
513+
}
503514

504-
if (unlikely(mem->spi->max_speed_hz != sfc->frequency) && !has_acpi_companion(sfc->dev)) {
515+
if (unlikely(mem->spi->max_speed_hz != sfc->speed[cs]) &&
516+
!has_acpi_companion(sfc->dev)) {
505517
ret = clk_set_rate(sfc->clk, mem->spi->max_speed_hz);
506518
if (ret)
507-
return ret;
508-
sfc->frequency = mem->spi->max_speed_hz;
519+
goto out;
520+
sfc->speed[cs] = mem->spi->max_speed_hz;
509521
dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%ldHz\n",
510-
sfc->frequency, clk_get_rate(sfc->clk));
522+
sfc->speed[cs], clk_get_rate(sfc->clk));
511523
}
512524

513525
rockchip_sfc_adjust_op_work((struct spi_mem_op *)op);
@@ -524,11 +536,17 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op
524536
if (ret != len) {
525537
dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir);
526538

527-
return -EIO;
539+
ret = -EIO;
540+
goto out;
528541
}
529542
}
530543

531-
return rockchip_sfc_xfer_done(sfc, 100000);
544+
ret = rockchip_sfc_xfer_done(sfc, 100000);
545+
out:
546+
pm_runtime_mark_last_busy(sfc->dev);
547+
pm_runtime_put_autosuspend(sfc->dev);
548+
549+
return ret;
532550
}
533551

534552
static int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
@@ -570,6 +588,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
570588
struct spi_controller *host;
571589
struct rockchip_sfc *sfc;
572590
int ret;
591+
u32 i, val;
573592

574593
host = devm_spi_alloc_host(&pdev->dev, sizeof(*sfc));
575594
if (!host)
@@ -602,9 +621,12 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
602621
"Failed to get sfc ahb clk\n");
603622

604623
if (has_acpi_companion(&pdev->dev)) {
605-
ret = device_property_read_u32(&pdev->dev, "clock-frequency", &sfc->frequency);
624+
ret = device_property_read_u32(&pdev->dev, "clock-frequency", &val);
606625
if (ret)
607-
return dev_err_probe(&pdev->dev, ret, "Failed to find clock-frequency\n");
626+
return dev_err_probe(&pdev->dev, ret,
627+
"Failed to find clock-frequency in ACPI\n");
628+
for (i = 0; i < SFC_MAX_CHIPSELECT_NUM; i++)
629+
sfc->speed[i] = val;
608630
}
609631

610632
sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma");
@@ -646,19 +668,36 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
646668
goto err_irq;
647669
}
648670

671+
platform_set_drvdata(pdev, sfc);
672+
649673
ret = rockchip_sfc_init(sfc);
650674
if (ret)
651675
goto err_irq;
652676

653677
sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc);
654678
sfc->version = rockchip_sfc_get_version(sfc);
655679

656-
ret = spi_register_controller(host);
680+
pm_runtime_set_autosuspend_delay(dev, ROCKCHIP_AUTOSUSPEND_DELAY);
681+
pm_runtime_use_autosuspend(dev);
682+
pm_runtime_set_active(dev);
683+
pm_runtime_enable(dev);
684+
pm_runtime_get_noresume(dev);
685+
686+
ret = devm_spi_register_controller(dev, host);
657687
if (ret)
658-
goto err_irq;
688+
goto err_pm_runtime_free;
689+
690+
pm_runtime_mark_last_busy(dev);
691+
pm_runtime_put_autosuspend(dev);
659692

660693
return 0;
661694

695+
err_pm_runtime_free:
696+
pm_runtime_get_sync(dev);
697+
pm_runtime_put_noidle(dev);
698+
pm_runtime_disable(dev);
699+
pm_runtime_set_suspended(dev);
700+
pm_runtime_dont_use_autosuspend(dev);
662701
err_irq:
663702
clk_disable_unprepare(sfc->clk);
664703
err_clk:
@@ -678,6 +717,74 @@ static void rockchip_sfc_remove(struct platform_device *pdev)
678717
clk_disable_unprepare(sfc->hclk);
679718
}
680719

720+
#ifdef CONFIG_PM
721+
static int rockchip_sfc_runtime_suspend(struct device *dev)
722+
{
723+
struct rockchip_sfc *sfc = dev_get_drvdata(dev);
724+
725+
clk_disable_unprepare(sfc->clk);
726+
clk_disable_unprepare(sfc->hclk);
727+
728+
return 0;
729+
}
730+
731+
static int rockchip_sfc_runtime_resume(struct device *dev)
732+
{
733+
struct rockchip_sfc *sfc = dev_get_drvdata(dev);
734+
int ret;
735+
736+
ret = clk_prepare_enable(sfc->hclk);
737+
if (ret < 0)
738+
return ret;
739+
740+
ret = clk_prepare_enable(sfc->clk);
741+
if (ret < 0)
742+
clk_disable_unprepare(sfc->hclk);
743+
744+
return ret;
745+
}
746+
#endif /* CONFIG_PM */
747+
748+
#ifdef CONFIG_PM_SLEEP
749+
static int rockchip_sfc_suspend(struct device *dev)
750+
{
751+
pinctrl_pm_select_sleep_state(dev);
752+
753+
return pm_runtime_force_suspend(dev);
754+
}
755+
756+
static int rockchip_sfc_resume(struct device *dev)
757+
{
758+
struct rockchip_sfc *sfc = dev_get_drvdata(dev);
759+
int ret;
760+
761+
ret = pm_runtime_force_resume(dev);
762+
if (ret < 0)
763+
return ret;
764+
765+
pinctrl_pm_select_default_state(dev);
766+
767+
ret = pm_runtime_get_sync(dev);
768+
if (ret < 0) {
769+
pm_runtime_put_noidle(dev);
770+
return ret;
771+
}
772+
773+
rockchip_sfc_init(sfc);
774+
775+
pm_runtime_mark_last_busy(dev);
776+
pm_runtime_put_autosuspend(dev);
777+
778+
return 0;
779+
}
780+
#endif /* CONFIG_PM_SLEEP */
781+
782+
static const struct dev_pm_ops rockchip_sfc_pm_ops = {
783+
SET_RUNTIME_PM_OPS(rockchip_sfc_runtime_suspend,
784+
rockchip_sfc_runtime_resume, NULL)
785+
SET_SYSTEM_SLEEP_PM_OPS(rockchip_sfc_suspend, rockchip_sfc_resume)
786+
};
787+
681788
static const struct of_device_id rockchip_sfc_dt_ids[] = {
682789
{ .compatible = "rockchip,sfc"},
683790
{ /* sentinel */ }
@@ -688,6 +795,7 @@ static struct platform_driver rockchip_sfc_driver = {
688795
.driver = {
689796
.name = "rockchip-sfc",
690797
.of_match_table = rockchip_sfc_dt_ids,
798+
.pm = &rockchip_sfc_pm_ops,
691799
},
692800
.probe = rockchip_sfc_probe,
693801
.remove = rockchip_sfc_remove,

0 commit comments

Comments
 (0)