summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2023-01-11 14:29:50 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2023-01-12 15:57:51 +0100
commitcbf1e375816d2e819c01be09f8c7cbc133131d85 (patch)
treeb34f5a780108aaa1fe13fd97d87a286917737096 /drivers/net
parent6096c133e989c4a14aac173e94d86412bb92957b (diff)
downloadbarebox-cbf1e375816d2e819c01be09f8c7cbc133131d85.tar.gz
net: dsa: ksz9477: switch to regmap_init_spi
Linux uses three regmaps for the KSZ9477 DSA driver, one for each of the three access sizes supported by the chip. While this increases overhead a bit, it'll allow us in future to extend the driver seamlessly for i2c support. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Link: https://lore.barebox.org/20230111132956.1153359-6-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/ksz9477.c150
-rw-r--r--drivers/net/ksz_common.h153
3 files changed, 180 insertions, 124 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2dafd9c7a8..e881b671d0 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -309,6 +309,7 @@ config DRIVER_NET_KSZ8873
config DRIVER_NET_KSZ9477
bool "KSZ9477 switch driver"
depends on SPI
+ select REGMAP_SPI
help
This option enables support for the Microchip KSZ9477
switch chip.
diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
index 99deaf6381..cddd5edb0c 100644
--- a/drivers/net/ksz9477.c
+++ b/drivers/net/ksz9477.c
@@ -7,13 +7,12 @@
#include <net.h>
#include <platform_data/ksz9477_reg.h>
#include <spi/spi.h>
+#include "ksz_common.h"
/* SPI frame opcodes */
-#define KS_SPIOP_RD 3
-#define KS_SPIOP_WR 2
#define SPI_ADDR_SHIFT 24
-#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1)
+#define SPI_ADDR_ALIGN 3
#define SPI_TURNAROUND_SHIFT 5
#define GBIT_SUPPORT BIT(0)
@@ -21,127 +20,8 @@
#define IS_9893 BIT(2)
#define KSZ9477_PHY_ERRATA BIT(3)
-struct ksz_switch {
- struct spi_device *spi;
- struct dsa_switch ds;
- struct device *dev;
- int phy_port_cnt;
- u32 chip_id;
- u8 features;
-};
-
-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[2];
-
- txbuf[0] = reg & SPI_ADDR_MASK;
- txbuf[0] |= (KS_SPIOP_WR << SPI_ADDR_SHIFT);
- txbuf[0] <<= SPI_TURNAROUND_SHIFT;
- txbuf[0] = cpu_to_be32(*txbuf);
- memcpy(&txbuf[1], val, len);
-
- return spi_write(spi, txbuf, 4 + len);
-}
-
-static int ksz_read8(struct ksz_switch *priv, u32 reg, u8 *val)
-{
- return ksz9477_spi_read_reg(priv->spi, reg, val, 1);
-}
-
-static int ksz_write8(struct ksz_switch *priv, u32 reg, u8 value)
-{
- return ksz9477_spi_write_reg(priv->spi, reg, &value, 1);
-}
-
-static int ksz_read16(struct ksz_switch *priv, u32 reg, u16 *val)
-{
- int ret = ksz9477_spi_read_reg(priv->spi, reg, (u8 *)val, 2);
-
- if (!ret)
- *val = be16_to_cpu(*val);
-
- return ret;
-}
-
-static int ksz_write16(struct ksz_switch *priv, u32 reg, u16 value)
-{
- struct spi_device *spi = priv->spi;
-
- value = cpu_to_be16(value);
- return ksz9477_spi_write_reg(spi, reg, (u8 *)&value, 2);
-}
-
-static int ksz_read32(struct ksz_switch *priv, u32 reg, u32 *val)
-{
- int ret = ksz9477_spi_read_reg(priv->spi, reg, (u8 *)val, 4);
-
- if (!ret)
- *val = be32_to_cpu(*val);
-
- return ret;
-}
-
-static int ksz_write32(struct ksz_switch *priv, u32 reg, u32 value)
-{
- struct spi_device *spi = priv->spi;
-
- value = cpu_to_be32(value);
- return ksz9477_spi_write_reg(spi, reg, (u8 *)&value, 4);
-}
-
-static void ksz_cfg(struct ksz_switch *priv, u32 addr, u8 bits, bool set)
-{
- u8 data;
-
- ksz_read8(priv, addr, &data);
- if (set)
- data |= bits;
- else
- data &= ~bits;
- ksz_write8(priv, addr, data);
-}
-
-static int ksz_pread8(struct ksz_switch *priv, int port, int reg, u8 *val)
-{
- return ksz_read8(priv, PORT_CTRL_ADDR(port, reg), val);
-}
-
-static int ksz_pwrite8(struct ksz_switch *priv, int port, int reg, u8 val)
-{
- return ksz_write8(priv, PORT_CTRL_ADDR(port, reg), val);
-}
-
-static int ksz_pread16(struct ksz_switch *priv, int port, int reg, u16 *val)
-{
- return ksz_read16(priv, PORT_CTRL_ADDR(port, reg), val);
-}
-
-static int ksz_pwrite16(struct ksz_switch *priv, int port, int reg, u16 val)
-{
- return ksz_write16(priv, PORT_CTRL_ADDR(port, reg), val);
-}
-
-static int ksz_pwrite32(struct ksz_switch *priv, int port, int reg, u32 val)
-{
- return ksz_write32(priv, PORT_CTRL_ADDR(port, reg), val);
-}
+KSZ_REGMAP_TABLE(ksz9477_spi, 32, SPI_ADDR_SHIFT,
+ SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg)
{
@@ -503,6 +383,24 @@ static int ksz_default_setup(struct ksz_switch *priv)
return 0;
}
+static int microchip_switch_regmap_init(struct ksz_switch *priv)
+{
+ const struct regmap_config *cfg;
+ int i;
+
+ cfg = ksz9477_spi_regmap_config;
+
+ for (i = 0; i < KSZ_REGMAP_ENTRY_COUNT; i++) {
+ priv->regmap[i] = regmap_init_spi(priv->spi, &cfg[i]);
+ if (IS_ERR(priv->regmap[i]))
+ return dev_err_probe(priv->dev, PTR_ERR(priv->regmap[i]),
+ "Failed to initialize regmap%i\n",
+ cfg[i].val_bits);
+ }
+
+ return 0;
+}
+
static int microchip_switch_probe(struct device *dev)
{
struct ksz_switch *priv;
@@ -518,6 +416,10 @@ static int microchip_switch_probe(struct device *dev)
priv->spi->mode = SPI_MODE_0;
priv->spi->bits_per_word = 8;
+ ret = microchip_switch_regmap_init(priv);
+ if (ret)
+ return ret;
+
gpio = gpiod_get(dev, "reset", GPIOF_OUT_INIT_ACTIVE);
if (gpio_is_valid(gpio)) {
mdelay(1);
diff --git a/drivers/net/ksz_common.h b/drivers/net/ksz_common.h
new file mode 100644
index 0000000000..01447b6141
--- /dev/null
+++ b/drivers/net/ksz_common.h
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef NET_KSZ_COMMON_H_
+#define NET_KSZ_COMMON_H_
+
+#include <linux/swab.h>
+#include <regmap.h>
+#include <linux/bitops.h>
+#include <platform_data/ksz9477_reg.h>
+
+struct ksz_switch {
+ struct spi_device *spi;
+ struct dsa_switch ds;
+ struct device *dev;
+ int phy_port_cnt;
+ u32 chip_id;
+ u8 features;
+ struct regmap *regmap[3];
+};
+
+static inline int ksz_read8(struct ksz_switch *priv, u32 reg, u8 *val)
+{
+ unsigned int value;
+ int ret = regmap_read(priv->regmap[0], reg, &value);
+
+ *val = value;
+ return ret;
+}
+
+static inline int ksz_read16(struct ksz_switch *priv, u32 reg, u16 *val)
+{
+ unsigned int value;
+ int ret = regmap_read(priv->regmap[1], reg, &value);
+
+ *val = value;
+ return ret;
+}
+
+static inline int ksz_read32(struct ksz_switch *priv, u32 reg, u32 *val)
+{
+ unsigned int value;
+ int ret = regmap_read(priv->regmap[2], reg, &value);
+
+ *val = value;
+ return ret;
+}
+
+static inline int ksz_read64(struct ksz_switch *priv, u32 reg, u64 *val)
+{
+ u32 value[2];
+ int ret;
+
+ ret = regmap_bulk_read(priv->regmap[2], reg, value, 2);
+ if (!ret)
+ *val = (u64)value[0] << 32 | value[1];
+
+ return ret;
+}
+
+static inline int ksz_write8(struct ksz_switch *priv, u32 reg, u8 value)
+{
+ return regmap_write(priv->regmap[0], reg, value);
+}
+
+static inline int ksz_write16(struct ksz_switch *priv, u32 reg, u16 value)
+{
+ return regmap_write(priv->regmap[1], reg, value);
+}
+
+static inline int ksz_write32(struct ksz_switch *priv, u32 reg, u32 value)
+{
+ return regmap_write(priv->regmap[2], reg, value);
+}
+
+static inline int ksz_write64(struct ksz_switch *priv, u32 reg, u64 value)
+{
+ u32 val[2];
+
+ /* Ick! ToDo: Add 64bit R/W to regmap on 32bit systems */
+ value = swab64(value);
+ val[0] = swab32(value & 0xffffffffULL);
+ val[1] = swab32(value >> 32ULL);
+
+ return regmap_bulk_write(priv->regmap[2], reg, val, 2);
+}
+
+static inline int ksz_pread8(struct ksz_switch *priv, int port, int reg, u8 *val)
+{
+ return ksz_read8(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static inline int ksz_pwrite8(struct ksz_switch *priv, int port, int reg, u8 val)
+{
+ return ksz_write8(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static inline int ksz_pread16(struct ksz_switch *priv, int port, int reg, u16 *val)
+{
+ return ksz_read16(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static inline int ksz_pwrite16(struct ksz_switch *priv, int port, int reg, u16 val)
+{
+ return ksz_write16(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static inline int ksz_pwrite32(struct ksz_switch *priv, int port, int reg, u32 val)
+{
+ return ksz_write32(priv, PORT_CTRL_ADDR(port, reg), val);
+}
+
+static void ksz_cfg(struct ksz_switch *priv, u32 addr, u8 bits, bool set)
+{
+ regmap_update_bits(priv->regmap[0], addr, bits, set ? bits : 0);
+}
+
+/* Regmap tables generation */
+#define KSZ_SPI_OP_RD 3
+#define KSZ_SPI_OP_WR 2
+
+#define swabnot_used(x) 0
+
+#define KSZ_SPI_OP_FLAG_MASK(opcode, swp, regbits, regpad) \
+ swab##swp((opcode) << ((regbits) + (regpad)))
+
+#define KSZ_REGMAP_ENTRY_COUNT 3
+
+#define KSZ_REGMAP_ENTRY(width, swp, regbits, regpad, regalign) \
+ { \
+ .name = #width, \
+ .val_bits = (width), \
+ .reg_stride = 1, \
+ .reg_bits = (regbits) + (regalign), \
+ .pad_bits = (regpad), \
+ .max_register = BIT(regbits) - 1, \
+ .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_COUNT] = { \
+ 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