1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
4  *
5  * Copyright (c) 2008 Marvell Semiconductor
6  *
7  * Copyright (c) 2017 National Instruments
8  *      Brandon Streiff <brandon.streiff@ni.com>
9  */
10 
11 #include "chip.h"
12 #include "global2.h"
13 
14 /* Offset 0x1A: Scratch and Misc. Register */
15 static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
16 				     u8 *data)
17 {
18 	u16 value;
19 	int err;
20 
21 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
22 				 reg << 8);
23 	if (err)
24 		return err;
25 
26 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
27 	if (err)
28 		return err;
29 
30 	*data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
31 
32 	return 0;
33 }
34 
35 static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
36 				      u8 data)
37 {
38 	u16 value = (reg << 8) | data;
39 
40 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
41 				  MV88E6XXX_G2_SCRATCH_MISC_UPDATE | value);
42 }
43 
44 /**
45  * mv88e6xxx_g2_scratch_gpio_get_bit - get a bit
46  * @chip: chip private data
47  * @nr: bit index
48  * @set: is bit set?
49  */
50 static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
51 					int base_reg, unsigned int offset,
52 					int *set)
53 {
54 	int reg = base_reg + (offset / 8);
55 	u8 mask = (1 << (offset & 0x7));
56 	u8 val;
57 	int err;
58 
59 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
60 	if (err)
61 		return err;
62 
63 	*set = !!(mask & val);
64 
65 	return 0;
66 }
67 
68 /**
69  * mv88e6xxx_g2_scratch_gpio_set_bit - set (or clear) a bit
70  * @chip: chip private data
71  * @nr: bit index
72  * @set: set if true, clear if false
73  *
74  * Helper function for dealing with the direction and data registers.
75  */
76 static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
77 					int base_reg, unsigned int offset,
78 					int set)
79 {
80 	int reg = base_reg + (offset / 8);
81 	u8 mask = (1 << (offset & 0x7));
82 	u8 val;
83 	int err;
84 
85 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
86 	if (err)
87 		return err;
88 
89 	if (set)
90 		val |= mask;
91 	else
92 		val &= ~mask;
93 
94 	return mv88e6xxx_g2_scratch_write(chip, reg, val);
95 }
96 
97 /**
98  * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
99  * @chip: chip private data
100  * @pin: gpio index
101  *
102  * Return: 0 for low, 1 for high, negative error
103  */
104 static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
105 					      unsigned int pin)
106 {
107 	int val = 0;
108 	int err;
109 
110 	err = mv88e6xxx_g2_scratch_get_bit(chip,
111 					   MV88E6352_G2_SCRATCH_GPIO_DATA0,
112 					   pin, &val);
113 	if (err)
114 		return err;
115 
116 	return val;
117 }
118 
119 /**
120  * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
121  * @chip: chip private data
122  * @pin: gpio index
123  * @value: value to set
124  */
125 static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
126 					      unsigned int pin, int value)
127 {
128 	u8 mask = (1 << (pin & 0x7));
129 	int offset = (pin / 8);
130 	int reg;
131 
132 	reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
133 
134 	if (value)
135 		chip->gpio_data[offset] |= mask;
136 	else
137 		chip->gpio_data[offset] &= ~mask;
138 
139 	return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
140 }
141 
142 /**
143  * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
144  * @chip: chip private data
145  * @pin: gpio index
146  *
147  * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
148  */
149 static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
150 					     unsigned int pin)
151 {
152 	int val = 0;
153 	int err;
154 
155 	err = mv88e6xxx_g2_scratch_get_bit(chip,
156 					   MV88E6352_G2_SCRATCH_GPIO_DIR0,
157 					   pin, &val);
158 	if (err)
159 		return err;
160 
161 	return val;
162 }
163 
164 /**
165  * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
166  * @chip: chip private data
167  * @pin: gpio index
168  */
169 static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,
170 					     unsigned int pin, bool input)
171 {
172 	int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :
173 			     MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);
174 
175 	return mv88e6xxx_g2_scratch_set_bit(chip,
176 					    MV88E6352_G2_SCRATCH_GPIO_DIR0,
177 					    pin, value);
178 }
179 
180 /**
181  * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting
182  * @chip: chip private data
183  * @pin: gpio index
184  * @func: function number
185  *
186  * Note that the function numbers themselves may vary by chipset.
187  */
188 static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,
189 					      unsigned int pin, int *func)
190 {
191 	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
192 	int offset = (pin & 0x1) ? 4 : 0;
193 	u8 mask = (0x7 << offset);
194 	int err;
195 	u8 val;
196 
197 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
198 	if (err)
199 		return err;
200 
201 	*func = (val & mask) >> offset;
202 
203 	return 0;
204 }
205 
206 /**
207  * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting
208  * @chip: chip private data
209  * @pin: gpio index
210  * @func: function number
211  */
212 static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,
213 					      unsigned int pin, int func)
214 {
215 	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
216 	int offset = (pin & 0x1) ? 4 : 0;
217 	u8 mask = (0x7 << offset);
218 	int err;
219 	u8 val;
220 
221 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
222 	if (err)
223 		return err;
224 
225 	val = (val & ~mask) | ((func & mask) << offset);
226 
227 	return mv88e6xxx_g2_scratch_write(chip, reg, val);
228 }
229 
230 const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {
231 	.get_data = mv88e6352_g2_scratch_gpio_get_data,
232 	.set_data = mv88e6352_g2_scratch_gpio_set_data,
233 	.get_dir = mv88e6352_g2_scratch_gpio_get_dir,
234 	.set_dir = mv88e6352_g2_scratch_gpio_set_dir,
235 	.get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,
236 	.set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,
237 };
238 
239 /**
240  * mv88e6xxx_g2_gpio_set_smi - set gpio muxing for external smi
241  * @chip: chip private data
242  * @external: set mux for external smi, or free for gpio usage
243  *
244  * Some mv88e6xxx models have GPIO pins that may be configured as
245  * an external SMI interface, or they may be made free for other
246  * GPIO uses.
247  */
248 int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
249 				      bool external)
250 {
251 	int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;
252 	int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1;
253 	int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2;
254 	bool no_cpu;
255 	u8 p0_mode;
256 	int err;
257 	u8 val;
258 
259 	err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val);
260 	if (err)
261 		return err;
262 
263 	p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK;
264 
265 	if (p0_mode == 0x01 || p0_mode == 0x02)
266 		return -EBUSY;
267 
268 	err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val);
269 	if (err)
270 		return err;
271 
272 	no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU);
273 
274 	err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);
275 	if (err)
276 		return err;
277 
278 	/* NO_CPU being 0 inverts the meaning of the bit */
279 	if (!no_cpu)
280 		external = !external;
281 
282 	if (external)
283 		val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
284 	else
285 		val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
286 
287 	return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);
288 }
289