Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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}