blob: ea93efc97df7535cdc363d57eba8ac3c87cfe1d1 [file] [log] [blame]
Benjamin Gaignarda550b542018-11-27 13:49:50 +01001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 */
5
Patrick Delaunay81313352021-04-27 11:02:19 +02006#define LOG_CATEGORY UCLASS_HWSPINLOCK
7
Benjamin Gaignarda550b542018-11-27 13:49:50 +01008#include <dm.h>
9#include <errno.h>
10#include <hwspinlock.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Benjamin Gaignarda550b542018-11-27 13:49:50 +010012#include <dm/device-internal.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <dm/device_compat.h>
14#include <linux/compat.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060015#include <asm/global_data.h>
Benjamin Gaignarda550b542018-11-27 13:49:50 +010016
17static inline const struct hwspinlock_ops *
18hwspinlock_dev_ops(struct udevice *dev)
19{
20 return (const struct hwspinlock_ops *)dev->driver->ops;
21}
22
23static int hwspinlock_of_xlate_default(struct hwspinlock *hws,
24 struct ofnode_phandle_args *args)
25{
26 if (args->args_count > 1) {
Sean Andersona1b654b2021-12-01 14:26:53 -050027 debug("Invalid args_count: %d\n", args->args_count);
Benjamin Gaignarda550b542018-11-27 13:49:50 +010028 return -EINVAL;
29 }
30
31 if (args->args_count)
32 hws->id = args->args[0];
33 else
34 hws->id = 0;
35
36 return 0;
37}
38
39int hwspinlock_get_by_index(struct udevice *dev, int index,
40 struct hwspinlock *hws)
41{
42 int ret;
43 struct ofnode_phandle_args args;
44 struct udevice *dev_hws;
45 const struct hwspinlock_ops *ops;
46
47 assert(hws);
48 hws->dev = NULL;
49
50 ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1,
51 index, &args);
52 if (ret) {
53 dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
54 __func__, ret);
55 return ret;
56 }
57
58 ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK,
59 args.node, &dev_hws);
60 if (ret) {
61 dev_dbg(dev,
62 "%s: uclass_get_device_by_of_offset failed: err=%d\n",
63 __func__, ret);
64 return ret;
65 }
66
67 hws->dev = dev_hws;
68
69 ops = hwspinlock_dev_ops(dev_hws);
70
71 if (ops->of_xlate)
72 ret = ops->of_xlate(hws, &args);
73 else
74 ret = hwspinlock_of_xlate_default(hws, &args);
75 if (ret)
76 dev_dbg(dev, "of_xlate() failed: %d\n", ret);
77
78 return ret;
79}
80
81int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout)
82{
83 const struct hwspinlock_ops *ops;
84 ulong start;
85 int ret;
86
87 assert(hws);
88
89 if (!hws->dev)
90 return -EINVAL;
91
92 ops = hwspinlock_dev_ops(hws->dev);
93 if (!ops->lock)
94 return -ENOSYS;
95
96 start = get_timer(0);
97 do {
98 ret = ops->lock(hws->dev, hws->id);
99 if (!ret)
100 return ret;
101
102 if (ops->relax)
103 ops->relax(hws->dev);
104 } while (get_timer(start) < timeout);
105
106 return -ETIMEDOUT;
107}
108
109int hwspinlock_unlock(struct hwspinlock *hws)
110{
111 const struct hwspinlock_ops *ops;
112
113 assert(hws);
114
115 if (!hws->dev)
116 return -EINVAL;
117
118 ops = hwspinlock_dev_ops(hws->dev);
119 if (!ops->unlock)
120 return -ENOSYS;
121
122 return ops->unlock(hws->dev, hws->id);
123}
124
Benjamin Gaignarda550b542018-11-27 13:49:50 +0100125UCLASS_DRIVER(hwspinlock) = {
126 .id = UCLASS_HWSPINLOCK,
127 .name = "hwspinlock",
Benjamin Gaignarda550b542018-11-27 13:49:50 +0100128};