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