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 }; 241*2510babcSAndrew Lunn 242*2510babcSAndrew Lunn /** 243*2510babcSAndrew Lunn * mv88e6xxx_g2_gpio_set_smi - set gpio muxing for external smi 244*2510babcSAndrew Lunn * @chip: chip private data 245*2510babcSAndrew Lunn * @external: set mux for external smi, or free for gpio usage 246*2510babcSAndrew Lunn * 247*2510babcSAndrew Lunn * Some mv88e6xxx models have GPIO pins that may be configured as 248*2510babcSAndrew Lunn * an external SMI interface, or they may be made free for other 249*2510babcSAndrew Lunn * GPIO uses. 250*2510babcSAndrew Lunn */ 251*2510babcSAndrew Lunn int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, 252*2510babcSAndrew Lunn bool external) 253*2510babcSAndrew Lunn { 254*2510babcSAndrew Lunn int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; 255*2510babcSAndrew Lunn int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1; 256*2510babcSAndrew Lunn int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2; 257*2510babcSAndrew Lunn bool no_cpu; 258*2510babcSAndrew Lunn u8 p0_mode; 259*2510babcSAndrew Lunn int err; 260*2510babcSAndrew Lunn u8 val; 261*2510babcSAndrew Lunn 262*2510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val); 263*2510babcSAndrew Lunn if (err) 264*2510babcSAndrew Lunn return err; 265*2510babcSAndrew Lunn 266*2510babcSAndrew Lunn p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK; 267*2510babcSAndrew Lunn 268*2510babcSAndrew Lunn if (p0_mode == 0x01 || p0_mode == 0x02) 269*2510babcSAndrew Lunn return -EBUSY; 270*2510babcSAndrew Lunn 271*2510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val); 272*2510babcSAndrew Lunn if (err) 273*2510babcSAndrew Lunn return err; 274*2510babcSAndrew Lunn 275*2510babcSAndrew Lunn no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU); 276*2510babcSAndrew Lunn 277*2510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val); 278*2510babcSAndrew Lunn if (err) 279*2510babcSAndrew Lunn return err; 280*2510babcSAndrew Lunn 281*2510babcSAndrew Lunn /* NO_CPU being 0 inverts the meaning of the bit */ 282*2510babcSAndrew Lunn if (!no_cpu) 283*2510babcSAndrew Lunn external = !external; 284*2510babcSAndrew Lunn 285*2510babcSAndrew Lunn if (external) 286*2510babcSAndrew Lunn val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 287*2510babcSAndrew Lunn else 288*2510babcSAndrew Lunn val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 289*2510babcSAndrew Lunn 290*2510babcSAndrew Lunn return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); 291*2510babcSAndrew Lunn } 292