1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018-2020 Broadcom */
4 #include <linux/device.h>
5 #include <linux/iopoll.h>
6 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/reset-controller.h>
11 #define BRCM_RESCAL_START 0x0
12 #define BRCM_RESCAL_START_BIT BIT(0)
13 #define BRCM_RESCAL_CTRL 0x4
14 #define BRCM_RESCAL_STATUS 0x8
15 #define BRCM_RESCAL_STATUS_BIT BIT(0)
17 struct brcm_rescal_reset
{
20 struct reset_controller_dev rcdev
;
23 static int brcm_rescal_reset_set(struct reset_controller_dev
*rcdev
,
26 struct brcm_rescal_reset
*data
=
27 container_of(rcdev
, struct brcm_rescal_reset
, rcdev
);
28 void __iomem
*base
= data
->base
;
32 reg
= readl(base
+ BRCM_RESCAL_START
);
33 writel(reg
| BRCM_RESCAL_START_BIT
, base
+ BRCM_RESCAL_START
);
34 reg
= readl(base
+ BRCM_RESCAL_START
);
35 if (!(reg
& BRCM_RESCAL_START_BIT
)) {
36 dev_err(data
->dev
, "failed to start SATA/PCIe rescal\n");
40 ret
= readl_poll_timeout(base
+ BRCM_RESCAL_STATUS
, reg
,
41 !(reg
& BRCM_RESCAL_STATUS_BIT
), 100, 1000);
43 dev_err(data
->dev
, "time out on SATA/PCIe rescal\n");
47 reg
= readl(base
+ BRCM_RESCAL_START
);
48 writel(reg
& ~BRCM_RESCAL_START_BIT
, base
+ BRCM_RESCAL_START
);
50 dev_dbg(data
->dev
, "SATA/PCIe rescal success\n");
55 static int brcm_rescal_reset_xlate(struct reset_controller_dev
*rcdev
,
56 const struct of_phandle_args
*reset_spec
)
58 /* This is needed if #reset-cells == 0. */
62 static const struct reset_control_ops brcm_rescal_reset_ops
= {
63 .reset
= brcm_rescal_reset_set
,
66 static int brcm_rescal_reset_probe(struct platform_device
*pdev
)
68 struct brcm_rescal_reset
*data
;
71 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
75 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
76 data
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
77 if (IS_ERR(data
->base
))
78 return PTR_ERR(data
->base
);
80 data
->rcdev
.owner
= THIS_MODULE
;
81 data
->rcdev
.nr_resets
= 1;
82 data
->rcdev
.ops
= &brcm_rescal_reset_ops
;
83 data
->rcdev
.of_node
= pdev
->dev
.of_node
;
84 data
->rcdev
.of_xlate
= brcm_rescal_reset_xlate
;
85 data
->dev
= &pdev
->dev
;
87 return devm_reset_controller_register(&pdev
->dev
, &data
->rcdev
);
90 static const struct of_device_id brcm_rescal_reset_of_match
[] = {
91 { .compatible
= "brcm,bcm7216-pcie-sata-rescal" },
94 MODULE_DEVICE_TABLE(of
, brcm_rescal_reset_of_match
);
96 static struct platform_driver brcm_rescal_reset_driver
= {
97 .probe
= brcm_rescal_reset_probe
,
99 .name
= "brcm-rescal-reset",
100 .of_match_table
= brcm_rescal_reset_of_match
,
103 module_platform_driver(brcm_rescal_reset_driver
);
105 MODULE_AUTHOR("Broadcom");
106 MODULE_DESCRIPTION("Broadcom SATA/PCIe rescal reset controller");
107 MODULE_LICENSE("GPL v2");