Loading...
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 */
15static 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
35static 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 */
50static 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 */
76static 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 */
104static 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 */
125static 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 */
149static 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 */
169static 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 */
188static 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 */
212static 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
230const 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 */
248int 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}
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 */
15static 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
35static 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 * @base_reg: base of scratch bits
48 * @offset: index of bit within the register
49 * @set: is bit set?
50 */
51static 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_gpio_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 */
78static 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 */
106static 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 */
127static 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 */
151static 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 */
172static 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 */
191static 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 */
215static 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
233const 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_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 */
251int 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}