Commit c881e10e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-dsa-microchip-Convert-to-regmap'



Marek Vasut says:

====================
net: dsa: microchip: Convert to regmap

This patchset converts KSZ9477 switch driver to regmap.

This was tested with extra patches on KSZ8795. This was also tested
on KSZ9477 on Microchip KSZ9477EVB board, which I now have.
====================

Signed-off-by: default avatarMarek Vasut <marex@denx.de>
parents 1c57de69 d4bcd99c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13,5 +13,6 @@ menuconfig NET_DSA_MICROCHIP_KSZ9477
config NET_DSA_MICROCHIP_KSZ9477_SPI
	tristate "KSZ9477 series SPI connected switch driver"
	depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
	select REGMAP_SPI
	help
	  Select to enable support for registering switches configured through SPI.
+15 −20
Original line number Diff line number Diff line
@@ -65,33 +65,28 @@ static const struct {
	{ 0x83, "tx_discards" },
};

static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{
	u32 data;
	regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
}

	ksz_read32(dev, addr, &data);
	if (set)
		data |= bits;
	else
		data &= ~bits;
	ksz_write32(dev, addr, data);
static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
			 bool set)
{
	regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset),
			   bits, set ? bits : 0);
}

static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
{
	regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0);
}

static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset,
			       u32 bits, bool set)
{
	u32 addr;
	u32 data;

	addr = PORT_CTRL_ADDR(port, offset);
	ksz_read32(dev, addr, &data);

	if (set)
		data |= bits;
	else
		data &= ~bits;

	ksz_write32(dev, addr, data);
	regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset),
			   bits, set ? bits : 0);
}

static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton,
+19 −95
Original line number Diff line number Diff line
@@ -10,119 +10,43 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>

#include "ksz_priv.h"
#include "ksz_spi.h"

/* SPI frame opcodes */
#define KS_SPIOP_RD			3
#define KS_SPIOP_WR			2
#include "ksz_common.h"

#define SPI_ADDR_SHIFT			24
#define SPI_ADDR_MASK			(BIT(SPI_ADDR_SHIFT) - 1)
#define SPI_ADDR_ALIGN			3
#define SPI_TURNAROUND_SHIFT		5

/* Enough to read all switch port registers. */
#define SPI_TX_BUF_LEN			0x100

static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val,
				unsigned int len)
{
	u32 txbuf;
	int ret;

	txbuf = reg & SPI_ADDR_MASK;
	txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT;
	txbuf <<= SPI_TURNAROUND_SHIFT;
	txbuf = cpu_to_be32(txbuf);

	ret = spi_write_then_read(spi, &txbuf, 4, val, len);
	return ret;
}

static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
				 unsigned int len)
{
	u32 *txbuf = (u32 *)val;

	*txbuf = reg & SPI_ADDR_MASK;
	*txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT);
	*txbuf <<= SPI_TURNAROUND_SHIFT;
	*txbuf = cpu_to_be32(*txbuf);

	return spi_write(spi, txbuf, 4 + len);
}

static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
			unsigned int len)
{
	struct spi_device *spi = dev->priv;

	return ksz9477_spi_read_reg(spi, reg, data, len);
}

static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data,
			 unsigned int len)
{
	struct spi_device *spi = dev->priv;

	if (len > SPI_TX_BUF_LEN)
		len = SPI_TX_BUF_LEN;
	memcpy(&dev->txbuf[4], data, len);
	return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len);
}

static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val)
{
	int ret;

	*val = 0;
	ret = ksz_spi_read(dev, reg, (u8 *)val, 3);
	if (!ret) {
		*val = be32_to_cpu(*val);
		/* convert to 24bit */
		*val >>= 8;
	}

	return ret;
}

static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value)
{
	/* make it to big endian 24bit from MSB */
	value <<= 8;
	value = cpu_to_be32(value);
	return ksz_spi_write(dev, reg, &value, 3);
}

static const struct ksz_io_ops ksz9477_spi_ops = {
	.read8 = ksz_spi_read8,
	.read16 = ksz_spi_read16,
	.read24 = ksz_spi_read24,
	.read32 = ksz_spi_read32,
	.write8 = ksz_spi_write8,
	.write16 = ksz_spi_write16,
	.write24 = ksz_spi_write24,
	.write32 = ksz_spi_write32,
	.get = ksz_spi_get,
	.set = ksz_spi_set,
};
KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT,
		 SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);

static int ksz9477_spi_probe(struct spi_device *spi)
{
	struct ksz_device *dev;
	int ret;
	int i, ret;

	dev = ksz_switch_alloc(&spi->dev, &ksz9477_spi_ops, spi);
	dev = ksz_switch_alloc(&spi->dev, spi);
	if (!dev)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
		dev->regmap[i] = devm_regmap_init_spi(spi,
					&ksz9477_regmap_config[i]);
		if (IS_ERR(dev->regmap[i])) {
			ret = PTR_ERR(dev->regmap[i]);
			dev_err(&spi->dev,
				"Failed to initialize regmap%i: %d\n",
				ksz9477_regmap_config[i].val_bits, ret);
			return ret;
		}
	}

	if (spi->dev.platform_data)
		dev->pdata = spi->dev.platform_data;

	dev->txbuf = devm_kzalloc(dev->dev, 4 + SPI_TX_BUF_LEN, GFP_KERNEL);

	ret = ksz9477_switch_register(dev);

	/* Main DSA driver may not be started yet. */
+1 −5
Original line number Diff line number Diff line
@@ -396,9 +396,7 @@ void ksz_disable_port(struct dsa_switch *ds, int port)
}
EXPORT_SYMBOL_GPL(ksz_disable_port);

