brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · 53a6d3e Raw
351 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support4 *5 * Copyright (c) 2008 Marvell Semiconductor6 *7 * Copyright (c) 2017 National Instruments8 *      Brandon Streiff <brandon.streiff@ni.com>9 */10 11#include "chip.h"12#include "global2.h"13 14/* Offset 0x1A: Scratch and Misc. Register */15static 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 35static 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_get_bit - get a bit46 * @chip: chip private data47 * @base_reg: base of scratch bits48 * @offset: index of bit within the register49 * @set: is bit set?50 */51static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,52					int base_reg, unsigned int offset,53					int *set)54{55	int reg = base_reg + (offset / 8);56	u8 mask = (1 << (offset & 0x7));57	u8 val;58	int err;59 60	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);61	if (err)62		return err;63 64	*set = !!(mask & val);65 66	return 0;67}68 69/**70 * mv88e6xxx_g2_scratch_set_bit - set (or clear) a bit71 * @chip: chip private data72 * @base_reg: base of scratch bits73 * @offset: index of bit within the register74 * @set: should this bit be set?75 *76 * Helper function for dealing with the direction and data registers.77 */78static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,79					int base_reg, unsigned int offset,80					int set)81{82	int reg = base_reg + (offset / 8);83	u8 mask = (1 << (offset & 0x7));84	u8 val;85	int err;86 87	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);88	if (err)89		return err;90 91	if (set)92		val |= mask;93	else94		val &= ~mask;95 96	return mv88e6xxx_g2_scratch_write(chip, reg, val);97}98 99/**100 * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin101 * @chip: chip private data102 * @pin: gpio index103 *104 * Return: 0 for low, 1 for high, negative error105 */106static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,107					      unsigned int pin)108{109	int val = 0;110	int err;111 112	err = mv88e6xxx_g2_scratch_get_bit(chip,113					   MV88E6352_G2_SCRATCH_GPIO_DATA0,114					   pin, &val);115	if (err)116		return err;117 118	return val;119}120 121/**122 * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin123 * @chip: chip private data124 * @pin: gpio index125 * @value: value to set126 */127static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,128					      unsigned int pin, int value)129{130	u8 mask = (1 << (pin & 0x7));131	int offset = (pin / 8);132	int reg;133 134	reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;135 136	if (value)137		chip->gpio_data[offset] |= mask;138	else139		chip->gpio_data[offset] &= ~mask;140 141	return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);142}143 144/**145 * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin146 * @chip: chip private data147 * @pin: gpio index148 *149 * Return: 0 for output, 1 for input.150 */151static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,152					     unsigned int pin)153{154	int val = 0;155	int err;156 157	err = mv88e6xxx_g2_scratch_get_bit(chip,158					   MV88E6352_G2_SCRATCH_GPIO_DIR0,159					   pin, &val);160	if (err)161		return err;162 163	return val;164}165 166/**167 * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin168 * @chip: chip private data169 * @pin: gpio index170 * @input: should the gpio be an input, or an output?171 */172static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,173					     unsigned int pin, bool input)174{175	int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :176			     MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);177 178	return mv88e6xxx_g2_scratch_set_bit(chip,179					    MV88E6352_G2_SCRATCH_GPIO_DIR0,180					    pin, value);181}182 183/**184 * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting185 * @chip: chip private data186 * @pin: gpio index187 * @func: function number188 *189 * Note that the function numbers themselves may vary by chipset.190 */191static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,192					      unsigned int pin, int *func)193{194	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);195	int offset = (pin & 0x1) ? 4 : 0;196	u8 mask = (0x7 << offset);197	int err;198	u8 val;199 200	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);201	if (err)202		return err;203 204	*func = (val & mask) >> offset;205 206	return 0;207}208 209/**210 * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting211 * @chip: chip private data212 * @pin: gpio index213 * @func: function number214 */215static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,216					      unsigned int pin, int func)217{218	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);219	int offset = (pin & 0x1) ? 4 : 0;220	u8 mask = (0x7 << offset);221	int err;222	u8 val;223 224	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);225	if (err)226		return err;227 228	val = (val & ~mask) | ((func & mask) << offset);229 230	return mv88e6xxx_g2_scratch_write(chip, reg, val);231}232 233const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {234	.get_data = mv88e6352_g2_scratch_gpio_get_data,235	.set_data = mv88e6352_g2_scratch_gpio_set_data,236	.get_dir = mv88e6352_g2_scratch_gpio_get_dir,237	.set_dir = mv88e6352_g2_scratch_gpio_set_dir,238	.get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,239	.set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,240};241 242/**243 * mv88e6390_g2_scratch_gpio_set_smi - set gpio muxing for external smi244 * @chip: chip private data245 * @external: set mux for external smi, or free for gpio usage246 *247 * Some mv88e6xxx models have GPIO pins that may be configured as248 * an external SMI interface, or they may be made free for other249 * GPIO uses.250 */251int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,252				      bool external)253{254	int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;255	int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1;256	int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2;257	bool no_cpu;258	u8 p0_mode;259	int err;260	u8 val;261 262	err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val);263	if (err)264		return err;265 266	p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK;267 268	if (p0_mode == 0x01 || p0_mode == 0x02)269		return -EBUSY;270 271	err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val);272	if (err)273		return err;274 275	no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU);276 277	err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);278	if (err)279		return err;280 281	/* NO_CPU being 0 inverts the meaning of the bit */282	if (!no_cpu)283		external = !external;284 285	if (external)286		val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;287	else288		val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;289 290	return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);291}292 293/**294 * mv88e6393x_g2_scratch_gpio_set_smi - set gpio muxing for external smi295 * @chip: chip private data296 * @external: set mux for external smi, or free for gpio usage297 *298 * MV88E6191X/6193X/6393X GPIO pins 9 and 10 can be configured as an299 * external SMI interface or as regular GPIO-s.300 *301 * They however have a different register layout then the existing302 * function.303 */304 305int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,306				       bool external)307{308	int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;309	int err;310	u8 val;311 312	err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);313	if (err)314		return err;315 316	if (external)317		val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;318	else319		val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;320 321	return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);322}323 324/**325 * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes326 * @chip: chip private data327 * @port: port number to check for serdes328 *329 * Indicates whether the port may have a serdes attached according to the330 * pin strapping. Returns negative error number, 0 if the port is not331 * configured to have a serdes, and 1 if the port is configured to have a332 * serdes attached.333 */334int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port)335{336	u8 config3, p;337	int err;338 339	err = mv88e6xxx_g2_scratch_read(chip, MV88E6352_G2_SCRATCH_CONFIG_DATA3,340					&config3);341	if (err)342		return err;343 344	if (config3 & MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL)345		p = 5;346	else347		p = 4;348 349	return port == p;350}351