123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
- *
- * Copyright (c) 2008 Marvell Semiconductor
- *
- * Copyright (c) 2017 National Instruments
- * Brandon Streiff <[email protected]>
- */
- #include "chip.h"
- #include "global2.h"
- /* Offset 0x1A: Scratch and Misc. Register */
- static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
- u8 *data)
- {
- u16 value;
- int err;
- err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
- reg << 8);
- if (err)
- return err;
- err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
- if (err)
- return err;
- *data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
- return 0;
- }
- static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
- u8 data)
- {
- u16 value = (reg << 8) | data;
- return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
- MV88E6XXX_G2_SCRATCH_MISC_UPDATE | value);
- }
- /**
- * mv88e6xxx_g2_scratch_get_bit - get a bit
- * @chip: chip private data
- * @base_reg: base of scratch bits
- * @offset: index of bit within the register
- * @set: is bit set?
- */
- static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
- int base_reg, unsigned int offset,
- int *set)
- {
- int reg = base_reg + (offset / 8);
- u8 mask = (1 << (offset & 0x7));
- u8 val;
- int err;
- err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
- if (err)
- return err;
- *set = !!(mask & val);
- return 0;
- }
- /**
- * mv88e6xxx_g2_scratch_set_bit - set (or clear) a bit
- * @chip: chip private data
- * @base_reg: base of scratch bits
- * @offset: index of bit within the register
- * @set: should this bit be set?
- *
- * Helper function for dealing with the direction and data registers.
- */
- static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
- int base_reg, unsigned int offset,
- int set)
- {
- int reg = base_reg + (offset / 8);
- u8 mask = (1 << (offset & 0x7));
- u8 val;
- int err;
- err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
- if (err)
- return err;
- if (set)
- val |= mask;
- else
- val &= ~mask;
- return mv88e6xxx_g2_scratch_write(chip, reg, val);
- }
- /**
- * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
- * @chip: chip private data
- * @pin: gpio index
- *
- * Return: 0 for low, 1 for high, negative error
- */
- static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
- unsigned int pin)
- {
- int val = 0;
- int err;
- err = mv88e6xxx_g2_scratch_get_bit(chip,
- MV88E6352_G2_SCRATCH_GPIO_DATA0,
- pin, &val);
- if (err)
- return err;
- return val;
- }
- /**
- * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
- * @chip: chip private data
- * @pin: gpio index
- * @value: value to set
- */
- static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
- unsigned int pin, int value)
- {
- u8 mask = (1 << (pin & 0x7));
- int offset = (pin / 8);
- int reg;
- reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
- if (value)
- chip->gpio_data[offset] |= mask;
- else
- chip->gpio_data[offset] &= ~mask;
- return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
- }
- /**
- * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
- * @chip: chip private data
- * @pin: gpio index
- *
- * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
- */
- static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
- unsigned int pin)
- {
- int val = 0;
- int err;
- err = mv88e6xxx_g2_scratch_get_bit(chip,
- MV88E6352_G2_SCRATCH_GPIO_DIR0,
- pin, &val);
- if (err)
- return err;
- return val;
- }
- /**
- * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
- * @chip: chip private data
- * @pin: gpio index
- * @input: should the gpio be an input, or an output?
- */
- static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,
- unsigned int pin, bool input)
- {
- int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :
- MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);
- return mv88e6xxx_g2_scratch_set_bit(chip,
- MV88E6352_G2_SCRATCH_GPIO_DIR0,
- pin, value);
- }
- /**
- * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting
- * @chip: chip private data
- * @pin: gpio index
- * @func: function number
- *
- * Note that the function numbers themselves may vary by chipset.
- */
- static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,
- unsigned int pin, int *func)
- {
- int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
- int offset = (pin & 0x1) ? 4 : 0;
- u8 mask = (0x7 << offset);
- int err;
- u8 val;
- err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
- if (err)
- return err;
- *func = (val & mask) >> offset;
- return 0;
- }
- /**
- * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting
- * @chip: chip private data
- * @pin: gpio index
- * @func: function number
- */
- static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,
- unsigned int pin, int func)
- {
- int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
- int offset = (pin & 0x1) ? 4 : 0;
- u8 mask = (0x7 << offset);
- int err;
- u8 val;
- err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
- if (err)
- return err;
- val = (val & ~mask) | ((func & mask) << offset);
- return mv88e6xxx_g2_scratch_write(chip, reg, val);
- }
- const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {
- .get_data = mv88e6352_g2_scratch_gpio_get_data,
- .set_data = mv88e6352_g2_scratch_gpio_set_data,
- .get_dir = mv88e6352_g2_scratch_gpio_get_dir,
- .set_dir = mv88e6352_g2_scratch_gpio_set_dir,
- .get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,
- .set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,
- };
- /**
- * mv88e6xxx_g2_scratch_gpio_set_smi - set gpio muxing for external smi
- * @chip: chip private data
- * @external: set mux for external smi, or free for gpio usage
- *
- * Some mv88e6xxx models have GPIO pins that may be configured as
- * an external SMI interface, or they may be made free for other
- * GPIO uses.
- */
- int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
- bool external)
- {
- int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;
- int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1;
- int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2;
- bool no_cpu;
- u8 p0_mode;
- int err;
- u8 val;
- err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val);
- if (err)
- return err;
- p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK;
- if (p0_mode == 0x01 || p0_mode == 0x02)
- return -EBUSY;
- err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val);
- if (err)
- return err;
- no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU);
- err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);
- if (err)
- return err;
- /* NO_CPU being 0 inverts the meaning of the bit */
- if (!no_cpu)
- external = !external;
- if (external)
- val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
- else
- val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
- return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);
- }
- /**
- * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes
- * @chip: chip private data
- * @port: port number to check for serdes
- *
- * Indicates whether the port may have a serdes attached according to the
- * pin strapping. Returns negative error number, 0 if the port is not
- * configured to have a serdes, and 1 if the port is configured to have a
- * serdes attached.
- */
- int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
- {
- u8 config3, p;
- int err;
- err = mv88e6xxx_g2_scratch_read(chip, MV88E6352_G2_SCRATCH_CONFIG_DATA3,
- &config3);
- if (err)
- return err;
- if (config3 & MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL)
- p = 5;
- else
- p = 4;
- return port == p;
- }
|