dm: core: Create a new header file for 'compat' features
[oweals/u-boot.git] / drivers / hwspinlock / hwspinlock-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2 /*
3  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <hwspinlock.h>
10 #include <dm/device-internal.h>
11 #include <dm/device_compat.h>
12 #include <linux/compat.h>
13
14 static inline const struct hwspinlock_ops *
15 hwspinlock_dev_ops(struct udevice *dev)
16 {
17         return (const struct hwspinlock_ops *)dev->driver->ops;
18 }
19
20 static int hwspinlock_of_xlate_default(struct hwspinlock *hws,
21                                        struct ofnode_phandle_args *args)
22 {
23         if (args->args_count > 1) {
24                 debug("Invaild args_count: %d\n", args->args_count);
25                 return -EINVAL;
26         }
27
28         if (args->args_count)
29                 hws->id = args->args[0];
30         else
31                 hws->id = 0;
32
33         return 0;
34 }
35
36 int hwspinlock_get_by_index(struct udevice *dev, int index,
37                             struct hwspinlock *hws)
38 {
39         int ret;
40         struct ofnode_phandle_args args;
41         struct udevice *dev_hws;
42         const struct hwspinlock_ops *ops;
43
44         assert(hws);
45         hws->dev = NULL;
46
47         ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1,
48                                          index, &args);
49         if (ret) {
50                 dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
51                         __func__, ret);
52                 return ret;
53         }
54
55         ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK,
56                                           args.node, &dev_hws);
57         if (ret) {
58                 dev_dbg(dev,
59                         "%s: uclass_get_device_by_of_offset failed: err=%d\n",
60                         __func__, ret);
61                 return ret;
62         }
63
64         hws->dev = dev_hws;
65
66         ops = hwspinlock_dev_ops(dev_hws);
67
68         if (ops->of_xlate)
69                 ret = ops->of_xlate(hws, &args);
70         else
71                 ret = hwspinlock_of_xlate_default(hws, &args);
72         if (ret)
73                 dev_dbg(dev, "of_xlate() failed: %d\n", ret);
74
75         return ret;
76 }
77
78 int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout)
79 {
80         const struct hwspinlock_ops *ops;
81         ulong start;
82         int ret;
83
84         assert(hws);
85
86         if (!hws->dev)
87                 return -EINVAL;
88
89         ops = hwspinlock_dev_ops(hws->dev);
90         if (!ops->lock)
91                 return -ENOSYS;
92
93         start = get_timer(0);
94         do {
95                 ret = ops->lock(hws->dev, hws->id);
96                 if (!ret)
97                         return ret;
98
99                 if (ops->relax)
100                         ops->relax(hws->dev);
101         } while (get_timer(start) < timeout);
102
103         return -ETIMEDOUT;
104 }
105
106 int hwspinlock_unlock(struct hwspinlock *hws)
107 {
108         const struct hwspinlock_ops *ops;
109
110         assert(hws);
111
112         if (!hws->dev)
113                 return -EINVAL;
114
115         ops = hwspinlock_dev_ops(hws->dev);
116         if (!ops->unlock)
117                 return -ENOSYS;
118
119         return ops->unlock(hws->dev, hws->id);
120 }
121
122 static int hwspinlock_post_bind(struct udevice *dev)
123 {
124 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
125         struct hwspinlock_ops *ops = device_get_ops(dev);
126         static int reloc_done;
127
128         if (!reloc_done) {
129                 if (ops->lock)
130                         ops->lock += gd->reloc_off;
131                 if (ops->unlock)
132                         ops->unlock += gd->reloc_off;
133                 if (ops->relax)
134                         ops->relax += gd->reloc_off;
135
136                 reloc_done++;
137         }
138 #endif
139         return 0;
140 }
141
142 UCLASS_DRIVER(hwspinlock) = {
143         .id             = UCLASS_HWSPINLOCK,
144         .name           = "hwspinlock",
145         .post_bind      = hwspinlock_post_bind,
146 };