Merge remote-tracking branches 'asoc/fix/imx-spdif', 'asoc/fix/mtk', 'asoc/fix/mxs...
[linux-2.6-block.git] / drivers / reset / hisilicon / hi6220_reset.c
1 /*
2  * Hisilicon Hi6220 reset controller driver
3  *
4  * Copyright (c) 2015 Hisilicon Limited.
5  *
6  * Author: Feng Chen <puck.chen@hisilicon.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/io.h>
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/bitops.h>
17 #include <linux/of.h>
18 #include <linux/reset-controller.h>
19 #include <linux/reset.h>
20 #include <linux/platform_device.h>
21
22 #define ASSERT_OFFSET            0x300
23 #define DEASSERT_OFFSET          0x304
24 #define MAX_INDEX                0x509
25
26 #define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
27
28 struct hi6220_reset_data {
29         void __iomem                    *assert_base;
30         void __iomem                    *deassert_base;
31         struct reset_controller_dev     rc_dev;
32 };
33
34 static int hi6220_reset_assert(struct reset_controller_dev *rc_dev,
35                                unsigned long idx)
36 {
37         struct hi6220_reset_data *data = to_reset_data(rc_dev);
38
39         int bank = idx >> 8;
40         int offset = idx & 0xff;
41
42         writel(BIT(offset), data->assert_base + (bank * 0x10));
43
44         return 0;
45 }
46
47 static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev,
48                                  unsigned long idx)
49 {
50         struct hi6220_reset_data *data = to_reset_data(rc_dev);
51
52         int bank = idx >> 8;
53         int offset = idx & 0xff;
54
55         writel(BIT(offset), data->deassert_base + (bank * 0x10));
56
57         return 0;
58 }
59
60 static struct reset_control_ops hi6220_reset_ops = {
61         .assert = hi6220_reset_assert,
62         .deassert = hi6220_reset_deassert,
63 };
64
65 static int hi6220_reset_probe(struct platform_device *pdev)
66 {
67         struct hi6220_reset_data *data;
68         struct resource *res;
69         void __iomem *src_base;
70
71         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
72         if (!data)
73                 return -ENOMEM;
74
75         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
76         src_base = devm_ioremap_resource(&pdev->dev, res);
77         if (IS_ERR(src_base))
78                 return PTR_ERR(src_base);
79
80         data->assert_base = src_base + ASSERT_OFFSET;
81         data->deassert_base = src_base + DEASSERT_OFFSET;
82         data->rc_dev.nr_resets = MAX_INDEX;
83         data->rc_dev.ops = &hi6220_reset_ops;
84         data->rc_dev.of_node = pdev->dev.of_node;
85
86         reset_controller_register(&data->rc_dev);
87
88         return 0;
89 }
90
91 static const struct of_device_id hi6220_reset_match[] = {
92         { .compatible = "hisilicon,hi6220-sysctrl" },
93         { },
94 };
95
96 static struct platform_driver hi6220_reset_driver = {
97         .probe = hi6220_reset_probe,
98         .driver = {
99                 .name = "reset-hi6220",
100                 .of_match_table = hi6220_reset_match,
101         },
102 };
103
104 static int __init hi6220_reset_init(void)
105 {
106         return platform_driver_register(&hi6220_reset_driver);
107 }
108
109 postcore_initcall(hi6220_reset_init);