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