1 /*
2 * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2017 National Instruments
7 * Brandon Streiff <brandon.streiff@ni.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15 #include "chip.h"
16 #include "global2.h"
17
18 /* Offset 0x1A: Scratch and Misc. Register */
mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip * chip,int reg,u8 * data)19 static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
20 u8 *data)
21 {
22 u16 value;
23 int err;
24
25 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
26 reg << 8);
27 if (err)
28 return err;
29
30 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
31 if (err)
32 return err;
33
34 *data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
35
36 return 0;
37 }
38
mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip * chip,int reg,u8 data)39 static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
40 u8 data)
41 {
42 u16 value = (reg << 8) | data;
43
44 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, value);
45 }
46
47 /**
48 * mv88e6xxx_g2_scratch_gpio_get_bit - get a bit
49 * @chip: chip private data
50 * @nr: bit index
51 * @set: is bit set?
52 */
mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip * chip,int base_reg,unsigned int offset,int * set)53 static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
54 int base_reg, unsigned int offset,
55 int *set)
56 {
57 int reg = base_reg + (offset / 8);
58 u8 mask = (1 << (offset & 0x7));
59 u8 val;
60 int err;
61
62 err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
63 if (err)
64 return err;
65
66 *set = !!(mask & val);
67
68 return 0;
69 }
70
71 /**
72 * mv88e6xxx_g2_scratch_gpio_set_bit - set (or clear) a bit
73 * @chip: chip private data
74 * @nr: bit index
75 * @set: set if true, clear if false
76 *
77 * Helper function for dealing with the direction and data registers.
78 */
mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip * chip,int base_reg,unsigned int offset,int set)79 static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
80 int base_reg, unsigned int offset,
81 int set)
82 {
83 int reg = base_reg + (offset / 8);
84 u8 mask = (1 << (offset & 0x7));
85 u8 val;
86 int err;
87
88 err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
89 if (err)
90 return err;
91
92 if (set)
93 val |= mask;
94 else
95 val &= ~mask;
96
97 return mv88e6xxx_g2_scratch_write(chip, reg, val);
98 }
99
100 /**
101 * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
102 * @chip: chip private data
103 * @pin: gpio index
104 *
105 * Return: 0 for low, 1 for high, negative error
106 */
mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip * chip,unsigned int pin)107 static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
108 unsigned int pin)
109 {
110 int val = 0;
111 int err;
112
113 err = mv88e6xxx_g2_scratch_get_bit(chip,
114 MV88E6352_G2_SCRATCH_GPIO_DATA0,
115 pin, &val);
116 if (err)
117 return err;
118
119 return val;
120 }
121
122 /**
123 * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
124 * @chip: chip private data
125 * @pin: gpio index
126 * @value: value to set
127 */
mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip * chip,unsigned int pin,int value)128 static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
129 unsigned int pin, int value)
130 {
131 u8 mask = (1 << (pin & 0x7));
132 int offset = (pin / 8);
133 int reg;
134
135 reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
136
137 if (value)
138 chip->gpio_data[offset] |= mask;
139 else
140 chip->gpio_data[offset] &= ~mask;
141
142 return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
143 }
144
145 /**
146 * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
147 * @chip: chip private data
148 * @pin: gpio index
149 *
150 * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
151 */
mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip * chip,unsigned int pin)152 static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
153 unsigned int pin)
154 {
155 int val = 0;
156 int err;
157
158 err = mv88e6xxx_g2_scratch_get_bit(chip,
159 MV88E6352_G2_SCRATCH_GPIO_DIR0,
160 pin, &val);
161 if (err)
162 return err;
163
164 return val;
165 }
166
167 /**
168 * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
169 * @chip: chip private data
170 * @pin: gpio index
171 */
mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip * chip,unsigned int pin,bool input)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 */
mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip * chip,unsigned int pin,int * func)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 */
mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip * chip,unsigned int pin,int func)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_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 */
mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip * chip,bool external)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