struct ksz_device *ksz_switch_alloc(struct device *base,
				    const struct ksz_io_ops *ops,
				    void *priv)
struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
{
	struct dsa_switch *ds;
	struct ksz_device *swdev;
@@ -416,7 +414,6 @@ struct ksz_device *ksz_switch_alloc(struct device *base,

	swdev->ds = ds;
	swdev->priv = priv;
	swdev->ops = ops;

	return swdev;
}
@@ -442,7 +439,6 @@ int ksz_switch_register(struct ksz_device *dev,
	}

	mutex_init(&dev->dev_mutex);
	mutex_init(&dev->reg_mutex);
	mutex_init(&dev->stats_mutex);
	mutex_init(&dev->alu_mutex);
	mutex_init(&dev->vlan_mutex);
+46 −111
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef __KSZ_COMMON_H
#define __KSZ_COMMON_H

#include <linux/regmap.h>

void ksz_port_cleanup(struct ksz_device *dev, int port);
void ksz_update_port_member(struct ksz_device *dev, int port);
void ksz_init_mib_timer(struct ksz_device *dev);
@@ -41,114 +43,44 @@ void ksz_disable_port(struct dsa_switch *ds, int port);

static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->read8(dev, reg, val);
	mutex_unlock(&dev->reg_mutex);
	unsigned int value;
	int ret = regmap_read(dev->regmap[0], reg, &value);

	*val = value;
	return ret;
}

static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->read16(dev, reg, val);
	mutex_unlock(&dev->reg_mutex);

	return ret;
}

static inline int ksz_read24(struct ksz_device *dev, u32 reg, u32 *val)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->read24(dev, reg, val);
	mutex_unlock(&dev->reg_mutex);
	unsigned int value;
	int ret = regmap_read(dev->regmap[1], reg, &value);

	*val = value;
	return ret;
}

static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->read32(dev, reg, val);
	mutex_unlock(&dev->reg_mutex);
	unsigned int value;
	int ret = regmap_read(dev->regmap[2], reg, &value);

	*val = value;
	return ret;
}

static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->write8(dev, reg, value);
	mutex_unlock(&dev->reg_mutex);

	return ret;
	return regmap_write(dev->regmap[0], reg, value);
}

static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->write16(dev, reg, value);
	mutex_unlock(&dev->reg_mutex);

	return ret;
}

static inline int ksz_write24(struct ksz_device *dev, u32 reg, u32 value)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->write24(dev, reg, value);
	mutex_unlock(&dev->reg_mutex);

	return ret;
	return regmap_write(dev->regmap[1], reg, value);
}

static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->write32(dev, reg, value);
	mutex_unlock(&dev->reg_mutex);

	return ret;
}

static inline int ksz_get(struct ksz_device *dev, u32 reg, void *data,
			  size_t len)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->get(dev, reg, data, len);
	mutex_unlock(&dev->reg_mutex);

	return ret;
}

static inline int ksz_set(struct ksz_device *dev, u32 reg, void *data,
			  size_t len)
{
	int ret;

	mutex_lock(&dev->reg_mutex);
	ret = dev->ops->set(dev, reg, data, len);
	mutex_unlock(&dev->reg_mutex);

	return ret;
	return regmap_write(dev->regmap[2], reg, value);
}

static inline void ksz_pread8(struct ksz_device *dev, int port, int offset,
@@ -187,35 +119,6 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset,
	ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data);
}

static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{
	u8 data;

	ksz_read8(dev, addr, &data);
	if (set)
		data |= bits;
	else
		data &= ~bits;
	ksz_write8(dev, addr, data);
}

static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
			 bool set)
{
	u32 addr;
	u8 data;

	addr = dev->dev_ops->get_port_addr(port, offset);
	ksz_read8(dev, addr, &data);

	if (set)
		data |= bits;
	else
		data &= ~bits;

	ksz_write8(dev, addr, data);
}

struct ksz_poll_ctx {
	struct ksz_device *dev;
	int port;
@@ -230,4 +133,36 @@ static inline u32 ksz_pread32_poll(struct ksz_poll_ctx *ctx)
	return data;
}

/* Regmap tables generation */
#define KSZ_SPI_OP_RD		3
#define KSZ_SPI_OP_WR		2

#define KSZ_SPI_OP_FLAG_MASK(opcode, swp, regbits, regpad)		\
	swab##swp((opcode) << ((regbits) + (regpad)))

#define KSZ_REGMAP_ENTRY(width, swp, regbits, regpad, regalign)		\
	{								\
		.val_bits = (width),					\
		.reg_stride = (width) / 8,				\
		.reg_bits = (regbits) + (regalign),			\
		.pad_bits = (regpad),					\
		.max_register = BIT(regbits) - 1,			\
		.cache_type = REGCACHE_NONE,				\
		.read_flag_mask =					\
			KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_RD, swp,	\
					     regbits, regpad),		\
		.write_flag_mask =					\
			KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp,	\
					     regbits, regpad),		\
		.reg_format_endian = REGMAP_ENDIAN_BIG,			\
		.val_format_endian = REGMAP_ENDIAN_BIG			\
	}

#define KSZ_REGMAP_TABLE(ksz, swp, regbits, regpad, regalign)		\
	static const struct regmap_config ksz##_regmap_config[] = {	\
		KSZ_REGMAP_ENTRY(8, swp, (regbits), (regpad), (regalign)), \
		KSZ_REGMAP_ENTRY(16, swp, (regbits), (regpad), (regalign)), \
		KSZ_REGMAP_ENTRY(32, swp, (regbits), (regpad), (regalign)), \
	}

#endif
Loading