1a73ccd61SBrandon Streiff /*
2a73ccd61SBrandon Streiff  * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
3a73ccd61SBrandon Streiff  *
4a73ccd61SBrandon Streiff  * Copyright (c) 2008 Marvell Semiconductor
5a73ccd61SBrandon Streiff  *
6a73ccd61SBrandon Streiff  * Copyright (c) 2017 National Instruments
7a73ccd61SBrandon Streiff  *      Brandon Streiff <brandon.streiff@ni.com>
8a73ccd61SBrandon Streiff  *
9a73ccd61SBrandon Streiff  * This program is free software; you can redistribute it and/or modify
10a73ccd61SBrandon Streiff  * it under the terms of the GNU General Public License as published by
11a73ccd61SBrandon Streiff  * the Free Software Foundation; either version 2 of the License, or
12a73ccd61SBrandon Streiff  * (at your option) any later version.
13a73ccd61SBrandon Streiff  */
14a73ccd61SBrandon Streiff 
15a73ccd61SBrandon Streiff #include "chip.h"
16a73ccd61SBrandon Streiff #include "global2.h"
17a73ccd61SBrandon Streiff 
18a73ccd61SBrandon Streiff /* Offset 0x1A: Scratch and Misc. Register */
19a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
20a73ccd61SBrandon Streiff 				     u8 *data)
21a73ccd61SBrandon Streiff {
22a73ccd61SBrandon Streiff 	u16 value;
23a73ccd61SBrandon Streiff 	int err;
24a73ccd61SBrandon Streiff 
25a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
26a73ccd61SBrandon Streiff 				 reg << 8);
27a73ccd61SBrandon Streiff 	if (err)
28a73ccd61SBrandon Streiff 		return err;
29a73ccd61SBrandon Streiff 
30a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
31a73ccd61SBrandon Streiff 	if (err)
32a73ccd61SBrandon Streiff 		return err;
33a73ccd61SBrandon Streiff 
34a73ccd61SBrandon Streiff 	*data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
35a73ccd61SBrandon Streiff 
36a73ccd61SBrandon Streiff 	return 0;
37a73ccd61SBrandon Streiff }
38a73ccd61SBrandon Streiff 
39a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
40a73ccd61SBrandon Streiff 				      u8 data)
41a73ccd61SBrandon Streiff {
42a73ccd61SBrandon Streiff 	u16 value = (reg << 8) | data;
43a73ccd61SBrandon Streiff 
44a73ccd61SBrandon Streiff 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, value);
45a73ccd61SBrandon Streiff }
46a73ccd61SBrandon Streiff 
47a73ccd61SBrandon Streiff /**
48a73ccd61SBrandon Streiff  * mv88e6xxx_g2_scratch_gpio_get_bit - get a bit
49a73ccd61SBrandon Streiff  * @chip: chip private data
50a73ccd61SBrandon Streiff  * @nr: bit index
51a73ccd61SBrandon Streiff  * @set: is bit set?
52a73ccd61SBrandon Streiff  */
53a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
54a73ccd61SBrandon Streiff 					int base_reg, unsigned int offset,
55a73ccd61SBrandon Streiff 					int *set)
56a73ccd61SBrandon Streiff {
57a73ccd61SBrandon Streiff 	int reg = base_reg + (offset / 8);
58a73ccd61SBrandon Streiff 	u8 mask = (1 << (offset & 0x7));
59a73ccd61SBrandon Streiff 	u8 val;
60a73ccd61SBrandon Streiff 	int err;
61a73ccd61SBrandon Streiff 
62a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
63a73ccd61SBrandon Streiff 	if (err)
64a73ccd61SBrandon Streiff 		return err;
65a73ccd61SBrandon Streiff 
66a73ccd61SBrandon Streiff 	*set = !!(mask & val);
67a73ccd61SBrandon Streiff 
68a73ccd61SBrandon Streiff 	return 0;
69a73ccd61SBrandon Streiff }
70a73ccd61SBrandon Streiff 
71a73ccd61SBrandon Streiff /**
72a73ccd61SBrandon Streiff  * mv88e6xxx_g2_scratch_gpio_set_bit - set (or clear) a bit
73a73ccd61SBrandon Streiff  * @chip: chip private data
74a73ccd61SBrandon Streiff  * @nr: bit index
75a73ccd61SBrandon Streiff  * @set: set if true, clear if false
76a73ccd61SBrandon Streiff  *
77a73ccd61SBrandon Streiff  * Helper function for dealing with the direction and data registers.
78a73ccd61SBrandon Streiff  */
79a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
80a73ccd61SBrandon Streiff 					int base_reg, unsigned int offset,
81a73ccd61SBrandon Streiff 					int set)
82a73ccd61SBrandon Streiff {
83a73ccd61SBrandon Streiff 	int reg = base_reg + (offset / 8);
84a73ccd61SBrandon Streiff 	u8 mask = (1 << (offset & 0x7));
85a73ccd61SBrandon Streiff 	u8 val;
86a73ccd61SBrandon Streiff 	int err;
87a73ccd61SBrandon Streiff 
88a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
89a73ccd61SBrandon Streiff 	if (err)
90a73ccd61SBrandon Streiff 		return err;
91a73ccd61SBrandon Streiff 
92a73ccd61SBrandon Streiff 	if (set)
93a73ccd61SBrandon Streiff 		val |= mask;
94a73ccd61SBrandon Streiff 	else
95a73ccd61SBrandon Streiff 		val &= ~mask;
96a73ccd61SBrandon Streiff 
97a73ccd61SBrandon Streiff 	return mv88e6xxx_g2_scratch_write(chip, reg, val);
98a73ccd61SBrandon Streiff }
99a73ccd61SBrandon Streiff 
100a73ccd61SBrandon Streiff /**
101a73ccd61SBrandon Streiff  * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
102a73ccd61SBrandon Streiff  * @chip: chip private data
103a73ccd61SBrandon Streiff  * @pin: gpio index
104a73ccd61SBrandon Streiff  *
105a73ccd61SBrandon Streiff  * Return: 0 for low, 1 for high, negative error
106a73ccd61SBrandon Streiff  */
107a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
108a73ccd61SBrandon Streiff 					      unsigned int pin)
109a73ccd61SBrandon Streiff {
110a73ccd61SBrandon Streiff 	int val = 0;
111a73ccd61SBrandon Streiff 	int err;
112a73ccd61SBrandon Streiff 
113a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_scratch_get_bit(chip,
114a73ccd61SBrandon Streiff 					   MV88E6352_G2_SCRATCH_GPIO_DATA0,
115a73ccd61SBrandon Streiff 					   pin, &val);
116a73ccd61SBrandon Streiff 	if (err)
117a73ccd61SBrandon Streiff 		return err;
118a73ccd61SBrandon Streiff 
119a73ccd61SBrandon Streiff 	return val;
120a73ccd61SBrandon Streiff }
121a73ccd61SBrandon Streiff 
122a73ccd61SBrandon Streiff /**
123a73ccd61SBrandon Streiff  * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
124a73ccd61SBrandon Streiff  * @chip: chip private data
125a73ccd61SBrandon Streiff  * @pin: gpio index
126a73ccd61SBrandon Streiff  * @value: value to set
127a73ccd61SBrandon Streiff  */
128a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
129a73ccd61SBrandon Streiff 					      unsigned int pin, int value)
130a73ccd61SBrandon Streiff {
131a73ccd61SBrandon Streiff 	u8 mask = (1 << (pin & 0x7));
132a73ccd61SBrandon Streiff 	int offset = (pin / 8);
133a73ccd61SBrandon Streiff 	int reg;
134a73ccd61SBrandon Streiff 
135a73ccd61SBrandon Streiff 	reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
136a73ccd61SBrandon Streiff 
137a73ccd61SBrandon Streiff 	if (value)
138a73ccd61SBrandon Streiff 		chip->gpio_data[offset] |= mask;
139a73ccd61SBrandon Streiff 	else
140a73ccd61SBrandon Streiff 		chip->gpio_data[offset] &= ~mask;
141a73ccd61SBrandon Streiff 
142a73ccd61SBrandon Streiff 	return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
143a73ccd61SBrandon Streiff }
144a73ccd61SBrandon Streiff 
145a73ccd61SBrandon Streiff /**
146a73ccd61SBrandon Streiff  * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
147a73ccd61SBrandon Streiff  * @chip: chip private data
148a73ccd61SBrandon Streiff  * @pin: gpio index
149a73ccd61SBrandon Streiff  *
150a73ccd61SBrandon Streiff  * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
151a73ccd61SBrandon Streiff  */
152a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
153a73ccd61SBrandon Streiff 					     unsigned int pin)
154a73ccd61SBrandon Streiff {
155a73ccd61SBrandon Streiff 	int val = 0;
156a73ccd61SBrandon Streiff 	int err;
157a73ccd61SBrandon Streiff 
158a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_scratch_get_bit(chip,
159a73ccd61SBrandon Streiff 					   MV88E6352_G2_SCRATCH_GPIO_DIR0,
160a73ccd61SBrandon Streiff 					   pin, &val);
161a73ccd61SBrandon Streiff 	if (err)
162a73ccd61SBrandon Streiff 		return err;
163a73ccd61SBrandon Streiff 
164a73ccd61SBrandon Streiff 	return val;
165a73ccd61SBrandon Streiff }
166a73ccd61SBrandon Streiff 
167a73ccd61SBrandon Streiff /**
168a73ccd61SBrandon Streiff  * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
169a73ccd61SBrandon Streiff  * @chip: chip private data
170a73ccd61SBrandon Streiff  * @pin: gpio index
171a73ccd61SBrandon Streiff  */
172a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,
173a73ccd61SBrandon Streiff 					     unsigned int pin, bool input)
174a73ccd61SBrandon Streiff {
175a73ccd61SBrandon Streiff 	int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :
176a73ccd61SBrandon Streiff 			     MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);
177a73ccd61SBrandon Streiff 
178a73ccd61SBrandon Streiff 	return mv88e6xxx_g2_scratch_set_bit(chip,
179a73ccd61SBrandon Streiff 					    MV88E6352_G2_SCRATCH_GPIO_DIR0,
180a73ccd61SBrandon Streiff 					    pin, value);
181a73ccd61SBrandon Streiff }
182a73ccd61SBrandon Streiff 
183a73ccd61SBrandon Streiff /**
184a73ccd61SBrandon Streiff  * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting
185a73ccd61SBrandon Streiff  * @chip: chip private data
186a73ccd61SBrandon Streiff  * @pin: gpio index
187a73ccd61SBrandon Streiff  * @func: function number
188a73ccd61SBrandon Streiff  *
189a73ccd61SBrandon Streiff  * Note that the function numbers themselves may vary by chipset.
190a73ccd61SBrandon Streiff  */
191a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,
192a73ccd61SBrandon Streiff 					      unsigned int pin, int *func)
193a73ccd61SBrandon Streiff {
194a73ccd61SBrandon Streiff 	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
195a73ccd61SBrandon Streiff 	int offset = (pin & 0x1) ? 4 : 0;
196a73ccd61SBrandon Streiff 	u8 mask = (0x7 << offset);
197a73ccd61SBrandon Streiff 	int err;
198a73ccd61SBrandon Streiff 	u8 val;
199a73ccd61SBrandon Streiff 
200a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
201a73ccd61SBrandon Streiff 	if (err)
202a73ccd61SBrandon Streiff 		return err;
203a73ccd61SBrandon Streiff 
204a73ccd61SBrandon Streiff 	*func = (val & mask) >> offset;
205a73ccd61SBrandon Streiff 
206a73ccd61SBrandon Streiff 	return 0;
207a73ccd61SBrandon Streiff }
208a73ccd61SBrandon Streiff 
209a73ccd61SBrandon Streiff /**
210a73ccd61SBrandon Streiff  * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting
211a73ccd61SBrandon Streiff  * @chip: chip private data
212a73ccd61SBrandon Streiff  * @pin: gpio index
213a73ccd61SBrandon Streiff  * @func: function number
214a73ccd61SBrandon Streiff  */
215a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,
216a73ccd61SBrandon Streiff 					      unsigned int pin, int func)
217a73ccd61SBrandon Streiff {
218a73ccd61SBrandon Streiff 	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
219a73ccd61SBrandon Streiff 	int offset = (pin & 0x1) ? 4 : 0;
220a73ccd61SBrandon Streiff 	u8 mask = (0x7 << offset);
221a73ccd61SBrandon Streiff 	int err;
222a73ccd61SBrandon Streiff 	u8 val;
223a73ccd61SBrandon Streiff 
224a73ccd61SBrandon Streiff 	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
225a73ccd61SBrandon Streiff 	if (err)
226a73ccd61SBrandon Streiff 		return err;
227a73ccd61SBrandon Streiff 
228a73ccd61SBrandon Streiff 	val = (val & ~mask) | ((func & mask) << offset);
229a73ccd61SBrandon Streiff 
230a73ccd61SBrandon Streiff 	return mv88e6xxx_g2_scratch_write(chip, reg, val);
231a73ccd61SBrandon Streiff }
232a73ccd61SBrandon Streiff 
233a73ccd61SBrandon Streiff const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {
234a73ccd61SBrandon Streiff 	.get_data = mv88e6352_g2_scratch_gpio_get_data,
235a73ccd61SBrandon Streiff 	.set_data = mv88e6352_g2_scratch_gpio_set_data,
236a73ccd61SBrandon Streiff 	.get_dir = mv88e6352_g2_scratch_gpio_get_dir,
237a73ccd61SBrandon Streiff 	.set_dir = mv88e6352_g2_scratch_gpio_set_dir,
238a73ccd61SBrandon Streiff 	.get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,
239a73ccd61SBrandon Streiff 	.set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,
240a73ccd61SBrandon Streiff };
2412510babcSAndrew Lunn 
2422510babcSAndrew Lunn /**
2432510babcSAndrew Lunn  * mv88e6xxx_g2_gpio_set_smi - set gpio muxing for external smi
2442510babcSAndrew Lunn  * @chip: chip private data
2452510babcSAndrew Lunn  * @external: set mux for external smi, or free for gpio usage
2462510babcSAndrew Lunn  *
2472510babcSAndrew Lunn  * Some mv88e6xxx models have GPIO pins that may be configured as
2482510babcSAndrew Lunn  * an external SMI interface, or they may be made free for other
2492510babcSAndrew Lunn  * GPIO uses.
2502510babcSAndrew Lunn  */
2512510babcSAndrew Lunn int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
2522510babcSAndrew Lunn 				      bool external)
2532510babcSAndrew Lunn {
2542510babcSAndrew Lunn 	int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;
2552510babcSAndrew Lunn 	int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1;
2562510babcSAndrew Lunn 	int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2;
2572510babcSAndrew Lunn 	bool no_cpu;
2582510babcSAndrew Lunn 	u8 p0_mode;
2592510babcSAndrew Lunn 	int err;
2602510babcSAndrew Lunn 	u8 val;
2612510babcSAndrew Lunn 
2622510babcSAndrew Lunn 	err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val);
2632510babcSAndrew Lunn 	if (err)
2642510babcSAndrew Lunn 		return err;
2652510babcSAndrew Lunn 
2662510babcSAndrew Lunn 	p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK;
2672510babcSAndrew Lunn 
2682510babcSAndrew Lunn 	if (p0_mode == 0x01 || p0_mode == 0x02)
2692510babcSAndrew Lunn 		return -EBUSY;
2702510babcSAndrew Lunn 
2712510babcSAndrew Lunn 	err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val);
2722510babcSAndrew Lunn 	if (err)
2732510babcSAndrew Lunn 		return err;
2742510babcSAndrew Lunn 
2752510babcSAndrew Lunn 	no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU);
2762510babcSAndrew Lunn 
2772510babcSAndrew Lunn 	err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);
2782510babcSAndrew Lunn 	if (err)
2792510babcSAndrew Lunn 		return err;
2802510babcSAndrew Lunn 
2812510babcSAndrew Lunn 	/* NO_CPU being 0 inverts the meaning of the bit */
2822510babcSAndrew Lunn 	if (!no_cpu)
2832510babcSAndrew Lunn 		external = !external;
2842510babcSAndrew Lunn 
2852510babcSAndrew Lunn 	if (external)
2862510babcSAndrew Lunn 		val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
2872510babcSAndrew Lunn 	else
2882510babcSAndrew Lunn 		val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
2892510babcSAndrew Lunn 
2902510babcSAndrew Lunn 	return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);
2912510babcSAndrew Lunn }
292