1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016-2017 Linaro Ltd.
4 * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
6 #include <linux/kernel.h>
7 #include <linux/mfd/syscon.h>
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/platform_device.h>
11 #include <linux/regmap.h>
12 #include <linux/reset-controller.h>
14 struct hi3660_reset_controller
{
15 struct reset_controller_dev rst
;
19 #define to_hi3660_reset_controller(_rst) \
20 container_of(_rst, struct hi3660_reset_controller, rst)
22 static int hi3660_reset_program_hw(struct reset_controller_dev
*rcdev
,
23 unsigned long idx
, bool assert)
25 struct hi3660_reset_controller
*rc
= to_hi3660_reset_controller(rcdev
);
26 unsigned int offset
= idx
>> 8;
27 unsigned int mask
= BIT(idx
& 0x1f);
30 return regmap_write(rc
->map
, offset
, mask
);
32 return regmap_write(rc
->map
, offset
+ 4, mask
);
35 static int hi3660_reset_assert(struct reset_controller_dev
*rcdev
,
38 return hi3660_reset_program_hw(rcdev
, idx
, true);
41 static int hi3660_reset_deassert(struct reset_controller_dev
*rcdev
,
44 return hi3660_reset_program_hw(rcdev
, idx
, false);
47 static int hi3660_reset_dev(struct reset_controller_dev
*rcdev
,
52 err
= hi3660_reset_assert(rcdev
, idx
);
56 return hi3660_reset_deassert(rcdev
, idx
);
59 static const struct reset_control_ops hi3660_reset_ops
= {
60 .reset
= hi3660_reset_dev
,
61 .assert = hi3660_reset_assert
,
62 .deassert
= hi3660_reset_deassert
,
65 static int hi3660_reset_xlate(struct reset_controller_dev
*rcdev
,
66 const struct of_phandle_args
*reset_spec
)
68 unsigned int offset
, bit
;
70 offset
= reset_spec
->args
[0];
71 bit
= reset_spec
->args
[1];
73 return (offset
<< 8) | bit
;
76 static int hi3660_reset_probe(struct platform_device
*pdev
)
78 struct hi3660_reset_controller
*rc
;
79 struct device_node
*np
= pdev
->dev
.of_node
;
80 struct device
*dev
= &pdev
->dev
;
82 rc
= devm_kzalloc(dev
, sizeof(*rc
), GFP_KERNEL
);
86 rc
->map
= syscon_regmap_lookup_by_phandle(np
, "hisi,rst-syscon");
87 if (IS_ERR(rc
->map
)) {
88 dev_err(dev
, "failed to get hi3660,rst-syscon\n");
89 return PTR_ERR(rc
->map
);
92 rc
->rst
.ops
= &hi3660_reset_ops
,
94 rc
->rst
.of_reset_n_cells
= 2;
95 rc
->rst
.of_xlate
= hi3660_reset_xlate
;
97 return reset_controller_register(&rc
->rst
);
100 static const struct of_device_id hi3660_reset_match
[] = {
101 { .compatible
= "hisilicon,hi3660-reset", },
104 MODULE_DEVICE_TABLE(of
, hi3660_reset_match
);
106 static struct platform_driver hi3660_reset_driver
= {
107 .probe
= hi3660_reset_probe
,
109 .name
= "hi3660-reset",
110 .of_match_table
= hi3660_reset_match
,
114 static int __init
hi3660_reset_init(void)
116 return platform_driver_register(&hi3660_reset_driver
);
118 arch_initcall(hi3660_reset_init
);
120 MODULE_LICENSE("GPL");
121 MODULE_ALIAS("platform:hi3660-reset");
122 MODULE_DESCRIPTION("HiSilicon Hi3660 Reset Driver");