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_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 */ 50 static 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 */ 76 static 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 */ 104 static 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 */ 125 static 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 */ 149 static 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 */ 169 static 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 */ 188 static 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 */ 212 static 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 230 const 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 */ 248 int 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 } 289