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