xref: /linux/drivers/net/dsa/motorcomm/smi.c (revision e9423a64d382ba77a2906f365416714ede67328e)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2026 David Yang
4  */
5 
6 #include <linux/iopoll.h>
7 
8 #include "chip.h"
9 #include "smi.h"
10 
11 #define YT921X_POLL_SLEEP_US	10000
12 #define YT921X_POLL_TIMEOUT_US	100000
13 
14 int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
15 {
16 	lockdep_assert_held_once(&priv->reg_lock);
17 
18 	return priv->reg_ops->read(priv->reg_ctx, reg, valp);
19 }
20 
21 int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
22 {
23 	lockdep_assert_held_once(&priv->reg_lock);
24 
25 	return priv->reg_ops->write(priv->reg_ctx, reg, val);
26 }
27 
28 int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
29 {
30 	u32 val;
31 	int res;
32 	int ret;
33 
34 	ret = read_poll_timeout(yt921x_reg_read, res,
35 				res || (val & mask) == *valp,
36 				YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
37 				false, priv, reg, &val);
38 	if (ret)
39 		return ret;
40 	if (res)
41 		return res;
42 
43 	*valp = val;
44 	return 0;
45 }
46 
47 int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
48 {
49 	int res;
50 	u32 v;
51 	u32 u;
52 
53 	res = yt921x_reg_read(priv, reg, &v);
54 	if (res)
55 		return res;
56 
57 	u = v;
58 	u &= ~mask;
59 	u |= val;
60 	if (u == v)
61 		return 0;
62 
63 	return yt921x_reg_write(priv, reg, u);
64 }
65 
66 static int
67 yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
68 		 unsigned int num_regs)
69 {
70 	int res;
71 
72 	for (unsigned int i = 0; i < num_regs; i++) {
73 		res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
74 		if (res)
75 			return res;
76 	}
77 
78 	return 0;
79 }
80 
81 static int
82 yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
83 		  unsigned int num_regs)
84 {
85 	int res;
86 
87 	for (unsigned int i = 0; i < num_regs; i++) {
88 		res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
89 		if (res)
90 			return res;
91 	}
92 
93 	return 0;
94 }
95 
96 static int
97 yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
98 			const u32 *vals, unsigned int num_regs)
99 {
100 	bool changed = false;
101 	u32 vs[4];
102 	int res;
103 
104 	BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
105 
106 	res = yt921x_regs_read(priv, reg, vs, num_regs);
107 	if (res)
108 		return res;
109 
110 	for (unsigned int i = 0; i < num_regs; i++) {
111 		u32 u = vs[i];
112 
113 		u &= ~masks[i];
114 		u |= vals[i];
115 		if (u != vs[i])
116 			changed = true;
117 
118 		vs[i] = u;
119 	}
120 
121 	if (!changed)
122 		return 0;
123 
124 	return yt921x_regs_write(priv, reg, vs, num_regs);
125 }
126 
127 static int
128 yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
129 		       unsigned int num_regs)
130 {
131 	bool changed = false;
132 	u32 vs[4];
133 	int res;
134 
135 	BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
136 
137 	res = yt921x_regs_read(priv, reg, vs, num_regs);
138 	if (res)
139 		return res;
140 
141 	for (unsigned int i = 0; i < num_regs; i++) {
142 		u32 u = vs[i];
143 
144 		u &= ~masks[i];
145 		if (u != vs[i])
146 			changed = true;
147 
148 		vs[i] = u;
149 	}
150 
151 	if (!changed)
152 		return 0;
153 
154 	return yt921x_regs_write(priv, reg, vs, num_regs);
155 }
156 
157 int
158 yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
159 {
160 	return yt921x_regs_write(priv, reg, vals, 2);
161 }
162 
163 int
164 yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
165 			 const u32 *vals)
166 {
167 	return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
168 }
169 
170 int
171 yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
172 {
173 	return yt921x_regs_clear_bits(priv, reg, masks, 2);
174 }
175 
176 int
177 yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
178 {
179 	return yt921x_regs_write(priv, reg, vals, 3);
180 }
181